Redis: somma dei PUNTEGGI nel set ordinato
Domanda
Qual è il modo migliore per ottenere la somma dei PUNTEGGI in un insieme ordinato di Redis?
Soluzione
L'unica opzione che penso sia l'iterazione dell'insieme ordinato e il calcolo della somma lato client.
Altri suggerimenti
Disponibile a partire da Redis v2.6 è la capacità più straordinaria di eseguire script Lua sul server Redis.Questo rende banale la sfida di riassumere i punteggi di un Sorted Set:
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
Esempio di runtime:
~$ 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
Se i set sono piccoli e non hai bisogno di prestazioni killer, io itererei semplicemente (zrange / zrangebyscore) e sommerei i valori lato client.
Se, d'altra parte, stai parlando di molte migliaia, milioni di articoli, puoi sempre mantenere un set di riferimenti con totali parziali per ogni utente e incrementarli / decrementarli man mano che i regali vengono inviati.
Quindi, quando esegui il tuo ZINCR 123:gifts 1 "3|345"
, potresti eseguire un comando ZINCR separato, che potrebbe essere qualcosa del genere:
ZINCR received-gifts 1 <user_id>
Quindi, per ottenere il numero di regali ricevuti per un determinato utente, è sufficiente eseguire uno ZSCORE:
ZSCORE received-gifts <user_id>
Ecco un piccolo script lua che mantiene il totale del punteggio zset mentre procedi, in un contatore con la chiave postfissa con ".ss".Puoi usarlo al posto di 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)