跳到主要内容

Redis 集合(Set)

1. 简介​

Redis 集合是字符串的无序集合,集合中的元素是唯一的,不允许重复。集合支持多种集合运算,如交集、并集、差集等。集合最多可以包含 2^32 - 1 个元素。

存储的元素无序、唯一且支持集合运算。

2. 基本命令​

命令描述示例
SADD key member [member ...]向集合添加一个或多个成员SADD language "chinese" "english"
SREM key member [member ...]移除集合中一个或多个成员SREM language "chinese"
SISMEMBER key member判断 member 元素是否是集合 key 的成员SISMEMBER language "english"
SMEMBERS key返回集合中的所有成员SMEMBERS language
SCARD key获取集合的成员数SCARD language
SPOP key [count]移除并返回集合中的一个随机元素SPOP language
SRANDMEMBER key [count]随机获取元素(不删除)SRANDMEMBER language

2.1 示例​

127.0.0.1:6379> SADD language "chinese" "english"
(integer) 2
# 重复元素不会被添加
127.0.0.1:6379> SADD language "chinese"
(integer) 0
127.0.0.1:6379> SISMEMBER language "english"
(integer) 1
127.0.0.1:6379> SMEMBERS language
1) "chinese"
2) "english"
127.0.0.1:6379> SCARD language
(integer) 2
127.0.0.1:6379> SRANDMEMBER language
"chinese"
127.0.0.1:6379> SREM language "chinese"
(integer) 1
127.0.0.1:6379> SPOP language
"english"

3. 集合运算命令​

对集合执行交集、并集、差集等运算的命令:

命令描述示例
SINTER key [key ...]返回给定所有集合的交集SINTER myset1 myset2
SINTERSTORE destination key [key ...]返回给定所有集合的交集并存储在 destination 中SINTERSTORE inter_set myset1 myset2
SUNION key [key ...]返回所有给定集合的并集SUNION myset1 myset2
SUNIONSTORE destination key [key ...]所有给定集合的并集存储在 destination 集合中SUNIONSTORE union_set myset1 myset2
SDIFF key [key ...]返回第一个集合与其他集合之间的差异SDIFF myset1 myset2
SDIFFSTORE destination key [key ...]返回给定所有集合的差集并存储在 destination 中SDIFFSTORE diff_set myset1 myset2

3.1 示例​

127.0.0.1:6379> SADD myset1 a b c
(integer) 3
127.0.0.1:6379> SADD myset2 b c d
(integer) 3
# 交集
127.0.0.1:6379> SINTER myset1 myset2
1) "b"
2) "c"
127.0.0.1:6379> SINTERSTORE inter_set myset1 myset2
(integer) 2
# 并集
127.0.0.1:6379> SUNION myset1 myset2
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> SUNIONSTORE union_set myset1 myset2
(integer) 4
# 差集
127.0.0.1:6379> SDIFF myset1 myset2
1) "a"
127.0.0.1:6379> SDIFFSTORE diff_set myset1 myset2
(integer) 1

4. 集合间移动​

在不同集合之间移动元素:

命令描述示例
SMOVE source destination member将 member 元素从 source 集合移动到 destination 集合SMOVE myset1 myset2 "element"

4.1 示例​

127.0.0.1:6379> SADD myset1 "element"
(integer) 1
127.0.0.1:6379> SMOVE myset1 myset2 "element"
(integer) 1
127.0.0.1:6379> SCARD myset1
(integer) 0

5. 集合遍历操作​

安全遍历大集合的命令:

命令描述示例
SSCAN key cursor [MATCH pattern] [COUNT count]迭代集合中的元素SSCAN language 0 MATCH "english"

5.1 示例​

127.0.0.1:6379> SADD language "english" "french" "german"
(integer) 3
127.0.0.1:6379> SSCAN language 0 MATCH "e*"
1) "0"
2) 1) "english"

6. 实际应用场景​

6.1 标签系统​

使用集合管理文章、用户的标签

# 文章标签
SADD article:1001:tags "Redis" "数据库" "缓存" "NoSQL"
SADD article:1002:tags "Python" "编程" "Web开发"
SADD article:1003:tags "Redis" "Python" "教程"

# 用户兴趣标签
SADD user:1001:interests "Redis" "Python" "机器学习"
SADD user:1002:interests "Java" "Spring" "微服务"

# 查找共同标签
SINTER article:1001:tags user:1001:interests
# 返回: ["Redis", "Python"] (用户感兴趣的文章标签)

# 推荐相关文章(有共同标签的文章)
SINTER article:1001:tags article:1003:tags
# 返回: ["Redis"] (两篇文章的共同标签)

# 获取所有标签
SUNION article:1001:tags article:1002:tags article:1003:tags
# 返回: 所有文章的标签集合

