浅谈NB推荐系统架构
导语:分享一种推荐系统架构(The Architecture Of NB Recommendation System),以及实际服务业务的时候遇到的一些问题和解决,可能比较粗糙,但可供参考。这里为了和其他人搭建的推荐系统区分开,所以取名叫NB推荐系统架构(不是Naive Bayesian)。
一、 背景与目标
1. 背景
使用推荐系统给用户千人千面的个性化推荐体验。
2. 目标
从零搭建一套灵活可插拔并且能为多种不同业务提供高可用推荐服务的系统。
3.举个栗子
这里举个与西瓜书(《机器学习 周志华》)里类似例子来形象描述什么是特征以及怎么根据特征进行推荐服务。
3.1 比如西瓜有属性色泽、根蒂、敲声这三个属性。
有的西瓜:色泽=青绿;根蒂=蜷缩;敲声=浊响,
有的西瓜:色泽=乌黑;根蒂=稍蜷;敲声=沉闷,
还有的西瓜:色泽=浅白;根蒂=稍蜷;敲声=清脆。
这里色泽、根蒂、敲声,我们都称之为西瓜的特征,而青绿、乌黑、浅白都是是西瓜色泽特征的可能的一种取值。
3.2 比如一个“色泽=浅白;根蒂=稍蜷;敲声=清脆”的西瓜,用户尝了之后“八分甜”,这里的”八分甜“就是一个label。最终“色泽=浅白;根蒂=稍蜷;敲声=清脆|八分甜”就构成了一条训练样本。
3.3 再比如已经上线了一个冷启动的模型(这里指训练完成后导出模型文件用于线上serving,而不是算法模型结构)。当来了一个特别喜欢吃“七分甜的西瓜”的用户来了之后,系统会挑出一部分西瓜,加上“七分甜”,去模型里给这些西瓜打分,然后把分数最高(最可能符合用户七分甜预期)的一批西瓜推荐给用户。然后用户给出的行为反馈有个西瓜是“五分甜”,那么我们又收获了一条样本“那个渣渣西瓜|五分甜”,进行再训练。
所以最开始推荐的可能不准,但等样本量足够大,用户的行为足够多,推荐系统可以推的越来越准。
二、 系统架构
1. 黄底的框框是业务层,分别是业务cgi组装层、业务推荐流feed层,业务召回层,主要用go来实现,并且每个业务都有各自的微服务。
a. 业务cgi组装层:面向终端用户,收到用户http请求后调起推荐流feed服务,收到推荐的物品id(比如商品id、直播间id、文章id、视频id等等)后,查各种存储拼装数据(比如商品价格和标题、文章作者和内容等),然后下发给客户端来展示给用户。
b. 业务推荐流feed层:这里说的feed就是那种可以不断往下刷的那种资源流,下拉一下刷出一些没有看过的视频、文章等。feed层主要是根据不同的场景的配置依次发起召回、粗排、精排、重排、多样性、混排等逻辑,比如有些业务可能是没有粗排、精排、重排的,只有召回、多样性和混排,这是可配置的。
c. 业务召回层:由召回代理(后文会讲解)触发,不同的业务的不同的场景会配置不同的trigger以及不同的索引(后文会讲解),然后会根据拿到的用户特征取查相应的索引。在qps、耗时、机器资源允许的情况下可能会在查出索引并且进行初步过滤之后,进行一次粗排并且截断返回。比如索引查出5000个物品,然后粗排返回300个物品,最终feed大概会下发10个物品。因此召回的上限决定了整个推荐效果的上限。
2. 蓝底的框框是推荐系统中台层(或者说公共层),通过不同的业务id拿到不同的配置,执行各自的流程,来为各个业务提供推荐服务。主要用c++来实现。后文会详细介绍。
3. Kafka、Redis、Spark、Flink、Hive、Hdfs等基础组件这里就不做详解了。
4. 如果是业务发展初期的话,可以直接使用cgi-feed-rank-recall-index的简单架构,不需要接模型,直接用人工规则排序。不需要建复杂的索引,直接全量索引。
三、 召回代理
这一层主要是为了可以从不同的召回服务那里召回不同的物品,然后进行融合。
这一层不一定要有,之前接入的业务都只有一个召回服务。并且召回代理一般是以sdk包的方式提供给业务,而不是微服务。主要原因是功能相对单一,所以想节约一次rpc序列化和反序列化耗时。实际使用的时候,召回服务常常会附带一些新生成的物品特征回来,以及物品的数量不少,节约一次rpc的序列化和反序列化还是很有效果的。
四、 索引
这里的索引是指可以根据某些key(比如业务id+全局索引专用key、业务id+活动id、业务id+类目id)索引到一部分物品id,并用于推荐。
索引从构建方式来分主要有基于Faiss[https://github.com/facebookresearch/faiss]的向量索引、Redis索引。中途也用ES建过索引,但性能不大好,用起来也不够灵活,感觉不大适合用于构建推荐系统底层索引。
从业务的逻辑来划分的话,大概有全量索引、活动索引、类目索引、各种奇奇怪怪的离线索引等。
全量索引一般基于上架时间排序,活动索引一般是基于活动id或者活动场景建的索引。而类目索引主要是用了做相关推荐的。
一般索引的入库方式有实时入库、离线入库两种。
1. 实时入库:监听业务物品db的binlog的kafka消息队列,比如有新商品上架、新文章发布,就是从消息队列里实时的把索引插入全量索引、类目索引等索引里。这里一般配置下kafka地址参数,索引参数,就可以完成入库。
2. 离线入库:是指算法同学自己用Spark离线计算好的一些特殊索引(比如热点商品、热点文章),然后写入kafka,然后配置索引入库。然后在召回的时候进行多路融合。
五、 排序
排序是为了从候选集中挑出最接近业务目标(GPV/点击率)的top n个物品。
1. 粗排:一般是查出索引后召回返回前,进行一次模型打分,然后排序截断。主要目标是剔除劣质物品。
2. 精排:一般是指使用算法模型精选打分排序,业务量小的话,不需要。主要目标是选择优质物品。
3. 重排:基于精排的ctr/cvr、gpv、疲劳度、新颖性、相关性等使用树模型再排一次。关于树模型,笔者也不懂,当时主要是手动开发了一个树模型的serving服务嵌入现有推荐系统,给算法同学自己配置上模型用。
4. 多样性:比如一次召回排序最终返回了比较多的同类型物品,那么可能会剔除一些。使得一些排的稍后一些的物品也能够下发出去。
5. 混排:比如商品和店铺从一个推荐类别下发。
6. 在排序完成的最后,还会进行最终的业务策略干预,比如置顶、扶持(调高某些指定类型物品的排名)。
六、 特征、样本、模型训练
特征系统算是一个比较独立的功能系统了,之后会出专门的单独文章来介绍(《从零搭建NB特征平台》)。这里只做简介。
特征主要是由用户特征、物品特征、(少量)全局特征构成。在线预测的时候会用用户特征+物品特征+全局特征,构成一条原始样本,然后去serving。serving之后也会把ctr、cvr等打分写入到特征里,以供更后面的排序逻辑使用。
样本拼接的时候也是拿这条由特征构成的原始样本去join标签,以构成训练样本,并且写入kafka。kafka里的样本可以直接继续实时训练该模型,以及也会落地到hive表,方便后续进行样本回溯。
机器学习框架我们没有使用TensorFlow,而是用的司内自研的超大规模分布式机器学习框架,主要原因是时效性好,扩展性好,有专人运维,持续迭代。
七、 性能优化(主要是特征系统的优化)
推荐系统当时遇到的最大问题是请求耗时高,而用户能接受的等待时间短。
1. 针对go传输和编解码耗时对大包增长明显的问题
单请求分小包并行处理
改用精简、使用更少格式转换和嵌套的数据结构
重复率高的数据(比如特征ID)采用字典压缩方式
采用请求分小包并发的方式
结果:降低了耗时,提高了并发量。
2. 针对连续的请求有大量item重复计算的问题
增加本地缓存,减少用户连续翻页带来的重复打分压力。
结果:提高了qps
3. 针对特征加工、模型打分时用户特征重复拼接导致item特征过长的问题
采用user、item特征拆分处理的方式
结果:降低了耗时
4. 针对部分用户特征数量过多易超时的问题
裁剪0值特征
裁剪无用特征
结果:使得特征较多用户的打分超时率大幅下降
八、 容灾
注:这里的灾难主要是部分推荐页为空,无任何物品等严重影响用户体验的情况。
1. 兜底策略:
排序模型失败:分包调用排序部分失败,自动补充item特征防止大部分item倍过滤
召回没有数据或者数据被全部过滤:取兜底列表下发
Cgi服务拉取推荐列表失败:取兜底列表下发
Cgi服务拉取组装数据失败:取已经组装好的列表数据补充下发
2. 模块开关:
a. 各个业务推荐模块(首页推荐、商品页相关推荐、文章详情页的推荐内容)的开关,发生问题,并且兜底策略没有起到作用,可以直接关闭该推荐页。
b.推荐内部模块也有开关,比如突然遇到大规模流量,机器扩容来不及,可以关闭粗排和精排,召回完成后直接重排,用展示降低推荐质量的方式,防止大规模灾难。
九、 监控
按重要程度分等级监控
1. 严重告警:影响用户使用,需要马上处理,例如白屏,告警为:邮件、企业微信、微信、电话。
2. 较严重告警:短时间内不影响用户使用,需要尽快处理,例如模型没有及时更新,告警为:邮件、企业微信、微信、电话。
3. 一般告警:不影响用户正常使用,需要关注,不一定要处理,例如正常流量波动告警,告警为:企业微信、微信。
具体的告警,比如
1. 数据无下发告警,可能是白屏了。
2. 特征覆盖率环比降低严重,说明哪里出问题了。
3. 索引构建告警,可能是源头kafka出问题了。
4. 召回比例监控告警,可能是索引脏了,导致查出来的物品大部分被合法性检查过滤掉了。
十、 鸣谢
感谢carbon、华明、shenquan的指引。
十一、 后记
个人感觉:可能推荐系统在大部分时候终究是锦上添花,而不是雪中送炭,尤其是中小规模的项目。这其实让人很无奈。
十二、后记+1
感谢“腾讯云开发者”公众号的转载与收录,
本博所有文章均为博主原创,未经许可不得转载。
https://www.prolightsfxjh.com/article/the-architecture-of-nb-recommendation-system/
Thank you!
------from ProLightsfx
如果对笔者的文章感兴趣的话,欢迎关注公众号。
本博所有文章均为博主原创,未经许可不得转载
如经许可后转载,请注明出处:https://prolightsfxjh.com/article/the-architecture-of-nb-recommendation-system/
共有 7 条评论