「从零入门推荐系统」17:推荐系统的web服务

作者 | gongyouliu

编辑 | gongyouliu

推荐系统是一种算法工程技术解决方案,目的是通过挖掘用户操作行为来为用户提供个性化的物品推荐,满足用户差异化的兴趣偏好。推荐系统要想真正产生作用,需要将训练好的推荐模型部署成web服务(一般是采用Restful API接口的形式),当用户在前端使用推荐模块时,推荐模块会调用推荐web服务,最终将该用户的推荐结果展示给用户,给用户所见即所得的视觉效果。

推荐web服务是推荐系统服务的最后“一公里”。用户体验好不好、推荐系统能否真正带来商业价值,推荐web服务起着至关重要的作用。本章我们重点讲解推荐web服务相关的知识,具体来说,我们会从推荐系统web服务的构成、推荐Restful API接口服务、推荐系统推断服务这3个部分来讲解。推荐Restful API接口服务要做的事情及所起的作用以及推荐推断服务,这2部分是重点,读者需要好好掌握。

17.1 推荐系统web服务的构成

用户与推荐系统交互的服务流程见下面图1,用户在使用产品过程中与推荐模块(产品上提供推荐能力的功能点)交互,前端(手机、PC、Pad、智能电视等)请求推荐web服务,推荐web服务获取该用户的推荐结果,将推荐结果返回给前端,前端通过适当的渲染将最终的推荐结果按照一定的样式和排列规则在产品上展示出来,这时用户就可以看到推荐系统给他的推荐结果了。

9aa21829286855a55b29f1aa7cdfadaa.png

图1:用户通过推荐web服务获取推荐结果的数据交互流程

上图中的绿色虚线框中的数据交互能力就是推荐web服务的范畴,它是前端(也叫终端)与后端的互动。企业级推荐系统web服务主要分成2个部分:一个是推荐Restful API接口服务(下面统一简称为推荐系统接口服务,不再特别说明);一个是推荐系统推断服务,下面两节(即17.2、17.3)我们来分别讲解它们解决的问题及作用,本节不做展开说明。图1中标注数字的流程代表的就是用户请求推荐服务后的数据处理链路,下面分别简单解释一下各个链路所做的事情。

① 用户访问推荐模块

这是用户在终端操作推荐模块的过程,类似用户打开抖音APP,在抖音首页滑动以获取自己的个性化推荐结果。

② 前端请求推荐API服务

当用户在终端操作时(比如抖音中下拉滑动),终端会向云端发起一次http请求,目的是获取该用户的个性化推荐列表。

③ 向推断服务请求数据

推荐系统一般是一个机器学习模型,当模型训练完成后需要部署到线上进行推断服务,这个流程就是从推荐推断服务获取该用户的推荐结果的过程。

④ 返回推荐列表给接口

③中推断服务完成推断过程后,就获得了该用户的推荐列表,然后会将推荐列表返回给推荐接口服务。

⑤ 服务返回最终推荐结果

④中推荐系统接口服务获取推断服务的推荐列表后,需要进行一些其它处理(具体17.2节讲解),获得最终的推荐结果。

⑥ 前端展示推荐结果给用户

将⑤中最终的推荐结果返回给终端,终端进行一定的渲染,这样用户在终端就可以看到给他的最终展现结果了。

上面图1只是一种简化的交互模型,在实际企业级服务中,往往比这个更加复杂,在前端和后端之间往往存在一层CDN层做缓存加速,以减轻前端服务对后端并发访问的压力(在用户量大的情况下,推荐系统属于高并发服务),并且一般推荐web服务中还存在一层Nginx代理层,通过Nginx代理,让推荐web服务可以水平扩容,以满足推荐系统高并发的要求。下面图2就是一种可行的完整推荐系统服务方案,供大家参考。

dff1e8acb7c4facebfd7b39050447edc.png

图2:完整的推荐系统业务架构图

