Redis集合Set #

一、集合概述 #

1.1 什么是集合 #

Redis集合是字符串的无序集合:

  • 无序:元素没有顺序
  • 唯一:不允许重复元素
  • 高效:O(1)时间复杂度的添加、删除、查找
text
集合结构:

┌─────────────────────────────────────────────┐
│              Set(哈希表实现)               │
│  ┌─────┐  ┌─────┐  ┌─────┐                │
│  │ "a" │  │ "b" │  │ "c" │                │
│  └─────┘  └─────┘  └─────┘                │
│                                             │
│  特点:                                     │
│  - 自动去重                                 │
│  - 快速判断元素是否存在                     │
│  - 支持集合运算                             │
└─────────────────────────────────────────────┘

最大元素数:2^32 - 1(约40亿)

1.2 集合编码 #

text
Redis集合的编码方式:

1. intset(整数集合)
   ┌─────────────────────────────────────────────┐
   │ 所有元素都是整数                            │
   │ 元素数量不超过512个                         │
   │ 内存连续,节省空间                          │
   └─────────────────────────────────────────────┘

2. hashtable(哈希表)
   ┌─────────────────────────────────────────────┐
   │ 元素包含非整数                              │
   │ 或元素数量超过512个                         │
   │ O(1)时间复杂度                              │
   └─────────────────────────────────────────────┘

二、基本操作 #

2.1 添加元素 #

bash
# SADD: 添加元素
SADD myset "a"
# (integer) 1  添加成功

SADD myset "b" "c" "d"
# (integer) 3  添加成功数量

# 添加重复元素
SADD myset "a"
# (integer) 0  已存在,不添加

2.2 查看集合 #

bash
# SMEMBERS: 获取所有元素
SADD myset "a" "b" "c"
SMEMBERS myset
# 1) "a"
# 2) "b"
# 3) "c"

# SCARD: 获取元素数量
SCARD myset
# (integer) 3

# SISMEMBER: 检查元素是否存在
SISMEMBER myset "a"
# (integer) 1  存在

SISMEMBER myset "x"
# (integer) 0  不存在

# SMISMEMBER: 批量检查(Redis 6.2+)
SMISMEMBER myset "a" "b" "x"
# 1) (integer) 1
# 2) (integer) 1
# 3) (integer) 0

2.3 删除元素 #

bash
# SREM: 删除元素
SREM myset "a"
# (integer) 1  删除成功

SREM myset "x"
# (integer) 0  元素不存在

# 删除多个元素
SREM myset "b" "c"
# (integer) 2

# SPOP: 随机弹出元素
SADD myset "a" "b" "c" "d"
SPOP myset
# "c"  随机返回一个元素

# 弹出多个元素
SPOP myset 2
# 1) "a"
# 2) "d"

2.4 随机元素 #

bash
# SRANDMEMBER: 随机获取元素(不移除)
SADD myset "a" "b" "c" "d" "e"

# 随机获取1个
SRANDMEMBER myset
# "b"

# 随机获取多个(可能重复)
SRANDMEMBER myset 3
# 1) "a"
# 2) "c"
# 3) "a"

# 随机获取多个(不重复)
SRANDMEMBER myset -3
# 1) "d"
# 2) "e"
# 3) "b"

# 获取数量超过集合大小
SRANDMEMBER myset 10
# 返回所有元素(不重复)

三、集合运算 #

3.1 交集 #

bash
# 准备数据
SADD set1 "a" "b" "c" "d"
SADD set2 "c" "d" "e" "f"
SADD set3 "c" "d" "g"

# SINTER: 获取交集
SINTER set1 set2
# 1) "c"
# 2) "d"

# 多个集合的交集
SINTER set1 set2 set3
# 1) "c"
# 2) "d"

# SINTERCARD: 获取交集元素数量(Redis 7.0+)
SINTERCARD 2 set1 set2
# (integer) 2

# SINTERSTORE: 保存交集到新集合
SINTERSTORE result set1 set2
# (integer) 2

SMEMBERS result
# 1) "c"
# 2) "d"

3.2 并集 #

bash
# SUNION: 获取并集
SUNION set1 set2
# 1) "a"
# 2) "b"
# 3) "c"
# 4) "d"
# 5) "e"
# 6) "f"

# 多个集合的并集
SUNION set1 set2 set3
# 1) "a"
# 2) "b"
# 3) "c"
# 4) "d"
# 5) "e"
# 6) "f"
# 7) "g"

# SUNIONSTORE: 保存并集到新集合
SUNIONSTORE result set1 set2
# (integer) 6

3.3 差集 #

bash
# SDIFF: 获取差集(set1 - set2)
SDIFF set1 set2
# 1) "a"
# 2) "b"

# 多个集合的差集
# set1 - set2 - set3
SDIFF set1 set2 set3
# 1) "a"
# 2) "b"

# SDIFFSTORE: 保存差集到新集合
SDIFFSTORE result set1 set2
# (integer) 2

SMEMBERS result
# 1) "a"
# 2) "b"

3.4 集合运算图解 #

text
交集 SINTER:
┌─────────────────────────────────────────────┐
│    set1          set2                       │
│  ┌───────┐    ┌───────┐                    │
│  │ a   b │    │ e   f │                    │
│  │   ┌───┼────┼───┐   │                    │
│  │   │ c │ d  │ c │ d │   ← 交集           │
│  │   └───┼────┼───┘   │                    │
│  └───────┘    └───────┘                    │
└─────────────────────────────────────────────┘

