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 BSDIFF 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 BSDIFF B A。顺序很重要。
Q 集合运算会修改原集合吗? *A:不会。SINTER/SUNION/SDIFF只读取,不修改。STORE命令会覆盖目标集合。

Q:如何计算多个集合的交集数量而不获取元素?

A 使用SINTERCARD命令(Redis 7.0+),或使用SINTER + 计数。
Q 集合运算的性能如何?
A 取决于集合大小。大集合运算会很慢,建议限制集合大小或使用缓存。

📖 小节

  • SINTER交集:同时存在于所有集合的元素
  • SUNION并集:存在于任一集合的元素
  • SDIFF差集:在第一个集合但不在其他集合
  • *STORE命令将运算结果存储到新集合
  • 集合运算应用:共同好友、推荐、筛选、权限检查
  • 性能:大集合运算慢,建议缓存或限制大小
  • SSCAN迭代大集合,避免一次性获取所有元素

📝 作业

  1. 共同好友: 创建两个用户的好友列表,计算共同好友
  2. 推荐系统: 实现简单的文章推荐,根据用户兴趣标签推荐文章
  3. 商品筛选: 使用集合实现多条件商品筛选(分类+品牌)
  4. 权限检查: 使用集合运算检查用户是否拥有资源所需的所有权限

下一课

下一课我们将学习 Redis 有序集合(上),学习有序集合的基本操作。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