作者 | gongyouliu
编辑 | auroral-L
全文共7426字,预计阅读时间30分钟。
大家好,我是强哥。一个热爱暴走、读书、写作的人!
本章目录
一、推荐算法的业务流程
1. 数据收集
2. ETL 与特征工程
3. 推荐模型构建
4. 推荐预测
5. 推荐Web服务
6. 离线评估与在线评估
7. 推荐算法的其他支撑模块
二、推荐系统的pipeline架构
三、推荐系统的工程架构设计原则
总结
推荐系统是一个偏业务的系统,工程实现和架构设计对推荐系统是否能够产生商业价值非常关键。好的工程实现和架构设计也方便推荐系统的维护与迭代。在后续章节讲解推荐算法和推荐系统工程实践方面的知识之前,我们在本章简单地介绍一下推荐系统工程与架构相关的基本原理和概念,方便读者更好地理解后续章节的内容。
作为推荐算法工程师(或者即将准备入行推荐算法)的我们,在平时工作中可能不会直接参与工程相关的工作,但是对推荐系统工程与架构有一个宏观和整体的认识可以更好地让我们去设计算法、更好地与工程团队交流。在小公司,算法和工程可能分得不是那么清楚,算法开发人员也会参与工程的实现,所以了解推荐系统工程架构方面的知识是非常必要的。
本章我们从推荐算法的业务流程、推荐系统pipeline架构、推荐系统的工程架构设计原则等3个方面来讲解。首先我们来介绍一下推荐算法的业务流程。
一、推荐算法的业务流程
推荐算法是机器学习的一个子领域,因此推荐算法的业务流程跟一般的机器学习过程是类似的,一般来说,推荐算法业务流程可以从数据流向的角度来加以说明,具体参考下面图1。
图1:推荐系统业务流程
上图中圆型和方形的蓝色模块是数据(或者模型),而红色的模块是基于数据之上的操作(算子),下面分别对上面的各个操作(数据收集、特征工程、推荐模型构建、推荐预测、推荐服务、离线评估、在线评估等)进行详细说明,让大家对每一个模块的功能和特色有更好的了解。
1. 数据收集
构建推荐算法模型需要收集很多数据,包括用户行为数据、用户相关数据、物品相关数据、场景化数据(如用户设备属性、用户当前地点、时间、用户停留的页面等)。如果将推荐算法进行推荐的过程类比为厨师做菜,那么这些数据是构建推荐算法模型的各种食材和配料。巧妇难为无米之炊,要构建好的推荐算法,收集到足够多的有价值的数据是非常关键和重要的。第3章《推荐系统的数据源与数据处理》已经对推荐系统相关的数据进行了全面的介绍,这里不再赘述。
2. ETL与特征工程
收集到的原始数据一般是非结构化的、杂乱无章的,一般在进行后续步骤之前还需要进行ETL,ETL的主要目的是从收集到的原始数据中提取推荐算法建模需要的关键字段(拿视频推荐来说,用户id、时间、播放的节目、播放时长等都是关键字段),将数据转化为结构化的数据存储到数据仓库中。同时根据一定的规则或策略过滤掉脏数据,保证数据质量。
在互联网公司中,用户行为数据跟用户规模呈正比,所以当用户规模很大时数据量非常大,一般采用HDFS、Hive、HBase等大数据分布式存储系统来存储数据。用户相关数据、物品相关数据一般是结构化的数据,一般是通过后台管理模块将数据存储到MySQL、ProgreSQL等关系型数据库中(或者快照到Hive表中)。第3章《推荐系统的数据源与数据处理》第二部分已经对ETL进行过介绍,这里不再说明。
做完了ETL的工作,接下来就是特征工程了。推荐系统采用各种机器学习算法来学习用户偏好,并基于用户偏好来为用户推荐物品。这些推荐算法用于训练的数据应该是可以被数学模型所理解和处理的,一般是向量的形式,其中向量的每一个分量/维度就是一个特征,所以特征工程的目的就是将推荐算法需要的原始数据通过ETL后再转换为推荐算法可以学习的特征。
当然,不是所有推荐算法都需要特征工程,比如,如果要做排行榜相关的热门推荐,只需要对数据做统计排序就可以了。最常用的基于物品的协同过滤和基于用户的协同过滤(后面章节会讲)也只用到用户id,物品id,用户对物品的评分三个维度,也谈不上特征工程(KNN推荐、bayes算法、关联规则等推荐算法也都不需要特征工程)。像logistic回归、FM、深度学习等等复杂一些的机器学习算法需要做特征工程,一般基于模型的推荐算法都需要特征工程。
特征工程是一个比较复杂的过程,要做好需要很多技巧、行业知识、经验等。我们在后面会单独用一章的篇幅来讲解特征工程,或者读者可以参考我的另外一个系列「推荐系统与特征工程」,这里不赘述。
3. 推荐模型构建
推荐算法模块是整个推荐系统的核心之一,该模块的核心是根据具体业务及可利用的所有数据设计一套精准、易于工程实现、可以处理大规模数据的(分布式)机器学习算法,进而可以预测用户的兴趣偏好。这里一般涉及到模型训练、预测两个核心模块。下面图2简单描述这两个过程,这也是机器学习的通用流程。好的推荐算法工程实现,希望尽量将这两个过程解耦合,尽量做到通用,方便用到各种推荐业务中。本节我们不详细讲解具体的推荐算法,留到后续章节讲解,下面一小节我们简单说说推荐模型预测。
图2:推荐算法建模过程
4. 推荐预测
当我们构建好推荐算法模型后,就可以用该模型进行预测了(即为用户进行个性化推荐)。如果是T+1(每天为用户进行一次推荐)的推荐模型,可以将推荐模型加载到推荐预测的代码块中(用计算机的术语,一般预测的逻辑是一个函数或者一个方法),循环(对所有待推荐的用户循环)为用户计算推荐结果。
在计算机工程中有所谓的“空间换时间”的说法,对于推荐系统来说,事先计算好每个用户的推荐结果, 将结果存储下来, 可以更快的为用户提供推荐服务,及时响应用户的请求,提升用户体验(对于T+1推荐,这样做是非常合适的)。由于推荐系统会为每个用户生成推荐结果,并且每天都会(基本全量)更新用户的推荐结果,一般采用NoSQL数据库来存储,并且要求数据库可拓展,高可用,支持大规模并发读写。
针对实时推荐,上面的方法也是可以行的(只不过需要基于用户的实时行为近实时更新用户的推荐结果),不过一般会将推荐预测过程部署成一个Web服务,对于用户的每一次请求,通过该服务来实时为用户提供推荐结果,像TorchServe就是提供这种能力的一种实现(T+1的推荐也可以采用这种方式,在为每个用户循环推荐的过程中调用该服务)。
图3:TorchServe的服务流程(图片来源于PyTorch官网)
推荐预测是推荐系统产生业务价值最重要的部分,真实的推荐系统更加复杂,还要进行很多工程和业务上的处理。在工业级推荐系统中,一般会将推荐预测过程拆分为更多子模块,方便进行更精细的业务控制,具体推荐模型在进行推荐过程中的工程实现细节我们在本章的5.2节中介绍。
5. 推荐Web服务
该模块是推荐系统直接服务用户的模块,该模块的主要作用是当用户在UI上使用推荐系统时,触发推荐Web接口服务(比如用户在抖音上刷,参见下面图4中的web服务模块),为用户提供个性化推荐,该模块的稳定性、响应时长直接影响到用户体验。跟上面的推荐存储模块类似,Web服务模块也需要支持高并发访问、水平可拓展、亚秒级(一般200ms之内)响应延迟。我们会在第17章中详细介绍推荐Web服务相关的知识点,这里不再赘述。
图4:推荐系统中的Web服务
6. 离线评估与在线评估
推荐评估模块的主要作用是评估整个推荐系统的质量及价值产出。一般来说可以从两个维度来评估。
l 离线评估
离线评估是在构建推荐算法模型过程中的评估(参见图1),主要是评估训练好的推荐模型的质量(即模型预测的好不好、准不准,常用的评估指标有准确度、召回率等)。模型在上线服务之前需要评估该模型的准确度,一般是将样本数据划分为训练集和测试集,训练集用于训练模型,而测试集用来评估模型的预测误差(一般还会有验证集,用于调优模型的超参数)。
l 在线评估
在线评估是在模型上线提供推荐服务过程中(参见上面的图1)评估一些真实的用户体验指标、转化指标,比如转化率、购买率、点击率、人均播放时长等。线上评估一般会结合AB测试做不同模型的对比实验,先对新模型放一部分量(用户或者接口访问),如果效果达到期望再逐步拓展到所有用户,避免模型线上效果不好严重影响用户体验和收益性指标等。
推荐系统评估是对推荐系统的推荐质量的一种度量,只有满足一定评估要求的推荐系统才能产生更好的业务效果。本节我们不详细说明评估的细节,在本书第14章我们会更细致地介绍推荐系统评估相关的话题。
7. 推荐算法的其他支撑模块
推荐系统各个模块(即上面讲到的模块)要真正发挥价值,需要部署到服务器上,并且能够自动化地运行,这就涉及到任务的调度。常用的任务调度有Linux的Crontab,针对少量任务的调度Crontab还可以胜任,当任务量多的时候就不那么方便了,Crontab也无法很好解决任务依赖关系。这时一般用更友好、更专业的Azkaban、Airflow等来实现。
推荐系统是一个工程系统 ,工程系统不可避免会偶尔出现问题(代码中隐含的bug或者软件及硬件的波动等因素都会导致出现问题),这时就需要监控模块,监控模块解决的是当推荐业务(依赖的)任务由于各种原因调度失败、运行报错时可以及时告警、及时发现错误的问题。监控系统在业务出现问题时会通过邮件或者短信通知运维或者业务的维护者,监控系统还可以做到更智能化,当出现问题时,可以自行判断问题的原因并可以在后台自动拉起服务重新启动(这要求你的业务是幂等的)。
我们可以对服务的各种状态做监控,可以事先根据业务需要定义一些监控指标(比如文件大小、状态变量的值、日期时间等),当这些状态变量无值或者值超过事先定义的阈值范围时及时告警。监控模块的主要目的是保证推荐业务的稳定性,时时刻刻为用户提供一致的、高质量的个性化推荐服务。监控模块的开发和设计一般需要运维人员来配合实施。
本节我们只是简单梳理了调度与监控相关的概念,让读者有一个基本的了解,我们会在本书的第18章详尽介绍推荐系统调度与监控相关的话题。
二、推荐系统的pipeline架构
上面一节我们从推荐算法业务流程的角度来简单介绍了推荐算法实施过程中涉及到的各个模块及其作用。这一节我们聚焦在推荐预测这一块,讲清楚推荐预测的一些处理方法和思路。工业级推荐系统为了更好地响应业务需求,为了将系统解耦合,需要对推荐预测进行更细致的拆分,一般将推荐预测过程按照pipeline的模式拆分为召回、排序、业务调控3个子阶段(见下面图5)。
图5:推荐系统的pipeline架构
召回就是将用户可能会感兴趣的物品通过召回算法从全量物品库中取出来,一般会采用多个算法来召回,比如热门召回、协同过滤召回、标签召回、地域召回等。排序阶段将召回阶段的物品列表根据用户可能的点击概率大小排序(即所谓的CTR预估,也可以是预测用户的停留时长,具体用什么指标作为目标需要根据业务来定)。在实际业务中,在排序后还会增加一层调控逻辑,根据业务规则及运营策略对排序后的列表进一步增补微调,满足特定的运营需求。我们会在本书的第三篇(6~9章)和第四篇(10~12章)分别讲解各种召回、排序策略,这里不赘述。
为了让大家更好地理解上面每个步骤的作用,这里拿相亲来举例说明召回、排序和业务调控的过程。对于单身的人,每年过年回家不可避免地被家长、亲戚们问起谈对象的事情,他们也会非常热心的帮我们介绍对象。假如你有3个亲戚朋友帮你介绍对象,每个人帮你物色了3个后续人(他们基于对你的了解,帮你物色的是他们认为和你比较合适的人),亲戚朋友帮你物色对象的过程就叫做召回,他们基于自己对你的了解及他们的人脉圈去选择合适的人,整个召回过程一共召回了9个候选人(越多人帮你介绍,你最终找到满意对象的概率也越大,在真实的推荐系统中也是会采用很多召回策略的)。由于你的时间有限,你不希望与这9个人每个人都见面,那么你的做法可能是基于这9个人的条件(长相、身材、学历、性格、家庭背景等)和自己的择偶标准,从这9个人中最终选择3个准备去见面更详细地了解,当你与他们见过面有了更深入的了解之后,这3个人在你心里的匹配度你基本就知道了,那么这个过程就是排序 。这时你的父母可能会给你一些建议,在你心里排在第2的人,你父母可能会觉得更合适,你可能会听父母的建议(毕竟父母阅历更多,有时看人会更准),最后会与父母觉得最合适的那个人深入接触。父母对你提建议并且影响你决策的过程就是业务调控。
有了上面这个例子,我相信你一定对什么是召回、排序、业务调控有了更深入的了解了,也知道了各个阶段的价值是什么。在真实业务场景中,整个推荐预测过程还需要做更多事情,比如进行不同算法的AB测试、过滤掉用户操作过的物品、对推荐结果进行信息填补(推荐结果在存储时一般只存物品的id,但展示在前端时需要有标题、海报图等metadata信息,所以需要填补这些在前端展示必要的信息)等。下面图6是推荐预测过程中的涉及到的操作时序关系图。
图6:推荐系统的pipeline架构的时序关系图
下面对上图中每个操作进行简单说明。首先当用户请求推荐服务时,我们获得了用户的id,这时如果推荐系统有AB测试的话,需要先获得用户的AB测试分组信息(AB测试中不同的组会用不同的召回、排序算法,AB测试的目的就是评估各个算法的效果),然后基于基于用户的分组去获得该用户的召回结果(即图中的recall_1、recall_2、... 、recall_n等),召回之后我们会过滤掉用户操作过的物品然后进行排序(即图中ranking),之后是一些业务规则(比如新闻资讯APP中会对某些新闻置顶等),然后是填补物品需要展示的metadata数据,最终将推荐结果在前端展现给用户。
这里顺便说一下,召回、排序都可以独立部署成一个Web服务(微服务),推荐预测过程可以通过RPC或者HTTP协议获取召回、排序结果,这样做的目的是解耦各个排序、召回算法,方便每个算法独立迭代,这么做是有一定的工程设计哲学考虑的,下面我们来介绍一下推荐系统的工程架构设计原则。
三、推荐系统的工程架构设计原则
作者在早期构建推荐系统时由于经验不足,而业务又比较多,当时的策略是每个算法工程师负责几个推荐业务(一个推荐业务对应一个推荐产品形态),由于每个人只对自己的业务负责,所以开发基本是独立的,每个人只关注自己的算法实现,虽然用到的算法很多都是一样的,但前期在开发过程中没有将通用的模块抽象出来,每个开发人员从ETL、模型训练、推荐预测、推荐结果存储、推荐web服务都是独立的,并且每个人在实现过程中整合了自己的一些优化逻辑,一竿子插到底(即所谓的烟囱式架构),导致资源(计算资源、存储资源、人力资源)利用率不高,开发效率低下,代码也极难复用。下面图7就是这两种设计方案的对比。
图7:烟囱式架构与模块化架构
为了支撑更多类型的推荐业务,减少系统的耦合,便于发现和追踪问题,节省人力成本,方便算法快速上线和迭代,需要设计比较好的推荐系统架构,而好的推荐系统架构应该具备4大原则:
通用性、模块化、组件化、可拓展性。下面分别对这4大原则做简要说明,阐述清楚它们的目标和意义。
l 通用性
所谓通用,就是该架构具备包容的能力,业务上的任何推荐产品都可以用这一套架构来涵盖和实现。对于多条相似的产品线,也可以采用同样的一套架构来满足。
l 模块化
模块化的目的在于将一个业务按照其功能做拆分,分成相互独立的模块,便于每个模块只包含与其功能相关的实现逻辑,模块之间通过一致性的协议调用(如HTTP、Thrift等)。将一个大的系统模块化之后,每个模块都可以被高度复用。模块化的目的是为了复用, 模块化后,各个模块可以方便重复使用到不同推荐业务逻辑、甚至不同的产品线中。
l 组件化
组件化就是基于方便维护的目的,将一个大的软件系统拆分成多个独立的组件,主要目的就是减少耦合。一个独立的组件可以是一个软件包、web服务、web资源或者是封装了一些函数的模块。这样,独立出来的组件可以单独维护和升级而不会影响到其他的组件。组件化的目的是为了解耦,把系统拆分成多个组件,确定各个组件边界和责任,便于独立升级和维护,组件可插拔,通过组件的拼接和增减提供更完整的服务能力。
组件化和模块化比较类似,目标分别是为了更好的解耦和重用,就像搭积木一样构建复杂系统。一个组件可以进一步分为多个模块,组件化是从业务功能的角度进行的划分,是更宏观的视角,而模块化是从软件实现层面进行的划分,是偏微观的视角。
l 可拓展性
系统具备支撑大数据量,高并发的能力,并且容易在该系统中增添新的模块,提供更丰富的能力,让业务更加完备自治。
下面来举例说明上面原则的应用。首先我们可以将利用输入数据通过“操作”得到输出的的过程抽象为“算子”(参考下面图8),按照这个抽象,ETL、机器学习训练模型、召回、排序、业务调控等功能都是算子。其中输入输出可以是数据或者模型。
图8:算法或者操作的算子抽象
其次,任何一个推荐业务都是由一系列算子组成的,它们的配合才能让整个推荐系统最终产生业务价值。任何一个推荐业务可以抽象为由数据/模型为节点,算子为边的“有向无环图”。下面图9是作者之前团队实现的一个利用深度学习做电影猜你喜欢的推荐业务流程, 整个流程是由各个算子通过依赖关系链接起来的,整个算法实现就是一个有向无环图。
图9:推荐业务的有向无环图抽象
我们在上一节中提到的将召回、排序实现成一个个微服务(参见图6)就是基于上面理念的一种很好的实现。当召回、排序部署为微服务后,就可以通过RPC或者HTTP供其他业务调用,那么调用的输入和输出就是算子的输入参数和输出参数。这么做的好处是各个系统之间是隔离的,每个召回、排序微服务都可以由独立的人员去实现,具体实现代码可以是Python的,也可以是Java的,这些实现细节就可以很好地被屏蔽掉了,算法开发人员只需要实现自己的功能,在接口层面跟其他使用微服务的使用方约定好就行了。这么做的另一个好处是便于定位和发现问题,一个模块出了问题不至于影响其他模块。
总结
本章我们讲解了推荐系统的业务流程、架构和具体的工程架构设计原则。在业务流程部分,我们讲解了推荐算法涉及到的数据收集、ETL、特征工程、模型训练、推荐预测、Web服务、效果评估及支撑组件等模块。在架构部分,我们简单介绍了推荐系统的pipeline架构,工业级推荐系统一般分为召回、排序和业务调控3个阶段。在工程架构设计原则部分,我们总结了好的推荐系统架构应该具备的4大原则:通用性、模块化、组件化、可拓展性,我们简单介绍了每个原则的意义。我们可以将推荐算法过程中的操作抽象为算法,整个推荐业务抽象为有向无环图,同时通过召回、排序的微服务抽象说明了这么做的好处。
本章所讲内容是作者多年推荐系统学习、实践经验的总结,希望能够帮助从事推荐系统开发的读者,让读者在工程实现上少走弯路。本章知识点的了解和掌握对于读者学习后面的章节也是大有裨益的。
我出版的畅销书《构建企业级推荐系统:算法、工程实现与案例分析》,可以跟这个系列文章一起阅读,大家有需要可以点击下面链接购买。