我一直在努力寻找嵌套评论的数据结构(只有1级嵌套,例如facebook)
为了实现注释的非嵌套“提要”,我一直使用有序集来跟踪注释,使用得分作为时间戳,将成员用作包含渲染所需信息的json编码属性集评论。
所以添加评论可能如下所示:
zadd 'users:1:comments', 123456789, {body : 'hello'}
检索它就像这样简单:
zrevrange 'users:1:comments', 0, 20
为了支持嵌套的评论,我试图以某种方式扩展它 我已经用两种不同的方式集思广益,但每种方式都有问题:
1)
将comment_id添加到comment_id指向父评论的属性列表
zadd 'users:1:comments', 123456789, {id : 1, body : 'hello'}
zadd 'comments:1:comments', 123456789, {id : 2, body : 'nested hello', comment_id : 123 }
看起来像这样:
-hello
-nested hello
这种方法的问题在于分页。例如,如果注释有20个嵌套注释,并且我只显示前10个注释,那么嵌套树将被截断(将检索父注释+ 9个嵌套注释)
2)
将嵌套的评论放入自己的Feed:
This is a parent comment
zadd 'users:1:comments', 123456789, {id: 1, body : 'hello'}
this is a nested comment
zadd 'comments:1:comments' 123456789, {id: 2, body : 'nested hello'}
但是,在尝试显示用户的Feed时,这会导致N + 1次redis查询:
zrevrange 'users:1:comments', 0, 20
zrevrange 'comments:1:comments', 0, 20
zrevrange 'comments:2:comments', 0, 20
etc...
...更不用说嵌套注释可能不应该用范围选择。
理想情况下,我希望这可以使用单个redis查询,但我不确定如何构建我的数据以便这样做。
想法?
答案 0 :(得分:1)
我能想出的唯一方法就是使用Lists进行单一redis查询。
添加父项时,您只需将LPUSH
添加到列表的顶部(左侧)即可。添加子评论时,您会使用类似LINSERT 'user:1:comments' AFTER parent-comment-data child-comment-data
的内容。
这会导致redis搜索父注释数据并将子数据紧跟在其后面。这是一个O(N)操作,从顶部(左)到底部(右)完成,所以在列表的下方,父操作所需的时间越长,因此对于极长列表这个可能会有问题(但如果您将列表/线程大小保持在4或5位数范围内,则应该没问题。)
然后,一个简单的LRANGE
可以获取父母和孩子的最新评论,限制为任何数字。
您可以使用排序集中的分数值执行类似操作,为孩子提供的分数仅低于父分数。这可能会使插入显着复杂化,因为您可能会用尽两个父评论之间的可用分数,这意味着您必须运行操作来为许多(甚至大多数)评论重新分配分数。如果在每个插件上发生这种情况,您的插件可能会(不必要地)昂贵。