合并在数据存储中排序?

时间:2012-08-16 22:47:01

标签: redis

我正在尝试为我正在进行的项目制作一个“朋友流”。我在Redis ZSETS中保存了各个用户流。类似的东西:

key : { stream_id : time }
user1-stream: { 1:9931112, 3:93291, 9:9181273, ...}
user2-stream: { 4:4239191, 2:92919, 7:3293021, ...}
user3-stream: { 8:3299213, 5:97313, 6:7919921, ...}
...

user4-friends: [1,2,3]

现在,为了制作user4的朋友流,我会打电话:

ZUNIONSTORE user4-friend-stream, [user1-stream, user2-stream, user3-stream]

但是,当你尝试合并超过1-2000个元素的ZSETS时,ZUNIONSTORE很慢。

我真的很想让Redis在ZSETS上进行合并排序,并将结果限制为几百个元素。是否有任何现成的数据存储可以满足我的需求?如果没有,是否有任何类型的框架用于开发类似redis的数据存储?

我想我可以分叉Redis并添加我需要的功能,但我希望避免这种情况。

1 个答案:

答案 0 :(得分:2)

人们倾向于认为zs​​et只是一个跳过列表。这是错的。它是跳过列表(有序数据结构)加上非有序字典(实现为哈希表)。必须定义合并操作的语义。例如,如何合并其共同项目不具有相同分数的非不相交zset?

要为ZUNIONSTORE实现合并算法,您必须获取订购的项目(使用跳过列表很容易),在构建输出时合并它们(也恰好是zset:skiplist plus dictionary)。

因为在算法开始时无法猜到结果的基数,所以我认为不可能在线性时间内构建这个跳转列表+字典。它最好是O(n log n)。因此合并是线性的,但构建输出不是:它失败了使用合并算法的好处。

现在,如果你想实现一个ZUNION(即直接返回结果,不将结果构建为zset),并将结果限制为给定数量的项,则合并算法是有意义的。

支持合并连接的RDBMS通常可以这样做(但由于随机I / O的成本,这通常不是非常有效)。我不知道NoSQL商店支持类似功能。

要在Redis中实现它,你可以尝试一个Lua服务器端脚本,但它可能很复杂,我认为只有当zsets远大于zunion中提供的限制时它才会有效。在这种情况下,项目数量的限制将抵消运行解释的Lua代码的开销。

最后一种可能性是在Redis源代码中用C实现它,这并不困难。缺点是为您使用的Redis版本维护补丁的负担。 Redis本身没有提供这样做的框架,并且定义Redis插件(与Redis源代码隔离)的想法通常被作者拒绝。