XRANGE、XREVRANGE:访问流中元素

正如前面所说,流本质上是一个有序序列,对于这种序列,使用有序方式获取序列中的各项元素是一种非常常见的操作。正如 Redis 为另一种有序序列数据结构列表提供了 LRANGE 命令一样,Redis 也为流提供了 XRANGE 命令,这个命令可以以遍历或者迭代的方式,访问流中的单个或者任意多个元素。

XRANGE 命令接受一个流、一个起始 ID、一个结束 ID 以及一个可选的 COUNT 选项作为参数:

XRANGE stream start-id end-id [COUNT n]

根据用户给定的参数不同,XRANGE 命令可以实现的功能也会有所不同,接下来的几个小节将分别介绍 XRANGE 命令的各种使用方法,其中包括如何获取单个元素、如何获取指定范围内的多个元素、如何获取所有元素以及如何迭代整个流等。

获取ID指定的单个元素

XRANGE 命令最简单的用法就是将命令的起始 ID 和结束 ID 设置为同一个流元素 ID,这样 XRANGE 命令就会从流中获取并返回 ID 指定的元素。

比如,如果我们想要从图10-9 所示的流 temp-stream 中获取 ID 为 3000000000000 的元素,那么只需要执行以下命令即可:

redis> XRANGE temp-stream 3000000000000 3000000000000
1) 1) 3000000000000-0 -- 流元素的ID
2) 1) "k3" -- 流元素包含的键
2) "v3" -- 流元素包含的值
image 2025 01 05 12 07 46 112
Figure 1. 图10-9 流temp-stream

XRANGE 命令在执行之后会返回一个列表作为结果。对于上面执行的 XRANGE 命令来说,命令返回了一个只包含单个项的列表,而这个项又包含了两个子项,它们分别是流元素的 ID 以及流元素包含的键值对。

另一方面,如果用户给定的 ID 不存在,那么 XRANGE 命令将返回一个空列表作为结果:

redis> XRANGE temp-stream 1234567891234 1234567891234
(empty list or set)

获取指定ID范围内的多个元素

XRANGE 命令除了可以用于获取单个元素之外,还可以用于获取多个元素:用户只需要将一个较小的元素 ID 设置为命令的起始 ID,并将一个较大的元素 ID 设置为命令的结束 ID,那么 XRANGE 命令就会从流中获取从起始 ID 到结束 ID 区间范围内的所有元素。

举个例子,对于之前提到的流 temp-stream 来说,我们可以通过执行以下命令,获取流中 ID 从 1000000000000 开始到 4000000000000 在内的所有元素:

redis> XRANGE temp-stream 1000000000000 4000000000000
1) 1) 1000000000000-0 -- 符合给定ID区间范围的第1个元素
2) 1) "k1"
2) "v1"
2) 1) 2000000000000-0 -- 第2个元素
2) 1) "k2"
2) "v2"
3) 1) 3000000000000-0 -- 第3个元素
2) 1) "k3"
2) "v3"
4) 1) 4000000000000-0 -- 第4个元素
2) 1) "k4"
2) "v4"

这个 XRANGE 命令调用返回了一个包含 4 个项的列表,其中每一个项都是一个流元素,图10-10 展示了这个命令的取值范围。

image 2025 01 05 12 10 25 932
Figure 2. 图10-10 使用XRANGE命令获取指定ID区间内的元素

获取所有元素

XRANGE 命令的起始 ID 和结束 ID 除了可以是流元素的 ID 之外,还可以是特殊值减号 - 和加号 +,其中前者用于表示流中的最小 ID,而后者则用于表示流中的最大 ID。在这两个特殊值的帮助下,用户可以通过 XRANGE 命令获取流包含的所有元素,或者 ID 大于等于或小于等于指定 ID 的所有元素。

举个例子,通过执行以下命令,我们可以获取流 temp-stream 包含的所有元素:

redis> XRANGE temp-stream - +
1) 1) 1000000000000-0
2) 1) "k1"
2) "v1"
2) 1) 2000000000000-0
2) 1) "k2"
2) "v2"
3) 1) 3000000000000-0
2) 1) "k3"
2) "v3"
-- 省略中间元素 --
9) 1) 9000000000000-0
2) 1) "k9"
2) "v9"

或者通过执行以下命令,获取流 temp-stream 中 ID 大于等于 4000000000000 的所有元素:

redis> XRANGE temp-stream 4000000000000 +
1) 1) 4000000000000-0
2) 1) "k4"
2) "v4"
2) 1) 5000000000000-0
2) 1) "k5"
2) "v5"
3) 1) 6000000000000-0
2) 1) "k6"
2) "v6"
4) 1) 7000000000000-0
2) 1) "k7"
2) "v7"
5) 1) 8000000000000-0
2) 1) "k8"
2) "v8"
6) 1) 9000000000000-0
2) 1) "k9"
2) "v9"

还可以通过执行以下命令,获取流 temp-stream 中 ID 小于等于 4000000000000 的所有元素:

redis> XRANGE temp-stream - 4000000000000
1) 1) 1000000000000-0
2) 1) "k1"
2) "v1"
2) 1) 2000000000000-0
2) 1) "k2"
2) "v2"
3) 1) 3000000000000-0
2) 1) "k3"
2) "v3"
4) 1) 4000000000000-0
2) 1) "k4"
2) "v4"

图10-11展示了以上 3 个命令不同的取值范围。

