Redis 7.x 系列【11】数据类型之位图(Bitmap)
有道无术,术尚可求,有术无道,止于术。
本系列Redis 版本 7.2.5
源码地址:https://gitee.com/pearl-organization/study-redis-demo
文章目录
- 1. 概述
- 2. 基本命令
- 2.1 SETBIT
- 2.2 GETBIT
- 2.3 BITCOUNT
- 2.4 BITPOS
- 2.5 BITFIELD
- 2.6 BITFIELD_RO
- 2.7 BITOP
- 3. 应用场景
- 3.1 用户登录状态
- 3.2 签到打卡
1. 概述
Redis Bitmap 实际不是一个独立的数据类型,而是基于 String 类型实现的。它主要用于存储二值状态(即集合元素的取值只有 0 和 1 两种)。由于每个位只能表示两种状态,在需要快速进行大量数据的排序、查找、去重等操作时具有显著优势。
Bitmap 实际上是利用 String 类型的最大容量(512 MB)存储一个连续的二进制序列。每个字节的 8 位可以分别代表 8 个独立的状态,因此可以用一个 Bitmap 来跟踪多达数百万甚至数十亿的状态。
2. 基本命令
所有命令:
| 命名 | 描述 |
|---|---|
| BITCOUNT | 统计给定范围内为1的位的数量 |
| BITFIELD | 对字符串类型的 key 进行基于位的操作 |
| BITFIELD_RO | 使用 BITFIELD命令进行只读操作 |
| BITOP | 执行针对多个 Bitmap 的并集、交集、差集等位操作 |
| BITPOS | 查找指定位值的第一个位置 |
| GETBIT | 获取指定偏移量处的位状态 |
| SETBIT | 设置指定偏移量处的位状态 |
2.1 SETBIT
SETBIT 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。时间复杂度为 O(1),因为直接在内存中操作字符串的位表示。返回值为存储在指定偏移量处的原始位值(0或1)。
基本语法:
SETBIT key offset value
参数说明:
key:操作的key。offset:指定偏移量,从0开始计数。注意,偏移量必须大于或等于0,且小于2^32value:设置的值,只能是0或1。
注意事项:
- 如果
key不存在,会自动为其创建一个新的字符串。 - 如果设置的偏移量超过了字符串的当前长度,会扩展字符串以确保可以在指定的偏移量处设置值。扩展部分会使用
0填充。 - 警告操作:当
key不存在,或者是比较小的字符串时,直接设置2^32-1位置时,会立即分配所有内存,这有可能会导致服务阻塞
示例:
# 想设置其偏移量为7的位为1
SETBIT mykey 7 1
2.2 GETBIT
GETBIT 命令是用于获取存储在 key 中的字符串值在指定偏移量上的位(bit)值的操作。返回值是一个整数,表示指定偏移量上的位的值。返回值只可能是 0 或 1 。
基本语法:
GETBIT key offset
示例:
# 获取偏移量为7的位的值
GETBIT mykey 7
2.3 BITCOUNT
BITCOUNT 命令用于统计指定 key 所储存的字符串值中,被设置为1的二进制位的数量。
基本语法:
BITCOUNT key [start] [end]
参数说明:
key:要统计的key,对应的值应该是一个字符串。start(可选):统计二进制位的开始位置,参数类型为整数,默认从0开始统计。end(可选):统计二进制位的结束位置,参数类型为整数,默认统计到整个字符串的末尾。
注意事项:
- 如果指定的
key不存在,会将其视为空字符串,因此返回值为0。 - 时间复杂度为
O(N),其中N是字符串的长度(以字节为单位)。在处理大数据量时,请注意性能问题。
无参示例:
redis> SET mykey "foobar"
OK
redis> BITCOUNT mykey
(integer) 26
带参示例:
redis> SET mykey "\xff\xf0\x00"
OK
redis> BITCOUNT mykey 0 7
(integer) 12
redis> BITCOUNT mykey 0 0 4
(integer) 4
redis> BITCOUNT mykey 1 1 4
(integer) 6
2.4 BITPOS
BITPOS 命令用于查找字符串中第一个设置为指定值(0或1)的 bit 位,并返回该位置。如果没有找到匹配的 bit,则返回-1。
基本语法:
BITPOS key bit [start] [end]
参数说明:
key:要操作的key,其值应为一个字符串。bit:要查找的bit值,只能是0或1。start(可选):开始查找的起始位置,默认为0。end(可选):结束查找的位置,默认为 -1,表示字符串的最后一个bit。
注意事项:
- 如果指定的
key不存在,会将其视为一个空字符串,并查找空字符串中的bit。 - 如果在指定的范围内没有找到匹配的
bit,则返回 -1。 - 查找范围是基于
bit的,而不是基于字节的。例如,start=0和end=7表示查找前8个bit,而不是第一个字节。 - 命令的时间复杂度为
O(N),其中N是字符串的长度(以bit为单位)。在处理大数据量时,请注意性能问题。
假设当前对应的字符串值为"\xff\x00\x00",这是一个二进制字符串的十六进制表示,"\xff"代表8个连续的1,"\x00"代表8个连续的0。
查找第一个为1的bit:
BITPOS mykey 1
(integer) 0
查找第一个为0的bit:
BITPOS mykey 0 8
(integer) -1
BITPOS mykey 0 9
(integer) 9
2.5 BITFIELD
BITFIELD 允许将 Redis 字符串视为一个位数组,并允许用户对其中的位进行操作,如获取、设置和递增等。对于每个子命令,BITFIELD都会返回一个响应数组,其中每个数组元素都与参数列表中的相应操作相匹配。
基本语法:
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW wrap|sat|fail]
参数说明:
key:要操作的Redis键。GET:用于从字符串中获取指定位置的位域值。SET:用于设置字符串中指定位置的位域值。INCRBY:用于将字符串中指定位置的位域值进行增加。OVERFLOW:用于指定溢出处理方式,可选值有wrap(回绕)、sat(饱和)和fail(失败)。
子命令GET参数说明:
type:指定读取数据的类型,可以是u(无符号整数)或i(有符号整数)。offset:位字段的起始偏移位置,从0开始计数。
子命令SET参数说明:
type:类型标识,可以是u(无符号整数)或i(有符号整数)。offset:位字段的起始偏移位置。value:要设置的位域值。
子命令INCRBY参数说明:
type:指定要递增的数据类型。offset:位字段的起始偏移位置。increment:递增的值。
OVERFLOW用于指定溢出处理方式,参数说明:
wrap:使用回绕方法处理溢出,位域超过最大值后再次增加数值则回到最小值。sat:饱和计算,超过最大值再增加则数值仍不变。fail:超过最大值再增加,则命令直接报错,拒绝指定。
注意事项:
- 可以在同一个命令调用中使用多个子命令,并按照给定的顺序执行它们。
- 命令的时间复杂度为
O(1),用于指定的每个子命令。 - 使用
BITFIELD命令时,请确保对二进制位操作有深入的理解,以避免出现意外的结果。
示例,假设有一个 key 其对应的字符串值为"abcd"(其ASCII码值分别为97, 98, 99, 100)。获取第一个字符的 ASCII 码值(无符号8位整数):
BITFIELD mykey GET u8 0
修改第二个字符的ASCII码值为大写'B'(ASCII码值为66):
BITFIELD mykey SET u8 8 66
将第三个字符的ASCII码值增加1('c'变为'd'):
BITFIELD mykey INCRBY u8 16 1
2.6 BITFIELD_RO
BITFIELD_RO 命令作为 BITFIELD 命令的只读变体。这个命令允许用户从二进制位图中安全地读取数据,而不需要担心在只读副本上执行写操作。
基本语法:
BITFIELD_RO key [GET encoding offset [GET encoding offset ...]]
参数说明:
key: 要操作的二进制位图的键名。GET: 表示读取操作。encoding: 指定要读取的数据的编码类型(如u8、i8、u16、i16、u32、i32、u64、i64、f32、f64)。offset: 指示在二进制位图中的起始位置(以位为单位)。
注意事项:
- 由于原始的
BITFIELD命令包含SET和INCRBY等写操作选项,因此它在Redis命令表中被标记为写命令。这意味着在Redis集群的只读副本上,即使连接处于只读模式,该命令也会被重定向到主实例。 - 为了在只读副本上允许
BITFIELD行为而不破坏命令标志的兼容性,Redis 6.2引入了BITFIELD_RO变体。 - 通过使用
BITFIELD_RO,可以在只读副本上安全地执行读取操作,而无需担心数据的不一致性或其他与写操作相关的问题
示例,假设有一个名为 hello 的二进制位图,并且我们想要从第 16 位开始读取一个 8 位有符号整数(i8):
BITFIELD_RO hello GET i8 16
2.7 BITOP
BITOP 命令用于对多个键(包含字符串值)执行位操作,并将结果存储在目标键中。它支持四种位操作:AND(与)、OR(或)、XOR(异或)和 NOT(非)。NOT 操作是特殊的,因为它只接受一个输入键,因为位反转只作为一元运算符才有意义。
基本语法:
BITOP <AND | OR | XOR | NOT> destkey key [key ...]
参数说明:
<AND | OR | XOR | NOT>:要执行的位操作类型。destkey:存储操作结果的目标键。key [key ...]:要参与位操作的键列表。对于NOT操作,只需要一个键。
示例:
redis> SET key1 "foobar"
"OK"
redis> SET key2 "abcdef"
"OK"
redis> BITOP AND dest key1 key2
(integer) 6
redis> GET dest
"`bc`ab"
3. 应用场景
Bitmap 以极小的空间存储大量数据,2^32次方(约40亿)数据只需要约 500MB 内存,并提供了快速的查询和统计功能。Redis Bitmap的应用场景广泛,尤其在处理大量二进制数据或需要快速进行二值状态统计的场合下表现出色。
二值状态统计是指在集合中,元素的取值只有 0 和 1 两种状态,在实际开发中,经常会遇到签到/未签到、登录/未登录等情况。
常用场景:
- 签到打卡:每个用户每天的签到情况可以用一个
bit位表示,签到为1未签到为0。 - 限制
IP地址访问频率:每个IP地址对应Bitmap的一个bit位,访问时设置该位为1。判断某个IP地址是否已经访问过,并据此限制其访问频率。 - 用户登录状态:可以使用
bit位来记录用户的登录状态,1表示已登录,0表示未登录。
3.1 用户登录状态
例如,当天 ID 为 0-3的用户进行了登录:
localhost:0>SETBIT login_status:20240624 0 1
"0"
localhost:0>SETBIT login_status:20240624 1 1
"0"
localhost:0>SETBIT login_status:20240624 2 1
"0"
localhost:0>SETBIT login_status:20240624 3 1
"0"
查看某个用户当天是否登录:
localhost:0>GETBIT login_status:20240624 3
"1"
localhost:0>GETBIT login_status:20240624 4
"0"
localhost:0>
查看当天登录用户总数:
localhost:0>BITCOUNT login_status:20240624
"4"
3.2 签到打卡

设置 ID 为 123 的用户在 202405 第一天和第六天进行了签到:
localhost:0>SETBIT sign:123:202405 0 1
"0"
localhost:0>SETBIT sign:123:202405 5 1
"0"
查看用户当月某日是否进行了签到:
localhost:0>GETBIT sign:123:202405 10
"0"
localhost:0>GETBIT sign:123:202405 0
"1"
统计当月的签到次数:
localhost:0>BITCOUNT sign:123:202405
"2"
查看当月第一次签到的日期:
localhost:0>BITPOS sign:123:202405 1
"0"
相关文章:
Redis 7.x 系列【11】数据类型之位图(Bitmap)
有道无术,术尚可求,有术无道,止于术。 本系列Redis 版本 7.2.5 源码地址:https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 基本命令2.1 SETBIT2.2 GETBIT2.3 BITCOUNT2.4 BITPOS2.5 BITFIELD2.6 BITF…...
如何评定旅游卡的品质与服务?
评定旅游卡的品质与服务,可以从以下几个关键方面进行综合考量: 公司实力与资质:选择有实力、资质齐全的公司发行的旅游卡。查看公司背景,确认其是否长期稳定运营,是否具有旅游行业的专业资质,如旅行社许可证…...
适合学生暑假适用的护眼大路灯有哪些?五款好用护眼灯分享!
在护眼领域,护眼大路灯已经成为越来越多人的选择。这种具备实力的工具可以有效地缓解用眼疲劳、改善光线环境,是学生党和办公族的必备神器。然而,市面上的护眼大路灯品牌众多,如何选择一款性价比高、品质优良的产品呢?…...
linux服务器 部署jenkins
在 Linux 服务器上部署 Jenkins 通常包括以下几个步骤: 更新系统软件包: sudo apt update sudo apt upgrade 安装 Java: Jenkins 需要 Java 运行时环境。推荐使用 OpenJDK 11。 sudo apt install openjdk-11-jdk 添加 Jenkins 软件源并导入…...
电商控价:系统监测的必要性与优势
在品牌的发展进程中,会遭遇各种各样的渠道问题,控价乃是其中颇为关键的一环。品牌进行控价的目的无疑是为了妥善治理低价链接,低价链接的发现途径可以是人工,也可以是系统。力维网络在为上百个品牌提供服务的过程中察觉到…...
港股下半年能恢复上涨趋势吗?
今日港股两大指数涨跌不一,早盘盘初恒指冲高,涨幅一度扩大至1%。截至收盘,香港恒生指数涨0.57%。板块方面,电力、航空、石油、内险股、燃料电池、环保等板块涨幅居前;互动媒体与服务、生物科技、汽车零部件、新经济概念…...
软件测试项目实战:银行贷款业务测试介绍-2
1、利息计算 正常利息贷款本金*借款天数*贷款年利率/360 罚息逾期本金*逾期天数*逾期年利率/360 复利逾期利息*逾期天数*逾期年利率/360 2、贷款五级分类 正常贷款:正常及逾期60天以内 关注贷款:逾期60天及以上,不足90天 次级贷款࿱…...
如何将Hive表的分区字段插入PG表对应的时间戳字段?
文章目录 1、背景描述2、场景分析 1、背景描述 数据仓库的建设通常是为业务和决策服务的。在数仓开发的应用层阶段,BI可以直接从主题层/业务层取数,而前端需要根据具体的作图需求通过后端查询数据库 作图的指标需要根据主题层/业务层做查询计算…...
Spring Boot与MyBatis的集成应用
Spring Boot与MyBatis的集成应用 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来聊聊Spring Boot与MyBatis的集成应用。MyBatis是一款优秀的持久层框…...
在昇腾服务器上使用llama-factory对baichuan2-13b模型进行lora微调
什么是lora微调 LoRA 提出在预训练模型的参数矩阵上添加低秩分解矩阵来近似每层的参数更新,从而减少适配下游任务所需要训练的参数。 环境准备 这次使用到的微调框架是llama-factory。这个框架集成了对多种模型进行各种训练的代码,少量修改就可使用。 …...
Kafka 管理TCP连接
生产者管理TCP连接 Kafka生产者程序概览 Kafka的Java生产者API主要的对象就是KafkaProducer。通常我们开发一个生产者的步骤有4步: 第1步:构造生产者对象所需的参数对象。 第2步:利用第1步的参数对象,创建KafkaProducer对象实例…...
electron教程(一)创建项目
一、方式① 根据官网描述将electron/electron-quick-start项目克隆下来并启动 electron/electron-quick-start地址: GitHub - electron/electron-quick-start: Clone to try a simple Electron app git clone https://github.com/electron/electron-quick-start…...
如何在Oracle、MySQL、PostgreSQL上终止会话或取消SQL查询
How to Kill session or Cancel SQL query on Oracle , MySQL, PostgreSQL 数据库维护过程中难免会遇到一些不正常的SQL或会话进程正在占用系统大量资源,临时需要终止查询或kill会话,在Oracle, MySQL, Postgresql数据库中不同的操作。 Oracle KILL会话…...
3、FTL基本工作过程
上文描述了FTL的四大功能,这里简述一下每个功能的含义。 地址转换简述 FTL要维护一个地址转换表,这个转换表是主机读/写硬盘的逻辑地址到硬盘实际物理地址的转换关系。 假如SSD的容量是128G,SSD逻辑块的大小是4KB,那SSD的逻辑块…...
微信小程序的跳转页面
在微信小程序中,要实现从当前页面返回到指定页面的功能,通常不直接使用“返回上一页”的逻辑,而是利用小程序的页面栈管理和navigateBack或者重新定向到目标页面的API。下面我将介绍两种主要的方法: 方法一:使用 navi…...
深入理解 Java 中的线程间通信:`wait()`, `notify()`, `notifyAll()`
引言 在多线程编程中,线程间通信是一个重要且复杂的主题。Java 提供了一套基本的机制来实现线程间通信,即使用 wait(), notify(), 和 notifyAll() 方法。这些方法由 Object 类提供,用于协调多个线程对共享资源的访问。本文将详细介绍这些方法…...
23种设计模式【创建型模式】详细介绍之【单例模式】
23种设计模式【创建型模式】详细介绍之【单例模式】 设计模式的分类和应用场景总结单例模式1. 概述2. 实现方式2.1 饿汉式单例模式2.2 懒汉式单例模式(非线程安全)2.3 懒汉式单例模式(线程安全) 3. 单例模式的优缺点3.1 优点3.2 缺…...
某汽车配件制造公司任职资格体系项目成功案例纪实
——基于岗位特点和核心能力要求,分层分级能力测评,实现个性化人才培养 【客户行业】生产制造;汽车配件制造 【问题类型】任职资格体系建立;人才管理系统 【客户背景】 某汽车配件制造公司是一家专注于汽车配件研发、生产和销…...
【Linux】生物信息学常用基本命令
wget网址用于直接从网上下载某个文件到服务器,当然也可以直接从网上先把东西下到本地然后用filezilla这个软件来传输到服务器上。 当遇到不会的命令时候,可以使用man “不会的命令”来查看这个命令的详细信息。比如我想要看看ls这个命令的详细用法&…...
React Native V0.74 — 稳定版已发布
嗨,React Native开发者们, React Native 世界中令人兴奋的消息是,V0.74刚刚在几天前发布,有超过 1600 次提交。亮点如下: Yoga 3.0New Architecture: Bridgeless by DefaultNew Architecture: Batched onLayout UpdatesYarn 3 for New Projects让我们深入了解每一个新亮点…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