如前面所讲,虽然推荐web服务包含前端与后端的交互,前端与后端一般还会有CDN层和Nginx代理层,但本文我们着重关注的是后端真正提供Restful API接口的服务及推荐推断服务的实现方案,也即上图中红色模块的具体实现方案。

推荐系统web服务模块是最终为用户提供推荐能力的部分,它设计得好不好直接影响用户体验,一般来说,该模块需要满足稳定、响应及时、容错、可以随着用户规模线性扩容等多个条件。随着Docker等容器技术及kubernetes等容器管理软件的发展和成熟,推荐web服务中的各个子模块都可以分别部署在容器中,采用微服务的方式进行数据交互,这样就可以高效管理这些服务,更好地进行服务的监控、错误恢复、线性扩容等。

17.2 推荐系统接口服务

为了给前端提供个性化推荐服务,图1中的推荐Restful API接口服务模块需要完成3件事情。首先需要获得该用户的推荐列表(直接获得已经计算好的推荐列表,这就是17.3.2节要讲的,或者通过临时计算获得推荐列表,这就是第17.3.3节要讲的),其次是将推荐列表组装成前端最终需要的数据结构(第一步获得的推荐列表一般是物品id的列表,实际展示给前端还需要物品的各种metadata信息,如标题、海报图、评分、价格等等,这些信息的组装就是在这一步完成的,这些信息一般会存放到关系型数据库中,或者采用json的形式存放到Redis、文档型NoSQL中,所以这里至少还有一次额外的数据库访问)及一些业务上的处理(下面会介绍),最后是响应前端的HTTP请求(一般是GET或者POST请求),将最终推荐结果返回给前端(一般是JSON结构,下面图图3就是一个参考案例)。

b580e015cf29276239250d83e6f2346d.png图3:最终返回给用户的推荐结果(JSON格式)

推荐接口服务模块一般是用Java来实现的(比如利用Tomcat、Spring系列等Java web服务框架),这主要是因为目前大部分公司的后端服务是基于Java生态系统来搭建的。Java生态系统非常完备和成熟,采用Java开发可以更好地将推荐服务整合到所有后端服务中(毕竟任何一个产品,除了推荐系统外,还有非常多的其他服务,比如淘宝的客户管理、库存管理、商家管理、购买下单等)。推荐系统推断服务一般是用Python来实现的(比如Flask、FastAPI等或者TensorFlow、PyTorch深度学习框架提供的推断服务框架),这主要是因为目前机器学习的主流编程语言是Python,用Python更加方便。推荐接口服务与推荐推断服务之间的交互是通过HTTP请求的方式来实现的。

在真实的企业级推荐系统服务中,情况会更复杂。我们在第5章《推荐系统业务流程与架构》中提到,企业级推荐系统一般分为召回、排序、业务规则调控等几个部分,另外实际推荐系统上线时还要做AB测试,还需要将用户之前操作过的物品过滤掉等一系列事情需要处理,所以真实的推荐接口服务需要做很多额外的处理工作,下面图4是推荐接口服务按照时序关系可能包含的一些处理步骤。

7479a6265c59dda9766d984f418c1cdf.png

图4:推荐接口服务处理流程的时序关系图

图4中的每一个召回(recall_1、recall_2、... 、recall_n)和ranking、业务规则等都可以分别部署为一个完整的服务,真正的推断服务包含一系列召回、排序等步骤,我们将它们统一称为推断服务。我们在下面一节中只按照某个推断服务来讲解,其它推断服务的实现方案都是类似的。

17.3 推荐系统推断服务

推荐系统推断服务是利用推荐算法(各种召回、排序、业务规则算法等)为用户生成推荐列表的过程,是推荐算法作为一种机器学习模型的推理过程。

17.3.1 推断服务的2种实现方式

推荐系统推断服务一般有两种实现方式,一种是事先计算型,另一种是实时装配型。在具体介绍之前,这里我先举一个比较形象的例子,让大家更好地理解这两种实现方式。

假设我们开了一家餐厅专门送外卖,餐厅提供10种不同的备选套餐。在午市或者晚市叫餐高峰时段,餐厅可以采用如下两种方案来准备套餐:第一种方案是事先将这10种套餐每种都做若干份,当有客户叫外卖时,将该客户叫的这个套餐(已经做好了)直接送出去;第二种方式是将这10种套餐需要的原材料都准备好,部分材料做成半成品(比如比较花时间的肉类),当有用户叫餐时,将该套餐需要的原材料下锅快速做好再送出去。

通过上面非常简化的案例介绍,大家应该不难理解,上面提到的第一种准备套餐的方式就是“事先计算型”,事先将套餐做好,而第二种方式就是“实时装配型”,当用户叫餐时,临时做并快速做好。

现在让我们回到推荐推断服务上,开始介绍这两种推荐推断服务实现方案。事先计算型就是将用户的推荐列表事先计算好,放到数据库中存放起来,当该用户在使用产品过程中访问推荐模块时,推荐推断服务模块直接将该用户计算好的推荐列表取出来,进行适当加工(比如过滤掉用户已经看过的视频),将最终推荐结果展示给用户。实时装配型是将计算推荐列表需要的数据(一般是各种特征)提前准备好,当用户访问推荐模块时,推荐推断服务通过简单的计算和组装(利用前面准备好的各种特征灌入推荐模型),生成该用户的推荐列表,再将推荐列表(补充完善后)返回给前端并展示给用户。

理解了这两种不同的推断服务实现方式的基本原理,我们在接下来的两节中分别对它们的实现细节进行详细介绍,让读者更好地理解它们的特性及技术实现细节。

17.3.2 事先计算型推断服务

这一节我们来讲解推荐系统事先计算型推断服务的架构实现与基本原理(参见下面图5)。对于T+1类推荐产品形态,这种方式是一种比较合适的方式(其实信息流推荐等实时推荐也可以采用该方式)。

77140b9ea55cf84fbd799c2de073518d.png

图5:事先计算型推断服务架构

该模式最大的特点是事先将每个用户的推荐列表计算出来,存到数据库中。一般可以采用Redis等NoSQL数据库,采用key-value的方式存储,key就是用户id,value就是给用户的推荐列表。如果是用Redis存,value的数据结构可以使Sorted Sets,这种数据结构比较适合推荐系统,Sorted Sets中的element可以是推荐的物品id,score是物品的预测评分或者预测概率值等,还可以根据Sorted Sets中的score进行分页筛选等操作。下面图6就是一种可行的推断服务返回的JSON数据结构。

ca5d46ce6dfb4b104e79ffb79be18d62.png

图6:推荐列表的数据结构

该架构既可以支持T+1推荐模式和实时推荐模式,对于T+1型推荐产品形态,每天为用户生成一次推荐结果,生成推荐结果时直接替换昨天的推荐结果就可以了。而对于实时推荐,情况会复杂一些,实时推荐可能会调整用户的推荐结果(而不是完全替换),对用户推荐结果进行增删形成新的推荐结果,这时可行的方法有两个:一是从推荐列表存储数据库中读出该用户的推荐列表,按照实时推荐算法逻辑对推荐列表进行修改,再将推荐列表存进去替换掉;另外一种做法是,增加一个中间的镜像存储(如果公司算法基础设施基于Spark平台的话,可以采用HBase),所有的算法逻辑修改只对镜像存储进行操作,操作完成后,将镜像存储中修改后的推荐列表同步到最终的推荐库中,这跟T+1更新就保持一致了,只不过现在是实时推荐,同一个用户一天可能会更新多次推荐列表。

17.3.3 实时装配型推断服务

本节我们来讲解实时装配型推断服务的实现原理与架构(参考下面图7)。这种方式事先不计算用户的推荐列表,当有用户请求时,推荐API接口服务从特征仓库(一般也是存放在Redis、HBase这种非关系型数据库中)中将该推荐模型需要的特征取出来,并将特征灌入推荐模型,获得该用户的推荐列表。

0f77ee783c954d1f7f36c54c3828c63b.png

图7:实时装配型推断服务架构(推荐API接口服务加载推荐模型)

这种架构需要将推荐模型加载到API接口服务中,可以实时基于用户特征获得推荐列表,这就要求推荐模型可以在极短的时间(毫秒级)内计算出推荐列表,计算一定要快,否则会影响用户体验。

TorchServe和TensorFlow Serving都是采用的这种方式来实现的,它们可以将训练好的模型直接部署成推理服务,读者可以参考相关文档来学习,本章不展开细讲。

另外一种可行的方案是,将推荐模型做成独立的模型服务,推荐API接口服务通过HTTP或者RPC访问模型服务获得推荐列表。具体架构如下面图8,这种方式的好处是推荐模型服务跟推荐API接口服务解耦,可以分别独立升级模型服务和推荐API接口服务,互相之间不会影响,只要保证它们之间数据交互的协议不变就可以了。

2794db1db261a29fe478594cdb4a6da5.png

图8:通过推荐模型服务来获取推荐列表的实时装配型推断服务架构

实时装配型架构在实际提供推荐服务时就与具体的推荐范式是T+1推荐还是实时推荐没有关系了,因为在任何时候推荐API接口服务都是临时调用推荐模型为用户生成推荐列表,这种实现方式更灵活。

T+1推荐的模型可以一天训练一次,也可以多天训练一次,只不过推荐列表是每天为全体用户生成一次。而实时推荐的模型可以是实时训练的(用户的每一次操作行为都会产生日志,通过实时日志处理,生成实时特征,灌入实时模型训练流程中,最终完成对模型的实时训练,让模型实时得到更新),也可以是一天或者多天训练一次,只不过推荐列表是实时为单个用户生成的。

17.3.4 两种推断服务的优劣对比

前面两节已经对两种推荐系统提供推断服务的实现方案的技术细节进行了详细介绍,在真实业务场景中可能比这个更复杂,可能不是单纯的某种方案,会有一些变体,在这两种方案的基础上做适当调整与变化,可能同一产品的不同推荐形态采用不同的方式,同一种推荐方案也可能会融合这两种方式。

在这一节我们对比一下这两个方案的优缺点,让读者更好地理解这两种推断服务方案,同时也为读者在具体推荐业务场景中进行选择提供参考。

17.3.4.1 事先计算型推断服务的优缺点

事先计算型最大的优势是提前将推荐列表准备好了,这样在提供推荐服务时可以直接获取推荐列表,因此大大提升了接口服务的响应速度,减少了响应时间,对用户体验是有极大帮助的。另外,事先计算好了,当模型推断出现问题(比如调度模型推断的计算服务挂了),最坏的情况是不更新推荐列表(这时无法插入最新推荐列表),用户访问产品上的推荐模块时还是可以获得推荐的,只不过给用户的是过去一天的推荐结果。如果是实时计算推荐列表(实时装配型),当模型出现问题时就无法获得推荐列表,如果接口没做很好的保护,这时接口可能会挂掉,导致前端出现无法展示任何推荐结果的故障,出现开天窗现象,因此事先计算型有更好的鲁棒性。

事先计算型另一个优点是架构更加简单,推断接口服务跟生成推荐列表的过程解耦,可以分别对推荐接口和推荐列表计算优化升级,而不会互相影响。

实际上很多用户不是每天都访问的,真正日活用户占总活跃用户(比如月活用户)的比例是很低的(当然像微信这类国民级APP除外),推荐模块访问用户数一般也远小于当天日活数。而事先计算型推荐服务需要事先为每个用户生成推荐列表,这就浪费了很多计算和存储资源,特别是有海量用户的APP,这时有大量的用户没有登录反而需要每天为其计算推荐列表,这时浪费是非常明显的。

