Lua booleans在redis中没有预期的行为

时间:2013-06-10 18:41:32

标签: string lua redis match string-matching

我有一个脚本

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
for i, field in pairs(fields) do
    if((string.match(tostring(field),'ev')) ~= nil) then
        retval[i] = {field, (string.match(tostring(field),'ev') ~= nil) }
    end
end
return retval

此脚本返回一个空列表

当我将if语句更改为

if((string.match(tostring(field),'.')) ~= nil) then
    ...

我得到一个包含以下内容的长列表

...
...
60) 1) "applet:1:metric:viewelement:20130607"
    2) (nil)
61) 1) "applet:1:total_events:20130529"
    2) (integer) 1
...
...

如果我用

替换if语句
if(1)

我得到相同长的密钥列表

我也尝试过使用string.find,它也有类似的行为。

似乎作为模式的唯一事情是,如果匹配的字符串在字符串中出现多次,或者如果它出现在开头,则if语句将通过。我不能确定这一点,但它可能会有所帮助。

我使用以下命令运行此脚本

$ redis-cli eval "$(cat get_keys.lua)" 0

2 个答案:

答案 0 :(得分:2)

  1. 您无需执行if((string.match(tostring(field),'ev')) ~= nil)。你可以if(string.match(tostring(field),'ev'))
  2. 您的脚本失败的原因是lua不支持表中的nil键。如果您设置some_table[1]some_table[2]some_table[5]然后返回数组,它看起来就像在some_table[2]处结束。由于您只在if语句通过时设置数组,如果它在retval[1]上失败,则不会返回任何数组的其余部分。
  3. 简单的解决方法是:

    local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
    local retval = {};
    for i, field in pairs(fields) do
        if(string.match(tostring(field),'ev')) then
            retval[i] = {field, (string.match(tostring(field),'ev') ~= nil) }
        else retval[i] = 'some_nil_value'
        end
    end
    return retval
    

    我认为您也可以使用table default values,但我还没有玩过这些,所以不能在这里提供太多信息。

    [编辑] OP表示他不想要零占位符。在这种情况下,可以使用以下内容:

    local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
    local retval = {};
    for i, field in pairs(fields) do
        if(string.match(tostring(field),'ev')) then
            retval[#retval+1] = {field, (string.match(tostring(field),'ev') ~= nil) }
        end
    end
    return retval
    

答案 1 :(得分:0)

Eli的回答是有效的,但我认为这是一个微妙的问题,就像在Lua中处理列表一样。我想解释一下我的想法。

因此,作为测试,我在retval中插入了一个额外的字段,偶尔它是零。我注意到在那些调用中,列表的其余部分没有返回。

我认为幕后发生的事情是redis正在整个列表中工作,但是当它返回时,它会在第一个nil被截断。所以有时会有一个列表,有时则没有。作为一个黑客,我重写了脚本

local fields = redis.call('hkeys', 'a:hash:full:of:stuff');
local retval = {};
local i = 0
for j, field in pairs(fields) do
    if string.find(field,"ev") then
        retval[i] = {field, string.match(field,'ev') }
        i = i+1;
    end
end
return retval

它有效!

所以Eli的回答是有效的,因为retval没有被截断。但是,当您需要解析返回的列表时,它会占用更多的带宽和CPU时间