使用场景
在我们平时开发过程中,会有一些 bool 型数据需要存取,比如用户一年的签到记录,签了是 1,没签是 0,要记录 365 天。如果使用普通的 key/value,每个用户要记录 365个,当用户上亿的时候,需要的存储空间是惊人的。为了解决这个问题,Redis 提供了位图数据结构,这样每天的签到记录只占据一个位,365 天就是 365 个位,46 个字节 (一个字节有8位) 就可以完全容纳下,这就大大节约了存储空间。
位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 byte 数组。我们可以使用普通的 get/set 直接获取和设置整个位图的内容,也可以使用位图操作 getbit/setbit
等将 byte 数组看成「位数组」来处理。
基本使用
Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自动将位数组进行零扩充。
零存整取
我们存入he
> setbit s 1 1
0
> setbit s 2 1
0
> setbit s 4 1
0
> setbit s 9 1
0
> setbit s 10 1
0
> setbit s 13 1
0
> setbit s 15 1
0
> get s
"he"
零存零取
> setbit w 1 1
0
> getbit w 1
1
> getbit w 2
0
整存零取
> set k h
OK
> getbit k 1
1
> getbit k 2
1
> getbit k 4
1
> getbit k 3
0
如果对应位的字节是不可打印字符,将会显示该字符的16进制形式。
> setbit x 0 1
0
> setbit x 1 1
0
> get x
"\xC0"
统计和查找
Redis提供了位图统计指令:bitcount
和位图查找指令:bitpos
。
- bitcount:统计指定位置范围内1的个数。
- bitpos:查找指定范围内出现的第一个0或1。
bitpos key 0/1 start end # start,end是字节索引,指定的位范围必须是8的倍数
> set w hello
OK
> bitcount w
21
> bitcount w 0 0 # 第一个字符中1的位数
3
> bitcount w 0 1 # 前两个字符中1的位数
7
> bitpos w 0 # 第一个0位
(integer) 0
> bitpos w 1 # 第一个1位
(integer) 1
> bitpos w 1 1 1 # 从第二个字符算起,第一个1位
(integer) 9
> bitpos w 1 2 2 # 从第三个字符算起,第一个1位
(integer) 17
魔术指令bitfield
redis 3.2版本
redis版本不足,待尝试。