Redis的Lua脚本,它总结了键的值

时间:2014-02-11 16:10:27

标签: database scripting compiler-errors lua redis

我正在构建我的第一个Redis服务器端脚本(用于调试),而我缺乏Lua经验让我陷入困境。

基本上有一个K / V对的数据集(包含~1000个值),我想从中列出与模式匹配的所有KEYS。例如,在redis-cli中:

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

根据上面的输出,我想通过执行Lua脚本返回这些键的总和。目前,我的sum.lua

上有以下内容
local sum = 0
local matches = redis.call('KEYS', 'carlos:*')

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

return sum

虽然上述脚本可能不正确,但偶然尝试redis.call('KEYS', 'carlos:*')会产生以下错误

  

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

     

(错误)ERR错误的参数数量为' eval'命令

我尝试过多次迭代我的语法无济于事。有什么想法吗?

由于

2 个答案:

答案 0 :(得分:20)

  1. EVAL至少需要两个参数;脚本和传递给脚本的键数。在这种情况下,您传递零键,这意味着可以按如下方式调用脚本:

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

    或:

    redis-cli --eval sum.lua
    
  2. 用于迭代从KEYS返回的值的循环结构不正确;我已经为你修好了。

  3. 您需要使用Lua的GET函数将从tonumber返回的值从字符串转换为数字。

  4. 通过上述更改,以下脚本应该适合您:

    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
    

答案 1 :(得分:1)

对于初学者的一些重要提示:

KEYS和ARGV :这些是Lua中的表,这些表将在Redis的Lua脚本内保存您的Redis客户端发送的数据。

  • 表是关联数组,而Lua唯一的机制 结构化数据。您可以将它们视为数组的等效项 用您最喜欢的任何一种语言。 基于索引的,即索引从1开始。因此,第一个元素 mytablemytable[1],第二个是mytable[2],依此类推。

  • 表不能保存nil值。如果一个操作会产生一个表 [ 1, nil, 3, 4 ],结果将改为[ 1 ]-表为 在第一个nil值处被截断。

注意: 为Redis编写Lua脚本时,应仅通过KEYS表访问每个被访问的键。 ARGV表用于参数传递

我认为您现在可以将密钥和参数从任何语言传输到Lua脚本。

现在,我们可以进入Lua的redis call来重新发布命令KEYS

要遍历返回的数据,您可以选择使用lua的pairsipairs,可以发现一些here的快速差异。对于上述情况,ipairs就可以了。

现在,我们可以继续进行数据类型问题

Lua和Redis具有不同的类型系统,因此了解跨Redis-Lua边界时值如何变化很重要。当一个数字从Lua返回到Redis客户端时,它变成一个整数-小数点后的任何数字都将被丢弃:

local indiana_pi = 3.2
return indiana_pi

运行此脚本时,Redis将返回3的整数-您会丢失有趣的pi。看起来很简单,但是当您在脚本中间开始与Redis交互时,事情会变得有些棘手。一个例子:

local indiana_pi = 3.2
redis.call("SET", "pi", indiana_pi)
return redis.call("GET", "pi")

这里的结果值是一个字符串:“ 3.2”为什么? Redis没有专用的数字类型。当我们第一个SET值时,Redis将其保存为字符串,从而丢失了Lua最初将值视为float的事实的所有记录。当我们稍后提取值时,它仍然是字符串。

使用GET/SET访问的Redis中的值应被视为字符串,除非对它们运行诸如INCRDECR之类的数字运算时除外。这些特殊的数字运算实际上将返回整数答复(并根据数学规则处理存储的值),但是Redis中存储的值的“类型”仍然是字符串值。

以上答案摘自以下真棒博客文章:

https://www.redisgreen.net/blog/intro-to-lua-for-redis-programmers/