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

Redis7学习--十大数据类型 bitmap、Hyperloglog、GEO、Stream、bitfield

目录

一、前言

二、Redis位图(bitmap)

基本命令

应用

三、Redis基数统计(Hyperloglog)

基数统计

HyperLogLog简介

基本命令

使用场景示例

注意事项

实际应用场景

四、Redis地理空间(GEO)

GEO

基本命令

使用场景示例

底层实现原理

实际应用场景

五、Redis流(Stream)

消息队列

Stream核心特性

基本命令

Stream应用场景

六、Redis位域(bitfield)

Bitfield核心特性

基本命令

注意事项

实际应用场景


一、前言

上篇文章中我们学习了Redis十大数据类型中的前五个,本篇文章我们再来学习后面的五个。

二、Redis位图(bitmap)

位图我们已经很熟悉了,C/C++中都有位图这个结构,且我们引入位图的目的都是差不多的,主要是为了提供一种极其节省内存且高效的方式来处理大规模的布尔型数据或进行位级别的操作

  1. 用String类型作为底层数据结构实现的一种统计二值状态的数据类型
  2. 位图本质是数组,它是基于String数据类型的按位的操作。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)
  3. Bitmap支持的最大位数是2^32位,它可以极大的节约存储空间,使用512M内存就可以存储多达42.9亿的字节信息(2的32次方 = 4294967296)

基本命令

setbit key offset value    // 将第offset的值设为value  value只能是0或1  offset 从0开始
getbit key offset        // 获得第offset位的值
strlen key              // 得出占多少字节 超过8位后自己按照8位一组一byte再扩容
bitcount key         // 得出该key里面含有几个1
bitop and destkey key1 key2 // 对一个或多个 key 求逻辑并,并将结果保存到 destkey 
bitop or destkey key1 key2 // 对一个或多个 key 求逻辑或,并将结果保存到 destkey 
bitop xor destkey key1 key2 // 对一个或多个 key 求逻辑异或,并将结果保存到 destkey 
bitop not destkey key // 对key 求逻辑非,并将结果保存到 destkey 

假设我们有一个网站,需要记录用户每天的签到情况。我们可以用位图来实现一个高效的签到系统。

  • key: 使用 user:sign:202310 作为 2023 年 10 月的签到记录 key。
  • offset: 用日期作为偏移量。10月1日的 offset 是 0,10月2日的 offset 是 1,以此类推,10月31日的 offset 是 30。
  • value (bit): 1 表示已签到,0 表示未签到。

假设用户在 10 月 1 日、10 月 3 日和 10 月 5 日签到了。

应用

如上面的例子,

  • 做签到很适合位图
    • 每天使用1个1亿位的Bitmap约占12MB的内存(10^8/8/1024/1024),10天的Bitmap的内存开销约为120MB,内存压力不算太高。
    • 在实际使用时,最好对Bitmap设置过期时间,让Redis自动删除不再需要的签到记录以节省内存开销。
  • 对于电影和广告是否被点击播放过也可以用位图。

三、Redis基数统计(Hyperloglog)

基数统计

基数统计是指统计一个集合中不重复元素的个数。例如:

  • 集合 {1,2,3,4,5} 的基数是5
  • 集合 {1,2,2,3,3,3} 的基数是3

在实际应用中,基数统计常用于:

  • 统计网站的独立访客数(UV)
  • 统计文章的阅读人数
  • 统计搜索关键词的不同数量

HyperLogLog简介

HyperLogLog是Redis提供的一种用于基数统计的算法,它具有以下特点:

  1. 高效利用内存:只需要12KB内存就可以统计多达2^64个不同元素的基数
  2. 误差率低:标准误差仅为0.81%
  3. 合并功能:多个HyperLogLog可以合并计算总基数

基本命令

pfadd key element [element...]  //向HyperLogLog中添加一个或多个元素。如果HyperLogLog不存在,会自动创建。pfcount key [key...]//获取基数的估计值
pfmerge destkey sourcekey [sourcekey ...]   //合并多个HyperLogLog

使用场景示例

假设我们要统计一个网站的UV,即独立访客数

注意事项

  1. 不是精确计数:HyperLogLog提供的是近似值,有约0.81%的误差,HyperLogLog是一种概率算法,它通过哈希和概率统计来估计基数,而不是精确计数
  2. 内存固定:无论存储多少元素,每个HyperLogLog只占用12KB内存,HyperLogLog使用16384(2^14)个6位的寄存器(桶)来存储数据
  3. 稀疏表示:对于小基数,Redis会使用稀疏表示来节省内存,当元素数量很少时(Redis配置的默认阈值是3000),使用更紧凑的表示法,不是立即分配12KB,而是用更少的内存记录实际元素,当基数超过阈值时,自动转换为完整的12KB表示
  4. 不支持元素查询:无法判断某个元素是否在HyperLogLog中,设计初衷就是只回答"有多少个不同元素",而不是"某个元素是否存在",只存储基数信息,不存储原始元素。
  5. 适合大数据量:对于小数据量,使用SET更合适

实际应用场景

案例1:大型电商UV统计

  • 使用HyperLogLog,因为:
    • 每天可能有数百万UV
    • 12KB/天的存储成本极低
    • 0.81%误差在业务可接受范围内

案例2:小型论坛在线用户

  • 使用SET,因为:
    • 同时在线用户可能只有几百人
    • 需要精确判断用户是否在线
    • 内存消耗不大(几百用户只需几十KB)

四、Redis地理空间(GEO)

地球上的地理位置是使用二维的经纬度表示,经度范围 (-180, 180],纬度范围 (-90, 90],只要我们确定一个点的经纬度就可以名取得他在地球的位置。

例如滴滴打车,最直观的操作就是实时记录更新各个车的位置,当我们要找车时,在数据库中查找距离我们(坐标x0,y0)附近r公里范围内部的车辆

GEO

Redis GEO 是 Redis 提供的地理位置相关功能,基于有序集合(Sorted Set)实现,可以存储地理位置信息并进行相关计算。

其特点是

  1. 基于Sorted Set实现:底层使用有序集合存储,元素是地理位置名称,score是经过编码的地理位置信息
  2. 经纬度精度:使用WGS84坐标系,经度范围[-180,180],纬度范围[-85.05112878,85.05112878]
  3. 高效查询:支持半径查询、距离计算等操作
  4. 距离单位:支持米(m)、千米(km)、英里(mi)、英尺(ft)

基本命令

//向指定key中添加一个或多个地理位置。key:存储地理位置的键 longitude:经度
//latitude:纬度  member:位置名称/标识
geoadd key longitude latitude member [longitude latitude member ...] //获取一个或多个位置成员的经纬度坐标
geopos key member [member ...]//计算两个位置之间的距离unit:距离单位,可选:m:米(默认) km:千米 mi:英里 ft:英尺
geodist key member1 member2 [unit]//查询指定圆心和半径内的位置成员(Redis 6.2+已废弃)
georadius key longitude latitude radius unit [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]//更强大的地理位置查询命令,支持半径和矩形区域查询
//FROMMEMBER:从指定成员位置开始 FROMLONLAT:从指定经纬度开始 BYRADIUS:按半径搜索 
//BYBOX:按矩形区域搜索 WITHCOORD:返回坐标 WITHDIST:返回距离 WITHHASH:返回Geohash值
//COUNT:限制返回数量 ASC/DESC:排序方式
geosearch key [FROMMEMBER member] [FROMLONLAT longitude latitude] [BYRADIUS radius unit] [BYBOX width height unit] [ASC|DESC] [COUNT count] [WITHCOORD] [WITHDIST] [WITHHASH]

使用场景示例

底层实现原理

Redis GEO功能基于:

  1. Geohash算法:将二维经纬度编码为一维字符串,附近的位置有相似的前缀
  2. Sorted Set:使用64位score存储Geohash的52位整数表示
  3. ZSET操作:所有GEO命令实际上都是对ZSET的操作

实际应用场景

  • 美团附近的饭店、酒店
  • 高德地图附近的店

五、Redis流(Stream)

Redis Stream是Redis 5.0引入的一种新的数据结构,专门为消息流式处理设计,它结合了日志数据结构的持久化和消息队列的消费组模式。

消息队列

实现消息队列的三个方式

List:

  • List实现消息队列
  • Pub/Sub 发布订阅
  • Stream流 (Redis版的MQ消息中间件+阻塞队列)

发布订阅:

Redis 发布订阅 (pub/sub) 有个缺点就是消息无法持久化,如果出现网络断开、Redis 崩溃等,消息就会被丢弃。而且也没有 Ack 机制来保证数据的可靠性,假设一个消费者都没有,那消息就直接被丢弃了。Stream流实现消息队列,它支持消息的持久化、支持自动生成全局唯一 ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠。

Stream结构:

Stream核心特性

  1. 持久化消息日志:所有消息都会被持久化存储
  2. 消息ID序列:基于时间戳和序列号的唯一ID
  3. 消费者组支持:多个消费者组可以独立消费同一条消息流
  4. 阻塞和非阻塞读取:支持等待新消息到达的模式
  5. 历史消息追溯:可以访问任意历史消息

基本命令

指令名称指令作用
XADD添加消息到队列末尾
XTRIM限制 Stream 的长度,如果已经超长会进行截取
XDEL删除消息
XLEN获取 Stream 中的消息长度
XRANGE获取消息列表(可以指定范围),忽略删除的消息
XREVRANGE和 XRANGE 相比区别在于反向获取,ID 从大到小
XREAD获取消息(阻塞 / 非阻塞),返回大于指定 ID 的消息
指令名称指令作用
XGROUP CREATE创建消费者组
XREADGROUP GROUP读取消费者组中的消息
XACKack 消息,消息被标记为 “已处理”
XGROUP SETID设置消费者组最后递送消息的 ID
XGROUP DELCONSUMER删除消费者组
XPENDING打印待处理消息的详细信息
XCLAIM转移消息的归属权(长期未被处理 / 无法处理的消息,转交给其他消费者组进行处理)
XINFO打印 Stream\Consumer\Group 的详细信息
XINFO GROUPS打印消费者组的详细信息
XINFO STREAM打印 Stream 的详细信息

XADD mystream * event "login" userid "123"

  • 命令解析

    • XADD:向一个 Stream 添加一个新的条目(entry)。
    • mystream:Stream 的名称,即数据将被添加到这个 Stream 中。
    • *:自动生成的 ID。Redis 会自动生成一个唯一的 ID 来标识这个条目。
    • event "login" 和 userid "123":键值对形式的数据,表示事件类型为 "login",用户 ID 为 "123"。
  • 返回值

    • "1755142944081-0":新添加条目的唯一 ID,由时间戳和序列号组成。

XREAD COUNT 1 STREAMS mystream 0

  • 命令解析

    • XREAD:从一个或多个 Stream 中读取消息。
    • COUNT 1:限制返回的消息数量为 1。
    • STREAMS mystream 0:指定要读取的 Stream 名称及起始 ID。这里 0 表示从 Stream 的最开始位置开始读取。
  • 返回值

    • 结果是一个嵌套数组,包含 Stream 名称、条目 ID 及其字段和值。

XGROUP CREATE mystream mygroup $

  • 命令解析

    • XGROUP CREATE:创建一个新的消费者组。
    • mystream:指定 Stream 名称。
    • mygroup:消费者组的名称。
    • $:指定消费者组开始消费的位置。$ 表示从当前最新条目之后开始消费。
  • 返回值

    • OK:表示命令执行成功。

XREADGROUP GROUP mygroup consumer1 STREAMS mystream >

  • 命令解析

    • XREADGROUP:从一个或多个 Stream 中读取消费者组未确认的消息。
    • GROUP mygroup consumer1:指定消费者组名称和消费者名称。
    • STREAMS mystream >:指定要读取的 Stream 名称及起始 ID。> 表示只读取新的消息。
  • 返回值

    • (nil):表示没有新的消息可以读取。

XACK mystream mygroup 1755142944081-0

  • 命令解析

    • XACK:确认消息已被处理。
    • mystream:Stream 的名称。
    • mygroup:消费者组的名称。
    • 1755142944081-0:要确认的消息 ID。
  • 返回值

    • (integer) 0:表示没有消息被确认(可能是因为该消息已经被确认过或者不存在)。

 XADD userchanges * userid 123 action "update" field "email" old "a@a.com" new "b@b.com"

  • 命令解析

    • XADD:向一个 Stream 添加一个新的条目。
    • userchanges:Stream 的名称。
    • *:自动生成的 ID。
    • userid 123action "update"field "email"old "a@a.com"new "b@b.com":键值对形式的数据,表示用户 ID 为 123 的邮箱更新记录。
  • 返回值

    • "1755143138810-0":新添加条目的唯一 ID。

XRANGE userchanges - +

  • 命令解析

    • XRANGE:按时间顺序返回 Stream 中的一个范围内的条目。
    • userchanges:Stream 的名称。
    • - 和 +:分别表示最早的 ID 和最新的 ID,即返回所有条目。
  • 返回值

    • 结果是一个嵌套数组,包含条目 ID 及其字段和值。

Stream应用场景

  1. 消息队列系统:替代传统的Redis列表实现的消息队列
  2. 事件溯源:记录所有状态变化事件
  3. 实时数据处理:处理传感器数据、日志等实时流
  4. 通知系统:实现用户通知的存储和分发
  5. 审计日志:记录所有操作的完整审计日志

六、Redis位域(bitfield)

