Valkey 中文社区

Set:去重、标签与集合运算

用无序不重复集合做标签、去重统计、共同好友与抽奖

Set 是一个无序、不重复的字符串集合。它的两大杀手锏:自动去重,以及内建的交集 / 并集 / 差集运算——这些用普通代码实现既繁琐又容易出错。

基本操作

127.0.0.1:6379> SADD tags:post:1 valkey 数据库 缓存 valkey
(integer) 3
127.0.0.1:6379> SMEMBERS tags:post:1
1) "valkey"
2) "数据库"
3) "缓存"
127.0.0.1:6379> SISMEMBER tags:post:1 缓存
(integer) 1
127.0.0.1:6379> SCARD tags:post:1
(integer) 3

注意上面 SADD 加了 4 个值但只成功 3 个——重复的 valkey 被自动忽略。

命令作用
SADD k m...添加成员(自动去重,返回新增数)
SREM k m...移除成员
SISMEMBER k m是否包含某成员(1/0)
SMISMEMBER k m1 m2批量判断多个成员
SMEMBERS k取全部成员
SCARD k成员数量
SPOP k随机弹出一个成员
SRANDMEMBER k n随机取 n 个(不删除)

场景一:标签系统

每篇文章一个 Set 存标签,天然去重。想找「同时带 valkey 和 缓存 两个标签的文章」?用集合运算。

集合运算:交集、并集、差集

127.0.0.1:6379> SADD a 1 2 3 4
(integer) 4
127.0.0.1:6379> SADD b 3 4 5 6
(integer) 4
127.0.0.1:6379> SINTER a b
1) "3"
2) "4"
127.0.0.1:6379> SUNION a b
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
127.0.0.1:6379> SDIFF a b
1) "1"
2) "2"
命令作用
SINTER k1 k2交集(都在)
SUNION k1 k2并集(合并去重)
SDIFF k1 k2差集(在 k1 不在 k2)
SINTERSTORE dst k1 k2把交集结果存进 dst
SINTERCARD n k1 k2只算交集的数量(可加 LIMIT)

场景二:共同好友

friends:用户Afriends:用户B 各存一个好友 Set,求交集就是共同好友:

127.0.0.1:6379> SINTER friends:alice friends:bob
1) "charlie"
2) "dave"

只想知道「有几个共同好友」而不需要名单时,用 SINTERCARD 更快,还能加 LIMIT 提前截断:

127.0.0.1:6379> SINTERCARD 2 friends:alice friends:bob LIMIT 10
(integer) 2

场景三:抽奖去重 + 开奖

用 Set 保证一个用户只能参与一次(自动去重),开奖时用 SPOP 随机弹出中奖者:

127.0.0.1:6379> SADD lottery u1 u2 u3 u4 u5
(integer) 5
127.0.0.1:6379> SPOP lottery 2
1) "u3"
2) "u5"

SPOP 会把中奖者从池子里移除,避免重复中奖;若想抽样但保留池子,用 SRANDMEMBER

场景四:UV(独立访客)统计

把访问页面的用户 ID SADD 进当天的 Set,SCARD 就是去重后的 UV:

127.0.0.1:6379> SADD uv:2026-06-13 user:1 user:2 user:1
(integer) 2
127.0.0.1:6379> SCARD uv:2026-06-13
(integer) 2

当 UV 量级达到千万且能接受约 0.81% 的误差时,用 HyperLogLog(PFADD / PFCOUNT)只需约 12 KB 内存。需要精确去重再选 Set。

安全遍历

和 Hash 一样,大 Set 不要用 SMEMBERS 全量取,用 SSCAN 游标式分批:

127.0.0.1:6379> SSCAN uv:2026-06-13 0 COUNT 100

下一篇

Set 是无序的。如果每个成员还要带一个「分数」并据此排序,就轮到 Sorted Set 登场了。

继续阅读 → Sorted Set:排行榜与延时队列

On this page