并集 SUNION:
┌─────────────────────────────────────────────┐
│    set1          set2                       │
│  ┌───────┐    ┌───────┐                    │
│  │ a   b │    │ e   f │                    │
│  │   c   │ d  │ c   d │   ← 全部元素       │
│  └───────┴────┴───────┘                    │
└─────────────────────────────────────────────┘

差集 SDIFF:
┌─────────────────────────────────────────────┐
│    set1          set2                       │
│  ┌───────┐    ┌───────┐                    │
│  │ a   b │ ←  │ e   f │                    │
│  │   c   │ d  │ c   d │                    │
│  └───────┘    └───────┘                    │
│  set1 - set2 = {a, b}                       │
└─────────────────────────────────────────────┘

四、移动元素 #

bash
# SMOVE: 将元素从一个集合移动到另一个集合
SADD set1 "a" "b" "c"
SADD set2 "x" "y"

SMOVE set1 set2 "a"
# (integer) 1  移动成功

SMEMBERS set1
# 1) "b"
# 2) "c"

SMEMBERS set2
# 1) "x"
# 2) "y"
# 3) "a"

# 移动不存在的元素
SMOVE set1 set2 "notexist"
# (integer) 0

五、扫描集合 #

bash
# SSCAN: 迭代扫描集合元素
SADD myset "a" "b" "c" "d" "e" "f" "g"

# 扫描
SSCAN myset 0
# 1) "0"  # 下一个游标(0表示结束)
# 2) 1) "a"
#    2) "b"
#    3) "c"

# 带数量
SSCAN myset 0 COUNT 3
# 1) "3"
# 2) 1) "a"
#    2) "b"
#    3) "c"

# 带模式
SSCAN myset 0 MATCH a*
# 1) "0"
# 2) 1) "a"

六、应用场景 #

6.1 标签系统 #

bash
# 文章标签
SADD article:1001:tags "redis" "database" "nosql"
SADD article:1002:tags "redis" "cache"

# 获取文章标签
SMEMBERS article:1001:tags

# 查找有特定标签的文章
SADD tag:redis:articles 1001 1002
SADD tag:database:articles 1001

# 查找同时有多个标签的文章
SINTER tag:redis:articles tag:database:articles
# 1) "1001"

6.2 社交关系 #

bash
# 用户关注
SADD user:1001:following 1002 1003 1004
SADD user:1002:following 1001 1003

# 用户粉丝
SADD user:1001:followers 1002

# 共同关注
SINTER user:1001:following user:1002:following
# 1) "1003"

# 我关注的人也关注了他
SINTER user:1001:following user:1002:followers

# 可能认识的人
SDIFF user:1002:following user:1001:following

6.3 抽奖系统 #

bash
# 添加参与者
SADD lottery:2024 user:1001 user:1002 user:1003 user:1004

# 查看参与者数量
SCARD lottery:2024
# (integer) 4

# 抽取1个中奖者(移除)
SPOP lottery:2024
# "user:1003"

# 抽取多个中奖者(不移除)
SRANDMEMBER lottery:2024 2
# 1) "user:1001"
# 2) "user:1004"

6.4 去重 #

bash
# 已读消息去重
SADD user:1001:read:messages msg:1 msg:2 msg:3

# 检查是否已读
SISMEMBER user:1001:read:messages msg:1
# (integer) 1

# 标记已读
SADD user:1001:read:messages msg:4

# UV统计(精确)
SADD page:home:uv user:1001 user:1002 user:1003
SCARD page:home:uv
# (integer) 3

6.5 商品筛选 #

bash
# 商品属性
SADD product:1001:color "red" "blue"
SADD product:1001:brand "nike"
SADD product:1001:size "M" "L"

SADD product:1002:color "red" "green"
SADD product:1002:brand "adidas"

# 红色商品
SADD color:red:products 1001 1002

# Nike商品
SADD brand:nike:products 1001

# 红色Nike商品
SINTER color:red:products brand:nike:products
# 1) "1001"

七、性能优化 #

7.1 避免大集合 #

bash
# 不推荐:超大集合
SADD huge:set item1 item2 ... item1000000

# 推荐:分片集合
SADD small:set:1 item1 item2 ... item10000
SADD small:set:2 item10001 item10002 ... item20000

7.2 使用SSCAN代替SMEMBERS #

bash
# 不推荐:获取所有元素
SMEMBERS myset  # 数据量大时阻塞

# 推荐:迭代扫描
SSCAN myset 0

7.3 集合运算优化 #

bash
# 集合运算时,小集合放前面
SINTER small_set large_set

# 使用SINTERCARD代替SINTER + SCARD
SINTERCARD 2 set1 set2

八、总结 #

集合操作命令:

命令 说明
SADD 添加元素
SREM 删除元素
SMEMBERS 获取所有元素
SISMEMBER 检查元素存在
SCARD 获取元素数量
SPOP 随机弹出
SRANDMEMBER 随机获取

集合运算命令:

命令 说明
SINTER 交集
SUNION 并集
SDIFF 差集
SINTERSTORE 保存交集
SUNIONSTORE 保存并集
SDIFFSTORE 保存差集

应用场景:

场景 实现方式
标签系统 SADD + SINTER
社交关系 SADD + SINTER + SDIFF
抽奖 SPOP / SRANDMEMBER
去重 SADD + SISMEMBER

下一步,让我们学习Redis哈希Hash!

最后更新:2026-03-27