时间序列(Timeseries)

redis-py 支持 RedisTimeSeries,这是 Redis 的一个时间序列数据库模块。

这个示例展示了如何使用 redis-py 处理时间序列数据。

健康检查(Health check)

[1]:
import redis

r = redis.Redis(decode_responses=True)
ts = r.ts()

r.ping()
[1]:
True

简单例子(Simple example)

创建一个时间序列(Create a timeseries)

[2]:
ts.create("ts_key")
[2]:
True

添加示例到时间序列(Add samples to the timeseries)

我们可以使用毫秒级的 UNIX 时间戳来设置时间戳,也可以使用 * 根据服务器的时钟设置时间戳。

[3]:
ts.add("ts_key", 1657265437756, 1)
ts.add("ts_key", "1657265437757", 2)
ts.add("ts_key", "*", 3)
[3]:
1657272304448

获取最后一个示例(Get the last sample)

[4]:
ts.get("ts_key")
[4]:
(1657272304448, 3.0)

获取两个时间戳之间的样本

最小和最大可能的时间戳可以分别用 - 和 + 表示。

[5]:
ts.range("ts_key", "-", "+")
[5]:
[(1657265437756, 1.0), (1657265437757, 2.0), (1657272304448, 3.0)]
[6]:
ts.range("ts_key", 1657265437756, 1657265437757)
[6]:
[(1657265437756, 1.0), (1657265437757, 2.0)]

删除两个时间戳之间的样本

[7]:
print("Before deletion: ", ts.range("ts_key", "-", "+"))
ts.delete("ts_key", 1657265437756, 1657265437757)
print("After deletion:  ", ts.range("ts_key", "-", "+"))
Before deletion:  [(1657265437756, 1.0), (1657265437757, 2.0), (1657272304448, 3.0)]
After deletion:   [(1657272304448, 3.0)]

带标签的多个时间序列

[8]:
ts.create("ts_key1")
ts.create("ts_key2", labels={"label1": 1, "label2": 2})
[8]:
True

向多个时间序列添加样本

[9]:
ts.madd([("ts_key1", "*", 1), ("ts_key2", "*", 2)])
[9]:
[1657272306147, 1657272306147]

添加带标签的样本

[10]:
ts.add("ts_key2", "*", 2,  labels={"label1": 1, "label2": 2})
ts.add("ts_key2", "*", 2,  labels={"label1": 3, "label2": 4})
[10]:
1657272306457

获取匹配特定标签的最后一个样本

获取匹配 “label1=1” 的最后一个样本,详细信息请参见 Redis 文档 以了解可用的过滤值。

[11]:
ts.mget(["label1=1"])
[11]:
[{'ts_key2': [{}, 1657272306457, 2.0]}]

获取样本的标签-值对:

[12]:
ts.mget(["label1=1"], with_labels=True)
[12]:
[{'ts_key2': [{'label1': '1', 'label2': '2'}, 1657272306457, 2.0]}]

保留期限(Retention period)

在创建时间序列对象或添加样本时间序列对象时,可以指定保留期限。一旦保留期限到期,样本将从时间序列中移除。

[13]:
retention_time = 1000
ts.create("ts_key_ret", retention_msecs=retention_time)
[13]:
True
[14]:
import time
# this will be deleted in 1000 milliseconds
ts.add("ts_key_ret", "*", 1, retention_msecs=retention_time)
print("Base timeseries:                     ", ts.range("ts_key_ret", "-", "+"))
# sleeping for 1000 milliseconds (1 second)
time.sleep(1)
print("Timeseries after 1000 milliseconds:  ", ts.range("ts_key_ret", "-", "+"))
Base timeseries:                      [(1657272307670, 1.0)]
Timeseries after 1000 milliseconds:   [(1657272307670, 1.0)]

这两个列表是相同的,这是因为当添加新的样本时,最旧的值会被删除。

[15]:
ts.add("ts_key_ret", "*", 10)
[15]:
1657272308849
[16]:
ts.range("ts_key_ret", "-", "+")
[16]:
[(1657272308849, 10.0)]

在这里,第一个样本已经被删除。

指定重复策略(Specify duplicate policies)

默认情况下,重复时间戳键的策略设置为“阻塞”,我们不能创建两个具有相同时间戳的样本:

[17]:
ts.add("ts_key", 123456789, 1)
try:
    ts.add("ts_key", 123456789, 2)
except Exception as err:
    print(err)
TSDB: Error at upsert, update is not supported when DUPLICATE_POLICY is set to BLOCK mode

您可以使用 duplicate_policy 参数更改此默认行为,例如:

[18]:
# using policy "LAST", we keep the last added sample
ts.add("ts_key", 123456789, 2, duplicate_policy="LAST")
ts.range("ts_key", "-", "+")
[18]:
[(123456789, 2.0), (1657272304448, 3.0)]

有关重复策略的更多信息,请参阅 Redis 文档

使用 Redis TSDB 跟踪一个值

[19]:
ts.add("ts_key_incr", "*", 0)
[19]:
1657272310241

增加该值:

[20]:
for _ in range(10):
    ts.incrby("ts_key_incr", 1)
    # sleeping a bit so the timestamp are not duplicates
    time.sleep(0.01)
[21]:
ts.range("ts_key_incr", "-", "+")
[21]:
[(1657272310241, 0.0),
 (1657272310533, 1.0),
 (1657272310545, 2.0),
 (1657272310556, 3.0),
 (1657272310567, 4.0),
 (1657272310578, 5.0),
 (1657272310589, 6.0),
 (1657272310600, 7.0),
 (1657272310611, 8.0),
 (1657272310622, 9.0),
 (1657272310632, 10.0)]

如何在开源 Redis 集群上执行多键命令

[4]:
import redis

r = redis.RedisCluster(host="localhost", port=46379)

# This command should be executed on all cluster nodes after creation and any re-sharding
# Please note that this command is internal and will be deprecated in the future
r.execute_command("timeseries.REFRESHCLUSTER", target_nodes="primaries")

# Now multi-key commands can be executed
ts = r.ts()
ts.add("ts_key1", "*", 2,  labels={"label1": 1, "label2": 2})
ts.add("ts_key2", "*", 10,  labels={"label1": 1, "label2": 2})
ts.mget(["label1=1"])
[4]:
[{'ts_key1': [{}, 1670927124746, 2.0]}, {'ts_key2': [{}, 1670927124748, 10.0]}]