2011-01-30 76 views

回答

12

我认为唯一的选择是迭代排序后的集合并计算总和客户端。

+0

谢谢!是的,我想这可能是Redis为了执行...而特别设计的一个特性。因为我甚至可能没有做一些明智的事情。我使用zset来存储用户收到的礼品ID和发送用户ID,SCORE是从同一个发件人收到同一礼品的次数。例如,`ZINCR 123:礼物1“3 | 345”`将来自用户345的礼物w id 3发送给用户123.因此,我希望得到用户已收到的总礼物。看到?也许有更好的方法来实现这一点?这就像Facebook Gift API。 Redis规则! :)谢谢你的一切! – ma11hew28 2011-02-02 17:55:36

3

如果集合很小,并且不需要杀手级的性能,那么我只需迭代(zrange/zrangebyscore)并对客户端的值进行求和即可。

另一方面,如果您谈论的是数千至数百万个项目,您可以随时为每个用户保留一个参考集合,然后在发送礼物时递增/递减总计。

所以,当你做你的ZINCR 123:gifts 1 "3|345",你可以做一个单独的ZINCR命令,这可能是这样的:

ZINCR received-gifts 1 <user_id> 

然后,得到的礼物#给定用户接收到的,你只需要运行ZSCORE:

ZSCORE received-gifts <user_id> 
+0

增量计数赢得了迄今为止的在线问题。扫描只能用于离线算法,恕我直言,因为没有人可以预测未来数据集的增长。这个答案应该是被接受的答案。 呵呵,顺便说一句:有人可能会写一个自定义命令,它可以同时执行这两个操作(增加一个集合并递增计数器;更新一个值并调整计数器,从集合中删除......) – 2015-05-23 19:07:36

5

可用,因为Redis v2.6是在Redis服务器上执行Lua脚本的最棒的能力。这使得一个有序集合的成绩总结琐碎的挑战:

local sum=0 
local z=redis.call('ZRANGE', KEYS[1], 0, -1, 'WITHSCORES') 

for i=2, #z, 2 do 
    sum=sum+z[i] 
end 

return sum 

运行例如:

~$ redis-cli zadd z 1 a 2 b 3 c 4 d 5 e 
(integer) 5 
~$ redis-cli eval "local sum=0 local z=redis.call('ZRANGE', KEYS[1], 0, -1, 'WITHSCORES') for i=2, #z, 2 do sum=sum+z[i] end return sum" 1 z 
(integer) 15 
+2

一个重要的注意事项是Redis服务器-Lua脚本封锁了一切,在大多数情况下这可能是一个破坏者。来源:http://stackoverflow.com/a/30896608/2440 – Sire 2016-12-20 08:32:23

1

这里是一个小LUA脚本,当您去维持的zset成绩总在一个柜台关键字后缀为'.ss'。您可以使用它来代替ZADD。

local delta = 0 
for i=1,#ARGV,2 do 
    local oldScore = redis.call('zscore', KEYS[1], ARGV[i+1]) 
    if oldScore == false then 
     oldScore = 0 
    end 
    delta = delta - oldScore + ARGV[i] 
end 
local val = redis.call('zadd', KEYS[1], unpack(ARGV)) 
redis.call('INCRBY', KEYS[1]..'.ss', delta) 
+1

该脚本不应该在lua(`KEYS [1] ..'。ss'`)中构造密钥,该密钥违反了EVAL命令语义,脚本使用的密钥应该使用KEYS数组传递“ - https://redis.io/commands/eval – Jonathan 2018-02-09 04:00:50