当前位置: 首页 > news >正文

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表的简单介绍

  1. 哈希函数:哈希表使用哈希函数将元素映射到一个数组的索引中。通过这个索引,我们可以快速定位到存储在该位置的元素。
  2. 存储结构:在 Redis 中,Set 存储元素时会使用一个哈希表,其键是元素的值,值通常是一个指向该元素的指针。这样,每个元素的插入、查找或删除操作都可以直接通过哈希表的索引进行。
  3. 添加元素(SADD):当添加一个新元素时,Redis 计算该元素的哈希值,并根据这个哈希值找到相应的索引位置。如果该位置为空(即没有相同的元素),就将该元素插入数组中。这一过程的时间复杂度是 O(1)。
  4. 删除元素(SREM):删除一个元素时,Redis 同样计算该元素的哈希值并找到相应的索引位置。如果该元素存在,就将其从哈希表中移除。这一过程也是 O(1)。
  5. 查找元素(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. 常见的业务场景

一般业务场景的使用是会根据对应数据结构的特性来说明的:

  1. 去重:当需要存储一组唯一的用户 ID、标签或其他信息时,可以使用 Set 来自动去重。例如,存储用户的浏览历史,确保每个用户的历史记录中没有重复的页面。【唯一性】
  2. 社交网络:在社交网络应用中,可以使用 Set 来表示用户的好友关系。比如,用户 A 的好友可以存储在 Set 中,快速判断用户 B 是否是用户 A 的好友。【唯一性,高效性】
  3. 标签系统:对于文章、商品等,可以使用 Set 来存储相关标签,方便进行标签查询和管理。【高效性】
  4. 投票系统:可以使用 Set 存储已经投票的用户 ID,确保每个用户只能投一次票。【唯一性】
  5. 实时分析:在实时分析场景中,可以使用 Set 来跟踪活跃用户、访问过的页面等。【高效性】

2.1. 标签系统

标签系统:Set类型可用于存储和处理具有标签特性的数据,如商品标签、文章分类标签等。
背景
在一个内容平台上,用户可以给文章打上不同的标签,系统需要根据标签过滤和推荐文章。
在这里插入图片描述
优势

  1. 快速查找:使用Set可以快速判断一个元素是否属于某个集合。
  2. 灵活的标签管理:方便地添加和删除标签,实现标签的灵活管理。
  3. 集合运算:通过集合运算,如交集和并集,可以轻松实现复杂的标签过滤逻辑。

代码实现

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类型可以表示用户的好友列表,支持快速好友关系测试和好友推荐。
背景
在一个社交网络应用中,用户可以添加和删除好友,系统需要管理用户的好友关系。
在这里插入图片描述
优势

  1. 唯一性:保证好友列表中不会有重复的好友。
  2. 快速关系测试:快速判断两个用户是否互为好友。
  3. 好友推荐:利用集合运算,如差集,推荐可能认识的好友。

解决方案
使用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问题。在一个强化学习过程中,一个智能体只能通过和它所处的环境互动学习最优策略。特别地,智能体首先观察自己当前的状态&#xf…...

【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 概述 生成方式&#xff1a;Proxy Class 是从 AutoSar 元模型的服务接口描述中生成的&#xff0c;ara::com 标准化了其接口&#xff0c;AP 产品供应商的工具链会生成实现该接口的代理实现类。 命名空间&#xff1a;ara::com 期望代理相关的工件在命名空间 “pro…...

【Scala入门学习】基本数据类型和变量声明

1. 基本数据类型 scala 的基本类型有 9种&#xff1a; Byte、Char、Short、Int、Long、Float、Double、Boolean、Unit Scala中没有基本数据类型的概念&#xff0c;所有的类型都是对象。 AnyVal&#xff1a;代表所有基本类型。 AnyRef&#xff1a;代表所以引用类型&#xff…...

C#基础(13)结构体

前言 随着函数的讲解完成&#xff0c;我想你已经初步有了写一些复杂逻辑功能的能力&#xff0c;但是我们会发现其实在我们大部分实际开发情况中&#xff0c;很多我们需要写的变量可能不只有一个属性。 他可能有很多变量&#xff0c;那这时候我们如果要把这些变量集中到一个东…...

Excel图片批量插入单元格排版处理插件【图片大师】

为了方便大家在图片的插入排版的重复工作中解放出来&#xff0c;最近发布了一款批量插入图片的插件&#xff0c;欢迎大家下载&#xff0c;免费试用。 这是图片的文件夹&#xff1a; 主要功能如下: 1&#xff0c;匹配单元格名称的多张图批量插入到一个单元格 该功能支持设置图…...

应用性能优化实践(二)提升应用启动和响应速度

一、提升应用启动和响应速度的方法 1、冷启动过程简介 应用启动时&#xff0c;后台无该应用的进程&#xff0c;需要创建新的进程&#xff0c;这种启动方式叫冷启动。 2、使用异步加载 使用异步加载可以在后台线程中处理耗时操作&#xff0c;从而提升应用响应速度。 3、延迟加载…...

接口测试系列文章专题

在你眼中什么是接口 HTTP协议 什么是接口测试 接口测试之工具 fiddler工具的原理 fiddler工具界面详解 fiddler工具的基本使用 fiddler使如何对手机app进行抓包的呢 fiddler手机app抓包教程 Charles自定义接口返回的数据内容 常用接口工具postman的基本使用方式 pos…...

Unity Hub自动安装指定版本Unity的Android开发环境

Unity开发Android环境要求SDK、DNK、JDK、Gradle版本都要对才能发布APK&#xff0c;自己去配置很容易出错。Unity Hub可以自动安装指定版本Unity的Android开发环境。 1.安装国内用的UnityHub&#xff08;我这里用的3.3.2-c6&#xff09; 2.找到对应的Unity版本 3.点击【从Unit…...

从0开始学ARM

1. ARM模式和寄存器 1.1 ARM处理器工作模式 Cortex系列之前的ARM处理器工作模式一共有7种。 1.1.1 工作模式 Cortex系列的ARM处理器工作模式有8种&#xff0c;多了1个monitor模式&#xff0c;如下图所示&#xff1a; ARM之所以设计出这么多种模式出来&#xff0c;就是为了…...

每日一题——第九十四题

// SortNumInFile.cpp : 此文件包含 “main” 函数。程序执行将在此处开始并结束。 // 题目&#xff1a;将一个文本文件number.txt中的数字按照从小到大排列后&#xff0c;重新写入到该文件中&#xff0c;要求排序前和排序后都输出该文件的内容。该文件中共有20个整数&#xf…...

Linux 开发工具(vim、gcc/g++、make/Makefile)+【小程序:进度条】-- 详解

目录 一、Linux软件包管理器 - yum&#xff08;ubuntu用apt代替yum&#xff09;1、Linux下安装软件的方式2、认识 yum3、查找软件包4、安装软件5、如何实现本地机器和云服务器之间的文件互传 二、Linux编辑器 - vim1、vim 的基本概念2、vim 下各模式的切换3、vim 命令模式各命令…...

后续学习规划 ----含我个人的学习路线,经历及感受

目前的基础 开发相关&#xff08;最重要&#xff09; 1.Java SE 从入门到起飞 2.Java Web开发 3.苍穹外卖 以上三个是和开发相关的基础。 我是按照书写的顺序学习的&#xff0c;有需要的朋友可以参考。 计算机相关 其他的话&#xff0c;都是比较久远的了。隔得时间一年半…...

Skytower

一、安装配置靶机 下载地址: SkyTower: 1 ~ VulnHub 下载之后解压发现是VirtualBox格式的 我们下载一个VirtualBox&#xff0c;这是官网 Downloads – Oracle VirtualBox 安装到默认路径就 打开后点击注册 选择解压后的vbox文件 然后点击左上角管理 点击导出虚拟电脑&…...

成型的程序

加一个提示信息 加上python 常用的包 整个程序打包完 250M 安装 960MB matplot numpy pandas scapy pysearial 常用的包 (pyvisa)… … 啥都有 Python 解释器组件构建 要比 lua 容易的多 &#xff08;C/Rust 的组件库)...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...