Redis Bitfield(位域)是Redis 3.2引入的一种高级数据结构,允许对字符串中的任意位进行读写操作,并支持多种位宽的整数(有符号/无符号)。它将字符串视为一个由二进制位组成的数组,提供了灵活的位级操作能力。

Bitfield核心特性

  1. 多类型位操作:支持8/16/32/64位有符号/无符号整数
  2. 位宽自定义:可操作1~64位任意宽度的整数
  3. 原子操作:多个位操作可以打包成事务执行
  4. 溢出控制:提供三种溢出处理策略
  5. 位偏移访问:可以从字符串的任意位偏移位置读写数据

基本命令

核心命令如下

BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]

类型(type)表示法

格式:[u|i]<bits>,其中:

  • u:无符号整数
  • i:有符号整数(使用补码表示)
  • <bits>:位宽(1~64),如u8表示8位无符号整数,i16表示16位有符号整数
bitfield key get type offset   //读取位域值
bitfield key set type offset value  //读取位域值
bitfield key incrby type increment   //位域值自增/自减
bitfield key overflow sat incrby u8 0 100 //设置溢出策略为饱和模式
//三种溢出处理策略:WRAP:环绕(默认,如u8最大值255+1=0) SAT:饱和(达到最大值后不再增长) FAIL:失败(不执行操作,返回空值)bitfield mykey GET u8 0 SET u8 0 255 INCRBY u8 0 1 OVERFLOW FAIL INCRBY u8 0 1//多个操作可以在一个命令中执行,按顺序返回结果

溢出测试

WRAP: 使用回绕 (Wrap around) 方法处理有符号和无符号整数溢出

Set: 使用饱和计算(saturation arithmetic) 方法处理溢出, 下溢计算的结果为最小的整数值,而上溢计算的结果为最大的整数值

FAIL :命令将拒绝执行那些会导致上溢或者下溢情况出现的计算,并向用户返回空值表示计算未被执行

注意事项

实际应用场景

用户签到系统:用1位表示1天的签到状态,1个字节(8位)可表示8天,1个字符串可表示365天(46字节)

库存计数器:用16位无符号整数存储商品库存,一个字符串可存储多个商品库存

  1. 位宽限制:最大支持64位整数,超过会返回错误
  2. 偏移计算:偏移量是指"位"偏移,而非字节偏移
  3. 内存分配:设置高位偏移时会自动扩展字符串长度
  4. 溢出处理:不同场景需选择合适的溢出策略,默认WRAP可能导致意外结果
  5. 返回值:多个操作时按顺序返回结果数组,失败返回nil

感谢阅读!

http://www.dtcms.com/a/330950.html

相关文章:

  • PAT乙级_1073 多选题常见计分法_Python_AC解法_含疑难点
  • mysql查询中的filesort是指什么
  • Linux软件编程:进程和线程
  • 火山引擎数智平台发布 Data Agent“一客一策“与 AI 数据湖“算子广场“
  • 【Python】新手入门:什么是python字符编码?python标识符?什么是pyhon保留字?
  • 【数据集介绍】多种飞机检测的YOLO数据集介绍
  • 服务器数据恢复—误删服务器卷数据的数据恢复案例
  • 配置docker pull走http代理
  • 集成电路学习:什么是Video Processing视频处理
  • 网络原理-HTTP
  • 【论文阅读】基于多变量CNN模型的可穿戴外骨骼机器人人体运动活动识别
  • Notepad++插件开发实战:从零打造效率工具
  • 边缘光效果加流光效果
  • 从0开始跟小甲鱼C语言视频使用linux一步步学习C语言(持续更新)8.14
  • 测试开发的社区:测试之家
  • 从根源到生态:Apache Doris 与 StarRocks 的深度对比 —— 论开源基因与长期价值的优越性
  • lib.dom.d.ts
  • 速通C++类型转换(代码+注释)
  • 【自动化测试】Web自动化测试 Selenium
  • docker rm删除容器命令入门教程
  • [论文阅读] 人工智能 + 软件工程 | 从模糊到精准:模块化LLM agents(REQINONE)如何重塑SRS生成
  • Flink CDC 实战:实时监听 MySQL Binlog 并同步到 Kafka
  • 监控插件SkyWalking(二)集成方法
  • kafka 单机部署
  • 【Android】适配器与外部事件的交互
  • Mybatis学习笔记(三)
  • [激光原理与应用-267]:理论 - 几何光学 - 胶卷相机的组成和工作原理
  • PostgreSQL 免安装
  • tomcat 定时重启
  • 通过 GitHub520 项目自动获取最新 Hosts 配置,无需手动查询 IP。