Redis 集合(下)
本课学习集合的交集、并集、差集运算,这些是集合最强大的功能。
集合运算概述
Redis支持三种集合运算:
| 运算 | 说明 | 命令 |
|---|---|---|
| 交集 | 同时存在于所有集合的元素 | SINTER |
| 并集 | 存在于任一集合的元素 | SUNION |
| 差集 | 在第一个集合但不在其他集合的元素 | SDIFF |
集合A: {1, 2, 3, 4}
集合B: {3, 4, 5, 6}
交集 A∩B: {3, 4}
并集 A∪B: {1, 2, 3, 4, 5, 6}
差集 A-B: {1, 2}
SINTER:交集
交集返回同时存在于所有集合的元素。
基本用法
REDIS
# 创建两个集合
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"
# 计算交集
SINTER set1 set2
1) "c"
2) "d"
多个集合的交集
REDIS
SADD set3 "c" "d" "g"
# 三个集合的交集
SINTER set1 set2 set3
1) "c"
2) "d"
集合不存在
REDIS
# 如果某个集合不存在,视为空集
SINTER set1 notexist
(empty array)
SINTERCARD:交集元素数量(Redis 7.0+)
REDIS
SINTERCARD 2 set1 set2
(integer) 2 # 交集有2个元素
SUNION:并集
并集返回存在于任一集合的元素。
基本用法
REDIS
SADD set1 "a" "b" "c"
SADD set2 "c" "d" "e"
# 计算并集
SUNION set1 set2
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
多个集合的并集
REDIS
SADD set3 "e" "f" "g"
# 三个集合的并集
SUNION set1 set2 set3
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"
SDIFF:差集
差集返回在第一个集合但不在其他集合的元素。
基本用法
REDIS
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"
# set1 - set2
SDIFF set1 set2
1) "a"
2) "b"
多个集合的差集
REDIS
SADD set3 "a" "g"
# set1 - set2 - set3
SDIFF set1 set2 set3
1) "b" # a在set3中,被排除
⚠️ 注意: 差集不满足交换律,
SDIFF A B ≠ SDIFF B A。
集合运算存储结果
SINTERSTORE:交集结果存储
REDIS
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"
# 将交集结果存储到新集合
SINTERSTORE result set1 set2
(integer) 2 # 结果集合有2个元素
SMEMBERS result
1) "c"
2) "d"
SUNIONSTORE:并集结果存储
REDIS
SUNIONSTORE result set1 set2
(integer) 6
SMEMBERS result
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
SDIFFSTORE:差集结果存储
REDIS
SDIFFSTORE result set1 set2
(integer) 2
SMEMBERS result
1) "a"
2) "b"
💡 用途: *STORE命令将结果保存到新集合,可以用于后续操作或缓存。
集合运算应用场景
场景1:共同好友
REDIS
# 用户1的好友
SADD user:1:friends "user:2" "user:3" "user:4" "user:5"
# 用户2的好友
SADD user:2:friends "user:3" "user:4" "user:6" "user:7"
# 共同好友
SINTER user:1:friends user:2:friends
1) "user:3"
2) "user:4"
场景2:可能认识的人
REDIS
# 我的好友
SADD user:1:friends "user:2" "user:3"
# 好友的好友
SADD user:2:friends "user:3" "user:4" "user:5"
SADD user:3:friends "user:4" "user:6"
# 好友的好友的并集
SUNIONSTORE friends:friends user:2:friends user:3:friends
# 推荐好友 = 好友的好友 - 我的好友 - 我
SADD me "user:1"
SUNIONSTORE exclude me user:1:friends
SDIFF friends:friends exclude
场景3:文章推荐
REDIS
# 用户喜欢的文章标签
SADD user:1:liked:tags "redis" "database" "cache"
# 文章标签
SADD article:123:tags "redis" "nosql"
SADD article:456:tags "mysql" "database"
SADD article:789:tags "redis" "cache" "performance"
# 推荐与用户兴趣匹配的文章(标签有交集)
SINTER user:1:liked:tags article:123:tags
1) "redis" # article:123匹配1个标签
SINTER user:1:liked:tags article:789:tags
1) "redis"
2) "cache" # article:789匹配2个标签,更推荐
场景4:商品筛选
REDIS
# 商品分类
SADD category:phone "product:1" "product:2" "product:3"
SADD category:laptop "product:4" "product:5"
# 商品品牌
SADD brand:apple "product:1" "product:4"
SADD brand:samsung "product:2" "product:5"
# 筛选:手机 + 苹果品牌
SINTER category:phone brand:apple
1) "product:1"
场景5:权限检查
REDIS
# 用户权限
SADD user:1:permissions "read" "write" "delete"
# 资源所需权限
SADD resource:123:required "read" "write"
# 检查用户是否有所有必需权限
SINTER user:1:permissions resource:123:required
1) "read"
2) "write"
# 如果结果数量等于所需权限数量,则有权限
场景6:标签聚合
REDIS
# 文章标签
SADD article:1:tags "redis" "database"
SADD article:2:tags "redis" "cache"
SADD article:3:tags "mysql" "database"
# 所有标签
SUNIONSTORE all:tags article:1:tags article:2:tags article:3:tags
SMEMBERS all:tags
1) "redis"
2) "database"
3) "cache"
4) "mysql"
集合运算性能
时间复杂度
| 命令 | 时间复杂度 | 说明 |
|---|---|---|
| SINTER | O(N*M) | N=最小集合大小,M=集合数量 |
| SUNION | O(N) | N=所有集合元素总数 |
| SDIFF | O(N) | N=所有集合元素总数 |
⚠️ 性能提示: 集合运算会遍历所有元素,大集合运算会很慢。建议:
- 使用SINTERCARD代替SINTER(只返回数量)
- 将结果缓存(使用*STORE命令)
- 限制集合大小
SSCAN:迭代大集合
当集合很大时,使用SSCAN分批迭代获取元素。
REDIS
# 创建一个大集合
SADD large:set value1 value2 ... value10000
# 开始迭代
SSCAN large:set 0
1) "127" # 下一次使用的游标
2) 1) "value1"
2) "value2"
...
# 继续迭代
SSCAN large:set 127
1) "0" # 游标为0表示迭代结束
2) ...
匹配模式
REDIS
# 只获取匹配模式的元素
SSCAN large:set 0 MATCH user:*
集合限制
1. 无序
REDIS
# 无法按顺序获取元素
SMEMBERS myset # 返回顺序不确定
如需有序,使用有序集合(Sorted Set)。
2. 只能存储字符串
REDIS
# 集合元素只能是字符串
SADD myset 123 # 存储的是字符串"123"
3. 无法存储嵌套结构
集合不支持嵌套集合或对象。
❓ 常见问题
Q SINTER和SINTERSTORE的区别?
A SINTER返回交集结果,SINTERSTORE将结果存储到新集合。
Q 差集满足交换律吗?
A 不满足。
SDIFF A B ≠ SDIFF B A。顺序很重要。Q 集合运算会修改原集合吗?
*A:不会。SINTER/SUNION/SDIFF只读取,不修改。STORE命令会覆盖目标集合。
Q:如何计算多个集合的交集数量而不获取元素?
A 使用SINTERCARD命令(Redis 7.0+),或使用SINTER + 计数。
Q 集合运算的性能如何?
A 取决于集合大小。大集合运算会很慢,建议限制集合大小或使用缓存。
📖 小节
- SINTER交集:同时存在于所有集合的元素
- SUNION并集:存在于任一集合的元素
- SDIFF差集:在第一个集合但不在其他集合
- *STORE命令将运算结果存储到新集合
- 集合运算应用:共同好友、推荐、筛选、权限检查
- 性能:大集合运算慢,建议缓存或限制大小
- SSCAN迭代大集合,避免一次性获取所有元素
📝 作业
- 共同好友: 创建两个用户的好友列表,计算共同好友
- 推荐系统: 实现简单的文章推荐,根据用户兴趣标签推荐文章
- 商品筛选: 使用集合实现多条件商品筛选(分类+品牌)
- 权限检查: 使用集合运算检查用户是否拥有资源所需的所有权限
下一课
下一课我们将学习 Redis 有序集合(上),学习有序集合的基本操作。



