redis中位图结构的使用

redis中位图结构的使用

如果有这样一个需求,要求使用redis记录用户的每日签到情况。如果使用普通的key/value。一个用户一年就要365个数据,如果有1亿用户,那这个数据量太大了。

有没有更合适的数据结构呢?

有的,Redis已经考虑到了这种情况。Redis提供了位图数据结构。不属于常用的5中数据结构。每天的签到只占一位。365天只需46个字节,只相当于一个稍微长点的字符串。大大节省了存储空间。

redis中位图结构的使用

位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 byte 数组。我们可以使用普通的 get/set 直接获取和设置整个位图的内容,也可以使用位图操作 getbit/setbit 等将 byte 数组看成「位数组」来处理。

在面试中有 Redis 位图使用经验的同学很少,如果你对 Redis 的位图有所了解,它将会是你的面试加分项。

基本用法:

Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自动将位数组进行零扩充。

要用位图来存储一个值,首先要知道一个字母的ASCII码的二进制值

这里我用js

console.log(‘i’.charCodeAt()); //105 得到ascii码的值

console.log('i'.charCodeAt().toString(2)); //1101001 转成二进制表示

console.log('h'.charCodeAt().toString(2)); // 1101000

比如我们要设置一个hi字符串。现在已经得到

h:1101000

i:1101001

redis中位图结构的使用

这里有个问题要注意:位数组的顺序和字符的位顺序是相反的。

比如h,我们数数组是地位在右,高位在做。应该是第3、5、6位值为1

但是数位顺序要反过来,地位在左,即第1、2、4位是1

i 继续往上数 应该是第9、10、12、15位是1

redis中位图结构的使用

这样通过对数组的零存整取,获得了字符串

同理,也有getbit用来取某一位的值

统计命令:

更好用的是,redis提供了位图的统计和查找命令。比如要统计用户一共签到了多少天。

命令是bitcount

redis中位图结构的使用

bitcount命令可以加start 和 end参数指定起始位置。但是,这里很遗憾。start和end只能是字节的位置,必须是 8 的倍数,即在这里0表示h,1表示i。

并不能随意指定位的起始和结束位置。这真的很不方便,不明白Antirez为什么这么设计。这样我就没办法直接取出一个月的签到情况。而必须计算好这个月覆盖的位范围。取出一个大概,再用getbit查看某几个不在该月的位的值。或者直接用getbit循环,自己计算,不使用bitcount。但是这个效率又会慢一点。

也可以通过 bitpos 指令查找用户从哪一天开始第一次签到。

redis中位图结构的使用

redis中位图结构的使用


分享到:


相關文章: