|
|
# 一、介绍
|
|
|
举个例子:用户一年的签到记录,签了是1,没签是0,要记录365天。如果使用kv存储那么需要365条。当用户数量过亿的时候,需要的存储空间就太大了。
|
|
|
为了解决这个问题redis提供了bitmap数据结构,这样每天的签到记录只占用1位,365天就是365位一共46个字节。位图的最小单位是比特(bit),每个bit的取值只能是0或1
|
|
|
![[Snipaste_2023-02-23_10-00-41 21.png]]
|
|
|
位图的内容就是普通字符串,byte数组,1byte=8bit。redis的位数组是自动扩展,如果设置了某个偏移位置超出了现有的范围就会自动补零
|
|
|
# 二、基本用法
|
|
|
|
|
|
**零存**: 使用setbit对位值进行逐个设置
|
|
|
**整存**:使用字符串一次性填充所有位数组
|
|
|
**零取**:使用getbit获取位数组的值
|
|
|
|
|
|
## 2.1 零存整取
|
|
|
使用位操作符将字符串设置为hello,先得到hello的ASCII码
|
|
|
![[Snipaste_2023-02-23_17-24-34.png]]
|
|
|
转换为8为ASCII码为
|
|
|
h:01101000
|
|
|
e:01100101
|
|
|
l:01101100
|
|
|
l:01101100
|
|
|
o:01101111
|
|
|
以h字符为例,只需要设置为1的位置,h字符有1/2/4位需要设置
|
|
|
![[Snipaste_2023-02-23_17-24-34 1.png]]
|
|
|
命令如下
|
|
|
![[Snipaste_2023-02-23_17-24-34 2.png]]
|
|
|
![[Snipaste_2023-02-23_17-24-34 3.png]]
|
|
|
## 2.2零存零取
|
|
|
![[Snipaste_2023-02-23_17-24-34 4.png]]
|
|
|
## 2.3整存零取
|
|
|
![[Snipaste_2023-02-23_17-24-34 5.png]]
|
|
|
## 2.4 统计和查找
|
|
|
位图统计指令bitcount:用来统计指定位置范围内1的个数
|
|
|
|
|
|
位图查找指令bitpos:用来查找指定范围内出现的第一个0或1
|
|
|
|
|
|
例:可以通过bitcount统计用户一共签到了多少天,通过bitpos指令查找用户从哪一天开始第一次签到。如果指定了范围参数[start,end],就可以统计在某个时间范围内用户签到了多少天,用户自某天以后的哪天开始签到。**注意,start和end参数是字节索引,也就是指定的位范围必须是8的倍数,而不能任意指定。**
|
|
|
因为这个设计导致无法直接计算某个月内用户签到了多少天,而必须将这个月所覆盖的字节内容全部取出来在内存中统计
|
|
|
|
|
|
### bitcount
|
|
|
例: bitcount w 0 0 统计第一个字符中1的位数
|
|
|
![[Snipaste_2023-02-23_17-24-34 6.png]]
|
|
|
### bitpos
|
|
|
例:bitpos w 0 第一个0位
|
|
|
![[Snipaste_2023-02-23_17-24-34 7.png]]
|
|
|
bitpos w 1 0 1 从第一个字符算起,第一个1位
|
|
|
![[Snipaste_2023-02-23_17-24-34 8.png]]
|
|
|
### bitfield
|
|
|
例:bitfield w get u4 0 从第一位开始取4个位,结果为6,对应4位二进制为0110
|
|
|
![[Snipaste_2023-02-23_17-24-34 9.png]]
|
|
|
例:bitfield w get u3 2 从第三位开始取3个位,结果为5,对应3位编码为101,前面补零为0101=5
|
|
|
![[Snipaste_2023-02-23_17-24-34 10.png]]
|
|
|
|
|
|
|
|
|
# 三、使用场景
|
|
|
+ 用户签到统计 |