【问题标题】:Redis: Sum of SCORES in Sorted SetRedis:排序集中的分数总和
【发布时间】:2016-03-14 13:43:13
【问题描述】:

在 Redis 排序集中获得 SCORES 总和的最佳方法是什么?

【问题讨论】:

    标签: sum redis sortedset


    【解决方案1】:

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

    【讨论】:

    • 谢谢!是的,我想这对于 Redis 来说可能过于具体而无法实现......尤其是。因为我什至可能没有做一些可取的事情。我正在使用 zset 来存储用户收到的礼物 ID 和发送用户 ID,SCORE 是从同一发件人那里收到相同礼物的次数。例如,ZINCR 123:gifts 1 "3|345" 将礼物 w id 3 从用户 345 发送给用户 123。所以,我想获取用户收到的礼物总数。看?也许有更好的方法来实现这一点?它就像 Facebook 礼物 API。 Redis 规则! :) 谢谢你的一切!
    【解决方案2】:

    自 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
    

    【讨论】:

    • 一个重要的注意事项是 Redis 服务器端 lua 脚本会阻塞一切,这在大多数情况下可能会破坏交易。来源:stackoverflow.com/a/30896608/2440
    【解决方案3】:

    如果集合很小,并且您不需要出色的性能,我会迭代 (zrange/zrangebyscore) 并对客户端的值求和。

    另一方面,如果您谈论的是成千上万 - 数百万个项目,您始终可以为每个用户保留一个包含运行总计的参考集,并在发送礼物时增加/减少它们。

    因此,当您执行 ZINCR 123:gifts 1 "3|345" 时,您可以执行单独的 ZINCR 命令,可能是这样的:

    ZINCR received-gifts 1 <user_id>
    

    然后,要获得给定用户收到的礼物数量,您只需要运行 ZSCORE:

    ZSCORE received-gifts <user_id>
    

    【讨论】:

    • 到目前为止,增量计数在在线问题上胜出。扫描只能用于离线算法,恕我直言,因为没有人可以预测未来数据集的增长。这个答案应该是被接受的。哦,顺便说一句:一个人可能会编写一个自定义命令,这两者都可以(添加到集合并增加计数器;更新值并调整计数器,从集合中删除......)
    • 显然这个答案已经很老了,但是,为什么要为“单独的命令”使用 ZSET 呢?从你的回答中我不清楚,据我所知,它与使用 INCR/GET 一样好(并且使用更少的内存)。
    【解决方案4】:

    这里有一个小 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)
    

    【讨论】:

    • 该脚本不应在 lua (KEYS[1]..'.ss') 中构造键,这“违反了 EVAL 命令语义​​,因为脚本使用的所有键都应使用 KEYS 数组传递” -- @987654321 @
    • @Jonathan你是对的,总分的key也应该在KEYS[]中传递
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-26
    • 2014-06-05
    • 1970-01-01
    相关资源
    最近更新 更多