作者 | 梁唐
大家好,我是梁唐。
今天和大家来聊聊推荐系统的架构,首先声明,这张架构图不是我画的,而是我在王喆老师《深度学习推荐系统》当中看到的。
这本书我读过两遍,第一遍是我刚做推荐的时候读的,第二遍是最近读的。第一次读的时候没有看仔细,这张图扫了一眼就过去了,最近读的时候仔细看了一下。这不看不知道,一看吓一跳,这张图实在是太强了。如果让我来画,虽然也行,但肯定画不到这么简洁、精细。
所以今天这篇文章就和大家仔细抠一下这张图,能把这张图看懂了,那么整个推荐系统的架构也就清楚了。
这张图是我从影印版中截的,如果大家想看高清版本,建议大家买本实体书支持一下王喆老师。
很明显这张图将推荐系统分成了两个部分, 分别是数据部分和模型部分。我们就从这两个部分入手,一点点深入剖析。
数据部分
我们首先来看数据部分。
整个数据部分其实是一整个链路,我们先来看看最上游的部分。主要是三块,分别是客户端及服务器实时数据处理、流处理平台准实时数据处理和大数据平台离线数据处理这三个部分。
看到这里,一个很直观的问题就是,为什么数据处理需要这么多步骤?这些步骤都是干嘛的,存在的意义是什么?
我们一个一个来说,首先是客户端和服务端的实时数据处理。这个很好理解,这个步骤的工作就是记录。将用户在平台上真实的行为记录下来,比如用户看到了哪些内容,和哪些内容发生了交互,和哪些没有发生了交互。如果再精细一点,还会记录用户停留的时间,用户使用的设备等等。除此之外还会记录行为发生的时间,行为发生的session等其他上下文信息。
这一部分主要是后端和客户端完成,行业术语叫做埋点。所谓的埋点其实就是记录点,因为数据这种东西需要工程师去主动记录,不记录就没有数据,记录了才有数据。
既然我们要做推荐系统,要分析用户行为,还要训练模型,显然需要数据。需要数据,就需要记录。
第二个步骤是流处理平台准实时数据处理,这个步骤基本上只在一些大厂中存在,一些小型企业里往往是没有的。这一步是干嘛的呢,其实也是记录数据,不过是记录一些准实时的数据。
很多同学又会迷糊了,实时我理解,就是当下立即的意思,准实时是什么意思呢?准实时的意思也是实时,只不过没有那么即时,比如可能存在几分钟的误差。这样存在误差的即时数据,行业术语叫做准实时。
那什么样的准实时数据需要记录呢?在推荐领域基本上只有一个类别,就是用户行为数据。也就是用户在观看这个内容之前还看过哪些内容,和哪些内容发生过交互。理想情况这部分数据也需要做成实时,但由于这部分数据量比较大,并且逻辑也相对复杂,所以很难做到非常实时,一般都是通过消息队列加在线缓存的方式做成准实时。
最后我们看第三个步骤,叫做离线数据处理,离线也就是线下处理,基本上就没有时限的要求了。
一般来说,离线处理才是数据处理的大头。所有“脏活累活”复杂的操作都是在离线完成的,比如说一些join操作。后端只是记录了用户交互的商品id,我们需要商品的详细信息怎么办?需要去和商品表关联查表。显然数据关联是一个非常耗时的操作,所以只能放到离线来做。
同样很多其他很复杂的操作也会放到离线完成,比如一些特殊的逻辑,对数据进行一些统计分析等操作。这部分操作的共同点就是耗时很大、逻辑也最复杂。
所以我们梳理一下这三个步骤会发现一个规律,实时性越强的数据操作越简单,逻辑越少,逻辑越复杂的操作实时性越差。
经过这三个步骤加工之后,我们就拿到了完整的数据,对于这部分数据行内一般称为raw feature。raw这个单词有生的意思,比如生鸡肉,英文就是raw chicken。所以raw feature指的就是未加工的,“生”的数据。
既然是生数据,显然是不能直接用的,我们还需要进行进一步加工。这一步工作称为特征工程(feature engineering),将原始的数据转化成模型能够识别的数据。比如raw feature可能是一个包含了很多字段的json文本,我们把它转化成模型能够读入的tensor结果。
到了这个时候,数据才算是真正加工完可以喂给模型了。
模型部分
模型这部分虽然看图片内容不多,但实际上这个部分非常复杂。涉及的细节很多,如果没有完整做过推荐系统,单纯看图可能会有盲区。
整个模型部分又可以被分成两个部分,分别是在线部分和离线部分。
我们先来说说底下离线部分,离线部分比较简单,包含的内容只有三个部分。第一个部分是离线评估,这个很好理解,我们训练了新的模型,总得有个指标评估,我们才能知道模型到底好不好。一般来说,最常用的指标就是AUC。计算起来方便容易,效果也不错。
离线评估效果好的模型才会进入第二个部分,也就是线上AB测试。所谓AB测试就是生物课上学的对照实验,同样的流量分配给两个不同的模型,一个是线上已有的模型,一个是新训练的模型。然后我们对比它们的一些指标,来判断模型的效果。如果现在的模型效果好,那么我们才会完整发布上线,推到全量。
第三个部分是在线更新,这个部分不是必须的,也和公司的技术积累有关。在线更新也就是每隔一段时间把线上的模型用最新的数据训练一下,更新一下参数,让模型学习一下最新的数据分布。毕竟流量是一直实时变化的,我们之前训练的模型只能从历史数据当中学到东西,很有可能因为时间的推移,数据当中的信息已经变化了。为了解决这个问题,才有了在线更新。
在线更新还有一个用途就是消弭AB实验时候的偏差,道理很简单,我们AB实验的时候都是和线上已有的模型进行对比。线上已有的模型可能是很久之前训练的,本身使用最新的数据训练就能带来一定的增益。所以如果直接对比,其实结果里都是隐含了模型新旧程度不同带来的偏差的。有了在线更新的部分可以消弭一些偏差。
说完了离线的部分,我们再来看看在线这块。
在线这个部分大同小异,一般无论公司大小,推荐系统基本上都是这个结构。首先我们要知道候选物品库往往是非常巨大的,比如淘宝,可能动辄有好几十亿的商品。所以如果我们每一次请求过来,我们都去几十亿的商品库去找推荐商品,显然是不可能的。
所以必须要进行精简,怎么精简呢?比较常规的做法是进行召回,也就是设计一些过滤算法,能够根据一些信息快速筛选出一小批相对比较不错的物品。一般这个量级大概在几百到一千左右,也就是说我们从几十亿物品当中被召回的只有一千左右。
针对这一千左右的商品,我们再进行排序,排序也就是让模型打分,然后根据模型的打分从高到低排序。排序本身也是一个过滤的过程,毕竟能够展示给用户的物品数量更少,这样只有排名靠前的物品才有被展出的可能。
当然一些大厂做得比较精细,在排序之后还有重排序,会再适度调整一下物品的位置。比如说把一些比较相似的商品分开,或者是穿插一些热门的内容等等。这一步也不是必须的,一般也只有大公司才有。小公司可能排序完就直接出结果了。
你会发现,说起来推荐系统好像只是一个系统,但其实这里面单拿出任何一个模块都非常复杂。这也是为什么大家都说大厂拧螺丝的原因,因为很可能某个人只会负责其中很小的一个模块。许多人说起自己的模块来如数家珍,但对于全局缺乏认识,带来的结果是当你某天跳槽了或者是工作内容变化了,之前从工作当中的学习积累很难沉淀下来,这对于程序员的成长来说是很不利的。
我最近抽了点时间复习了一下相关内容,感触尤为深刻。这个系列我也会继续更新下去,如果喜欢不要忘了给我一点支持,最后,感谢大家的阅读~