Redis数据结构之Set

news2025/1/21 18:35:45

Set 类型是一个无序并唯一的键值集合,它的存储顺序不会按照插入的先后顺序进行存储。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。相对于列表,集合也有两个特点:无序、不可重复

一个集合最多可以存储 2^32-1 个元素。概念和数学中个的集合基本类似,数学集合的概念是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。

简而言之,Redis 集合就是一些不重复值的组合。利用集合(Set)这个数据结构,Redis 可以存储一些集合类型的数据,Redis也通过一些简便的命令很好的支持了交集、并集和差集等集合的基本运算。


文章目录

    • @[toc]
        • 1、Set数据类型
          • 1.1、Set类型简介
          • 1.2、Set应用场景
        • 2、Set底层结构
          • 2.1、List底层结构介绍
          • 2.2、整数集合IntSet
          • 2.3、哈希表HashTable
        • 3、Set常用命令
          • 3.1、添加集合元素
          • 3.2、查看集合所有值
          • 3.3、判断一个值是否在集合中
          • 3.4、查看某集合的存值的数量
          • 3.5、删除集合中指定值的元素
          • 3.6、随机选出某集合中一个元素
          • 3.7、随机删除某集合中一个元素
          • 3.8、将一个集合中的某值移动至另一个集合
          • 3.9、集合运算:差集
          • 3.10、集合运算:交集
          • 3.11、集合运算:并集

1、Set数据类型

1.1、Set类型简介

Set 类型是一个无序并唯一的键值集合,它的存储顺序不会按照插入的先后顺序进行存储。Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。相对于列表,集合也有两个特点:无序、不可重复

一个集合最多可以存储 2^32-1 个元素。概念和数学中个的集合基本类似,数学集合的概念是指具有某种特定性质的具体的或抽象的对象汇总而成的集体。

简而言之,Redis 集合就是一些不重复值的组合。利用集合(Set)这个数据结构,Redis 可以存储一些集合类型的数据,Redis也通过一些简便的命令很好的支持了交集、并集和差集等集合的基本运算。

1.2、Set应用场景

常见的应用场景有:投票系统、标签系统、共同好友、共同关注、共同爱好、抽奖、商品筛选栏,访问 IP 统计等

使用场景:

  • 点赞、踩、收藏:Set 类型可以保证一个用户只能点一个赞;
  • 共同关注、标签:Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等;
  • 抽奖活动:存储某活动中中奖的用户名 ,Set 类型因为有去重功能,可以保证同一个用户不会中奖两次

2、Set底层结构

2.1、List底层结构介绍

Redis Set 的底层存储采用 整数集合 IntSet 和哈希表,二者是相互转换的,使用 IntSet 存储必须满足下面两个条件,否则使用 HashTable,条件如下:

  • 结合对象保存的所有元素都是整数值;
  • 集合对象保存的元素数量不超过 512 个

以 Set 的 SADD 命令为例子,整个添加过程如下:

  • 检查 Set 是否存在不存在则创建一个 Set 结合。
  • 根据传入的 Set 集合一个个进行添加,添加的时候需要进行内存压缩。
  • setTypeAdd 执行 Set 添加过程中会判断是否进行编码转换
void saddCommand(redisClient *c) {
    robj *set;
    int j, added = 0;
 
    // 取出集合对象
    set = lookupKeyWrite(c->db,c->argv[1]);
 
    // 对象不存在,创建一个新的,并将它关联到数据库
    if (set == NULL) {
        set = setTypeCreate(c->argv[2]);
        dbAdd(c->db,c->argv[1],set);
 
    // 对象存在,检查类型
    } else {
        if (set->type != REDIS_SET) {
            addReply(c,shared.wrongtypeerr);
            return;
        }
    }
 
    // 将所有输入元素添加到集合中
    for (j = 2; j < c->argc; j++) {
        c->argv[j] = tryObjectEncoding(c->argv[j]);
        // 只有元素未存在于集合时,才算一次成功添加
        if (setTypeAdd(set,c->argv[j])) added++;
    }
 
    // 如果有至少一个元素被成功添加,那么执行以下程序
    if (added) {
        // 发送键修改信号
        signalModifiedKey(c->db,c->argv[1]);
        // 发送事件通知
        notifyKeyspaceEvent(REDIS_NOTIFY_SET,"sadd",c->argv[1],c->db->id);
    }
 
    // 将数据库设为脏
    server.dirty += added;
 
    // 返回添加元素的数量
    addReplyLongLong(c,added);
}

