Redis: сумма баллов в отсортированном наборе - PullRequest
7 голосов
/ 31 января 2011

Какой лучший способ получить сумму баллов в наборе, отсортированном по Redis?

Ответы [ 4 ]

15 голосов
/ 31 января 2011

Я думаю, что единственная опция - это итерация отсортированного набора и вычисление суммы на стороне клиента.

11 голосов
/ 23 мая 2015

Доступно, так как Redis v2.6 - самая удивительная возможность выполнять сценарии Lua на сервере Redis. Это делает задачу суммирования баллов отсортированного набора тривиальной:

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
4 голосов
/ 19 февраля 2011

Если наборы малы и вам не нужна убийственная производительность, я бы просто повторил (zrange / zrangebyscore) и суммировал значения на стороне клиента.

Если, с другой стороны, вы говорите о многих тысячах - миллионах предметов, вы всегда можете сохранить набор ссылок с промежуточными итогами для каждого пользователя и увеличивать / уменьшать их по мере отправки подарков.

Таким образом, когда вы делаете ZINCR 123:gifts 1 "3|345", вы можете выполнить отдельную команду ZINCR, которая может выглядеть примерно так:

ZINCR received-gifts 1 <user_id>

Затем, чтобы получить количество подарков, полученных для данного пользователя, вам нужно просто запустить ZSCORE:

ZSCORE received-gifts <user_id>
1 голос
/ 14 марта 2016

Вот небольшой скрипт 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)
...