bitmap实现签到功能🚩
用BitMap实现亿级数据统计:
-
常见场景:二值状态统计
- 给一个 userId ,判断用户登陆状态;
- 显示用户某个月的签到次数和首次签到时间;
- 两亿用户最近 7 天的签到情况,统计 7 天内连续签到的用户总数
-
Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保存位数组,Redis 把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 表示一个元素的二值状态(不是 0 就是 1)。
-
判断用户登陆状态:
SETBIT <key> <offset> <value>
GETBIT <key> <offset>
判断 ID = 10086 的用户的登陆情况:
-
表示用户已登录:
SETBIT login_status 10086 1
-
检查该用户是否登陆:
GETBIT login_status 10086
-
登出:
SETBIT login_status 10086 0
-
-
用户每个月的签到情况:
用户在 2021 年 5 月 16 号打卡:
- 用户在 2021 年 5 月 16 号打卡:
SETBIT uid:sign:89757:202105 15 1
- 判断编号 89757 用户在 2021 年 5 月 16 号是否打卡:
GETBIT uid:sign:89757:202105 15
- 统计该用户在 5 月份的打卡次数:
BITCOUNT uid:sign:89757:202105
- 用户在 2021 年 5 月 16 号打卡:
-
连续签到用户总数:
在记录了一个亿的用户连续 7 天的打卡数据,如何统计出这连续 7 天连续打卡用户总数呢?
把每天的日期作为Bitmap的 key,userId 作为 offset,若是打卡则将 offset 位置的 bit 设置成 1。
一共有 7 个这样的 Bitmap,如果我们能对这 7 个 Bitmap 的对应的 bit 位做 『与』运算。
同样的 UserID offset 都是一样的,当一个 userID 在 7 个 Bitmap 对应对应的 offset 位置的 bit = 1 就说明该用户 7 天连续打卡。
结果保存到一个新 Bitmap 中,我们再通过
BITCOUNT
统计 bit = 1 的个数便得到了连续打卡 7 天的用户总数了。 -
统计单个用户的连续签到天数:
-
查到bitmap里的所有记录:
BITFIELD sign:5:202203 GET u14 0
(无符号14个数据,从0开始) -
循环遍历这个数和1与运算,为0则未签到,结束,为1则签到了,计数器加一。
-
最后再右移一位。
int count = 0; while(true){ if(num & 1 == 0){ break; }else{ count++; } num >>>= 1; }
-