redis基本数据结构-set
文章目录
- 1. set的基本介绍
- 1.1. set底层结构之hash表的简单介绍
- 1.2. 常用命令
- 2. 常见的业务场景
- 2.1. 标签系统
- 2.2. 社交网络好友关系
1. set的基本介绍
参考链接:https://mp.weixin.qq.com/s/srkd73bS2n3mjIADLVg72A
redis 的 set 数据结构是一个无序的集合,可以存储不重复的元素。适合于多种应用场景,尤其是在需要去重、快速查找和集合运算的场合。从上面的介绍可以看到set主要的特性为:
无序性:元素在set中没有特定的顺序;
唯一性:set中的元素是唯一的,不能重复。
其中还有一个比较重要的特性就是高效性。因为redis 的 Set 数据结构是基于哈希表(hash table)实现的,这也是为什么对元素的添加、删除和查找操作的时间复杂度都是 O(1) 的原因。
1.1. set底层结构之hash表的简单介绍
- 哈希函数:哈希表使用哈希函数将元素映射到一个数组的索引中。通过这个索引,我们可以快速定位到存储在该位置的元素。
- 存储结构:在 Redis 中,Set 存储元素时会使用一个哈希表,其键是元素的值,值通常是一个指向该元素的指针。这样,每个元素的插入、查找或删除操作都可以直接通过哈希表的索引进行。
- 添加元素(SADD):当添加一个新元素时,Redis 计算该元素的哈希值,并根据这个哈希值找到相应的索引位置。如果该位置为空(即没有相同的元素),就将该元素插入数组中。这一过程的时间复杂度是 O(1)。
- 删除元素(SREM):删除一个元素时,Redis 同样计算该元素的哈希值并找到相应的索引位置。如果该元素存在,就将其从哈希表中移除。这一过程也是 O(1)。
- 查找元素(SISMEMBER):查找一个元素是否在集合中,Redis 计算该元素的哈希值,并通过该哈希值定位到对应的索引位置。如果该元素存在于该位置,则返回 true;如果不存在,则返回 false。这一过程同样是 O(1)。
理论上的限制
尽管哈希表的平均时间复杂度是 O(1),在某些情况下,哈希表可能会出现冲突(即不同的元素计算出相同的哈希值)。当发生冲突时,多个元素可能会存储在同一个索引位置,导致查找、插入和删除的性能下降。此时,复杂度可能退化为 O(n),其中 n 是发生冲突的元素数量。然而,Redis 使用了一些策略(如动态扩容和链表/树结构来处理冲突)来保持哈希表的性能,使得在大多数情况下,操作的时间复杂度仍然可以保持在 O(1)。
1.2. 常用命令
SADD key member [member ...]:将一个或多个成员添加到集合中。
SREM key member [member ...]:移除集合中的一个或多个成员。
SISMEMBER key member:判断某个成员是否是集合中的成员。
SMEMBERS key:返回集合中的所有成员。
SCARD key:返回集合中成员的数量。
交集:SINTER key1 [key2 ...]:返回所有给定集合的交集。
并集:SUNION key1 [key2 ...]:返回所有给定集合的并集。
差集:SDIFF key1 [key2 ...]:返回第一个集合与其他集合的差集。
SADD myset "apple" "banana" "orange"
SREM myset "banana"
SISMEMBER myset "apple" # 返回 1 (true)
SMEMBERS myset # 返回 ["apple", "orange"]
SCARD myset # 返回 2SADD set1 "a" "b" "c"
SADD set2 "b" "c" "d"
SINTER set1 set2 # 返回 ["b", "c"]
SUNION set1 set2 # 返回 ["a", "b", "c", "d"]
SDIFF set1 set2 # 返回 ["a"]
2. 常见的业务场景
一般业务场景的使用是会根据对应数据结构的特性来说明的:
- 去重:当需要存储一组唯一的用户 ID、标签或其他信息时,可以使用 Set 来自动去重。例如,存储用户的浏览历史,确保每个用户的历史记录中没有重复的页面。【唯一性】
- 社交网络:在社交网络应用中,可以使用 Set 来表示用户的好友关系。比如,用户 A 的好友可以存储在 Set 中,快速判断用户 B 是否是用户 A 的好友。【唯一性,高效性】
- 标签系统:对于文章、商品等,可以使用 Set 来存储相关标签,方便进行标签查询和管理。【高效性】
- 投票系统:可以使用 Set 存储已经投票的用户 ID,确保每个用户只能投一次票。【唯一性】
- 实时分析:在实时分析场景中,可以使用 Set 来跟踪活跃用户、访问过的页面等。【高效性】
2.1. 标签系统
标签系统:Set类型可用于存储和处理具有标签特性的数据,如商品标签、文章分类标签等。
背景
在一个内容平台上,用户可以给文章打上不同的标签,系统需要根据标签过滤和推荐文章。