6.2 好友关系​

使用集合管理用户的好友关系

# 用户好友列表
SADD user:1001:friends "user1002" "user1003" "user1004" "user1005"
SADD user:1002:friends "user1001" "user1003" "user1006" "user1007"
SADD user:1003:friends "user1001" "user1002" "user1008"

# 查找共同好友
SINTER user:1001:friends user:1002:friends
# 返回: ["user1003"] (共同好友)

# 推荐好友(朋友的朋友,但不是自己的朋友)
SUNIONSTORE result user:1002:friends user:1003:friends # 朋友的朋友
SDIFFSTORE result result user:1001:friends # 排除已有好友
SREM result "user1001" # 排除自己
SMEMBERS result # 推荐结果

# 检查是否为好友
SISMEMBER user:1001:friends "user1002" # 返回: 1 (是好友)

# 添加/删除好友
SADD user:1001:friends "user1009" # 添加好友
SREM user:1001:friends "user1004" # 删除好友

6.3 抽奖系统​

使用集合实现抽奖和去重功能:

# 参与抽奖的用户
SADD lottery:2024:participants "user1001" "user1002" "user1003" "user1004" "user1005"

# 随机抽取中奖者
SRANDMEMBER lottery:2024:participants 3 # 随机选择3个中奖者(可重复)
SPOP lottery:2024:participants 3 # 随机弹出3个中奖者(不重复)

# 查看剩余参与者
SCARD lottery:2024:participants # 剩余参与者数量
SMEMBERS lottery:2024:participants # 剩余参与者列表

# 防止重复参与
SADD lottery:2024:participants "user1006" # 添加新参与者
SADD lottery:2024:participants "user1001" # 重复参与者不会被添加

# 已中奖用户(防止重复中奖)
SADD lottery:2024:winners "user1001" "user1003"
SDIFF lottery:2024:participants lottery:2024:winners # 未中奖的参与者

6.4 搜索过滤​

使用集合实现多条件搜索过滤:

# 商品分类
SADD category:electronics "product1001" "product1002" "product1003"
SADD category:books "product2001" "product2002" "product1003"
SADD category:clothing "product3001" "product3002"

# 商品品牌
SADD brand:apple "product1001" "product1002"
SADD brand:samsung "product1003" "product1004"
SADD brand:nike "product3001" "product3002"

# 价格区间
SADD price:100-500 "product1001" "product2001" "product3001"
SADD price:500-1000 "product1002" "product1003"
SADD price:1000+ "product1004" "product2002"

# 多条件搜索:电子产品 AND 苹果品牌 AND 500-1000价格区间
SINTER category:electronics brand:apple price:500-1000
# 返回: ["product1002"] (满足所有条件的商品)

# 或条件搜索:苹果品牌 OR 三星品牌
SUNION brand:apple brand:samsung
# 返回: 苹果或三星的所有商品

6.5 数据去重​

使用集合进行数据去重处理:

# 网站访问者去重
SADD daily:visitors:2024-01-15 "192.168.1.1" "192.168.1.2" "192.168.1.1"
SCARD daily:visitors:2024-01-15 # 返回: 2 (去重后的访问者数量)

# 邮件订阅者去重
SADD newsletter:subscribers "user1@example.com" "user2@example.com" "user1@example.com"
SMEMBERS newsletter:subscribers # 返回: 去重后的邮件列表

# 文章阅读者去重
SADD article:1001:readers "user1001" "user1002" "user1001"
SCARD article:1001:readers # 返回: 2 (去重后的阅读者数量)

# 合并多天的访问者
SUNIONSTORE weekly:visitors:2024-w3 \
daily:visitors:2024-01-15 \
daily:visitors:2024-01-16 \
daily:visitors:2024-01-17
SCARD weekly:visitors:2024-w3 # 一周内的唯一访问者数量

7. 性能优化建议​

  • 避免大集合: 单个集合元素数量不宜过多(建议小于 10 万)
  • 使用SSCAN: 遍历大集合时使用SSCAN而不是SMEMBERS
  • 合理使用运算: 集合运算的时间复杂度较高,注意性能
  • 批量操作: 使用SADD的多元素版本减少网络往返
  • 选择合适场景: 需要去重和集合运算时使用 Set
  • 内存优化: Redis 对小集合有特殊的内存优化

8. 集合 vs 其他数据类型​

8.1 数据类型选择建议​

  • Set vs List: Set 不允许重复且无序,List 允许重复且有序
  • Set vs Hash: Set 存储单一值,Hash 存储键值对
  • Set vs Sorted Set: Set 无序,Sorted Set 按分数有序
  • 使用 Set 的场景: 标签系统、好友关系、去重、抽奖、搜索过滤