稍微深入分析一下set的单个元素的添加过程,首先如果已经是 HashTable 的编码,那么我们就走正常的 HashTable 的元素添加,如果原来是 IntSet 的情况,那么我们就需要进行如下判断:

  • 如果能够转成 int 的对象(isObjectRepresentableAsLongLong),那么就用 IntSet 保存。
  • 如果用 IntSet 保存的时候,如果长度超过5 12(REDIS_SET_MAX_INTSET_ENTRIES)就转为 HashTable 编码。
  • 其他情况统一用 HashTable 进行存储。
2.2、整数集合IntSet

整数集合 IntSet 是 Redis用来保存整数值的集合的一种数据结构,可以用来保存 int 类型数据,并且可以保证不会出现重复元素。因此当一个集合中只包含整数元素且数量不多的时候,Redis 会选择使用整数集合作为底层实现。

IntSet 内部其实是一个数组(int8_t coentents[] 数组),而且存储数据的时候是有序的,因为在查找数据的时候是通过二分查找来实现的。

img

如果你的集合只有整数值元素,并且数量是轻量的,这时候 Redis 会使用使用整数集合作为 Redis 集合的底层数据结构。参考如下代码:

typedef struct IntSet{
     // 编码格式
     uint32_t encoding;
     // 集合中的元素个数
     uint32_t length;
     // 保存元素数据
     int8_t contents[];
} IntSet;

我们拆解下:

属性说明
“encoding”编码方式
“length”数组中元素个数,也就是数组的整体长度
“contents[]”整数集合,集合的每个元素都是数组的一个数组项(item)。具有特点:按值的大小增序排列、不包含任何重复项

“contents” 是整数集合的底层实现,保存了整数集合的每一个元素,每个元素在该数组中从小到大有序排列,并且不重复(如何保证有序性和唯一性我们后面讨论插入的时候在说)。“contents” 数组虽然声明为 int8_t 类型,但其实真正的类型取决于 “encoding” 的值。在操作一个整数集合的时候,会首先获取 “encoding” 的值。

举个栗子,当我们执行 SADD numbers 1 3 5 向集合对象插入数据时,该集合对象在内存的结构如下:

image-20230823235054892

2.3、哈希表HashTable

Redis 中的 key-value 是通过 dictEntry 对象来实现的,而哈希表就是将 dictEntry 进行了再一次的包装得到的,这就是哈希表对象 dictht:

typedef struct dictht {
    dictEntry **table;//哈希表数组
    unsigned long size;//哈希表大小
    unsigned long sizemask;//掩码大小,用于计算索引值,总是等于size-1
    unsigned long used;//哈希表中的已有节点数
} dictht;

PS:table 是一个数组,其每个元素都是一个 dictEntry 对象。

hashtable 编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象对应一个集合元素,字典的值都是 NULL。当我们执行 SADD fruits "apple" "banana" "cherry" 向集合对象插入数据时,该集合对象在内存的结构如下:

image-20230823235716144


3、Set常用命令

3.1、添加集合元素

使用 SADD 命令添加集合元素

SADD set value

若值已存在,则不进行添加,并返回 0

image-20230821235344528

3.2、查看集合所有值

使用 SMEMBERS 命令查看集合所有值

SMEMBERS set

image-20230821235614136

3.3、判断一个值是否在集合中

使用 SISMEMBER 命令判断一个值是否在集合中

image-20230821235954832

3.4、查看某集合的存值的数量

使用 SCARD 命令查看某集合的存值的数量

SCARD set

image-20230822000410786

3.5、删除集合中指定值的元素

使用 SREM 删除集合中指定值的元素

SREM set value

image-20230822000710429

3.6、随机选出某集合中一个元素

使用 SRANDMEMBER 命令随机选出某集合中一个元素

