# 一、介绍 举个例子:用户一年的签到记录,签了是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]] # 三、使用场景 + 用户签到统计