Redis:在列表或有序集合中分发新闻提要?

5

我正在使用Redis缓存扇出新闻订阅,方法如下:

每个订阅活动都是一个键/值对,例如形如activity:id,其中值是数据的JSON字符串。

每个新闻订阅目前都是一个列表,键为feed:user:user_id,列表包含相关活动的键。

为了检索新闻订阅,我使用例如“sort feed:user:user_id by nosort get * limit 0 40”这样的命令。

我正在考虑将订阅更改为排序集合,其中分数是活动的时间戳,这样订阅总是按时间排序。

我读到了http://arindam.quora.com/Redis-sorted-sets-and-lists-Pertaining-to-Newsfeed,它推荐使用列表,因为排序集合的时间复杂度,但如果继续使用列表,我必须注意插入顺序,插入过去的故事需要遍历列表并找到正确的索引进行推送 (在分布式环境中可能会引起新的问题)。

我应该继续使用列表还是选择排序集合?

是否有一种从排序集合中立即检索新闻订阅的方法(类似于对于列表的sort ... get *命令),还是必须使用zrange,然后遍历结果并获取每个值?

1个回答

6

是的,有序集合非常快速和强大。它们似乎比 SORT 操作更适合您的要求。时间复杂度经常被误解。O(log(N)) 非常快,并且可以很好地扩展。我们在一个有序集合中使用它来处理数千万个成员。检索和插入的时间小于一毫秒。

使用 ZRANGEBYSCORE key min max WITHSCORES [LIMIT offset count] 来获取您的结果。

根据您如何将时间戳存储为“分数”,ZREVRANGEBYSCORE 可能更好。

关于时间戳的小备注:不需要小数部分的有序集合SCORES应使用15位数字或更少。因此,SCORE必须保持在-999999999999999到999999999999999的范围内。注意:这些限制存在,因为Redis服务器实际上将分数(浮点数)作为redis字符串表示内部存储。
因此,我建议使用此格式,转换为 Zulu Time:-20140313122802以获得秒精度。如果要保持完美精度,则可以添加1个数字以获得100ms精度,但不能再添加更多。顺便说一句,它仍然是float64,因此在某些情况下,精度损失可能是可以接受的,但您的情况适用于“完美精度”范围,因此这是我推荐的。
如果您的数据在10年内过期,则还可以跳过前三位数字(CCY或CCYY),以实现0.0001秒的精度。
我建议在这里使用负数分数,这样您可以使用更简单的ZRANGEBYSCORE而不是REV。您可以使用-inf作为起始分数(负无穷大),并使用LIMIT 0 100来获取前100个结果。
两个排序集合members (或'keys',但这是不明确的,因为排序集合本身也是一个键) 可能共享一个score,这没有问题,在相同的score中,结果是按字母顺序排列的。
希望这有所帮助,TW 聊天后编辑 该用户想要使用ZSET从不同的键(GET/SETHGET/HSET)中收集数据。这可以通过JOIN完成,但ZRANGEBYSCORE无法实现。最好的方法是使用一个简单的Lua脚本。该Lua脚本在服务器上执行。在下面的示例中,我使用EVAL来简化操作,在生产环境中,您将使用SCRIPT EXISTSSCRIPT LOADEVALSHA。大多数客户端库都内置了一些记录逻辑,因此您不需要每次上传脚本。

以下是一个example.lua示例:

local r={}
local zkey=KEYS[1]
local a=redis.call('zrangebyscore', zkey, KEYS[2], KEYS[3], 'withscores', 'limit', 0, KEYS[4])
for i=1,#a,2 do
  r[i]=a[i+1]
  r[i+1]=redis.call('get', a[i])
end
return r

你可以这样使用它 (原始示例,未针对性能编码):
redis-cli -p 14322 set activity:1 act1JSON
redis-cli -p 14322 set activity:2 act2JSON
redis-cli -p 14322 zadd feed 1 activity:1
redis-cli -p 14322 zadd feed 2 activity:2 

redis-cli -p 14322 eval '$(cat example.lua)' 4 feed '-inf' '+inf' 100

结果:

1) "1"
2) "act1JSON"
3) "2"
4) "act2JSON"

1
我使用UNIX时间戳(10位数字)作为分数。我能直接从排序集合中获取反馈吗?对于列表,我可以执行“sort feed by nosort get *....” - Gal Ben-Haim
当然可以。10位数比15位数小。顺便说一下,我在关于大O的帖子中加了一些额外的信息。 - Tw Bert
1
谢谢您详细的回答,我该如何直接获取数据流?(实际活动的值而不仅仅是它们的键)。'ZRANGE'将返回带或不带分数的键。 - Gal Ben-Haim
你有没有尝试过它?你不需要使用ZRANGE,只需要用ZADDZREVRANGEBYSCORE。如果我误解了你的问题,请原谅。 - Tw Bert
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Gal Ben-Haim
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接