一、小试牛刀:setbit
先不说位图,在查看redis文档的时候,遇到了一串非常有意思的命令:
> SETBIT bitmapsarestrings 2 1
> SETBIT bitmapsarestrings 3 1
> SETBIT bitmapsarestrings 5 1
> SETBIT bitmapsarestrings 10 1
> SETBIT bitmapsarestrings 11 1
> SETBIT bitmapsarestrings 14 1
> GET bitmapsarestrings
"42"
冥思苦想,不知为何结果会输出42,经过查阅资料终于找到了原因,其实redis是想告诉我们它的底层是通过ASCII码来存储字符串的,用户可以通过setbit命令直接操作该ASCII码的bit位来达到存储字符串的目的,且不考虑这样子绕来绕去的命令有什么实际意义,它确实可以这么做。
二、为什么是42?
显而易见,42由4和2两个字符构成,在ASCII码对照表中,4对应的ASCII值位52,2对应的ASCII的值位50,其实我们也可以通过一段java代码来得到这个ASCII值:
public static void main(String[] args) {
byte[] bytes = "42".getBytes();
for (byte bit : bytes){
System.out.println(bit);
}
}
输出结果:
52
50
那计算机如何来存储52和50呢?自然是二进制,52对应的二进制为00110100,50对应的二进制位00110010,它们两个连起来就是:
下面红色的数字代表bit位,在2、3、5、10、11、14bit位的地方值为1。
三、一个小练习
那么我们如何使用setbit命令实现在redis存储key为say,value为hi呢?经查阅,h的ASCII值为104,对应的二进制位01101000,i的ASCII值为105,对应的二进制为01101001,因此连接到一起就是:0110100001101001,即我们需要把1、2、4、9、10、12、15的bit为设置为1:
127.0.0.1:6379> setbit say 1 1
(integer) 0
127.0.0.1:6379> setbit say 2 1
(integer) 0
127.0.0.1:6379> setbit say 4 1
(integer) 0
127.0.0.1:6379> setbit say 9 1
(integer) 0
127.0.0.1:6379> setbit say 10 1
(integer) 0
127.0.0.1:6379> setbit say 12 1
(integer) 0
127.0.0.1:6379> setbit say 15 1
(integer) 0
127.0.0.1:6379> get say
"hi"
注意:没有设置的bit为默认为0
四、getbit、bitcount、bitpos
既然有setbit,那如果我想知道某个位的值是不是1,应该怎么办呢?答案:gitbit
127.0.0.1:6379> getbit say 1
(integer) 1
127.0.0.1:6379> getbit say 8
(integer) 0
我想知道say对应的value hi一共有多少bit位设置成了1:
127.0.0.1:6379> bitcount say
(integer) 7
我想知道say对应的value的第一个字符h有多少位被设置成了1(命令范式:bitcount key start end,start end为字节索引,从0开始):
127.0.0.1:6379> bitcount say 0 0
(integer) 3
我想知道say对应的value hi是从第几位开始是0的和从第几位开始是1的:
127.0.0.1:6379> bitpos say 0
(integer) 0
127.0.0.1:6379> bitpos say 1
(integer) 1
我想知道say对应的value hi的第一个字节是从第几位开始时0的和从第几位开始是1的(命令范式:bitpos key 0还是1 start end,start end为字节索引,从0开始):
127.0.0.1:6379> bitpos say 0 0 0
(integer) 0
127.0.0.1:6379> bitpos say 1 0 0
(integer) 1
todo:bitfield hyperloglog 布隆过滤器