在Lua脚本中,如何对所有Redis TS.RANGE调用返回的值求和?

vkc1a9a2  于 9个月前  发布在  Redis
关注(0)|答案(2)|浏览(67)

在启用了TimeSeries模块的Azure Redis Enterprise中,我在键“key1”处有以下4个值为1的时间序列:

$ TS.RANGE key1 - +

1) 1) (integer) 1693381431951
   2) 1
2) 1) (integer) 1693381435201
   2) 1
3) 1) (integer) 1693381436720
   2) 1
4) 1) (integer) 1693381438037
   2) 1

我可以通过Lua脚本检索相同的结果:

$ EVAL "return redis.call('TS.RANGE', KEYS[1], '-', '+')" 1 key1

1) 1) (integer) 1693381431951
   2) 1
2) 1) (integer) 1693381435201
   2) 1
3) 1) (integer) 1693381436720
   2) 1
4) 1) (integer) 1693381438037
   2) 1

我的问题是如何将这些值相加(并在所示情况下得到4)?
我正在尝试以下Lua代码:

$ EVAL "local sum = 0; for stamp, val in redis.call('TS.RANGE', KEYS[1], '-', '+') do sum = sum + val end; return sum" 1 key1

(error) ERR Error running script (call to f_28243bc2b451f1770c76c1d7fcce23e7285f3baa): @user_script:1: user_script:1: attempt to call a table value

TS.RANGE不是返回时间戳和数值对吗?
我的背景是,我在C#应用程序中调用ScriptEvaluateAsync(),并希望在给定键时对时间序列中的所有值求和。

jtw3ybtb

jtw3ybtb1#

这可能会有点混乱,Redis Lua调试器可以提供帮助(https://redis.io/docs/interact/programmability/lua-debugging/)。
这里有一个解决方案,将做你需要的,但Lua可能会优化-我不是一个LuaMaven:)

local sum = 0; 
local rangeResponse = redis.call('ts.range', KEYS[1], '-', '+')
for _, item in pairs(rangeResponse) do
  local val = tonumber(item[2]["ok"])
  sum = sum + val
end
return sum

这将解包TS.RANGE响应并对值求和。让我们设置一些数据来使用它:

127.0.0.1:6379> 4 ts.add key1 * 1
(integer) 1693393058028
(integer) 1693393058034
(integer) 1693393058035
(integer) 1693393058036

看看我们有什么:

127.0.0.1:6379> TS.RANGE key1 - +
1) 1) (integer) 1693393058028
   2) 1
2) 1) (integer) 1693393058034
   2) 1
3) 1) (integer) 1693393058035
   2) 1
4) 1) (integer) 1693393058036
   2) 1

现在让我们将脚本存储在redis服务器中(我将脚本放在一个名为sumts.lua的文件中:

$ redis-cli -x script load < ~/Desktop/sumts.lua
"caf0749de1e79a8955e212a2fb0ea34e6c76a28c"

我们得到了脚本的SHA值,可以用它来调用它:

127.0.0.1:6379> evalsha caf0749de1e79a8955e212a2fb0ea34e6c76a28c 1 key1
(integer) 4

我们得到整数响应4,时间序列中的值之和。
下面是一个如何在Lua调试器中运行此脚本并查看局部变量的示例:

$ redis-cli --ldb --eval ~/Desktop/sumts.lua key1

然后...

Lua debugging session started, please use:
quit    -- End the session.
restart -- Restart the script in debug mode again.
help    -- Show Lua script debugging commands.

* Stopped at 1, stop reason = step over
-> 1   local sum = 0;
lua debugger> n
* Stopped at 2, stop reason = step over
-> 2   local rangeResponse = redis.call('ts.range', KEYS[1], '-', '+')
lua debugger> n
<redis> ts.range key1 - +
<reply> [[1693393058028,"+1"],[1693393058034,"+1"],[1693393058035,"+1"],[1693393058036,"+1"]]
* Stopped at 3, stop reason = step over
-> 3   for _, item in pairs(rangeResponse) do
lua debugger> n
* Stopped at 4, stop reason = step over
-> 4     local val = tonumber(item[2]["ok"])
lua debugger> n
* Stopped at 5, stop reason = step over
-> 5     sum = sum + val
lua debugger> print
<value> sum = 0
<value> rangeResponse = {{1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}}
<value> (for generator) = "function@0x562d34cb1590"
<value> (for state) = {{1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}; {1.69339e+12; {["ok"]="1"}}}
<value> (for control) = 1
<value> _ = 1
<value> item = {1.69339e+12; {["ok"]="1"}}
<value> val = 1

您可以继续使用n来遍历循环。
希望这对你有帮助。

dgenwo3n

dgenwo3n2#

通过研究cjson.encode(tsrange),我提出了以下解决方案,我也想分享一下:
int sum = 0; local tsrange = redis.call('TS. RANGE',KEYS[1],'-','+');对于i = 1,#tsrange do sum = sum + tsrange[i][2]'ok'] end; return sum”1 key1
然后我在我的C#应用程序中调用它:

private const string LUA_SCRIPT = @"local sum = 0; local tsrange = redis.call('TS.RANGE', KEYS[1], '-', '+'); for i = 1, #tsrange do sum = sum + tsrange[i][2]['ok'] end; return sum";

private static async Task<int> CalcSumAsync(IDatabase db, string key)
{
    RedisResult result = await db.ScriptEvaluateAsync(LUA_SCRIPT, new RedisKey[] { key });
    return result.Type == ResultType.Integer ? (int)result : 0;
}

相关问题