简介
redis的五种数据类型相信大家都非常清楚了,任何人问你基本都能脱口而出(string,hash,list,set,zset)。如果还不清楚,建议先看看redis基础,但是还有这几种类型很多人会忽略到。比如 Setbit(位操作),GEO(地理位置信息)等等。
今天我们就来看一看setbit,看一看实际场景中到底是怎么用的,以及有哪些优势?我们先来回顾一下setbit吧,大家知道位操作,只有两个值,0和1,8个位正好是1b,所以位操作是非常节省空间的一种操作。
setbit用法:
redis> SETBIT bit 10086 1 #把第10086个位置设置为1 (integer) 0 redis> GETBIT bit 10086 #获取第10086个位置的值 看是0还是1 (integer) 1 redis> GETBIT bit 100 # bit 默认被初始化为 0 (integer) 0
其实就是把某个位标记为1或者0而已,但是它的好处在于非常节省空间。另外既然是位,就会涉及到或运算或者与运算。
实例
场景: 1亿个用户,每个用户登陆/做任意操作,记为 今天活跃,否则记为不活跃。
每周评出: 有奖活跃用户: 连续7天活动
每月评,等等...
其实简单说就是统计一下连续7天(或者连续30天)有多少人连续登陆过。
咱们先来想一想传统的方案
很容易就会想到只要用户登陆了,我在表中插入一条数据,并且记录上对应的日期,然后用mysql里面的记录来逐个判断,类似于这样:
Userid date active 1 2020-07-27 1 1 2020-07-26 1 2 2020-07-27 1 ...
但这样是存在一些问题的,主要的问题在于用户量高达1亿,每个用户登陆一次就远远的超过mysql的极限了,更不要说统计一星期了,而且用上group ,sum运算,计算也是非常慢的。所以在这种用户量大,而且统计比较简单的问题上,咱们可以运用位(setbit)操作来解决问题。
先分析一下思路,对于某一天来说,我们可以把这一天想像成一根小木棍,分成了不同的段落,每个段落对应的就是用户的位(因为有user_id),默认值都是0,只要有人登陆了,就把对应的用户的位置标为1即可。
如上图所示,这个就是一天的登陆情况,user_id为6和user_id为8的用户登陆过。其余的都为没有登陆过。因为这个是位操作,所以占的空间很小,1亿的用户,所占的空间也就不到12M。
一天的问题咱们解决了,如何解决他们是否连续登陆过呢?
我们可以用上多个"木棍"
我们可以把每一天作为一个键,然后每天对用户登陆状态进行标记,在最后用每天做一个"与运算"就可以准确的知道哪些用户连续登陆了。
其实总结一下过程如下:
1. 记录用户登陆
每天按日期生成一个位图, 用户登陆后,把user_id位上的bit值置为1
2. 把1周的位图 and 计算
位上为1的,即是连续登陆的用户
代码实现如下:
redis 127.0.0.1:6379> setbit mon 100000000 0(integer) 0 redis 127.0.0.1:6379> setbit mon 3 1(integer) 0 redis 127.0.0.1:6379> setbit mon 5 1(integer) 0 redis 127.0.0.1:6379> setbit mon 7 1(integer) 0 redis 127.0.0.1:6379> setbit thur 100000000 0(integer) 0 redis 127.0.0.1:6379> setbit thur 3 1(integer) 0 redis 127.0.0.1:6379> setbit thur 5 1(integer) 0 redis 127.0.0.1:6379> setbit thur 8 1(integer) 0 redis 127.0.0.1:6379> setbit wen 100000000 0(integer) 0 redis 127.0.0.1:6379> setbit wen 3 1(integer) 0 redis 127.0.0.1:6379> setbit wen 4 1(integer) 0 redis 127.0.0.1:6379> setbit wen 6 1(integer) 0 redis 127.0.0.1:6379> bitop and res mon feb wen(integer) 12500001
如上例,优点为:
1、节约空间, 1亿人每天的登陆情况,用1亿bit,约1200WByte,约10M 的字符就能表示
2、计算方便
转自:
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn