需求: 上亿个用户,统计一周内连续活跃用户
100000000/8/1024/1024 = 11.9M 一个bitmap占用 不到12M
好在一周只有7天, 我们用7个key的bitmap来存储状态即可,
加上最后的一个结果res的bitmap: 12*8=100M 内存即可!
遵循下面步骤即可:
- 用户编号是前提, 每个用户的编号从1到n(n=就是说的那个上亿的最大值);
- 声明7个bitmap, 从周一到周日: mon tue wed thur fri sat sun;
- 每个用户编号所在的offset在周1如果登录了, 就是1, 没登录就是0;
- 7个bitmap都设值记录;
- 用bitop 对7个bitmap进行位AND操作, 7天都登录的当天的位上才是1
- 最后的结果进行
bitcount
操作, 就是上亿用户一周内连续
活动的人数! - 如果想知道连续活跃的用户都有哪些人, 遍历
getbit 每一天的key(mon/tue/...) id
即可!
示例: 我们模拟5个用户吧:
用户ID | mon | tue | wed | thur | fri | sat | sun |
---|---|---|---|---|---|---|---|
001 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
002 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
003 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
004 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
005 | 0 | 1 | 0 | 1 |
2.2 前4步: 初始化7个bitmap
周一的key: mon, 周一所有用户的登录状态记录:
127.0.0.1:6379> setbit mon 1 1
(integer) 0
127.0.0.1:6379> setbit mon 2 0
(integer) 0
127.0.0.1:6379> setbit mon 3 1
(integer) 0
127.0.0.1:6379> setbit mon 4 1
(integer) 0
127.0.0.1:6379> setbit mon 5 0
(integer) 0
周二的key: tue, 所有用户的登录状态记录:
127.0.0.1:6379> setbit tue 1 1
(integer) 0
127.0.0.1:6379> setbit tue 2 0
(integer) 0
127.0.0.1:6379> setbit tue 3 1
(integer) 0
127.0.0.1:6379> setbit tue 4 1
(integer) 0
127.0.0.1:6379> setbit tue 5 1
(integer) 0
周三的key: wed, 所有用户的登录状态记录:
127.0.0.1:6379> setbit wed 1 1
(integer) 0
127.0.0.1:6379> setbit wed 2 0
(integer) 0
127.0.0.1:6379> setbit wed 3 1
(integer) 0
127.0.0.1:6379> setbit wed 4 1
(integer) 0
127.0.0.1:6379> setbit wed 5 0
(integer) 0
周四的key: thur, 所有用户的登录状态记录:
127.0.0.1:6379> setbit thur 1 1
(integer) 0
127.0.0.1:6379> setbit thur 2 0
(integer) 0
127.0.0.1:6379> setbit thur 3 1
(integer) 0
127.0.0.1:6379> setbit thur 4 1
(integer) 0
127.0.0.1:6379> setbit thur 5 1
(integer) 0
周五的key: fri, 所有用户的登录状态记录:
127.0.0.1:6379> setbit fri 1 1
(integer) 0
127.0.0.1:6379> setbit fri 2 0
(integer) 0
127.0.0.1:6379> setbit fri 3 1
(integer) 0
127.0.0.1:6379> setbit fri 4 1
(integer) 0
127.0.0.1:6379> setbit fri 5 0
(integer) 0
周六的key: sat, 所有用户的登录状态记录:
127.0.0.1:6379> setbit sat 1 1
(integer) 0
127.0.0.1:6379> setbit sat 2 1
(integer) 0
127.0.0.1:6379> setbit sat 3 1
(integer) 0
127.0.0.1:6379> setbit sat 4 1
(integer) 0
127.0.0.1:6379> setbit sat 5 1
(integer) 0
周日的key: sun, 所有用户的登录状态记录:
127.0.0.1:6379> setbit sun 1 1
(integer) 0
127.0.0.1:6379> setbit sun 2 1
(integer) 0
127.0.0.1:6379> setbit sun 3 1
(integer) 0
127.0.0.1:6379> setbit sun 4 1
(integer) 0
127.0.0.1:6379> setbit sun 5 1
(integer) 0
我去, 数据终于录入完了, 费劲那个~~
2.3 用bitop对7个bitmap进行位AND操作
127.0.0.1:6379> bitop and res mon tue wed thur fri sat sun
(integer) 1
2.4 bitcount对结果bitmap, 见证奇迹的时刻到了
127.0.0.1:6379> bitcount res
(integer) 3
2.5 想知道连续活跃的用户都有哪些人
getbit res 1
表示 用户编号为1的结果: 1说明用户ID=1的, 7天都活跃!
5个用户结果如下:
127.0.0.1:6379> getbit res 1
(integer) 1
127.0.0.1:6379> getbit res 2
(integer) 0
127.0.0.1:6379> getbit res 3
(integer) 1
127.0.0.1:6379> getbit res 4
(integer) 1
127.0.0.1:6379> getbit res 5
(integer) 0
2.6 扩展:
如果需求是: 求一周内活跃过的用户数: 只要将 上面命令中bitop and
改为: bitop or
即可~
连续 的话要求是AND, 活跃过 的话, 只要有一天就可以
over!
2.7 小结
bitmap的操作命令:
- setbit key offset value
- getbit key offset
- bitcount key [start end]
- bitop operation destkey [key ...]
operation: 支持 AND/OR/NOT/XOR四种操作,除NOT 外,其他操作都可接受一个或多个 key 作输入
destkey: 后面所有 key([key...])的
与或非异或
操作的结果存入一个目标key, 取个名字!key... 可以n个key做
与或非异或
操作, 传入这些bitmap的key 列表
原文链接:https://segmentfault.com/a/1190000023704266