持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
bitmap,用0和1来表示状态的bit数组
在基础的数据类型中
1个bit,是一个0或1,就是二进制
1个byte,是8个bit
8bit = 1byte
bitmap就是使用bit数组来表示0或1,类似于下面这种
| 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
|---|
比如我们做一个签到功能,1个用户1年365天的签到记录,也只需用到365bit
365/8=45.6byte,可以极大的节省空间
基础命令
# 设置值 value只接受0或1
setbit key offset value
# 获取值
getbit key offset
# start和end非必填,不写的话,查询的是key里面含有value=1的总共有多少个?
bitcount key [start] [end]
统计一周7天用户签到次数
第一天,用户签到了
setbit user:1001 0 1
第二天,用户没签到
setbit user:1001 1 0
第三天,用户签到了
setbit user:1001 2 1
第四天,用户签到了
setbit user:1001 3 1
第五天,用户签到了
setbit user:1001 4 1
第六天,用户没签到了
setbit user:1001 5 0
第七天,用户没签到了
setbit user:1001 6 0
可以看到, offset 偏移量是从0开始的,因为是数组嘛,下标从0开始
这个时候,如果我想看该用户第三天和第七天有没有签到
> getbit user:1001 2
1
> getbit user:1001 6
0
1代表签到了,0代表没签到
查询这7天,总共有几天签到了
> bitcount user:1001 0 6
4
这里 offset 偏移量,也可以写成日期,比如
# 26号没签到
setbit user:1001 20220626 0
# 27号签到了
setbit user:1001 20220627 1
bitmap 底层编码使用的也是 string 类型
> type user:1001
string
但其实质是二进制的ascii编码
比如我们执行一下下面几步操作
> setbit user:1005 1 1
0
> setbit user:1005 2 1
0
> setbit user:1005 7 1
0
> get user:1005
a
这个时候,bitmap的数组应该如下
01100001
二进制 01100001 对应的 10 进制是 97,对应的 16进制是61,对应的ascii编码是小写的a
在 redis 中的显示
使用bitmap统计连续签到用户数
这里需要对用户做一下映射:
user:1001 -> 1
user:1002 -> 2
user:1003 -> 3
25号都签到了
> setbit 20220625 1 1
0
> setbit 20220625 2 1
0
> setbit 20220625 3 1
0
26号,3号用户没签到
> setbit 20220626 1 1
0
> setbit 20220626 2 1
0
> setbit 20220626 3 0
0
27号,还是3号用户没签到
> setbit 20220627 1 1
0
> setbit 20220627 2 1
0
> setbit 20220627 3 0
0
统计 25、26、27三天都签到的用户有多少
先对 20220625、20220626、20220627 三个bitmap做与运算
然后再对计算结果(threeday)做bitcount统计
> bitop and threeday 20220625 20220626 20220627
1
> bitcount threeday
2
最终统计出来的数据就是这3天都签到的用户数量
bitop 与运算逻辑
| 用户1 | 用户2 | 用户3 | |
|---|---|---|---|
| 20220625 | 1 | 1 | 1 |
| 20220626 | 1 | 1 | 0 |
| 20220627 | 1 | 1 | 0 |
| 连续签到合计 | 1 | 1 | 0 |
与运算规则: 有0就是0,全是1才是1