我正在用以下方式缓存Redis的扇形新闻提要:
每个feed活动都是一个键/值,如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…获取*命令的列表),或者它必须是zrange,然后遍历结果并获得每个值?
是的,排序集非常快速和强大。它们似乎比SORT
操作更符合您的要求。时间复杂性经常被误解。O(log(N))非常快,缩放也很好。我们用它来表示一个排序集中的数千万个成员。检索和插入时间低于毫秒。
使用ZRANGEBYSCORE key min max WITHSCORES [LIMIT offset count]
得到你的结果。
根据你如何将时间戳存储为"分数",ZREVRANGEBYSCORE可能更好。
关于时间戳的一个小注释:不需要小数部分的排序集SCORES
应该使用15位或更少的数字。所以SCORE
必须保持在- 99999999999999999到99999999999999999的范围内。注意:这些限制的存在是因为Redis服务器实际上在内部将分数(float)存储为Redis字符串表示。
因此,我建议使用这种格式,将其转换为祖鲁时间:-20140313122802以获得秒精度。您可以为100ms的精度增加1位,但是如果不希望精度损失,则不能增加。顺便说一下,它仍然是一个float64,所以在某些情况下失去精度可能是好的,但你的情况适合"完美精度"范围,所以这就是我的建议。
如果您的数据在10年内过期,您也可以跳过前三位数字(CCYY的CCY),以达到0.0001秒的精度。
我建议负分数在这里,所以你可以使用更简单的ZRANGEBYSCORE
代替REV
一个。您可以使用 -inf
作为起始分数(负无穷)和LIMIT 0 100
来获得前100名的结果。
两个排序集members
(或'keys'
,但这是模棱两可的,因为排序集本身也是一个键)可以共享score
,这没有问题,相同score
中的结果是按字母顺序排列的。
希望有帮助,TW
聊天后编辑
OP想要从不同的键(GET
/SET
或HGET
/HSET
键)收集数据(使用ZSET
)。JOIN
可以为你做这件事,ZRANGEBYSCORE
不能。这样做的首选方法是使用一个简单的Lua脚本。Lua脚本在服务器上执行。在下面的示例中,为了简单起见,我使用EVAL
,在生产环境中,您将使用SCRIPT EXISTS
、SCRIPT LOAD
和EVALSHA
。大多数客户端库都有一些内置的簿记逻辑,所以您不必每次都上传脚本。
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"