SRANDMEMBER set

image-20230822000949807

3.7、随机删除某集合中一个元素

使用 SPOP 命令随机删除某集合中一个元素

SPOP set

image-20230822001227634

3.8、将一个集合中的某值移动至另一个集合

使用 SMOVE 命令 将一个集合中的某值移动至另一个集合

SMOVE source target value

image-20230822001457709

3.9、集合运算:差集

使用 SDIFF 命令进行集合运算:差集

SDIFF set1 set2

image-20230822001906994

3.10、集合运算:交集

使用 SINTER 命令进行集合运算:交集

SINTER set1 set2

image-20230822002039149

3.11、集合运算:并集

使用 SUNION 命令进行集合运算:并集

SUNION set1 set2

image-20230822001939037

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/925181.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker安装redis并持久化数据

1. 创建挂载目录 sudo mkdir -p /home/redis/conf sudo mkdir -p /home/redis/data sudo touch /home/redis/conf/redis.confcat > /home/redis/conf/redis.conf << EOF appendonly yes EOFrootk8s-master:/home/redis# ls conf data rootk8s-master:/home/redis# t…

基于SSM的小说网站的设计与实现(论文+源码)

目 录 1 绪论................................................................................................... 1 1.1 项目背景................................................................................................................ 1 1.2 发展历程..…

ssm+vue毕业论文管理系统源码和论文

ssmvue毕业论文管理系统053 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 高校规模越来越大&#xff0c;学生越来越多&#xff0c;每年都有大批的大学生完成学业。毕业之前&#xff0c;各大高校设立…

【经验贴】大型复杂项目的风险管理如何做?

同事小李在年初的时候&#xff0c;接了一个大型项目&#xff0c;以为今年的年终奖都靠它了&#xff0c;结果现在面临着超支、超期的风险&#xff0c;各种风险及问题频发。前段时间经常跟我们沟通讨论&#xff0c;在大家的建议下&#xff0c;项目才逐渐步入正轨&#xff0c;这次…

Linux_4_文本处理工具和正则表达式

目录 1文本编辑工具之神VIM1.1 vi和vim简介1.2使用vim1.2.1 vim 命令格式1.2.2三种主要模式和转换 1.3扩展命令模式1.3.1扩展命令模式基本命令1.3.2 地址定界1.3.3查找并替换1.3.4定制vim的工作特性1.3.4.1行号1.3.4.2忽略字符的大小写1.3.4.3白动缩进1.3.4.4复制粘贴保留格式1…

如何使用IDEA链接数据库并自动生成POJO类?

如何使用IDEA链接数据库并自动生成POJO类&#xff1f; 在 IntelliJ IDEA 中使用数据库连接和自动生成 POJO 类的步骤如下&#xff1a; 1.打开 IntelliJ IDEA 并选择要打开的项目。 2.在顶部菜单中选择 “View” > “Tool Windows” > “Database”&#xff0c;打开数据…

如何自己实现一个丝滑的流程图绘制工具(三)自定义挂载vue组件

背景 bpmn-js是个流程图绘制的工具&#xff0c;但是现在我希望实现的是&#xff0c;绘制的不是节点而是一个vue组件。 保留线的拖拽和连接。 方案 那就说明不是依赖于节点的样式&#xff0c;找到了他有个属性&#xff0c;就是类似覆盖节点的操作。 思路就是用vue组件做遮罩&…

element ui - el-select获取点击项的整个对象item

1.背景 在使用 el-select 的时候&#xff0c;经常会通过 change 事件来获取当前绑定的 value &#xff0c;即对象中默认的某个 value 值。但在某些特殊情况下&#xff0c;如果想要获取的是点击项的整个对象 item&#xff0c;该怎么做呢&#xff1f; 2.实例 elementUI 中是可…

四信房屋建筑监测解决方案

方案背景 房屋建筑安全是人们生产、经营、居住等经济生活和人身安全的基本保证。由于房屋安全事故倒塌的案例频繁发生&#xff0c;造成了人员安全和极大财产损失。导致原因可能是房屋在建设结构设计、建造、施工等监管方面可能存在缺陷&#xff0c;再加上房屋年久材料环境等因…

Android 查看签名文件的MD5 SHA1值

1.找到存放签名文件所在的文件夹 2.输入命令&#xff1a;keytool -list -v -keystore atui.jks 3.输入口令&#xff08;keystore.jks签名文件的密码&#xff09;

Mybatis-分页与动态字符

目录 一.Mybatis动态分页 什么是动态分页&#xff1a; 导入pom依赖 配置拦截器 编写Bookmapper文件 配置pageBean文件 配置BookBiz接口类 配置BookBizImpl实现接口类 编写实现类demo 测试结果 ​编辑 不走插件&#xff0c;不会分页 二.Mybatis的特殊字符 编写一个Book…

EMERSON PR6423010-140+CON021传感器

测量类型&#xff1a;这个传感器可能用于测量不同类型的物理量&#xff0c;如温度、压力、流量、液位、湿度等&#xff0c;具体取决于应用需求。 高精度&#xff1a;通常&#xff0c;这种传感器具有高精度&#xff0c;以确保准确的测量结果。 通信接口&#xff1a;一些型号的…

SpringBootWeb案例 Part3

目录 1. 新增员工 1.1 需求 1.2 接口文档 1.3 思路分析 PostMapping RequestBody //把前端传递的JSON数据填充到实体类中 1.4 功能开发 1.5 功能测试 1.6 前后端联调 2. 文件上传 2.1 文件上传简介 Spring中提供了一个API&#xff1a;MultipartFile&#xff0c;使…

智能微型断路器;智慧用电在线监控装置;故障电弧探测器在金融行业中的应用-安科瑞黄安南

【摘要】&#xff1a;基于人工智能、物联网、云计算、大数据等新ICT技术的智慧用电安全管理服务平台&#xff0c;通过云计算、人工智能对营业网点、办公大楼、紫湖银行等区域的电气检测数据进行分析、预警和控制&#xff0c;实现电气火灾的在线综合治理。 【关键词】&#xff…

python+tkinter实现多页面多菜单的demo实例

本篇文章主要讲解,python+tkinter多页面多菜单的demo实例,支持一个新窗口弹出、多页面切换,顶部菜单构建及事件绑定。 日期:2023年8月25日 版本:python3.9.6 实际效果 消息菜单-具体效果: 页面菜单具体效果: 事件菜单具体效果: 环境及依赖 python 3.9.6 依赖信息: …

beego框架项目实例

1、创建项目 cd /root/go/src/ bee new myproject 2、运行项目 cd /root/go/src/myproject bee run 通过浏览器访问: http://localhost:8080 , 可以看到如下效果&#xff1a; 3、项目路由设置

C#__使用Thread启动线程和传输数据

class Program{static void Test(){Console.WriteLine("Start……");Thread.Sleep(2000); // 1s等于1000ms&#xff0c;暂停2sConsole.WriteLine("end");}static void Download(Object ob){string str ob as string; // 遍历传递过来的ob字符串Console.Wr…

抖音换脸小程序开发方案

【引言】随着抖音平台的风靡&#xff0c;换脸功能成为用户们最为喜爱的特色之一。为了满足用户的需求&#xff0c;开发一款抖音换脸小程序成为了迫切的任务。本文将深入探讨抖音换脸小程序的开发方案&#xff0c;结合专业性和创新之处&#xff0c;为读者提供一份全面的解决方案…

【安装】Linux安装MongoDB过程记录

一、下载 MongoDB 安装包 Install MongoDB Community Kubernetes Operator | MongoDB 下载 复制下载地址 cd /usr/local/ wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel80-7.0.1-rc0.tgz 二、解压 MongoDB 安装包 cd /usr/local tar -zxvf mongodb-li…

windows IIS 站点迁移

为实现负载平衡或者服务器迁移时&#xff0c;我们可能会使用多个 Web 服务器&#xff0c;也就会需要给多个 IIS配置同样的站点和应用程序池。根据需求一个一个重新建吗?当然不用!那得花费多少时间!我们只需要执行一些简单的命令即可在 IIS 上进行这些配置的导出导入~ 当我们在…