Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua script for Redis which sums the values of keys

I am building out my first Redis server side script (for debugging) and my lack of Lua experience has me quite stuck.

Essentially have a dataset of K/V pairs (containing ~1000 values) from which I want to list all the KEYS that match a pattern. For example in redis-cli:

> KEYS "carlos:*"
1) "carlos:1"
2) "carlos:2"
3) "carlos:3"
4) "carlos:4"

Based on the above output I want to return the sum of those keys by executing a Lua script. Currently I have the following on my sum.lua

local sum = 0
local matches = redis.call('KEYS', 'carlos:*')

for unpack(matches)
   sum = sum + redis.call('GET', matches)
end

return sum

While the above script is likely incorrect, trying even redis.call('KEYS', 'carlos:*') by itself produces the following error

root@carlos:~# redis-cli EVAL "$(cat sum.lua)"

(error) ERR wrong number of arguments for 'eval' command

I have tried a number of iterations of my syntax to no avail. Any ideas?

Thanks

like image 626
Carlos Avatar asked Feb 11 '14 16:02

Carlos


People also ask

What is Lua scripting in Redis?

Executing Lua in Redis. Redis lets users upload and execute Lua scripts on the server. Scripts can employ programmatic control structures and use most of the commands while executing to access the database. Because scripts execute in the server, reading and writing data from scripts is very efficient.

Are Redis Lua scripts Atomic?

Rate Limiting Lua Script​ Redis has the ability to execute Lua scripts on the server side. Lua scripts are executed atomically, that is, no other script or command will run while a script is running, which gives us the same transactional semantics as MULTI / EXEC .

Which Lua command causes script to terminate when Redis returns?

call() will raise a Lua error that in turn will force EVAL to return an error to the command caller, while redis. pcall will trap the error returning a Lua table representing the error." So according to the documentation , in the case of using redis.


1 Answers

  1. EVAL requires a minimum of two arguments; the script and the number of keys you are passing to the script. In this case, you are passing zero keys, meaning the script can be invoked as follows:

    redis-cli EVAL "$(cat sum.lua)" 0
    

    or:

    redis-cli --eval sum.lua
    
  2. Your loop structure for iterating over the values returned from KEYS was incorrect; I have fixed it for you.

  3. You need to convert the value returned from GET from a string to a number using Lua's tonumber function.

With the above changes made, the following script should work for you:

local sum = 0
local matches = redis.call('KEYS', 'carlos:*')

for _,key in ipairs(matches) do
    local val = redis.call('GET', key)
    sum = sum + tonumber(val)
end

return sum
like image 130
Tim Cooper Avatar answered Oct 01 '22 10:10

Tim Cooper