使用Azure Redis缓存(启用了TimeSeries模块的Enterprise E10),可以通过调用以下命令来检索键“12345678:5”的时间序列中的所有时间戳:
$ TS.RANGE 12345678:5 - +
1) 1) (integer) 1693407731665
2) 1
2) 1) (integer) 1693407731694
2) 1
3) 1) (integer) 1693407731745
2) 1
4) 1) (integer) 1693407731771
2) 1
...
18) 1) (integer) 1693407732075
2) 1
19) 1) (integer) 1693407732103
2) 1
20) 1) (integer) 1693407732127
2) 1
但我只对最近30分钟(1800000毫秒)的时间戳/值感兴趣。
因此,我通过Lua脚本计算时间戳“start”和“now”:
$ EVAL "local time = redis.call('TIME'); local now = time[1] * 1000 + time[2] / 1000; local start = now - tonumber(ARGV[1]); return { tonumber(ARGV[1]), start, now }" 1 12345678:5 1800000
1) (integer) 1800000
2) (integer) 1693493878001
3) (integer) 1693495678001
然后我尝试使用Lua脚本调用TS.RANGE:
$ EVAL "local time = redis.call('TIME'); local now = time[1] * 1000 + time[2] / 1000; local start = now - tonumber(ARGV[1]); local tsrange = redis.call('TS.RANGE', KEYS[1], start, now); return tsrange" 1 12345678:5 1800000
(error) ERR Error running script (call to f_a99152dc66083038fe6d6b9b6acef33495ef1960): @user_script:1: ERR TSDB: wrong fromTimestamp
请告诉我,我做错了什么?
我的真实的背景是,我尝试在我的C# web应用中调用TS.ADD和TS.RANGE(自动过期似乎并不真正工作,所以我不能只调用TS.RANGE key - +
,但必须显式地指定TS.RANGE的fromTimestamp,toTimestamp参数):
private static readonly TimeSpan RETENTION_TIME = TimeSpan.FromMinutes(30);
// The script returns 0 if there are 20 or more timestamps in the past 30 min (1800000 ms).
// Otherwise it adds a new timestamp to the time series at the key and returns 1.
private const string LUA_SCRIPT =
@"
local sum = 0
local time = redis.call('TIME')
-- the final timestamp for TS.RANGE command in milliseconds
local now = time[1] * 1000 + time[2] / 1000
-- the start timestamp for TS.RANGE command in milliseconds
local start = now - tonumber(ARGV[1])
local tsrange = redis.call('TS.RANGE', KEYS[1], start, now)
for i = 1, #tsrange do
-- calculate a sum of all values stored in the time series, from start to now
sum = sum + tsrange[i][2]['ok']
-- if there are enough timestamps in the time period, then just return 0
if (sum >= 20) then
return 0
end
end
-- otherwise add the current timestamp and the value 1 to the time series
redis.call('TS.ADD', KEYS[1], '*', 1, 'RETENTION', ARGV[1], 'ON_DUPLICATE', 'SUM', 'ENCODING', 'UNCOMPRESSED')
return 1
";
private static async Task<bool> AddTimestampAsync(IDatabase db, string key, long retentionTime)
{
RedisResult result = await db.ScriptEvaluateAsync(LUA_SCRIPT, new RedisKey[] { key }, new RedisValue[] { retentionTime });
// return true if the Lua script returns 1, otherwise false
return result.Type == ResultType.Integer && (int)result == 1;
}
我希望我不必通过修改上面的for循环和逐个比较每个时间戳来解决我的问题。
1条答案
按热度按时间xtupzzrd1#
这里有几件事
下面是一个Lua脚本,它使用计算的时间戳成功调用了
TS.RANGE
:为了让它工作,我对它做了以下修改:
TIME
的响应是一对字符串值,因此将它们更改为数字。math.floor
来获取十进制毫秒值。此脚本的调试会话示例: