Redis的八种数据类型介绍

news2024/11/18 10:01:57

Redis 是一个高性能的键值存储,它支持多种丰富的数据类型。每种数据类型都有其特定的用途和底层实现。下面我将介绍 Redis 支持的主要数据类型及其背后的数据结构。
本人这里还有几篇详细的Redis用法文章,可以用来进阶康康!

1. 字符串 (String)

数据结构

字符串是 Redis 中最基本的数据类型,可以是文本、数字、二进制数据等。它在 Redis 内部是以动态字符串 (SDS, Simple Dynamic String) 实现的。SDS 除了字符串本身,还有额外的属性来缓存长度。

  • 简单动态字符串 (SDS)
    • length:当前已使用的字符串长度。
    • free:未使用的预分配空间长度。
    • buf:实际存储字符串的缓冲区。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.set("key", "value");  // 设置键值对
String value = jedis.get("key");  // 获取值
System.out.println(value);
jedis.close();

2. 哈希 (Hash)

数据结构

哈希是键值对的集合,适合表示对象的属性。最常用的是用来存储对象。内部实现主要有两种:

  • 压缩列表 (ziplist):当哈希数量较少且每个键值对的长度较短时会使用。
  • 哈希表 (hashtable):当哈希数量增多或其中某个键或值变长后,自动转为哈希表。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.hset("user:1000", "name", "John");
jedis.hset("user:1000", "age", "30");
String name = jedis.hget("user:1000", "name");
System.out.println(name);
jedis.close();

3. 列表 (List)

数据结构

列表是一组有序的字符串,可以从列表的头部或尾部添加或删除元素。内部实现有以下两种:

  • 压缩列表 (ziplist):元素数量较少且每个元素较短时使用。
  • 双向链表 (linkedlist):元素数量多时,会自动转为双向链表。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.lpush("tasks", "Task1");  // 从头部插入
jedis.rpush("tasks", "Task2");  // 从尾部插入
String task = jedis.lpop("tasks");  // 从头部弹出
System.out.println(task);
jedis.close();

4. 集合 (Set)

数据结构

集合是无序且唯一的字符串集合。内部采用哈希表 (hashtable) 实现,哈希表的键是集合的值,值是 null。

用法示例
Jedis jedis = new Jedis("localhost");
jedis.sadd("tags", "java");
jedis.sadd("tags", "redis");
jedis.sadd("tags", "java");  // 不会重复添加
Set<String> tags = jedis.smembers("tags");
System.out.println(tags);
jedis.close();

5. 有序集合 (Sorted Set)

数据结构

有序集合类似集合,但每个元素都会关联一个分数(score),元素按分数排序。内部使用一种结构:跳表 (skiplist) 和哈希表 (hashtable) 结合。

  • 跳表 (skiplist):快速实现范围查询和排序。
  • 哈希表 (hashtable):快速定位元素。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.zadd("leaderboard", 100, "Player1");
jedis.zadd("leaderboard", 200, "Player2");
Set<String> topPlayers = jedis.zrange("leaderboard", 0, -1);  // 按分数排序获取元素
System.out.println(topPlayers);
jedis.close();

6. 位图 (Bitmap)

数据结构

位图将字符串值视为一个位数组,可以进行位操作。内部存储采用字符串,最大长度可达 512 MB。

  • 字节数组 (byte array):实际存储位图数据的结构,是一个连续的内存区域。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.setbit("user:active", 1, true);  // 设置第2位为1
boolean isActive = jedis.getbit("user:active", 1);
System.out.println(isActive);
jedis.close();

7. HyperLogLog

数据结构

HyperLogLog 是基数估算数据结构,用于估算不重复元素的数量。利用概率算法实现,误差率约 0.81%。用于大规模数据去重计数。

  • 稀疏矩阵 (Sparse Representation):当元素少时,用压缩方法存储。
  • 密集矩阵 (Dense Representation):当元素多到一定程度时,转为密集表示。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.pfadd("unique_visitors", "user1");
jedis.pfadd("unique_visitors", "user2");
jedis.pfadd("unique_visitors", "user1");
long uvCount = jedis.pfcount("unique_visitors");
System.out.println(uvCount);
jedis.close();

8. 地理空间 (Geospatial)

数据结构

Redis 的地理空间扩展允许存储地理坐标,并提供地理范围查询、距离计算等功能。内部使用有序集合 (Sorted Set) 数据类型实现,利用 GeoHash 编码。

  • GeoHash 编码 (geohash):将地理坐标编码为字符串,保证地理位置靠近的两个编码也是靠近的。
  • 跳表 (skiplist) 和哈希表 (hashtable):与有序集合共享的实现,支持半径查询和排序。
用法示例
Jedis jedis = new Jedis("localhost");
jedis.geoadd("locations", 13.361389, 38.115556, "Palermo");
jedis.geoadd("locations", 15.087269, 37.502669, "Catania");

List<GeoCoordinate> coordinates = jedis.geopos("locations", "Palermo");
System.out.println(coordinates);

double distance = jedis.geodist("locations", "Palermo", "Catania", GeoUnit.KM);
System.out.println(distance);
jedis.close();

结论

Redis 提供了丰富的数据结构,每种数据结构都有其特定的应用场景和优势。在实践中,可以根据具体需求选择合适的数据类型,提高系统性能与效率。了解这些数据结构的底层实现有助于更好地理解和使用 Redis,优化数据存储和操作。

另(面试突出加分项):
跳表(SkipList)是一种用于有序集合的高效数据结构,支持快速的插入、删除和查找操作。它的时间复杂度为 O(log N),接近于平衡二叉树,但实现相对简单。跳表是 Redis 中 Sorted Set(有序集合)数据类型的主要底层实现之一。

在这里插入图片描述

跳表的数据结构

跳表由多层有序链表组成,下层链表包含所有元素,每一层链表是其下一层链表的抽样。跳表的最底层是一条完整的有序链表,从头到尾包含所有的元素。每一层往上减少一部分元素,通过跳过一些元素使操作更高效。

  • Level 0:包含所有节点,构成最底层链表。
  • Level 1:包含部分节点,跳过一些元素,形成较高层次的链表。
  • Level k:最高层链表,包含最少的元素。

跳表的节点

每个节点包含多个指针,每个指针指向该层中的下一个节点。节点结构如下:

  • score:用于排序的分数。
  • member:实际存储的值。
  • forward pointers:指向各层下一个节点的指针数组。

跳表的操作

跳表支持插入、删除和查找操作,具体步骤如下:

插入操作
  1. 从最高层开始,找到要插入的位置。
  2. 随机生成节点的高度(层数)。
  3. 将新节点插入到对应的每一层链表中。
删除操作
  1. 从最高层开始,找到要删除的节点。
  2. 更新指针,跳过该节点。
  3. 逐层删除该节点。
查找操作
  1. 从最高层开始,根据分数找到目标位置。
  2. 如果当前层找不到,降到下一层继续查找。
  3. 直到找到目标节点或确认节点不存在。

跳表在 Redis 中的实现

以下是 Redis 跳表的数据结构和主要操作的实现:

节点结构
typedef struct zskiplistNode {
    struct zrobj *obj; // 存储成员对象(value)
    double score;      // 分数,用于排序
    struct zskiplistNode *backward; // 后退指针
    struct zskiplistLevel {
        struct zskiplistNode *forward; // 前进指针
        unsigned int span;             // 跨度
    } level[]; // 层指针数组
} zskiplistNode;
跳表结构
typedef struct zskiplist {
    struct zskiplistNode *header, *tail; // 头尾指针
    unsigned long length;                // 节点数量
    int level;                           // 当前最大层数
} zskiplist;
插入操作
zskiplistNode *zslInsert(zskiplist *zsl, double score, robj *obj) {
    // 临时存储每一层的前一个节点
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL];
    zskiplistNode *x;
    int i, level;
    
    x = zsl->header;
    for (i = zsl->level-1; i >= 0; i--) {
        while (x->level[i].forward && 
               (x->level[i].forward->score < score ||
               (x->level[i].forward->score == score &&
                compareStringObjects(x->level[i].forward->obj, obj) < 0))) {
            x = x->level[i].forward;
        }
        update[i] = x;
    }
    
    level = zslRandomLevel(); // 随机生成节点层数
    if (level > zsl->level) {
        for (i = zsl->level; i < level; i++) {
            update[i] = zsl->header;
        }
        zsl->level = level;
    }

    x = zslCreateNode(level, score, obj); // 创建新节点
    for (i = 0; i < level; i++) {
        x->level[i].forward = update[i]->level[i].forward;
        update[i]->level[i].forward = x;
    }
    x->backward = (update[0] == zsl->header ? NULL : update[0]);
    if (x->level[0].forward)
        x->level[0].forward->backward = x;
    else
        zsl->tail = x;
    zsl->length++;
    return x;
}
删除操作
int zslDelete(zskiplist *zsl, double score, robj *obj) {
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
    int i;
    
    x = zsl->header;
    for (i = zsl->level-1; i >= 0; i--) {
        while (x->level[i].forward && 
               (x->level[i].forward->score < score ||
               (x->level[i].forward->score == score &&
                compareStringObjects(x->level[i].forward->obj, obj) < 0))) {
            x = x->level[i].forward;
        }
        update[i] = x;
    }

    x = x->level[0].forward;
    if (x && score == x->score && compareStringObjects(x->obj, obj) == 0) {
        for (i = 0; i < zsl->level; i++) {
            if (update[i]->level[i].forward == x) {
                update[i]->level[i].forward = x->level[i].forward;
            }
        }
        if (x->level[0].forward) {
            x->level[0].forward->backward = x->backward;
        } else {
            zsl->tail = x->backward;
        }
        while (zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL) {
            zsl->level--;
        }
        zsl->length--;
        zslFreeNode(x);
        return 1;
    }
    return 0;
}
查找操作
zskiplistNode *zslFind(zskiplist *zsl, double score, robj *obj) {
    zskiplistNode *x = zsl->header;
    int i;

    for (i = zsl->level-1; i >= 0; i--) {
        while (x->level[i].forward && 
               (x->level[i].forward->score < score ||
               (x->level[i].forward->score == score &&
                compareStringObjects(x->level[i].forward->obj, obj) < 0))) {
            x = x->level[i].forward;
        }
    }
    x = x->level[0].forward;
    if (x && score == x->score && compareStringObjects(x->obj, obj) == 0) {
        return x;
    }
    return NULL;
}

跳表的优点

  1. 高效性:查找、插入、删除的平均时间复杂度为 O(log N)。
  2. 简单性:相较于平衡树,跳表的实现和维护更为简单。
  3. 灵活性:能够快速应对动态变化的数据,有较好的适应性。

在 Redis 中的应用

跳表主要用于 Redis 的有序集合 (Sorted Set) 数据类型。通过跳表,可以高效实现按分数排序的多种操作,如范围查询、排名查询等。它与哈希表结合使用,实现了元素的快速访问和分数范围内的高效查询。

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

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

相关文章

Python数据分析-分子数据分析和预测

一、设计背景 分子结构设计与性质计算对研发新型高能量密度材料具有重要意义。机器学习作为一种大数据计算模型&#xff0c;可以避免复杂、危险的实验&#xff0c;大幅提高研发效率、降低设计和计算成本。本文基于机器学习的方法以及通过构建神经网络&#xff0c;实现对高能量…

网络基础:IS-IS协议

IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;是一种链路状态路由协议&#xff0c;最初由 ISO&#xff08;International Organization for Standardization&#xff09;为 CLNS&#xff08;Connectionless Network Service&#xff09;网络设计。…

TP8/6 子域名绑定应用

原www.xxx.com/admin改为admincms.xxx.com config/app.php 官方文档&#xff1a;ThinkPHP官方手册

fastadmin 如何给页面添加水印

偶然发现fastadmin框架有个水印插件&#xff0c;看起来漂亮&#xff0c;就想也实现这样的功能&#xff0c;看到需要费用。但是现成的插件需要费用&#xff0c;自己动手丰衣足食。说干就干。 1. 找到watermark.js &#xff0c;放到assets/js/ 下面 2.具体页面引入 <script…

基于单片机的粉尘检测报警防护系统研究

摘要 &#xff1a; 粉尘检测是环境保护的重要环节&#xff0c;传统的粉尘检测防护系统的预防方式较为单一。本文设计了一种基于单片机的粉尘检测报警防护系统&#xff0c;能有效地检测粉尘浓度&#xff0c;进行多种方式的报警防护&#xff0c;以保证工作人员的生命健康和安全。…

平价猫粮新选择!福派斯鲜肉猫粮,让猫咪享受美味大餐!

福派斯鲜肉猫粮&#xff0c;作为一款备受铲屎官们青睐的猫粮品牌&#xff0c;凭借其卓越的品质和高性价比&#xff0c;为众多猫主带来了健康与美味的双重享受。接下来&#xff0c;我们将从多个维度对这款猫粮进行解析&#xff0c;让各位铲屎官更加全面地了解它的魅力所在。 1️…

强大的文档编辑工具——坤Tools正式版 V0.4.4【免费的Word转PDF、PDF转Word、替换内容、转换图片、合并图片工具】

在这个信息爆炸的时代&#xff0c;我们每个人都像是一名勇敢的探险家&#xff0c;在茫茫的数据海洋中寻找着属于自己的宝藏。 软件链接&#xff1a;吾爱原创 | 全功能批量处理器&#xff0c;绿色版本&#xff01; 今天给大家带来一款功能强大的文档编辑工具——坤Tools正式版…

孙溟㠭篆刻《睡片原谅一切,醒来不问过往》

孙溟㠭篆刻《睡片原谅一切&#xff0c;醒来不问过往》 佛陀言&#xff1a;睡前原谅一切&#xff0c;醒来不问过往&#xff0c;珍惜所有不期而遇&#xff0c;看淡所有不辞而别甲辰夏溟㠭于寒舍小窗下刊。