image 2025 01 05 12 13 47 371
Figure 3. 图10-11 使用特殊值获取temp-stream的全部或边界元素

获取指定数量的元素

虽然使用 XRANGE 命令可以很简单地获取多个元素,但是对于一些长度非常大的流来说,一次返回数量众多的元素可能会导致客户端因为体积庞大的回复而被阻塞,这并不是一件好事。

为此,用户可以通过 XRANGE 命令的 COUNT 选项去限制一次命令调用能够返回的最大元素数量:

XRANGE stream start-id end-id [COUNT n]

比如,通过执行以下命令,我们可以只获取 temp-stream 流中 ID 最小的 3 个元素:

redis> XRANGE temp-stream - + COUNT 3
1) 1) 1000000000000-0
2) 1) "k1"
2) "v1"
2) 1) 2000000000000-0
2) 1) "k2"
2) "v2"
3) 1) 3000000000000-0
2) 1) "k3"
2) "v3"

又或者只获取 ID 大于等于 4000000000000 的前两个元素:

redis> XRANGE temp-stream 4000000000000 + COUNT 2
1) 1) 4000000000000-0
2) 1) "k4"
2) "v4"
2) 1) 5000000000000-0
2) 1) "k5"
2) "v5"

对流进行迭代

用户可以通过 XRANGE 命令对流进行迭代,具体步骤如下:

  1. 使用 - 作为起始 ID,+ 作为结束 ID,调用带有 COUNT 选项的 XRANGE 命令,获取流的前 N 个元素。

  2. 对于命令返回的最后一个元素,将该元素 ID 的顺序部分加 1,得到一个新 ID。

  3. 使用新 ID 作为起始 ID,+ 作为结束 ID,继续调用带有 COUNT 选项的 XRANGE 命令。

  4. 重复步骤 2 和 3,直到 XRANGE 命令返回空列表为止,返回空列表表示整个流已经被迭代完毕。

image 2025 01 05 12 28 06 697
Figure 4. 图10-12 一个ID稠密排列的流dense-stream

让我们来看一个详细的迭代例子。对于图 10-12 所示的流来说,我们可以通过执行以下命令,以 - 为起始 ID,+ 为结束 ID,并将 COUNT 选项的值设置为 3,以此来获取 dense-stream 流最开始的 3 个元素:

redis> XRANGE dense-stream - + COUNT 3
1) 1) 1000000000000-0
2) 1) "k1"
2) "v1"
2) 1) 1000000000000-1
2) 1) "k2"
2) "v2"
3) 1) 1000000000000-2
2) 1) "k3"
2) "v3"

因为这次迭代获得的最后一个元素 ID 为 1000000000000-2,所以我们只需要将这个 ID 的顺序编号加上 1,就可以得到下一次迭代的起始 ID 1000000000000-3 了。与上一次迭代一样,命令接受的结束 ID 也是特殊值 +

redis> XRANGE dense-stream 1000000000000-3 + COUNT 3
1) 1) 1000000000000-3
2) 1) "k4"
2) "v4"
2) 1) 2000000000000-0
2) 1) "k5"
2) "v5"
3) 1) 2000000000000-1
2) 1) "k6"
2) "v6"

第二次迭代返回的最后一个元素的 ID 为 2000000000000-1,我们再次将这个 ID 的顺序编号加上 1,然后将这个新 ID 2000000000000-2 用作起始 ID,再次执行迭代操作:

redis> XRANGE dense-stream 2000000000000-2 + COUNT 3
1) 1) 3000000000000-0
2) 1) "k7"
2) "v7"
2) 1) 4000000000000-0
2) 1) "k8"
2) "v8"
3) 1) 4000000000000-1
2) 1) "k9"
2) "v9"

跟之前一样,第三次迭代也获得了 ID 为 4000000000000-1 的最后元素,我们将这个 ID 的顺序编号加上 1,得到新 ID 4000000000000-2,然后再次进行迭代:

redis> XRANGE dense-stream 4000000000000-2 + COUNT 3
(empty list or set)

与之前 3 次不一样,XRANGE 命令这次返回了一个空列表,这表明整个流已经被迭代完毕,迭代到此结束。图10-13 展示了上述整个迭代流程。

image 2025 01 05 12 31 32 146
Figure 5. 图10-13 迭代dense-stream的具体流程

以逆序访问流中元素

XREVRANGE 命令是 XRANGE 命令的逆序版本,前者除了会按照 ID 从大到小而不是从小到大的顺序访问流元素之外,其他作用后者是相同的:

XREVRANGE key end start [COUNT count]

另外需要注意的是,XREVRANGE 命令先接受结束 ID,后接受起始 ID,这种做法跟 XRANGE 命令正好相同。

以下是一个 XREVRANGE 命令的使用示例:

-- 获取temp-stream中ID最大的3个元素
redis> XREVRANGE temp-stream + - COUNT 3
1) 1) 9000000000000-0
2) 1) "k9"
2) "v9"
2) 1) 8000000000000-0
2) 1) "k8"
2) "v8"
3) 1) 7000000000000-0
2) 1) "k7"
2) "v7"

其他信息

  • 复杂度:O(log(N)+M),其中 N 为流包含的元素数量,而 M 则为命令返回的元素数量。

  • 版本要求:XRANGE 命令和 XREVRANGE 命令从 Redis 5.0.0 版本开始可用。