# Redis Set 结构如何实现抽奖、共同关注等场景?
# 标准答案
Redis Set(集合) 是 无序、去重的集合结构,支持 快速查找、随机抽取、交集并集操作,非常适用于 抽奖、共同关注、标签匹配等场景。
- 抽奖:
SRANDMEMBER
可随机抽取元素,SPOP
可实现不重复抽奖。 - 共同关注:
SINTER
可高效计算多个用户的共同关注。 - 标签匹配:
SUNION
获取多个标签的合集,SDIFF
计算差集筛选目标用户。
# 答案解析
# 1. Redis Set 结构特点
Redis 的 Set 是一个 无序、去重的集合,底层实现基于 哈希表 + 整数数组,支持 O(1)
级别的插入、删除、判断是否存在操作,同时提供 随机抽取、交集、并集、差集等集合运算,适用于 去重、随机选取、关系计算 相关场景。
常见指令:
操作 | 命令 | 说明 |
---|---|---|
添加元素 | SADD key member1 member2 | O(1) 复杂度,向集合中添加元素 |
移除元素 | SREM key member | O(1) 复杂度,从集合中移除元素 |
随机抽取 | SRANDMEMBER key [count] | O(1),随机获取一个或多个元素 |
随机弹出 | SPOP key [count] | O(1),从集合中移除并返回一个或多个元素 |
交集 | SINTER key1 key2 | O(N) 复杂度,计算多个集合的交集 |
并集 | SUNION key1 key2 | O(N) 复杂度,计算多个集合的并集 |
差集 | SDIFF key1 key2 | O(N) 复杂度,计算 A - B 的差集 |
查询成员 | SISMEMBER key member | O(1),判断成员是否在集合中 |
获取大小 | SCARD key | O(1),获取集合元素数量 |
# 2. Redis Set 实现抽奖功能
# (1)单次随机抽奖
场景:从 100 万用户中 随机抽取 1 人 中奖。
SRANDMEMBER lottery_users 1
1
- 优点:不会影响原集合,可用于 随机推荐、幸运用户抽取。
- 缺点:可能会重复抽取相同用户。
# (2)不重复抽奖
场景:从 100 万用户中 抽取 10 人,保证 不会重复。
SPOP lottery_users 10
1
- 优点:抽出的用户会从集合中删除,确保不会重复中奖。
- 缺点:破坏原集合,需事先备份数据。
📌 解决方案:若要保留用户池,可 备份数据
SUNIONSTORE lottery_backup lottery_users # 备份原数据
SPOP lottery_backup 10 # 在副本中抽奖
1
2
2
# 3. Redis Set 计算共同关注
# (1)计算共同关注
场景:用户 A(关注 x、y、z),用户 B(关注 y、z、w),计算 共同关注的人。
SINTER user:A user:B
1
- 示例数据
SADD user:A "Tom" "Jerry" "Mike"
SADD user:B "Jerry" "Mike" "David"
SINTER user:A user:B # 共同关注:["Jerry", "Mike"]
1
2
3
4
2
3
4
- 优点:查询 O(N) 复杂度,比 SQL
JOIN
计算更快,适合大规模用户关系计算。
# (2)计算好友推荐
场景:用户 A 和用户 B 的好友合集(即可能的好友推荐)。
SUNION user:A user:B
1
优化策略:
过滤掉用户本身
SDIFF user:A user:B
1- 可过滤掉
user:A
关注过的好友,避免推荐已经认识的人。
- 可过滤掉
按活跃度排序推荐
ZINTERSTORE common_followers 2 user:A user:B WEIGHTS 1 1
1- 结合 Sorted Set 计数权重,推荐共同关注最多的用户。
# 4. Redis Set 计算标签匹配
# (1)计算兴趣标签匹配
场景:用户 A 喜欢
篮球、足球、音乐
,用户 B 喜欢足球、音乐、电影
,计算相同兴趣。
SINTER user:A_tags user:B_tags
1
- 示例数据
SADD user:A_tags "basketball" "football" "music"
SADD user:B_tags "football" "music" "movie"
SINTER user:A_tags user:B_tags # 结果:["football", "music"]
1
2
3
4
2
3
4
- 应用场景:用于兴趣推荐、个性化匹配、社交匹配等场景。
# 5. Redis Set vs. List / Hash / Sorted Set
结构 | 适用场景 | 主要特点 |
---|---|---|
Set(集合) | 去重、不重复抽取、关系计算 | 无序、去重、高效交并集计算 |
List(列表) | 消息队列、聊天记录 | 有序、允许重复、支持索引操作 |
Hash(哈希表) | 用户信息存储 | 适用于存储对象,字段查找高效 |
Sorted Set(有序集合) | 排行榜、热度排序 | 有序存储,可按分数排序 |
# 深入追问
- 为什么 Redis
Set
适用于抽奖,而List
不适合? SINTER
在用户量百万级时,如何优化性能?- 如何用 Redis 计算相似用户推荐?
Set
与Sorted Set
在排行榜场景的区别?- 如何高效存储百万级用户的兴趣标签?
# 相关面试题
- Redis
SINTER
计算共同关注的底层原理是什么? SRANDMEMBER
与SPOP
在抽奖场景下的区别?Set
和Sorted Set
在社交应用中的不同应用场景?- Redis
SUNION
查询合并多个标签的性能优化策略? - 为什么 Kafka 不使用 Redis
Set
结构存储消息?
# 总结
- Redis
Set
适用于无序去重场景**,高效支持 抽奖、共同关注、标签匹配等计算。 SPOP
适用于一次性抽奖**,而SRANDMEMBER
适用于可重复抽奖**。SINTER
可高效计算共同关注**,SUNION
可合并多个集合,SDIFF
可用于排除筛选。- 相比 SQL
JOIN
,RedisSet
计算速度快,适用于社交网络、兴趣推荐等场景。 - Set 不适用于有序数据(如排行榜),此时应使用
Sorted Set
。