Search code examples
performanceluaredisroundtrip

Lua script in Redis: HMGET with table?


Does any similar behaviour to passing a table to a single redis.call('HMGET',[key],...) exist, rather than looping through the table and running multiple redis.call, one after another?


I have a hash key in Redis that represents a Fenwick tree with 100000 entries. It has sequential integer indexes and float values:

127.0.0.1:6379[1]> hmget fenwick 1 2 3 4 ...
1) "0.75865226460558"
2) "1.0234678955857959"
3) "0.057608450324092272"
4) "1.1002286486794375"
...

I am trying to find the sum to some random entry entryid using Redis' built-in Lua interpreter. Obviously, the naive way of doing so would be to perform single accesses against the table one at a time like this:

local sum=0
while entryid>0 do
    sum=sum+redis.pcall('HGET',KEYS[1],temp)
    entryid=entryid-bit.band(entryid,-entryid)
end

I've tried to generate and load a string to compress all the commands into one HMGET and reduce round trips:

local evalstr="return redis.pcall('HMGET',KEYS[1]"
local sum=0
while entryid>0 do
    evalstr=evalstr..','..temp
    entryid=entryid-bit.band(temp,-temp)
end
local vals=loadstring(evalstr..')')()
for i=1,#vals do
    sum=sum+vals[i]
end

However, the overhead of compilation makes this query slower than the first no matter what size fenwick is.

Essentially, I'm looking for this behaviour:

local tbl={}
local c=1
while temp>0 do
    tbl[c]=temp
    c=c+1
    temp=temp-bit.band(temp,-temp)
end
local vals=redis.pcall('HMGET',KEYS[1],tbl)
local sum=0
for i=1,#vals do
    sum=sum+vals[i]
end

But obviously it doesn't work. Is there some way to collect all the values I want to query to Redis in Lua first, then send them to Redis in a single command?


Solution

  • You can turn a Lua table into a series of arguments to a variadic function with the built-in unpack function.

    In your case, do the following in your Lua script:

    redis.pcall('HMGET',KEYS[1],unpack(tbl))