豆瓣首页的动态流如何设计与实现?

2016-04-23 10:05:01 +08:00
 vJianZhen

先看图,有个直观认识:

豆瓣首页上面的动态的类型有很多,有广播、日记、东西、(想看的)电影、(看过的)电影、友邻新关注的用户……等等很多很多,它是如何设计与实现的?

疑惑点主要是:

不同的内容数据存在不同的数据库,比方说广播存在 boardcast 表,日记存在 note 表,电影存在 movie 表……而豆瓣首页是按时间呈现动态的,如何在各个表中取出数据再做时间倒序排?难道是联合查询吗,那样的话用在查询数据库上面的时间岂不是很大。

再有就是如何针对不同的内容数据来渲染,比方说广播需要显示内容和赞评论等,而新写的日记显示摘要外还显示『喜欢』按钮……不同的内容虽然有大致一样的样式,但是细节上面又有区别,那么怎么显示?如果在 HTML 模板上使用模板引擎(如 Jinja2 )的 for 和 if 语法,但不同的内容类型不能写在一个 for 里面( for i in content ),因为模型对象的类型不一致;即使能克服上面的问题,那在 if 语句里面怎么判断内容的类型,再针对性地写渲染样式?

我能想到的是再加一个『中间表 timeline 』。当用户发表了日记,除了把数据写入 note 表,再把内容摘要写入 timeline 表(如内容类型代码 xxx ,时间 xxx ,内容 IDxxx 等);当用户发表了广播,除了把数据写入 boardcast 外,再把内容摘要写入 timeline 表(如内容类型 xxx ,时间 xxx ,内容 IDxxx 等)……这样首页动态流只需要从 timeline 表统一取数据,再根据不同的内容类型及其 ID 写不同的渲染样式。可是又有一个问题,如果我取关友邻, ta 的动态就不该出现在我的首页上,即在往这个 timeline 表插入数据时,如何做选择策略。

可能说的很乱,上一段可以不看。是不是我想复杂了,针对这个问题,不知道各位有什么设计和实现方法?还请不吝赐教,在下万分感激~

5919 次点击
所在节点    Python
22 条回复
JiShuTui
2016-04-23 10:13:22 +08:00
另有一张 feed 表用于存储,只存其他表的 id 就可以
vJianZhen
2016-04-23 10:23:40 +08:00
如果一个用户一张 feed 表,那么在关注某友邻以后,该友邻之前的动态怎么插入这个表?截止到什么时候的动态应该插入?相对应地,取关也有这个问题。
@JiShuTui
JiShuTui
2016-04-23 10:24:38 +08:00
@vJianZhen 我没说一个用户一张啊
vJianZhen
2016-04-23 10:26:06 +08:00
那能具体说说怎么实现吗?全站一个表也很难想象……囧。
@JiShuTui
zonghua
2016-04-23 10:32:36 +08:00
@JiShuTui 继承然后泛化吗
bingwenshi
2016-04-23 10:37:26 +08:00
跟朋友圈的逻辑是一样的,如果你的友邻更新了内容,只需要插入到你的 feed 流上就行了
vJianZhen
2016-04-23 10:44:57 +08:00
如果 feed 是一张表,还是那个问题,在关注用户 /取消关注后该用户的动态都要在 feed 表里面插入 /删除吗?

再有,这个表中的记录有多少,如果你有 150 个好友,平均一个好友有 500 条动态,难道这个表就有 150*500 个记录吗?

feed 表是否是动态的呢?因为如果用户没有刷得很深(不去查看很久以前的动态),那些动态是没有必要显示的,那那些动态还在表里面吗?还是这个表是随着用户上拉查看而动态生成的?
@bingwenshi
bingwenshi
2016-04-23 11:00:26 +08:00
虽然我没具体去了解过这部分,不过有几点可以讨论下

1. 关注用户,应该不会再去插入到 feed 里面,但是这个友邻新生成消息可以插入到你的 feed 上
2. 取关,直接在你的 feed 里面删了这个友邻的信息就可以了
bingwenshi
2016-04-23 11:04:57 +08:00
feed 这个数据应该不会保存你所有的数据,另外,数据不是动态生成的,是一开始就插入好了,包括 title , summary

你可以测试下嘛,我这边是到第 79 页 https://www.douban.com/?p=79 第 80 页就没数据了 https://www.douban.com/?p=80
vJianZhen
2016-04-23 11:13:00 +08:00
这个动态流是不是有这样的特性:我新关注的用户在这个关注时间点所发布的所有动态不会出现在 feed 表中,即如果我在今天关注了 xxx ,那我往后翻我的首页动态流,不会出现 xxx 在昨天前天以前发布的动态?

会有这个想法是因为按照你所说的实现方案,那新关注的用户的旧的动态流就没有必要加入 feed 表中。

其实,我大概赞同你的想法。
@bingwenshi
vJianZhen
2016-04-23 11:15:02 +08:00
我的也是,最终到 79 页。

@bingwenshi 这样的话,我慢慢理清思路了。谢谢~
pubby
2016-04-23 11:27:05 +08:00
通常关注的人不会太多(比如 100 ),所以另外一个思路是我的 feed 表只有自己的数据,同时把 feed 中最新 1000 条(比如)放入 redis

然后一次性获取 100 人的 top1000 ,重排序就行了
vJianZhen
2016-04-23 11:28:26 +08:00
没用过 redis ,它的作用是缓存么?
@pubby
pubby
2016-04-23 11:47:15 +08:00
redis 只是一种思路,因为常规数据库 IN (100 个 id) 的条件查询效率不高,不过 top1000 放内存表也是另外一种优化思路。

如果要最严谨的实现,那就是所有你关注的人的动态都要插入你自己的 timeline 列表
kongkongyzt
2016-04-23 12:02:00 +08:00
@vJianZhen 我试了一下, 在豆瓣上关注了一个在 2 小时前, 2 天前都发表了动态的人, 关注后刷新我的主页, 立马显示了他 2 小时前和 2 天前的那几条动态
vJianZhen
2016-04-23 12:03:48 +08:00
我也尝试过,跟你的情况一样。也许豆瓣有更好的实现方案吧,这也是我这个问题最想知道的。
@kongkongyzt
junnplus
2016-04-23 12:26:43 +08:00
feed 流大体上有两种实现方式,一种推,一种拉
junnplus
2016-04-23 12:30:25 +08:00
pubby
2016-04-23 12:35:30 +08:00
@vJianZhen 可以看一下这个 http://www.infoq.com/cn/articles/three-people-background-team-and-billions-daily-release

“相册表写好了之后,会触发一个批处理的动作。这个动作就是去跟小王的每个好友说,小王有一个新的发布,请把这个发布插入到每个好友的时间线里面去。”

“这是一个单数据副本写扩散的过程。但是相对应的,读取就很简单了,每一个用户只需要读取自己的时间线表,就这一个动作就行,而不需要去遍历所有好友的相册表。”
vincenttone
2016-04-23 16:28:26 +08:00
就看要不要根据目前的关注变化动态调整从前的消息了,如果有的话就需要增加一些操作,但是大体上都可以通过一个核心消息服务来解决。
各个模块在上线前按照一定规则推送消息到一个队列里, feed 那头接收消息存储就可以了。
如果需要动态调整从前的内容的话,就需要建一个库处理了,里面都是冗余数据,需要根据其他模块的状态和数据做调整。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/273821

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX