【发布时间】:2016-03-14 13:43:13
【问题描述】:
在 Redis 排序集中获得 SCORES 总和的最佳方法是什么?
【问题讨论】:
在 Redis 排序集中获得 SCORES 总和的最佳方法是什么?
【问题讨论】:
我认为唯一的选择是迭代排序集并计算总和客户端。
【讨论】:
ZINCR 123:gifts 1 "3|345" 将礼物 w id 3 从用户 345 发送给用户 123。所以,我想获取用户收到的礼物总数。看?也许有更好的方法来实现这一点?它就像 Facebook 礼物 API。 Redis 规则! :) 谢谢你的一切!
自 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
【讨论】:
如果集合很小,并且您不需要出色的性能,我会迭代 (zrange/zrangebyscore) 并对客户端的值求和。
另一方面,如果您谈论的是成千上万 - 数百万个项目,您始终可以为每个用户保留一个包含运行总计的参考集,并在发送礼物时增加/减少它们。
因此,当您执行 ZINCR 123:gifts 1 "3|345" 时,您可以执行单独的 ZINCR 命令,可能是这样的:
ZINCR received-gifts 1 <user_id>
然后,要获得给定用户收到的礼物数量,您只需要运行 ZSCORE:
ZSCORE received-gifts <user_id>
【讨论】:
这里有一个小 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)
【讨论】:
KEYS[1]..'.ss') 中构造键,这“违反了 EVAL 命令语义,因为脚本使用的所有键都应使用 KEYS 数组传递” -- @987654321 @