优势
- 快速查找:使用Set可以快速判断一个元素是否属于某个集合。
- 灵活的标签管理:方便地添加和删除标签,实现标签的灵活管理。
- 集合运算:通过集合运算,如交集和并集,可以轻松实现复杂的标签过滤逻辑。
代码实现
package mainimport ("context""fmt""github.com/go-redis/redis/v8"
)var ctx = context.Background()// Redis 客户端初始化
var rdb = redis.NewClient(&redis.Options{Addr: "", // Redis 服务器地址Password: "", // 密码DB: 0, // 使用默认 DB
})// 文章标签管理结构体
type ArticleTagManager struct{}// 给文章添加标签
func (atm *ArticleTagManager) AddTagToArticle(articleID string, tags []string) error {_, err := rdb.SAdd(ctx, "article:"+articleID+":tags", tags).Result()if err != nil {return err}for _, tag := range tags {_, err := rdb.SAdd(ctx, "global:tags:"+tag, "article:"+articleID).Result()if err != nil {return err}}log.Printf("Added tags %v to article %s\n", tags, articleID)return nil
}// 从文章中删除标签
func (atm *ArticleTagManager) RemoveTagFromArticle(articleID string, tag string) error {_, err := rdb.SRem(ctx, "article:"+articleID+":tags", tag).Result()if err != nil {return err}log.Printf("Removed tag %s from article %s\n", tag, articleID)return nil
}// 获取文章的所有标签
func (atm *ArticleTagManager) GetTagsOfArticle(articleID string) ([]string, error) {tags, err := rdb.SMembers(ctx, "article:"+articleID+":tags").Result()if err != nil {return nil, err}return tags, nil
}// 根据标签获取文章列表
func (atm *ArticleTagManager) GetArticlesByTag(tag string) ([]string, error) {articles, err := rdb.SMembers(ctx, "global:tags:"+tag).Result()if err != nil {return nil, err}return articles, nil
}// 获取文章的标签数量
func (atm *ArticleTagManager) GetTagCountOfArticle(articleID string) (int64, error) {count, err := rdb.SCard(ctx, "article:"+articleID+":tags").Result()if err != nil {return 0, err}return count, nil
}// 获取某个标签的文章数量
func (atm *ArticleTagManager) GetArticleCountByTag(tag string) (int64, error) {count, err := rdb.SCard(ctx, "global:tags:"+tag).Result()if err != nil {return 0, err}return count, nil
}func main() {atm := &ArticleTagManager{}// 为文章添加标签if err := atm.AddTagToArticle("1", []string{"Golang", "Redis"}); err != nil {log.Fatalf("Error adding tags: %v", err)}if err := atm.AddTagToArticle("2", []string{"Python", "Redis"}); err != nil {log.Fatalf("Error adding tags: %v", err)}if err := atm.AddTagToArticle("3", []string{"Golang", "Python"}); err != nil {log.Fatalf("Error adding tags: %v", err)}// 获取文章的所有标签if tags, err := atm.GetTagsOfArticle("1"); err == nil {fmt.Println("Tags for article 1:")for _, tag := range tags {fmt.Println(tag)}}// 根据标签获取文章列表if articles, err := atm.GetArticlesByTag("Golang"); err == nil {fmt.Println("Articles with tag 'Golang':")for _, article := range articles {fmt.Println(article)}}// 获取文章标签数量if count, err := atm.GetTagCountOfArticle("1"); err == nil {fmt.Printf("Article 1 has %d tags.\n", count)}// 获取某个标签的文章数量if count, err := atm.GetArticleCountByTag("Redis"); err == nil {fmt.Printf("Tag 'Redis' has %d articles associated.\n", count)}// 测试完移除整个集合rdb.Del(ctx, "article:1:tags")rdb.Del(ctx, "article:2:tags")rdb.Del(ctx, "article:3:tags")rdb.Del(ctx, "global:tags:Golang")rdb.Del(ctx, "global:tags:Redis")rdb.Del(ctx, "global:tags:Python")
}
运行结果:

