redis set(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
什么是 Redis Set?
Redis Set 是一种无序、不重复的字符串元素集合,类似于数学中的集合概念。它通过哈希表实现,支持快速添加、删除和查询元素,同时提供交集、并集、差集等集合运算功能。对于需要存储唯一值且频繁进行集合操作的场景,Redis Set 是理想的选择。
例如,你可以用 Redis Set 存储网站的独立访客 ID,或者管理标签与文章的关联关系。它的核心特性包括:
- 元素唯一性:同一个 Set 中不能有重复元素。
- 无序性:元素存储顺序与添加顺序无关。
- 高效性:所有操作的时间复杂度均为 O(1) 或 O(N),适合高并发场景。
Redis Set 的基础操作命令
1. 添加元素:SADD
SADD key member [member ...]
命令用于向 Set 中添加一个或多个元素。若元素已存在,则忽略该操作。
示例代码:
SADD fruits apple banana orange
SADD fruits apple mango # 第二次添加 apple 会被忽略
2. 查询元素:SISMEMBER
SISMEMBER key member
返回 1 表示存在,0 表示不存在。
示例代码:
SISMEMBER fruits banana # 返回 1
SISMEMBER fruits grape # 返回 0
3. 获取所有元素:SMEMBERS
SMEMBERS key
返回 Set 中的所有元素,结果以列表形式展示。
示例代码:
SMEMBERS fruits # 输出 [apple, banana, orange, mango]
4. 删除元素:SREM
SREM key member [member ...]
用于删除指定元素。若元素不存在,不会报错。
示例代码:
SREM fruits banana # 删除 banana
SMEMBERS fruits # 输出 [apple, orange, mango]
5. 获取元素数量:SCARD
SCARD key
返回 Set 中元素的总数。
示例代码:
SCARD fruits # 返回 3
Redis Set 的集合运算
Redis Set 的强大之处在于支持多种集合运算,这些操作在社交网络、推荐系统等场景中非常实用。
1. 交集运算:SINTER
SINTER key [key ...]
返回多个 Set 的共同元素。
示例场景:
假设用户 A 和用户 B 分别收藏了以下电影:
SADD user_a_movies "Inception" "Interstellar" "The Matrix"
SADD user_b_movies "Inception" "The Dark Knight" "The Matrix"
通过 SINTER user_a_movies user_b_movies
可以找到两人共同喜欢的电影:
["Inception", "The Matrix"]
2. 并集运算:SUNION
SUNION key [key ...]
返回多个 Set 的所有元素(去重后)。
示例场景:
统计网站 A 和网站 B 的独立访客总数:
SADD website_a_visitors "user1" "user2" "user3"
SADD website_b_visitors "user2" "user4" "user5"
SUNION website_a_visitors website_b_visitors # 输出 ["user1", "user2", "user3", "user4", "user5"]
3. 差集运算:SDIFF
SDIFF key destination_key [key ...]
返回第一个 Set 中存在但其他 Set 中不存在的元素。
示例场景:
找出仅在用户 A 的收藏列表中出现的电影:
SDIFF user_a_movies user_b_movies # 输出 ["Interstellar"]
集合运算的存储操作
若希望将运算结果存储到新 Set 中,可以使用带 STORE
后缀的命令:
SINTERSTORE
:存储交集结果SUNIONSTORE
:存储并集结果SDIFFSTORE
:存储差集结果
示例代码:
SINTERSTORE common_movies user_a_movies user_b_movies
SMEMBERS common_movies # 输出 ["Inception", "The Matrix"]
Redis Set 的实际应用场景
场景 1:统计独立访客
假设你需要统计某篇文章的独立阅读次数。每次用户访问时,将用户 ID 添加到一个 Set 中:
SADD article_123_views user_id_123
最终通过 SCARD
获取总访问人数:
SCARD article_123_views # 返回唯一访问者的数量
场景 2:实现标签系统
文章与标签的关联可通过 Set 实现。例如,文章 1001 标有 "技术" 和 "编程" 标签:
SADD article_1001_tags "技术" "编程"
查询所有带有 "编程" 标签的文章,可以通过遍历所有文章的标签 Set,但这可能效率较低。更好的方式是反向索引:
SADD tag_编程_articles "article_1001" "article_2002"
场景 3:抽奖系统
从大量用户中随机抽取幸运用户时,可以先将所有用户存入一个 Set,然后使用 SRANDMEMBER
随机获取元素:
SADD participants user_1 user_2 ... user_10000
SRANDMEMBER participants 5 # 随机选取5个用户
Redis Set 的高级用法
1. 随机元素获取:SRANDMEMBER
SRANDMEMBER key [count]
可以随机返回一个或多个元素,且支持重复获取(通过 REPLACE
参数)。
示例代码:
SRANDMEMBER fruits 2 # 返回两个随机元素,如 ["mango", "apple"]
2. 原子性操作:SPOP
SPOP key [count]
用于随机删除并返回元素,常用于实现分布式锁或任务队列。
示例场景:
从任务池中取出待处理的任务:
SADD task_pool "task_1" "task_2" "task_3"
SPOP task_pool 1 # 返回一个任务并从集合中删除
3. 有序集合与 Set 的结合
虽然 Set 本身无序,但可以通过 SORTED SET
(ZSET)结合分数实现有序存储。例如,记录用户的登录时间:
ZADD last_login_times user_123 1704987600 # 时间戳作为分数
Redis Set 的性能优化
1. 避免频繁的集合运算
集合运算的时间复杂度为 O(N),当数据量极大时可能影响性能。建议:
- 对于超大规模数据,分批次处理或使用 Lua 脚本优化
- 使用 Redis 6.0+ 的
SINTERCARD
直接获取交集元素数量,避免实际计算集合
2. 合理设置过期时间
通过 EXPIRE
或 PEXIRE
为 Set 设置过期时间,避免内存浪费。例如:
EXPIRE session_set 3600 # Set 1小时后自动失效
3. 使用 Pipeline 提升批量操作效率
当需要频繁添加或删除元素时,使用 Pipeline 可减少网络延迟。例如:
MULTI
SADD fruits grape
SADD fruits kiwi
EXEC
常见问题与解决方案
问题 1:元素重复添加后如何处理?
Redis Set 会自动去重,无需额外操作。但若需记录重复次数,可改用 Hash 或 Sorted Set。
问题 2:如何实现 Set 的增量更新?
使用 SUNIONSTORE
将两个 Set 合并到新 Set 中:
SUNIONSTORE new_set set_a set_b
问题 3:Set 的最大容量是多少?
Redis Set 的理论容量为 2^32-1 元素(约43亿),但实际受限于内存。建议合理规划数据规模。
总结
Redis Set 作为一种轻量级、高性能的集合数据结构,为开发者提供了丰富的操作接口和灵活的使用场景。无论是统计独立用户、实现推荐系统,还是处理复杂的数据关系,Redis Set 都能以简洁的方式解决问题。
通过本文的讲解,读者应能掌握 Set 的基本操作、集合运算、实际应用及优化技巧。在后续实践中,建议结合具体业务需求,探索更多高级功能(如与发布/订阅的结合)或与其他数据类型的组合使用,进一步提升系统性能与扩展性。
(全文约 1800 字)