事先计算型另外一个缺点是,事先计算好了,这就失去了灵活性,要调整、修改用户的推荐列表成本代价更高(信息流推荐等实时推荐产品需要对推荐列表进行近实时调整)。就像前面的案例讲的,套餐做好了,没法满足用户特定的口味了,比如用户想要重辣,那也没办法了。

17.3.4.2 实时装配型推断服务的优缺点

实时装配型跟事先计算型基本是对称的,事先计算型的优点是它的缺点,事先计算型的缺点反而是它的优点。

实时装配型需要临时为用户生成推荐列表,因此推荐API接口服务需要多做一步处理,对接口性能有一定负面影响。另外,当推荐模型需要升级调整或者模型服务出现问题时(实时装配型另一种实现方案是推荐模型作为一个独立服务),会有短暂时间的不可用,这时会导致推荐API接口无法计算出推荐列表,进而无法给前端提供反馈信息。这两种情况都会影响用户体验(当然做得好的系统会有模型热更新,模型升级不会导致无法响应的情况出现,TensorFlow Serving就具备这种能力)。

实时装备型的架构也更加复杂,耦合度更高(在推荐API接口整合了推荐模型这种实时装配型中,推荐API接口跟推荐结果计算是完全耦合在一起的,参见图7)。

实时装配型由于是实时为用户计算推荐列表,因此相比事先计算型不会占用太多的存储、计算资源,对于节省费用是有极大帮助的,特别是在海量用户场景下,这种节省更加明显。它的另一个优点是对推荐列表调整空间大,因为是临时计算,可以在计算过程中增加一些场景化的处理逻辑,对推荐算法有更好的干预能力,更加适合实时推荐场景。

上面介绍完了这两种方案的优缺点,我们用一个表格整理一下,方便对比查看它们之间的异同点。

推荐推断服务类型

优点

缺点

事先计算型

1. 接口响应更快

2. 整个系统有更好的鲁棒性,推荐计算出问题不影响接口返回结果

3. 架构更加简单,耦合度低,可以对接口和推荐计算分别优化升级

1. 浪费计算存储资源

2. 对推荐列表调整的灵活度低

实时装配型

1. 更省存储计算资源

2. 系统更灵活,可以方便临时调整推荐逻辑

1. 接口有更多的处理逻辑,响应相对较慢

2. 当推荐模型或模型服务出现问题时,无法给用户提供推荐,影响用户体验

3. 架构相对复杂,耦合度高,推荐接口和推荐列表计算存在直接依赖关系

表1:事先计算型和实时装配型的优缺点对比

总结

本章我们讲解了推荐系统web服务的基础知识,这些知识的掌握对实现一个企业级的推荐系统至关重要。推荐系统web服务分为推荐系统接口服务和推荐系统推断服务两部分,其中推荐系统接口服务的处理链路及推荐系统推断服务是本章的2个重点。

推荐推断服务主要有两种实现方式。一种是事先计算型,提前将用户的推荐列表计算出来并存放到NoSQL中,当用户使用推荐模块时,推荐推断服务直接将该用户的推荐列表返回给推荐接口服务。另一种是实时装配型,我们需要将计算推荐列表需要的原材料准备成“半成品”(就是各种特征),将这些中间状态事先存起来,当用户使用推荐服务时,推荐API服务通过简单的组装与计算(调用封装好的推荐模型),将“半成品”加工成该用户的推荐列表,并最终给到推荐系统接口服务。

这两种提供推断服务的实现方案各有优缺点,我们需要根据公司现在的技术储备、人员能力、团队规模、产品形态等多个维度进行评估和选择。不管采用哪种方式,最终的目的是一样的,我们需要为用户提供个性化的、响应及时的优质推荐服务。


大家如果对推荐系统感兴趣,可以点击下面链接购买我出版的图书《构建企业级推荐系统》,全面深入地学习企业级推荐系统的方法论。

bb635d5a7bf95e37fea1190d430eea4b.png

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据与智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值