DiceDB SCARD 命令详解:获取集合基数(Cardinality)的完整指南
【免费下载链接】dicedbOpen-source, low-latency key/value engine built on Valkey with query subscriptions and hierarchical storage tiers.项目地址: https://gitcode.com/GitHub_Trending/dic/dicedb
SCARD 是 DiceDB 中用于获取 Set(集合)中成员数量的命令,即返回存储在指定 key 下集合的基数(cardinality)。它是构建计数器、去重统计、在线状态追踪、实时榜单等场景中最常配合 SADD/SREM 使用的只读命令。读完本文,你将掌握 SCARD 的语法、参数与返回值、五种典型行为分支、错误处理细节,以及它在 DiceDB 源码与测试中的真实实现方式,能够直接在127.0.0.1:7379上进行验证与实战使用。
命令概述
SCARD(Set Cardinality)是 DiceDB 集合类型命令族中的核心只读命令。它的职责非常单一:返回集合中存储的成员数量。
在 DiceDB 中,Set 是一种无序、成员唯一(不可重复)的集合数据结构。因此SCARD返回的数值就是该集合当前去重后的元素个数,常用于:
- 统计去重后的活跃用户数、唯一访客数;
- 判断集合是否为空(返回
0); - 与 SADD / SREM 配合,动态监控集合规模变化;
- 在实时榜单、标签系统、好友关系中快速获取集合规模。
DiceDB 的命令元数据注册在 internal/eval/commands.go,其中scardCmdMeta声明了该命令的名称(SCARD)、元信息(Returns the number of elements of the set stored at key)以及固定参数数量Arity: 2(命令名加 1 个 key 参数,即严格要求只接受一个 key)。
语法与参数
SCARD key参数说明
| 参数 | 描述 | 类型 | 是否必填 |
|---|---|---|---|
key | 要查询的集合 key,用于获取其成员数量(基数) | String | 是 |
命令只接受1 个key 参数,多传或少传都会触发参数数量错误(详见下文"错误处理"一节)。
命令元数据中的约束
在 internal/eval/commands.go 中,scardCmdMeta的Arity字段为2,表示"SCARD + 1 个参数",这与原文档"最多只能传一个 key"的约束完全一致;KeySpecs的BeginIndex: 1则向框架声明该命令的第一个参数(索引 1)是 key 位置,便于命令解析与 key 定位。
返回值
| 条件 | 返回值 |
|---|---|
| key 存在且为 Set 类型 | 集合中元素的数量(整数) |
| key 不存在 | 0 |
| 语法错误 / key 为错误类型 | 返回 error |
返回值统一以 RESP 协议中的整数(integer)形式返回,例如(integer) 3。
行为规则
当执行SCARD命令时,DiceDB 会按照以下流程处理:
- 检查参数数量:只允许恰好 1 个 key,否则返回参数数量错误;
- 检查 key 是否存在:若 key 不存在,直接返回
0; - 检查 key 的类型:若 key 存在但不是 Set 类型(例如 String、List、Hash、Sorted Set),返回
WRONGTYPE类型错误; - 计算并返回基数:若 key 是合法集合,返回该集合当前成员个数。
这一行为在源码 internal/eval/store_eval.go 的evalSCARD函数中得到了一一印证:
// evalSCARD returns the number of elements of the set stored at key // Returns 0 if the key does not exist // An error response is returned if the command is used on a key that contains a non-set value(eg: string) func evalSCARD(args []string, store *dstore.Store) *EvalResponse { if len(args) != 1 { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongArgumentCount("SCARD"), } } key := args[0] // Get the set object from the store. obj := store.Get(key) if obj == nil { return &EvalResponse{ Result: 0, Error: nil, } } // If the object exists, check if it is a set object. if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, } } // Get the set object. count := len(obj.Value.(map[string]struct{})) return &EvalResponse{ Result: count, Error: nil, } }从实现可以看出三个关键点:
- 时间复杂度为 O(1):
count := len(obj.Value.(map[string]struct{}))直接对 Go 的 map 取长度,不遍历成员,因此无论集合多大,SCARD都能常数时间内返回结果; - 底层数据结构:DiceDB 的 Set 在内部使用
map[string]struct{}表示(internal/eval/store_eval.go),struct{}空结构体不占额外内存,同时天然保证了成员唯一性——这正是集合"成员不重复"特性的底层来源; - 类型判定:
object.AssertType配合object.ObjTypeSet(定义于 internal/object/object.go)完成类型检查,错误路径统一返回diceerrors.ErrWrongTypeOperation。
错误处理
1. 类型错误(Wrong Type of Key)
- 错误信息:
(error) ERROR WRONGTYPE Operation against a key holding the wrong kind of value - 触发条件:key 存在,但关联的不是 Set 类型,而是 String、List、Hash 或 Sorted Set 等其他数据类型。DiceDB 期望 key 必须关联集合类型。
- 源码依据:internal/eval/store_eval.go 中
object.AssertType(obj.Type, object.ObjTypeSet)失败后返回diceerrors.ErrWrongTypeOperation;该错误消息定义在 internal/errors/errors.go。
2. 参数数量错误(Wrong Number of Arguments)
- 错误信息:
(error) ERROR wrong number of arguments for 'scard' command - 触发条件:传入了 0 个 key 或 2 个及以上 key。
- 源码依据:internal/eval/store_eval.go 中
len(args) != 1时返回diceerrors.ErrWrongArgumentCount("SCARD");该错误由 internal/errors/errors.go 的工厂函数生成。
示例
以下示例全部基于 DiceDB 默认端口127.0.0.1:7379。
基础示例
向集合myset依次添加三个成员,再用SCARD获取集合基数:
127.0.0.1:7379> SADD myset "apple" (integer) 1 127.0.0.1:7379> SADD myset "banana" (integer) 1 127.0.0.1:7379> SADD myset "cherry" (integer) 1 127.0.0.1:7379> SCARD myset (integer) 3集合去重特性对 SCARD 的影响
由于 Set 保证成员唯一,重复添加相同成员不会增加基数。利用这一特性,SCARD天然成为"去重计数"工具:
127.0.0.1:7379> SADD tag:users "alice" (integer) 1 127.0.0.1:7379> SADD tag:users "alice" (integer) 0 127.0.0.1:7379> SADD tag:users "bob" (integer) 1 127.0.0.1:7379> SCARD tag:users (integer) 2第二次SADD返回0说明成员已存在未新增,因此SCARD仍为2而非3。
不存在的 key
查询一个从未创建过的 key,返回0(DiceDB 不报错,直接视为空集合):
127.0.0.1:7379> SCARD nonexistingset (integer) 0错误示例:类型错误
对存储字符串值的 key 执行SCARD:
127.0.0.1:7379> SET mystring "hello" OK 127.0.0.1:7379> SCARD mystring (error) ERROR WRONGTYPE Operation against a key holding the wrong kind of value错误示例:参数数量错误
不传参数或传入多个参数:
127.0.0.1:7379> SCARD (error) ERROR wrong number of arguments for 'scard' command 127.0.0.1:7379> SCARD myset1 myset2 (error) ERROR wrong number of arguments for 'scard' command源码与测试验证
SCARD 的实现位于 internal/eval/store_eval.go,命令注册位于 internal/eval/commands.go。
在单元测试 internal/eval/eval_test.go 的testEvalSCARD中,覆盖了五类关键场景,与本文所述行为一一对应:
| 测试用例 | 输入 | 预期结果 |
|---|---|---|
| SCARD with wrong number of arguments | ["mykey", "value"] | ErrWrongArgumentCount("SCARD") |
| SCARD on key with invalid type | 先SET mykey value,再SCARD mykey | ErrWrongTypeOperation |
| SCARD with non existing key | SCARD mykey(key 不存在) | 0,无错误 |
| SCARD with existing key and no member | 先SADD mykey(空添加)再 SCARD | 0,无错误 |
| SCARD with existing key | 先SADD mykey a b再 SCARD | 2,无错误 |
这些测试通过runMigratedEvalTests驱动evalSCARD执行,完整覆盖了"参数错误、类型错误、空集合、非空集合"全部行为分支,可作为理解命令语义与回归验证的直接依据。
使用建议与注意事项
- 用 SCARD 而非 LLEN/HLEN 判断集合规模:SCARD 只适用于 Set 类型,若 key 被误存为其他类型会报
WRONGTYPE错误,业务代码中应先通过TYPE命令确认 key 类型,或使用 try/catch 捕获类型错误; - 空集合与不存在 key 等价:两者都返回
0,因此无法仅凭SCARD区分"key 不存在"与"key 存在但为空集",如业务需要区分,可结合EXISTS命令判断; - 频繁调用成本极低:由于底层是 map 长度取值,
SCARD是 O(1) 操作,即使在高频监控集合大小的场景下也无需担心性能开销; - 注意命令名称大小写:DiceDB 命令名大小写不敏感,
SCARD、scard、Scard均可正常执行,但参数数量必须严格为一个 key。
通过本文的语法说明、行为规则、错误处理与源码佐证,你已经可以放心地在项目中用SCARD完成集合基数的查询与监控,并能够根据报错信息快速定位数据类型或参数层面的问题。
【免费下载链接】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),仅供参考