Search code examples
luaredisevalredis-cli

intersect multiple sets with lua script using redis.call("sinter", ...) command


I want to intersect multiple sets (2 or more). The number of sets to be intersected are passed as ARGV from command line. As number of sets are being passed from command-line. So the number of arguments in redis.call() function are uncertain.

How can I do so using redis.call() function in Lua script.

However, I have written a script which has algo like:

  • Accepting the number of sets to be intersected in the KEYS[1].
  • Intersecting the first two sets by using setIntersected = redis.call(ARGV[1], ARGV[2]).
  • Running a loop and using setIntersected = redis.call("sinter", tostring(setIntersected), set[i])
  • Then finally I should get the intersected set.

The code for the above algorithm is :

local noOfArgs = KEYS[1] -- storing the number of arguments that will get passed from cli

--[[
    run a loop noOfArgs time and initialize table elements, since we don't know the number of sets to be intersected so we will use Table (arrays)
--]]

local setsTable = {}

for i = 1, noOfArgs, 1 do
    setsTable[i] = tostring(ARGV[i])
end


-- now find intersection
local intersectedVal = redis.call("sinter", setsTable[1], setsTable[2]) -- finding first intersection because atleast we will have two sets
local new_updated_set = ""
for i = 3, noOfArgs, 1 do
    new_updated_set = tostring(intersectedVal)
    intersectedVal = redis.call("sinter", new_updated_set, setsTable[i])
end

return intersectedVal

This script works fine when I pass two sets using command-line.

EG:

redic-cli --eval scriptfile.lua 2 , points:Above20 points:Above30

 output:-  

 1) "playerid:1"

 2) "playerid:2"

 3) "playerid:7"

Where points:Above20 and points:Above30 are sets. This time it doesn't go through the for loop which starts from i = 3.

But when I pass 3 sets then I always get the output as:

(empty list or set)

So there is some problem with the loop I have written to find intersection of sets.

Where am I going wrong? Is there any optimized way using which I can find the intersection of multiple sets directly?


Solution

  • What you're probably looking for is the elusive unpack() Lua command, which is equivalent to what is known as the "Splat" operator in other languages.

    In your code, use the following:

    local intersectedVal = redis.call("sinter", unpack(setsTable))
    

    That said, SINTER is variadic and can accept multiple keys as arguments. Unless your script does something in addition to just intesects, you'd be better use that instead.