DiceDB 的 ZRANGE 命令详解:有序集合区间查询从入门到源码级剖析
【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb
ZRANGE 是 DiceDB 中用于按索引(或按分数)返回有序集合(Sorted Set)区间成员的核心命令,是排行榜、实时计分与 Top-N 查询场景的基础原语。本文以 DiceDB 官方命令文档为骨架,结合 命令实现源码、有序集合底层实现 与 集成测试 进行纵深展开,帮助读者掌握 ZRANGE 的完整语法、边界行为、错误处理,并理解它在 DiceDB 中的真实执行链路。
命令概览
ZRANGE用于返回存储在指定key中的有序集合里、位于某个区间内的成员列表。有序集合中的成员始终按照分数(score)从低到高排序,因此该命令天然适用于「按分数取前 N 名」「分段统计」等场景。
在 DiceDB 中,有序集合由内部类型SortedSet表示(见 internal/types/sortedset.go),其底层封装了跳跃表(skiplist)实现,ZRANGE 的区间查询正是构建在这一高效数据结构之上。
语法与参数
命令的完整语法如下:
ZRANGE key start stop [WITHSCORES] [REV]各参数说明:
| 参数 | 说明 | 类型 | 是否必填 |
|---|---|---|---|
key | 要查询的有序集合的键名 | String | 是 |
start | 区间的起始索引 | Integer | 是 |
stop | 区间的结束索引 | Integer | 是 |
WITHSCORES | 可选,返回结果时同时携带各成员的分数 | 无值 | 否 |
REV | 可选,按分数从高到低的逆序返回成员 | 无值 | 否 |
返回值
| 条件 | 返回值 |
|---|---|
| key 存在且区间有效 | 返回指定区间内的成员数组 |
| key 不存在 | 返回空数组 |
| key 不是有序集合类型 | 返回错误 |
这一行为与源码完全一致:在 evalZRANGE 中,当s.Get(key)返回nil(键不存在)时,直接返回空结果ZRANGEResNilRes(对应空数组);而当对象类型不是object.ObjTypeSortedSet时,则返回errors.ErrWrongTypeOperation错误。
行为细节
- ZRANGE 返回
key所对应有序集合中指定区间的元素,元素按分数从低到高排列。 start与stop均为 0 起始索引:0表示第一个元素,1表示第二个,依此类推。- 索引同样支持负值,表示从有序集合尾部开始计数:
-1是最后一个元素,-2是倒数第二个,依此类推。 - 指定
WITHSCORES时,命令在返回元素的同时返回其分数。 - 指定
REV时,命令按分数从高到低的逆序返回元素。
错误处理
ZRANGE 在以下两类场景会返回错误:
类型错误(Wrong type of value or key)
- 错误消息:
(error) WRONGTYPE Operation against a key holding the wrong kind of value - 触发条件:对存储了非有序集合类型的 key 执行 ZRANGE。
- 源码依据:见 evalZRANGE 中的类型检查。
- 错误消息:
语法错误(Invalid syntax or conflicting options)
- 错误消息:
(error) ERR syntax error - 触发条件:命令语法不正确,例如参数缺失、不兼容的选项组合等。
- 此外,参数个数不合法(少于 3 个或多于 4 个)会返回
wrong number of arguments for 'ZRANGE' command,start/stop无法解析为整数时返回value is not an integer or a float——这两条行为在 集成测试 中有完整断言。
- 错误消息:
示例用法
以下示例均假设 DiceDB 运行在默认端口7379。
基础用法
先写入一个名为leaderboard的排行榜,再取出索引 0 到 2 的成员:
127.0.0.1:7379> ZADD leaderboard 50 "Alice" 70 "Bob" 60 "Charlie" (integer) 3 127.0.0.1:7379> ZRANGE leaderboard 0 2 1) "Alice" 2) "Charlie" 3) "Bob"注意返回顺序:Alice(50 分)→ Charlie(60 分)→ Bob(70 分),严格按分数从低到高。
使用 WITHSCORES
同时返回分数:
127.0.0.1:7379> ZRANGE leaderboard 0 2 WITHSCORES 1) "Alice" 2) "50" 3) "Charlie" 4) "60" 5) "Bob" 6) "70"使用 REV
按分数从高到低返回:
127.0.0.1:7379> ZRANGE leaderboard 0 2 REV 1) "Bob" 2) "Charlie" 3) "Alice"非法用法
对非有序集合类型执行 ZRANGE:
127.0.0.1:7379> SET foo bar OK 127.0.0.1:7379> ZRANGE foo 0 2 (error) WRONGTYPE Operation against a key holding the wrong kind of value缺少必需参数:
127.0.0.1:7379> ZRANGE leaderboard 0 (error) ERR syntax error源码级剖析:ZRANGE 的执行链路
命令注册与参数校验
ZRANGE 在 internal/cmd/cmd_zrange.go 中通过CommandRegistry.AddCommand注册,其CommandMeta声明了命令名、语法、帮助文本与执行函数。核心执行函数evalZRANGE的执行流程为:
- 校验参数个数必须在 3~4 之间,否则返回参数个数错误;
- 解析
start、stop为整数,失败则返回格式错误; - 从 store 中取出 key 对应的对象,不存在则返回空数组;
- 校验对象类型必须为
object.ObjTypeSortedSet; - 调用
SortedSet.ZRANGE(start, stop, byScore, byRank)完成实际查询。
在分片架构下,executeZRANGE会先通过sm.GetShardForKey(c.C.Args[0])定位 key 所属分片,再在该分片的 store 上执行evalZRANGE(见 executeZRANGE)。
底层区间查询实现
真正的区间查询逻辑位于 SortedSet.ZRANGE:当按排名(byRank)查询时,调用底层跳跃表的GetByRankRange(start, stop, false);当按分数(byScore)查询时,则调用GetByScoreRange。查询结果会组装为wire.ZElement结构,其中包含Member(成员)、Score(分数)与Rank(排名)三个字段,并经由newZRANGERes包装成 RESP 兼容的结果返回给客户端。
测试印证
zrange_test.go 覆盖了以下关键行为:
- 参数不足(如
ZRANGE、ZRANGE key、ZRANGE key 1)返回wrong number of arguments; - 非整数索引(如
ZRANGE key a b)返回value is not an integer or a float; - 不存在的 key 返回空结果;
- 对非有序集合执行返回
wrongtype错误; - 正常查询返回按分数排序的元素及其 rank。
当前仓库的 ZRANGE 变体:BYSCORE / BYRANK
需要特别说明的是:本仓库当前的官方文档(docs/src/content/docs/commands/ZRANGE.md)与命令实现(CommandMeta.Syntax)中,ZRANGE 的语法为:
ZRANGE key start stop [BYSCORE | BYRANK]即当前实现默认按排名(BYRANK)查询,也支持切换为按分数区间(BYSCORE)查询;排名采用1 起始的闭区间语义(第一个元素 rank 为 1 而非 0),start与stop均包含在内。若需逆序,官方建议在写入时将分数取反(flipped sign)。本文开头所述WITHSCORES/REV变体来自命令文档库中的历史/参考文档(docs/src/_skipped_commands/ZRANGE.md),使用时请以当前源码实现与实际返回为准。
进阶:ZRANGE.WATCH 查询订阅
ZRANGE 还衍生出 DiceDB 特色的实时查询能力——ZRANGE.WATCH。它创建对 ZRANGE 命令的查询订阅:客户端执行后,当该 key 的数据被任何客户端更新时,订阅方会实时收到重新执行 ZRANGE 的完整结果(而非仅变更通知),见 cmd_zrange_watch.go 与 ZRANGE.WATCH 文档。
典型用法是「排行榜实时刷新」:客户端 A 订阅ZRANGE.WATCH users 1 5,客户端 B 向集合中ZADD新成员后,客户端 A 无需轮询即可收到包含新成员的最新 Top-N 榜单。
实战建议
- Top-N 榜单:
ZRANGE key 0 N-1一次取回分数最高的前 N 名(配合分数处理);若需要低分在前,直接使用默认升序区间即可。 - 翻页遍历:利用负索引(如
-5到-1)从尾部向前取页,或结合start/stop偏移实现游标分页。 - 防御性编码:调用前先确认 key 类型(如使用
TYPE命令),避免WRONGTYPE错误;同时确保start/stop为合法整数。 - 注意版本差异:DiceDB 当前实现的 ZRANGE 使用 1 起始排名与
BYSCORE | BYRANK选项,与旧文档中的 0 起始 +WITHSCORES/REV语义不同,生产代码请以当前仓库源码与运行版本为准。
通过本文的语法详解、错误矩阵与源码链路分析,读者可以放心地在自己的排行榜、积分与实时榜单业务中正确、高效地使用 DiceDB 的 ZRANGE 系列命令。
【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考