基于用户画像的实时异步化视频推荐系统

前言

这个月做的事情还是蛮多的。上线了一个百台规模的ES集群,还设计开发了一套实时推荐系统。 标题有点长,其实是为了突出该推荐系统的三个亮点,一个是实时,一个是基于用户画像去做的,一个是异步化。

实时主要体现在三个层面:

  1. 用户画像中的的短期兴趣模型实时构建。

    也就是你看完一个视频,这个视频几秒内就影响了你的短期兴趣模型,并且反应到你下次的推荐中。

  2. 候选集实时变更。

    在我设计的推荐系统中,候选集的概念是不同类型的待推荐给用户的视频库,一个用户并不能看到某个候选集的全部,而是能够看到经过匹配算法处理完后的候选集的一部分。 候选集的更新周期直接影响用户能够看到的视频的实时性。候选集可以有很多,通过不同的候选集解决不同的推荐场景问题。比如结合最新候选集和最近N小时最热候选集,我们可以做到类似今日头条的推荐效果。新内容候选集的产生基本就是实时的,而最近N小时热门视频候选集则可能是分钟级别就可以得到更新。还有比如协同就可以做视频的相关推荐,而热门候选集则可以从大家都关心的内容里进一步筛出用户喜欢的内容。

  3. 推荐效果指标的实时呈现。

    上线后你看到的一些比较关键的指标例如点击转化率,都可以在分钟级别得到更新。推荐系统有个比较特殊的地方,就是好不好不是某个人说了算,而是通过一些指标来衡量的。比如点击转化率。

用户画像和视频画像

用户画像则体现在兴趣模型上。通过构建用户的长期兴趣模型和短期兴趣模型可以很好的满足用户兴趣爱好以及在用户会话期间的需求。做推荐的方式可以很多,比如协同,比如各种小trick,而基于用户画像和视频画像,起步难度会较大,但是从长远角度可以促进团队对用户和视频的了解,并且能够支撑推荐以外的业务。

异步化

推荐的计算由用户刷新行为触发,然后将用户信息异步发送到Kafka,接着Spark Streaming程序会消费并且将候选集和用户进行匹配计算,计算结果会发送到Redis 的用户私有队列。接口服务只负责取推荐数据和发送用户刷新动作。新用户或者很久没有过来的用户,它的私有队列可能已经过期,这个时候异步会产生问题。前端接口一旦发现这个问题,有两种解决方案:

  1. 会发送一个特殊的消息(后端接的是Storm集群), 接着hold住,等待异步计算结果
  2. 自己获取用户兴趣标签,会按一定的规则分别找协同,然后到ES检索,填充私有队列,并迅速给出结果。(我们采用的方案)

除了新用户,这种情况总体是少数。大部分计算都会被异步计算cover住。

流式技术对推荐系统的影响

我之前写了很多文章鼓吹流式技术,最露骨的比如 数据天生就是流式的。 当然主要和我这一两年部门的工作主体是构建
流式流水线(Pipline),解决实时日志计费等相关问题。流式计算对推荐系统的影响很大,可以完全实现

在推荐系统中,除了接口服务外,其他所有计算相关的,包括但不限于:

  1. 新内容预处理,如标签化,存储到多个存储器
  2. 用户画像构建 如短期兴趣模型
  3. 新热数据候选集
  4. 短期协同
  5. 推荐效果评估指标如点击转化率

这些流程都是采用Spark Streaming来完成。对于长期协同(一天以上的数据),用户长期兴趣模型等,则是采用Spark 批处理。因为采用了StreamingPro这个项目,可以做到所有计算流程配置化,你看到的就是一堆的描述文件,这些描述文件构成了整个推荐系统的核心计算流程。

这里还值得提的三点是:

  1. 推荐效果评估,我们采用Spark Streaming + ElasticSearch的方案。也就是Spark Streaming 对上报的曝光点击数据进行预处理后存储到ES,然后ES提供查询接口供BI报表使用。这样避免预先计算指标导致很多指标实现没有考虑到而不断变更流式计算程序。

  2. 复用现有的大数据基础设施。整个推荐系统只有对外提供API的服务是需要单独部署的,其他所有计算都使用Spark跑在Hadoop集群上。

  3. 所有计算周期和计算资源都是可以方便调整的,甚至可以动态调整(Spark Dynamic Resource Allocatioin)。这点非常重要,我完全可以放弃一定的实时性来节省资源或者在闲暇时让出更多资源给离线任务。当然这些都益于Spark 的支持。