第11课:推荐系统的架构设计(下)

在第 10 课中我们对于整体的推荐系统所要解决的问题,以及系统整体的系统逻辑架构都有一个大致的了解。

在接下来的章节里,我们将继续延续对架构进行解析,从技术栈选择、数据流向以及实时离线架构分析等维度进行拆解,最后将重点讲讲实验平台,使用一个实例来呈现推荐实验平台的构建。

埋点上报

在了解系统逻辑架构的基础上,如果要落地实操,最终还是细化到技术机构上,我们来简单了解一下,基于上个章节的系统逻辑架构基础上,我们使用最通用的大数据相关组件,进行整个结构的搭建。

1-6

我们根据数据的流向来看这个图。

自下而上,原始数据层其实依然是业务表和埋点上报,业务表不多说,埋点上报,实际上是一个相对比较大的体系了,构建一个埋点上报体系,在流程上我们前端按要求进行上报信息封装,调用 JS 进行接口上报,当然这里的上报也可以封装成一个 SDK 包。

实际过程是一样的,都是调用接口,将数据上报过来,这里设计埋点服务的话也是可以做方案选择的,一种是重度的做法,就是实际起一个埋点服务,将上报的信息进行存储,另一种轻量级做法就是,实际上后端并没有一个后端服务,只是起了一个 Nginx 服务,将所有接口传入的信息以 Nginx 日志的形式落地下来。

我们发现,两种方式都能将我们要的信息上报,只不过一个是真正的服务,我们可以进行接口返回,以及跟前端做一些更灵活的交互,而后一种方式是个伪服务,说白了就是伪装成一个服务,拿到上报接口信息而已,这种没有这么灵活,但是架设起来成本很低。

数据落到文件层,再通过 Kafka 进行增量消费,最终发到 Spark Streaming 中处理。而业务数据则更简单了,直接通过离线的方式,通过 Sqoop 周期导入到 Hive 的数仓 ods 层进行汇总即可。

而对于埋点的设计,我们来看个简单的 App 页面上报设计逻辑实例:

{
    "static_args":                        //统一数据参数
    {
        "app_id":1,                     //app的类型标识id(三种)
        "device_id":"2b0a6f51a3cd6775", //设备唯一ID
        "report_time":1434556935,       //数据统一上报时间,long类型秒级
        "token":"65148d53ca3ab47502e8e393e0779f37",     //token加密串
        "manufacturer":"Apple",         //设备厂商:Apple/三星/小米/...
        "device": "iPhone 5",           //设备型号:iPhone 5/iPhone 6s/...
        "os":"iOS",                     //设备操作系统:ios/android/windows/...
        "os_version":"7.0",             //操作系统版本号:7.0/8.1.1/...
        "app_version":"2.6.5",          //app版本号:2.6.6/2.6.7/...
        "nsp":"CMCC",                   //网络供应商:CMCC/CUCC/CTCC/...
        "net_mode":"wifi",              //网络模式:wifi/4G/5G/3G/2G/...
        "screen_width":320,             //设备宽度
        "screen_height":640,            //设备长度
        "extend_str1":"",               //静态扩展字段1,无填充空str非null
        "extend_str2":"",               //静态扩展字段2,无填充空str非null
        "extend_str3":""                //静态扩展字段3,无填充空str非null
    },
    "dynamic_args":                     //动态数据
    [
        {
            "time":1434556935,      //该条数据生产时间,long类型秒级
            "user_id":89757,        //用户id,未登录的填充0
            "page_id":8,            //当前页面id
            "content_id":191833,    //页面承载的主体内容ID,例如商品ID/...,无填充0
            "module_id":2,          //页面模块id,部分是公共模块id,部分是页面专用id
            "opt_id":1,             //操作类型id,例如点击/滑动/...
            "extend_str1":"",       //动态扩展字段1,无填充空str非null
            "extend_str2":"",       //动态扩展字段2,无填充空str非null
            "extend_str3":""        //动态扩展字段3,无填充空str非null
        },
        ...
    ]
}

我们可以看到,这个上报结构设计,我们可以很方便的收集到我们所需要的静态信息,例如设备相关的,也可以收集到用户的动态行为,比如用户在访问哪个页面,当前做什么操作(点击/滑动等)等。

从数据的角度来说,收集越全的信息越有助于我们后续的分析,此外我们在设计上报体系的时候,一定要有足够的长远预见性,因为这个体系一旦落地,后续就更无法进行修改了,数据只会越累积越多,所以我们需要考虑足够多的兼容性,这也是为何上面实例中我们可以看到,预留了很多的扩展字段。

数据仓库

通过 Hive 以及 HBase 等进行数仓的搭建实际上是个比较好的解决方案。我们知道,数仓实际上是个更偏业务逻辑的概念,我们需要把数据进行分层清洗,分层/维度进行构建。

数据仓库是用以更好地支持企业或组织的决策分析处理的、面向主题的、集成的、不可更新的、随时间不断变化的数据集合,而我们的推荐算法所需要特征数据,输入数据,也都是需要基于数仓的处理结果进行的。

2-5

至于说每层的作用,这里就不过多阐述了,感兴趣的读者可以查查资料或者理解一下上面这张图就好。

模型层

关于模型层,我们可以看到,在批量逻辑计算的时候,是比较推荐 Spark 的,至于说一些模型的训练等等,这里就无所谓了。

我们所有的推荐召回,排序,都将会在 Spark 中完成,最终在这一层完成。

对于模型的训练,很多时候 Spark 的 MLlib 的局限性稍大,其算法集成度并不算很高,所以很多时候相关的模型将使用 Python 进行训练,当然也有可能基于 Spark 进行相关算法的实现,再进行分布式的部署。

存储 & 服务化

我们目前的做法是将推荐的最终候选集存储到 Redis 中,这里的存储颗粒度只到模型层,两层的 Key 来获取到对应的列表,第一层是模型 ID,每种模型每个迭代版本都有对应的唯一 ID,第二层是列表 Key,即比如如果是商品场景,这里的 Key 就是商品 ID,如果用户场景就是用户 ID。

即如果传入的是一个模型的指定 ID,以及指定的商品 ID 或者用户 ID,我们就可以对应拉出推荐列表,至于说到底应该传什么参数进来,由服务化应用读取实验平台中的配置来决定。

而推荐服务需要承担很多的业务逻辑,比如读取实验平台的配置,根据配置来找推荐列表数据,根据规则配置来走规则过滤,根据融合配置来融合算法模型的结果等等。

至于说怎么窜起来这个过程,我们后面针对于推荐实验平台详说。

数据闭环

我们可以看到推荐从业务层出去之后,会产生例如电商购买的业务数据,以及推荐的曝光点击反馈数据,还有用户的行为数据,最终又回到我们的数据源底层,形成一个闭环。

通过闭环的构建,我们就可以不断的优化这整个过程,通过数据的反馈来优化推荐算法,来优化策略的配置。

我们上面在涉及推荐服务化的时候,说到过,很多的配置都是通过实验平台进行管控,最终达到算法优化,迭代调优的目的,所以,我们整个机制需要支持这些逻辑。

在最后的章节里,我们将最最重要的推荐实验平台构建进行阐述,并且将会结合实际的实例进行讲解。

推荐实验平台是整个推荐系统能够保证稳定快速迭代的基础,并且最后我们还会结合推荐的产品设计的一些思维进行发散,我们下个章节见。

(全文完)

(转载本站文章请注明作者和出处 第11课:推荐系统的架构设计(下)