在 Redis 中,Set
(集合)是一种无序、唯一的字符串元素集合,支持高效的成员添加、删除、查询以及集合间的交集、并集、差集等操作,适用于存储不重复的数据并进行关联分析(如共同好友、标签聚合等)。
一、核心特性
- 无序性:集合中的元素没有固定顺序,不能通过索引访问。
- 唯一性:每个元素在集合中仅出现一次,重复添加会被自动忽略。
- 高效操作 :添加、删除、判断元素是否存在的时间复杂度均为
O(1)
,集合间运算(交集、并集等)效率也极高。 - 内部编码 :根据元素数量自动选择编码:
intset
(整数集合):当集合元素全为整数且数量较少(默认 < 512 个)时使用,节省内存。hashtable
(哈希表):元素包含字符串或数量较多时使用,支持更灵活的存储。
二、常用命令
1. 基础操作
命令格式 | 说明 | 示例 | 返回值 |
---|---|---|---|
SADD key member [member...] |
向集合添加一个或多个元素 | SADD tags "java" "python" |
成功添加的元素数量 |
SREM key member [member...] |
从集合删除一个或多个元素 | SREM tags "java" |
成功删除的元素数量 |
SMEMBERS key |
返回集合中所有元素(无序) | SMEMBERS tags |
元素列表(无固定顺序) |
SISMEMBER key member |
判断元素是否在集合中 | SISMEMBER tags "python" |
1 (存在)或 0 (不存在) |
SCARD key |
返回集合中元素的数量 | SCARD tags |
元素总数 |
SRANDMEMBER key [count] |
随机返回集合中 count 个元素(不删除) |
SRANDMEMBER tags 2 |
随机元素列表(默认返回 1 个) |
SPOP key [count] |
随机删除并返回集合中 count 个元素 |
SPOP tags 1 |
被删除的元素(默认删除 1 个) |
2. 集合间运算
命令格式 | 说明 | 示例 | 返回值 |
---|---|---|---|
SINTER key1 [key2...] |
计算多个集合的交集(共同元素) | SINTER set1 set2 |
交集元素列表 |
SINTERSTORE dest key1 [key2...] |
将交集结果存储到 dest 集合 |
SINTERSTORE common set1 set2 |
交集元素数量 |
SUNION key1 [key2...] |
计算多个集合的并集(所有元素) | SUNION set1 set2 |
并集元素列表 |
SUNIONSTORE dest key1 [key2...] |
将并集结果存储到 dest 集合 |
SUNIONSTORE all set1 set2 |
并集元素数量 |
SDIFF key1 [key2...] |
计算多个集合的差集(key1 独有的元素) | SDIFF set1 set2 |
差集元素列表 |
SDIFFSTORE dest key1 [key2...] |
将差集结果存储到 dest 集合 |
SDIFFSTORE unique set1 set2 |
差集元素数量 |
3. 其他实用命令
命令格式 | 说明 | 示例 |
---|---|---|
SMOVE source dest member |
将元素从 source 集合移动到 dest 集合 |
SMOVE set1 set2 "java" |
S清 key |
清空集合(Redis 无直接命令,需用 DEL key 删除集合后重建) |
DEL tags |
三、使用示例
场景:存储用户标签并分析
-
给用户添加标签:
redis
SADD user:100:tags "java" "backend" "linux" SADD user:101:tags "python" "backend" "docker"
-
查看用户 100 的所有标签:
redis
SMEMBERS user:100:tags # 输出:1) "java" 2) "backend" 3) "linux"(顺序不固定)
-
计算两个用户的共同标签(交集):
redis
SINTER user:100:tags user:101:tags # 输出:1) "backend"
-
计算用户 100 独有的标签(差集):
redis
SDIFF user:100:tags user:101:tags # 输出:1) "java" 2) "linux"
四、应用场景
- 去重存储:如存储用户浏览过的商品 ID(避免重复)。
- 关联分析:如计算共同好友、相似兴趣标签(基于交集)。
- 随机推荐 :用
SRANDMEMBER
随机返回集合元素(如随机推荐文章、商品)。 - 标签系统:为用户或内容添加多标签,通过集合运算快速筛选(如 "同时包含标签 A 和 B 的内容")。
- 黑名单 / 白名单 :用
SISMEMBER
快速判断用户是否在黑名单中。
五、注意事项
- 无序性 :
SMEMBERS
返回的元素顺序不固定,若需有序集合,应使用Sorted Set
(ZSet)。 - 元素类型:集合元素只能是字符串(或整数,Redis 会自动转换为字符串存储)。
- 内存占用 :
intset
编码比hashtable
更节省内存,尽量存储整数类型元素(如 ID)以优化内存。 - 大数据量集合运算 :对超大型集合进行交集 / 并集运算可能耗时,建议使用
SINTERSTORE
等命令将结果存储后再处理,避免重复计算。
六、内部编码
Redis 中的 SET 类型(集合)会根据存储元素的特点自动选择不同的内部编码方式,以优化内存占用和操作性能。主要有以下两种内部编码:
1. intset(整数集合)
当集合满足以下两个条件时,Redis 会使用 intset 编码:
• 集合中的所有元素都是整数(64 位有符号整数)
• 集合元素数量不超过配置参数 set-max-intset-entries 的值(默认值为 512)
特点:
• 内存紧凑,以数组形式存储整数,按升序排列
• 支持快速的查找、插入、删除操作(时间复杂度 O (log n))
• 不存储重复元素,自动去重
示例:
SADD numbers 1 3 5 7 9 # 会使用 intset 编码
2. hashtable(哈希表)
当集合不满足
intset
的条件时(如包含字符串元素,或元素数量超过阈值),Redis 会使用hashtable
编码。这里的
hashtable
与 Redis 的HASH
类型底层结构类似,是一种字典结构:
- 键:集合中的元素值
- 值:统一为
NULL
(仅用键来存储集合元素,值无实际意义)特点:
- 支持存储任何类型的元素(字符串、整数等)
- 元素数量无严格限制(仅受内存限制)
- 查找、插入、删除操作的平均时间复杂度为 O (1)
示例:
SADD fruits "apple" "banana" "cherry" # 包含字符串,使用 hashtable 编码 SADD large-set 1 2 3 ... 513 # 元素数量超过 512,使用 hashtable 编码
编码转换规则
- 当
intset
中的元素数量超过set-max-intset-entries
时,会自动转换为hashtable
- 当
intset
中插入非整数元素时,会立即转换为hashtable
- 转换是单向的:
intset
→hashtable
(一旦转换为hashtable
,不会再转回intset
)