流动的推荐系统——兴趣Feed技术架构与实现

 

图7 Pinnability的模型流程


兴趣Feed的技术要点
分析完Pinterest的兴趣Feed实现,我们再总结一下一个通用的兴趣Feed需要考虑哪些方面。

整体逻辑

整体逻辑上,一个兴趣Feed逻辑结构大致如图8所示。


 

图8 兴趣Feed整体逻辑


数据模型

Feed这种形式又叫做Activity Stream。顾名思义,就是用户的动作(Activity)形成的数据流(Stream)。

Feed的基本数据有三个:用户(User)、动态(Activity)和关系(Connection)。

表达用户动态(Activity)的元素有相应的规范,叫做Atom,可以参考它,并结合产品需求,定义出自己的Feed数据模型。根据Atom的定义,一条动态包含以下元素:

  • Time:发生的时间。
  • Actor:由谁发出的?通常Actor就是用户ID,但是我们也可以扩展到其它拟人化物体上,如关注的一个“店铺”、收藏的一部“电影”。
  • Verb:动词,动态核心是哪一个动作?比如“follow”、“like”等。
  • Object:动作作用到最主要的对象,只能有一个。
  • Target:动作的最终目标,与verb有关,可以没有。它对应英语中介词to后接的事物,比如“John saved a movie to his wishlist”(John保存了一部电影到清单里),这里电影就是Object,而清单就是Target。
  • Title:动态的标题,自然语言描述。
  • Summary:通常是一小段HTML代码,是对这个Activity的描述,还可能包含类似缩略图这样的可视化元素,可以理解为Activity的view,不是必须的。


举个例子: 2016年5月6日23:51:01(Time)@刑无刀(Actor)分享了(Verb) 一条微博(Object)给 @ResysChina(Target)。Title就是前面这句话去掉括号后的内容,Summary暂略。

关系即连接。互联网产品里处处皆连接,有强有弱,好友关系、关注关系等社交是较强的连接,还有点赞、收藏、评论、浏览,这些动作都可以认为用户和另一个对象之间建立了连接。有了连接,就有Feed的传递和发布。

定义一个连接的元素有:

  • from: 连接的发起方。
  • to:被连接方。
  • type/name: 连接的类型/名字、关注、加好友、点赞、浏览、评论等。
  • affinity:连接的强弱。


如果把建立一个连接也视为一个Atom模型的话,from就对应其中的Actor,to就对应其中的Object。

连接的发起从from到to,动态的流动从to到from。连接和动态是相互加强的,类似蛋和鸡的关系:有了动态,就会产生新的连接;有了新的连接,就可以喂(Feed)给你更多的动态内容。

发布新动态

用户登录/刷新后,Feed是怎么产生的?内容出现在受众的Feed中,这个过程称为Fan-out。

我们的直觉上是这样实现的:

  • 获取用户所有连接的终点(如好友或者关注对象)。
  • 获取这些连接终点(关注对象)产生的新内容(Activity)。
  • 排序后输出。

 


 

图9 拉模式产生内容


这就是行话说的拉模式(Fan-out-on-load),Feed是在用户登录/刷新后实时产生的。

拉模式的好处如下:

  • 实现简单直接:一行SQL就搞定了。
  • 实时:内容产生了,受众只要刷新就看得见。


但是也存在不足:

  • 随着连接数的增加,这个操作的复杂度是指数级增加的,显然不可取。
  • 内存中要保留每个人的产生的内容。
  • 服务很难做到高可用。


与拉模式对应的,还有一个推模式(Fan-out-on-write)。


 

图10 推模式产生内容


当一个用户(Actor)产生了一条Activity后,不管受众是否刷新,立即将这条内容推送给相应的用户(和这个Actor建立了连接的人),系统为每一个用户单独开辟一个Feed存储区域,用于接收推送的内容。当用户登录后,系统只需要读取他自己的Feed即可。

推模式的好处显而易见:在用户访问自己的Feed时,几乎没有任何复杂的查询操作,所以服务可用性较高。