Hadoop-15-Hive 元数据管理与存储 Metadata 内嵌模式 本地模式 远程模式 集群规划配置 启动服务 3节点云服务器实测

章节内容 上一节我们完成了&#xff1a; Hive中数据导出&#xff1a;HDFSHQL操作上传内容至Hive、增删改查等操作 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&am…

KIVY 3D Rotating Monkey Head¶

3D Rotating Monkey Head — Kivy 2.3.0 documentation KIVY 3D Rotating Monkey Head kivy 3D 旋转猴子头 This example demonstrates using OpenGL to display a rotating monkey head. This includes loading a Blender OBJ file, shaders written in OpenGL’s Shading…

机器学习筑基篇,​Ubuntu 24.04 快速安装 PyCharm IDE 工具,无需激活!

[ 知识是人生的灯塔&#xff0c;只有不断学习&#xff0c;才能照亮前行的道路 ] Ubuntu 24.04 快速安装 PyCharm IDE 工具 描述&#xff1a;虽然在之前我们安装了VScode&#xff0c;但是其对于使用Python来写大型项目以及各类配置还是比较复杂的&#xff0c;所以这里我们还是推…

docker buildx 交叉编译设置

dockerd配置文件 /etc/docker/daemon.json设置&#xff1a; rootubuntu:/etc/docker# cat daemon.json {"insecure-registries":["localhost:5000","127.0.0.1:5000","172.16.67.111:5000"],"features": {"buildkit&…

三、数据库系统(考点篇)

1、三级模式一两级映像 内模式&#xff1a;管理如何存储物理的 数据 &#xff0c;对数据的存储方式、优化、存放等。 模式&#xff1a;又称为概念模式&#xff0c; 就是我们通常使用的表这个级别 &#xff0c;根据应用、需求将物理数据划分成一 张张表。 外模式&#xff1a;…

springboot出租房租赁系统-计算机毕业设计源码80250

摘 要 随着城市化进程的不断推进&#xff0c;人口流动日益频繁&#xff0c;住房租赁需求逐渐增加。为了更好地满足人们对住房租赁服务的需求&#xff0c;本论文基于Spring Boot框架&#xff0c;设计并实现了一套出租房租赁系统。 首先&#xff0c;通过对市场需求和现有系统的调…

职升网:中级统计师是否属于中级职称?

中级统计师确实属于中级职称。 在统计专业人员的职称体系中&#xff0c;中级统计师占据了重要的位置&#xff0c;它属于中级职称范畴。这个职称体系包括初级、中级、高级和正高级四个层次&#xff0c;每个层次都对应着不同的专业技术岗位等级。初级职称只设助理级&#xff0c;…

Podman 深度解析

目录 引言Podman 的定义Podman 的架构Podman 的工作原理Podman 的应用场景Podman 在 CentOS 上的常见命令实验场景模拟总结 1. 引言 随着容器化技术的发展&#xff0c;Docker 已成为容器管理的代名词。然而&#xff0c;由于 Docker 的一些局限性&#xff0c;如需要守护进程和 …

昇思25天学习打卡营第08天|模型训练

模型训练 模型训练一般分为四个步骤&#xff1a; 构建数据集。定义神经网络模型。定义超参、损失函数及优化器。输入数据集进行训练与评估。 现在我们有了数据集和模型后&#xff0c;可以进行模型的训练与评估。 ps&#xff1a;这里的训练和Stable Diffusion中的训练是一样…

BUUCTF - Basic

文章目录 1. Linux Labs 【SSH连接漏洞】2. BUU LFI COURSE【文件包含漏洞】3. BUU BRUTE【暴力破解用户名密码】4. BUU SQL COURSE【SQL注入-当前数据库】5. Upload-Labs-Linux 1【文件上传漏洞】7. Buu Upload Course 1【文件上传包含漏洞】8. sqli-labs 1【SQL注入-服务器上…

【论文笔记】BEVCar: Camera-Radar Fusion for BEV Map and Object Segmentation

原文链接&#xff1a;https://arxiv.org/abs/2403.11761 0. 概述 本文的BEVCar模型是基于环视图像和雷达融合的BEV目标检测和地图分割模型&#xff0c;如图所示。模型的图像分支利用可变形注意力&#xff0c;将图像特征提升到BEV空间中&#xff0c;其中雷达数据用于初始化查询…

Linux 进程间的信号

1.信号的初认识 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。通俗来说信号就是让用户或进程给其他用户和进程发生异步信息的一种方式。对于信号我们可以根据实际生活&#xff0c;对他有以下几点认识&#xff1a;1.在没有产生信号时我们就知道产生信号要怎么处…