Redis允许使用二进制数据的Key(binary keys) 和二进制数据的Value(binary values)。Bitmap就是二进制数据的value。Redis的 setbit(key, offset, value)操作对指定的key的value的指定偏移(offset)的位置1或0,时间复杂度是O(1)。
Redis BitMaps的操作命令:
SETBIT key offset value
对指定的key的value的指定偏移(offset)的位置1或0
GETBIT key offset
获取offset设置的值,未设置过默认返回0
BITCOUNT key [start end]
统计指定key位置为1的数量(区间统计不建议使用,bitcount用的是byte来计算位数,其他setbit和getbit用的是bit,详见:http://blog.linuxphp.org/archives/1627/)
BITOP operation destkey key [key ...]
Bit运算,BITOP 支持四种表达式运算: AND(交集), OR(并集), XOR(异或) 和NOT(取非), 用法如下:
BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP NOT destkey srckey
BITPOS key bit [start] [end]
返回设置为1或0的一个字符串中的第一个点的位置
活跃用户统计
活跃用户是项目中经常需要统计的一个项目,我们之前的做法是:
直接从用户的登录日志中计算提取 (需要脚本定时计算,比较耗时)
将每天的登录用户的uid存在Redis的SET结构中 (用户基数大的情况下,开销大)
以上做法固然没有什么问题,但是当用户规模特别大的时候,就显得笨拙或者开销比较大,于是Redis bitmaps就上场了。
为统计某一天的用户登陆数量,首先以当天的日志加固定的前缀作为key,建立一个bitmap。例如:userlogin:2016-01-15,每一位二进制的位做为一个用户ID的标识(offset)。当用户访问时,就把bitmap中标识此用户的二进制(value)从0置为1。
用户登录时执行一次SETBIT(key, userId, 1),将bitmap中对应位置的位置为1。当统计某一天用户活跃数时,直接bitcount那天对应的key,当然还可以用bitop计算出如最近7天,一月个的用户活跃数。代码如下:
2. 用户行为统计
网站一般经常有个场景就是,判断用户是否操作过某个动作,比如是否点击过某个按钮(根据是否点击改变按钮颜色),是否领取过优惠券(是否领取过展示逻辑不同)。
这些场景其实也可以运用到bitMap,但是前提是不大关注行为的人,因为bitMap并不能计算出用户的uid。
之所以选择用bitmap,就是因为bitmap的操作非常快,而且也比较节省资源。
扩展下,其实如点赞喜欢的判断逻辑也可以用bitmap来实现,当然关系逻辑还是存在mysql中(因为这些关系有时候很重要),用bitmap来加速判断逻辑。
最后,说一下bitmap的两个容易采坑的地方:
第一个,就是bitcount命令,在使用start,end的时候一定要注意,setbit和getbit命令操作的是bit,但是bitcount用的是byte来计算位数,两者差了8倍,因此这点很容易采坑,也不建议用。
setbit的offset是用大小限制的,在0到 232(最大使用512M内存)之间,即0~4294967296之前,超过这个数会自动将offset转化为0,因此使用的时候一定要注意。
参考:
使用redis的setbit和bitcount来进行区间统计的坑
来源:oschina
链接:https://my.oschina.net/u/436644/blog/603442