本文延续上一篇博文,继续介绍推荐离线层的一些策略设计
背景
本文主要介绍关于推荐推荐策略的设计 , 以及简单介绍推荐中常用的ABtest分流验证策略(好坏)的方法
本项目的实现代码在: Recommend Offline
离线层策略设计
上一篇文章中简要提到了,我们的设计从大到小,按照如下几个等级称呼
1 | 产品线 --> 策略 --> 模型(算法) |
解释如下:一个产品线下可以配置多个策略,一个策略可以是单个模型(算法)计算得到的结果,也可以是混合得到
ABtest在其中的位置:对某个产品线中的多个策略,进行流量划分
反馈:根据日志采集的结果指标,可视化之后对比各个策略的表现,调整ABtest中的流量划分,使得推荐效果最大化,单个策略则需要调整各个模型的占比
大体逻辑如下图

设计实现
那有了以上说的内容,我们将其逐步实现,以下我们均使用音乐推荐相关的维度来进行说明
model(算法)
1234567891011121314151617181920 | all_model=[{ "id":18, "name":"cf_new", #算法名,用作解释 "version":"1.0.0", #版本号,暂未使用 "source":"1", #单一算法的策略值,不能与混合策略重复 "struct":"zset", #redis中存储数据类型,一般zset "key":"cf_songnw_songid" #redis中存储的key格式,一般取得其前缀,拼接对应类型的基础数据(songid,albumid,singerid)},{ "id":19, "name":"lrc_simiSong", "version":"1.0.0", "source":"1", "struct":"zset", "key":"lrc_simiSong_songid"},{ .... }, #新增model{ .... }] |
以上定义的一个model需要定义的部分内容,由于我们只需要使用它,生成它的算法不作讨论,所以这部分内容写在配置文件中即可,按照代码中说明添加即可
strategy(策略)
123456789101112131415161718192021 | product_strategy = { "linear_similar_song":{ "name":"linear_similar_song", "class":"song", #使用哪种类型的rdd(song,album,singer),基础数据 "key":"abtest_simSong_songid", #合并策略灌入redis 的结果key "source":23, "rerankid":2, "strategy":[ #策略 混合多种model { "modelid":18, "weight":2 }, { "modelid":19, "weight":2 } ] },大专栏 听云推荐系统贰n> "xxxxxx":{}, #新增策略 "xxxxxx":{}} |
由于本项目在混合离线数据的时候,使用到了spark去获取并合并需要的算法结果,所以我们需要指定class – 表明加载哪种类型的基础数据(生成spark使用的rdd),去获取对应结果的redis数据整合
1234567 | 比如我需要取得是相似歌曲,即 -- 歌曲关联歌曲 那对应的rdd class是: song , 因为是: song -- song 此时对应的strategy中配置的基础model应该也都是: song -- song 的算法,这个是我们主动配置的,比如上面代码中的: cf_new -- cf_songnw_songid , 这个redis key中存放的是某首歌曲根据cf_new这个算法得到的相似歌曲 |
一般某个算法得到的离线结果都是list类型的,在redis中存储的格式为zset,我们可以使用zrange方法取到
spark在这里相当于是一个加速的效果,使得混合大量离线数据结果的效率变快.
实际数据说明
假设我需要知道一首歌: 《星月神话》的相似歌曲, 这首歌的songid是545076619, 存储在本地的 song_dict_path=”song.id.dat” 文件中
这时候我们需要使用spark读取class == song 类型的基础数据, 将其load成rdd(需了解spark中rdd的概念,简单来说就是spark的一种数据定义,使用其能方便地利用内存集群去快速操作数据),我们的操作是查询每个歌曲关联的算法的redis结果,取出数据然后按照权重配置来合并并重新排序
我们可以看到linear_similar_song(相似歌曲)的策略中有两个算法:18 / 19 , 比重均是2, 继续去看all_model 中modelid 18 和 19 的算法, 是:cf_new 和 lrc_simiSong ,那么对应的redis 的结果数据应该可按照如下方法查询到
1234567 | 127.0.0.1:6379> zrange cf_songnw_545076619 0 -1 withscores1) "545076365"2) "0.6"127.0.0.1:6379> zrange lrc_simiSong_545076619 0 -1 withscores1) "545076365"2) "0.8" |
为了方便我只列举了同一首歌曲的score值,这里计算的过程如下:
123456789 | model name songid : scorecf_songnw_545076619 545076365 : 0.6lrc_simiSong_545076619 545076365 : 0.8合并相同值的权重(weight = 2),和歌曲545076365 的关联最终score值(0.6 * 2 + 0.8 * 2) / (2 + 2) = 0.7 |
得到了最终的结果,我们就可以将其灌入redis,指定一个新的key值,查询结果如下
123 | 127.0.0.1:6379> zrange abtest_simSong_545076619 0 -1 withscores1) "545076365"2) "0.7" |
可以看到对应的:545076619 – 545076365 的final score值是0.7
ABtest
概念
一种网站优化的方法,通过科学的:实验设计,采样样本代表性,流量分割,小流量测试等方式 , 来获取具有代表性的实验结论,并确信改结论推广到全部流量可信。
简单来说:为同一个目标制定两套方案 (比如同一个网页),让一部分的用户使用A , 另外一部分使用B , 记录下使用(反馈)的情况,比如点击率,停留时长等等指标,看哪个更符合设计
总结
关于ABtest这部分,就暂时不在这篇文章中再细聊,因为这部分一般都是在在线逻辑层去完成的,要想将其放到离线中,须新的设计,不仅仅是离线层能做的事情,还需要调整在线层使用数据的逻辑
以上关于算法混合的部分均已经自动化,只需要按照配置在base_conf.py中添加,并且主动将依赖的redis数据灌入,再运行脚本即可得到结果
但这部分数据仅仅只是按照配置将不同算法的数据结合的结果,要想得到更符合用户喜欢的结果,在线层还可以做的一些事:基于用户画像(喜好)二次排序 ,手动配置优质内容 …. 这些都是可选择的方法