redis–09–操作–Bitmaps
1、简介
- Bitmaps可以实现对位的操作(1位=8字节)
- Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value), 但是它可以对字符串value的位进行操作。可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。
2、Bitmaps与set对比
假设网站有1亿用户, 每天独立访问的用户有5千万, 如果每天用集合类型和Bitmaps分别存储活跃用户可以得到表
set和Bitmaps存储一天活跃用户对比
数据类型 | 每个用户id占用空间 | 需要存储的用户量 | 全部内存量 |
set | 64位 | 50000000 | 64位*50000000 = 400MB |
Bitmaps | 1位 | 100000000 | 1位*100000000 = 12.5MB |
很明显, 这种情况下使用Bitmaps能节省很多的内存空间, 尤其是随着时间推移节省的内存还是非常可观的。
set和Bitmaps存储独立用户空间对比
数据类型 | 一天 | 一月 | 一年 |
set | 400MB | 12GB | 144GB |
Bitmaps | 12.5MB | 375MB | 4.5GB |
但Bitmaps并不是万金油, 假如该网站每天的独立访问用户很少, 例如只有10万(大量的僵尸用户), 那么两者的对比如下表所示, 很显然, 这时候使用Bitmaps就不太合适了, 因为基本上大部分位都是0。
set和Bitmaps存储一天活跃用户对比(独立用户比较少)
数据类型 | 每个用户id占用空间 | 需要存储的用户量 | 全部内存量 |
set | 64位 | 100000 | 64位*100000 = 800KB |
Bitmaps | 1位 | 100000000 | 1位*100000000 = 12.5MB |
3、操作
3.1、setbit key off setvalue
1.设置Bitmaps中某个偏移量的值(0或1)
2.offset:偏移量从0开始
3.1.1、案例
每个独立用户是否访问过网站存放在Bitmaps中,将访问的用户记做1,没有访问的用户记做0,用偏移量作为用户的id。
设置键的第offset个位的值(从0算起),假设现在有20个用户,userid=1,6,11,15,19的用户对网站进行了访问,那么当前Bitmaps初始化结果如图
127.0.0.1:6379> setbit users:20220202 1 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 6 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 11 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 15 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 19 1
(integer) 0
127.0.0.1:6379>
users:20220202代表2022-02-02这天的独立访问用户的Bitmaps
注
很多应用的用户id以一个指定数字(例如10000000)开头,直接将用户id和Bitmaps的偏移量对应会造成一定的浪费,因为在第1次初始化Bitmaps时,假如偏移量非常大,那么整个初始化过程执行会比较慢,可能会造成Redis的阻塞。
通常的做法是每次做setbit操作时将用户id减去这个指定数字。
3.2、getbit key offset
获取键的第offset位的值(从0开始算)
3.2.1、案例
获取id=15,id=8的用户是否在2022-02-02这天访问过,返回0说明没有访问过:
127.0.0.1:6379> getbit users:20220202 15
(integer) 1
127.0.0.1:6379> getbit users:20220202 8
(integer) 0
127.0.0.1:6379>
3.3、bitcount key [start end]
- 统计字符串从start字节到end字节比特值为1的数量
- start、end是指bit组的字节的下标数
3.3.1、案例
计算2022-02-02这天的独立访问用户数量
计算用户id在第1个字节到第3个字节之间的独立访问用户数
start和end代表起始和结束字节数,下面操作计算用户id在第1个字节到第3个字节之间的独立访问用户数
127.0.0.1:6379> bitcount users:20220202 1 3
(integer) 3
127.0.0.1:6379>
1,6,11,15,19 对应的字节数组如下
01000010 00010001 00010000
对应字节数组【0,1,2】
第1个字节到第3个字节就是:00010001 00010000
这里面有3个1,所以返回3,对应的用户id也就是11,15,19。
3.3.2、举例
K1 【01000001 01000000 00000000 00100001】,对应【0,1,2,3】
bitcount K1 1 2
统计下标1、2字节组中bit=1的个数,即
01000000 00000000
结果:1
bitcount K1 1 3
统计下标1、3字节组中bit=1的个数,即
01000000 00000000 00100001
结果:3
bitcount K1 0 -2
统计下标0到下标倒数第2,字节组中bit=1的个数,即
01000001 01000000 00000000
结果:3
3.4、bitop and(or/not/xor) destkey [key…]
bitop是一个复合操作,它可以做多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)操作,并将结果保存在destkey中。
3.4.1、
2022-02-01日访问网站的userid=1,2,5,9。
127.0.0.1:6379> setbit users:20220201 1 1
(integer) 0
127.0.0.1:6379> setbit users:20220201 2 1
(integer) 0
127.0.0.1:6379> setbit users:20220201 5 1
(integer) 0
127.0.0.1:6379> setbit users:20220201 9 1
(integer) 0
127.0.0.1:6379>
2022-02-02日访问网站的userid=0,1,4,9。
(integer) 0
127.0.0.1:6379> setbit users:20220202 0 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 1 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 4 1
(integer) 0
127.0.0.1:6379> setbit users:20220202 9 1
(integer) 0
127.0.0.1:6379>
计算出两天都访问过网站的用户数量
127.0.0.1:6379> bitop and desc users:20220201 users:20220202
(integer) 2
127.0.0.1:6379>
原理
users:20220201--> 01100100 01000000
users:20220202--> 11010000 01000000
and
desc------------> 01000000 01000000
计算出任意一天都访问过网站的用户数量(例如月活跃就是类似这种),可以使用or求并集
127.0.0.1:6379> bitop or desc2 users:20220201 users:20220202
(integer) 2
127.0.0.1:6379>