2
\$\begingroup\$

Here is the code I invoke as Lua script in Redis. I use Redis sorted set to store game scores. This function is used to get some kind of overview of leaderboard. It returns id, score and rank of:

  • first 3 results
  • 2 above player
  • player
  • 2 below player
  • worst 3

It works as I wanted but I don't write much Lua code so review from expert would be nice. Parameters passed to script:

  • keys[1] = lb_id used as redis key
  • keys[2] = member (player id)
  • argv[1] = order (true -> desc)

And the script itself:

local myRank = 0
if (ARGV[1])
then
    myRank = redis.call('ZREVRANK', KEYS[1], KEYS[2])
else
    myRank = redis.call('ZRANK', KEYS[1], KEYS[2])
end
-- get total number of scores in lb
local total = redis.call('ZCARD', KEYS[1])
-- prepare array for response
local result = {}
--get top 3 playes
local head = {}
if (ARGV[1])
then
    head = redis.call('ZREVRANGE',KEYS[1], 0, 2, 'WITHSCORES')
else
    head = redis.call('ZRANGE',KEYS[1], 0, 2, 'WITHSCORES')
end

-- redis returns rank inside of range as index of array (0 based)
-- we need to inject proper rank into response so backend could use it
-- as it's return as list of strings (id, score, id, score...)
-- just add rank every 2 lines

for k,v in pairs(head) do 
    if (k%2 == 0)
    then
        result[#result + 1] = v
        result[#result + 1] = k/2
    else
        result[#result + 1] = v
    end 
end
--get players around me (ranks -/+ 2) including player
-- -1 is because we get 2 players above and rank in response is 0 indexed
local s = -1
local myLocal = {}
if (ARGV[1])
then
    myLocal = redis.call('ZREVRANGE', KEYS[1], myRank - 2, myRank + 2, 'WITHSCORES')
else
    myLocal = redis.call('ZRANGE', KEYS[1], myRank - 2, myRank + 2, 'WITHSCORES')
end
for k,v in pairs(myLocal) do 
    if (k%2 == 0)
    then
        result[#result + 1] = v
        result[#result + 1] = myRank + s
        s = s + 1
    else
        result[#result + 1] = v
    end
end
-- get last 3 players
-- do this if player is not one of last ones
if (myRank < total -3)
then
    -- -2 is because we get 3 players above and rank in response is 0 indexed
    s = -2
    local tail = {}
    if (ARGV[1])
    then
        tail = redis.call('ZREVRANGE', KEYS[1], total - 3, total, 'WITHSCORES')
    else
        tail = redis.call('ZRANGE', KEYS[1], total - 3, total, 'WITHSCORES')
    end
    for k,v in pairs(tail) do 
        if (k%2 == 0)
        then
            result[#result + 1] = v
            result[#result + 1] = total + s
            s = s + 1
        else
            result[#result + 1] = v
        end 
    end
end
return result

Isn't this too heavy for Redis script? Is there a better way to inject numeric rank value into response?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.