2.2. 社交网络好友关系
社交网络好友关系:Set类型可以表示用户的好友列表,支持快速好友关系测试和好友推荐。
背景
在一个社交网络应用中,用户可以添加和删除好友,系统需要管理用户的好友关系。

优势
- 唯一性:保证好友列表中不会有重复的好友。
- 快速关系测试:快速判断两个用户是否互为好友。
- 好友推荐:利用集合运算,如差集,推荐可能认识的好友。
解决方案
使用Redis Set类型存储用户的好友集合,实现好友关系的管理。
代码实现
package mainimport ("context""fmt""github.com/go-redis/redis/v8""log"
)var ctx = context.Background()// Redis 客户端初始化
var rdb = redis.NewClient(&redis.Options{Addr: "", // Redis 服务器地址Password: "", // 密码DB: 0, // 使用默认 DB
})// 添加好友
func addFriend(userOneID string, userTwoID string) error {_, err := rdb.SAdd(ctx, "user:"+userOneID+":friends", userTwoID).Result()if err != nil {return err}_, err = rdb.SAdd(ctx, "user:"+userTwoID+":friends", userOneID).Result()return err
}// 判断是否是好友
func isFriend(userOneID string, userTwoID string) bool {return rdb.SIsMember(ctx, "user:"+userOneID+":friends", userTwoID).Val()
}// 获取用户的好友列表
func getFriendsOfUser(userID string) ([]string, error) {friends, err := rdb.SMembers(ctx, "user:"+userID+":friends").Result()return friends, err
}// 删除好友
func removeFriend(userOneID string, userTwoID string) error {_, err := rdb.SRem(ctx, "user:"+userOneID+":friends", userTwoID).Result()if err != nil {return err}_, err = rdb.SRem(ctx, "user:"+userTwoID+":friends", userOneID).Result()return err
}// 推荐可能认识的好友
func recommendFriends(userID string) ([]string, error) {// 获取用户的好友friends, err := getFriendsOfUser(userID)if err != nil {return nil, err}// 如果没有好友,则没有推荐if len(friends) == 0 {return nil, nil}// 找到所有好友的好友,以及去掉自己的好友和自己potentialFriends := make(map[string]struct{})for _, friendID := range friends {friendFriends, err := getFriendsOfUser(friendID)if err != nil {return nil, err}for _, potentialFriend := range friendFriends {// 排除自己和直接好友if potentialFriend != userID {potentialFriends[potentialFriend] = struct{}{}}}}// 将推荐的好友转换为切片recommendations := []string{}for friend := range potentialFriends {// 确保不是已经存在的好友if !isFriend(userID, friend) {recommendations = append(recommendations, friend)}}return recommendations, nil
}func main() {// 示例:添加好友if err := addFriend("user1", "user2"); err != nil {log.Fatalf("Error adding friend: %v", err)}// 示例:检查好友关系if isFriend("user1", "user2") {fmt.Println("user1 and user2 are friends.")}// 示例:获取好友列表friends, err := getFriendsOfUser("user1")if err != nil {log.Fatalf("Error getting friends: %v", err)}fmt.Println("Friends of user1:", friends)// 示例:推荐可能认识的好友recommendations, err := recommendFriends("user1")if err != nil {log.Fatalf("Error recommending friends: %v", err)}fmt.Println("Recommended friends for user1:", recommendations)// 示例:删除好友if err := removeFriend("user1", "user2"); err != nil {log.Fatalf("Error removing friend: %v", err)}
}
注意事项:
- 虽然Set是无序的,但Redis会保持元素的插入顺序,直到集合被重新排序。
- Set中的元素是唯一的,任何尝试添加重复元素的操作都会无效。
- 使用集合运算时,需要注意结果集的大小,因为它可能会影响性能。
相关文章:
redis基本数据结构-set
文章目录 1. set的基本介绍1.1. set底层结构之hash表的简单介绍1.2. 常用命令 2. 常见的业务场景2.1. 标签系统2.2. 社交网络好友关系 1. set的基本介绍 参考链接:https://mp.weixin.qq.com/s/srkd73bS2n3mjIADLVg72A redis 的 set 数据结构是一个无序的集合&#…...
Android 应用安装-提交阶段
经过前面准备、浏览、协调这些步骤,马上要进入提交阶段了。所谓提交,就是把这些安装应用的相关信息和状态都放到系统中。对于已安装普通应用,它其实分为两个步骤,先卸载旧包,再安装新包。当然,如果是新安装…...
强化学习Reinforcement Learning|Q-Learning|SARSA|DQN以及改进算法
一、强化学习RL 强化学习是机器学习的一个重要的分支,是一种有效的工具,在文献中被广泛用于解决MDP问题。在一个强化学习过程中,一个智能体只能通过和它所处的环境互动学习最优策略。特别地,智能体首先观察自己当前的状态…...
【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设置
文章目录 【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设置RelativeContainer 和 AlignRules 的关系AlignRules 语法详解 【HarmonyOS NEXT开发】如何设置水平/垂直方向的左/居中/右对齐——RelativeContainer的AlignRules设…...
java之认识异常
在 Java 中,异常(Exception)用于处理程序运行时出现的错误或异常情况。Java 的异常处理机制基于 try, catch, finally 和 throw 关键字。 1.异常的分类: 1.1:检查型异常(CheckedException): 定义:程序在…...
JSON处理工具类
JSON处理工具类 import org.json.JSONArray; import org.json.JSONObject;import java.util.ArrayList; import java.util.List;/*** JSON处理工具类*/ public class JsonUtils {/****将json字符串转为map* param json* return java.util.Map<java.lang.String, java.lang.O…...
2022高教社杯全国大学生数学建模竞赛C题 问题一(2) Python代码演示
目录 1.2 结合玻璃的类型,分析文物样品表面有无风化化学成分含量的统计规律数据预处理绘图热力图相关系数图百分比条形图箱线图小提琴图直方图KED图描述性统计分析偏度系数峰度系数其它统计量1.2 结合玻璃的类型,分析文物样品表面有无风化化学成分含量的统计规律 数据预处理 …...
ARACom Proxy Class API 概念
1. Proxy Class 概述 生成方式:Proxy Class 是从 AutoSar 元模型的服务接口描述中生成的,ara::com 标准化了其接口,AP 产品供应商的工具链会生成实现该接口的代理实现类。 命名空间:ara::com 期望代理相关的工件在命名空间 “pro…...
【Scala入门学习】基本数据类型和变量声明
1. 基本数据类型 scala 的基本类型有 9种: Byte、Char、Short、Int、Long、Float、Double、Boolean、Unit Scala中没有基本数据类型的概念,所有的类型都是对象。 AnyVal:代表所有基本类型。 AnyRef:代表所以引用类型ÿ…...
C#基础(13)结构体
前言 随着函数的讲解完成,我想你已经初步有了写一些复杂逻辑功能的能力,但是我们会发现其实在我们大部分实际开发情况中,很多我们需要写的变量可能不只有一个属性。 他可能有很多变量,那这时候我们如果要把这些变量集中到一个东…...
Excel图片批量插入单元格排版处理插件【图片大师】
为了方便大家在图片的插入排版的重复工作中解放出来,最近发布了一款批量插入图片的插件,欢迎大家下载,免费试用。 这是图片的文件夹: 主要功能如下: 1,匹配单元格名称的多张图批量插入到一个单元格 该功能支持设置图…...
应用性能优化实践(二)提升应用启动和响应速度
一、提升应用启动和响应速度的方法 1、冷启动过程简介 应用启动时,后台无该应用的进程,需要创建新的进程,这种启动方式叫冷启动。 2、使用异步加载 使用异步加载可以在后台线程中处理耗时操作,从而提升应用响应速度。 3、延迟加载…...
接口测试系列文章专题
在你眼中什么是接口 HTTP协议 什么是接口测试 接口测试之工具 fiddler工具的原理 fiddler工具界面详解 fiddler工具的基本使用 fiddler使如何对手机app进行抓包的呢 fiddler手机app抓包教程 Charles自定义接口返回的数据内容 常用接口工具postman的基本使用方式 pos…...
Unity Hub自动安装指定版本Unity的Android开发环境
Unity开发Android环境要求SDK、DNK、JDK、Gradle版本都要对才能发布APK,自己去配置很容易出错。Unity Hub可以自动安装指定版本Unity的Android开发环境。 1.安装国内用的UnityHub(我这里用的3.3.2-c6) 2.找到对应的Unity版本 3.点击【从Unit…...
从0开始学ARM
1. ARM模式和寄存器 1.1 ARM处理器工作模式 Cortex系列之前的ARM处理器工作模式一共有7种。 1.1.1 工作模式 Cortex系列的ARM处理器工作模式有8种,多了1个monitor模式,如下图所示: ARM之所以设计出这么多种模式出来,就是为了…...
每日一题——第九十四题
// SortNumInFile.cpp : 此文件包含 “main” 函数。程序执行将在此处开始并结束。 // 题目:将一个文本文件number.txt中的数字按照从小到大排列后,重新写入到该文件中,要求排序前和排序后都输出该文件的内容。该文件中共有20个整数…...
Linux 开发工具(vim、gcc/g++、make/Makefile)+【小程序:进度条】-- 详解
目录 一、Linux软件包管理器 - yum(ubuntu用apt代替yum)1、Linux下安装软件的方式2、认识 yum3、查找软件包4、安装软件5、如何实现本地机器和云服务器之间的文件互传 二、Linux编辑器 - vim1、vim 的基本概念2、vim 下各模式的切换3、vim 命令模式各命令…...
后续学习规划 ----含我个人的学习路线,经历及感受
目前的基础 开发相关(最重要) 1.Java SE 从入门到起飞 2.Java Web开发 3.苍穹外卖 以上三个是和开发相关的基础。 我是按照书写的顺序学习的,有需要的朋友可以参考。 计算机相关 其他的话,都是比较久远的了。隔得时间一年半…...
Skytower
一、安装配置靶机 下载地址: SkyTower: 1 ~ VulnHub 下载之后解压发现是VirtualBox格式的 我们下载一个VirtualBox,这是官网 Downloads – Oracle VirtualBox 安装到默认路径就 打开后点击注册 选择解压后的vbox文件 然后点击左上角管理 点击导出虚拟电脑&…...
成型的程序
加一个提示信息 加上python 常用的包 整个程序打包完 250M 安装 960MB matplot numpy pandas scapy pysearial 常用的包 (pyvisa)… … 啥都有 Python 解释器组件构建 要比 lua 容易的多 (C/Rust 的组件库)...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
