大家都知道redis的五种常用类型string、hash、list、set、zset,除此以外redis还有一些特殊类型,bitMap就是其中的一种.
bitMap 原本的含义是用一个比特位来映射某个元素的状态。由于一个比特位只能表示 0 和 1 两种状态,所以bitMap能映射的状态有限,但是使用比特位的优势是能大量的节省内存空间
在Redis中,可以吧bitMap当成一个以比特位为单位的数组,数组的每个元素只能存储0和1,数组的下标在bitMap中叫做偏移量
bitMap在Redis中不是一个新的数据类型,其底层是Redis string实现。
BitMap 相关命令
# 设置值,其中value只能是 0 和 1
setbit key offset value
# 获取值
getbit key offset
# 获取指定范围内值为 1 的个数
# start 和 end 以字节为单位
bitcount key start end
# BitMap间的运算
# operations 位移操作符,枚举值
# AND 与运算 &
# OR 或运算 |
# XOR 异或 ^
# NOT 取反 ~
# result 计算的结果,会存储在该key中
# key1 … keyn 参与运算的key,可以有多个,空格分割,not运算只能一个key
# 当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0。返回值是保存到 destkey 的字符串的长度(以字节byte为单位),和输入 key 中最长的字符串长度相等。
bitop [operations] [result] [key1] [keyn…]
# 返回指定key中第一次出现指定value(0/1)的位置
bitpos [key] [value]
案例
# 分别给signa signb填充数据
127.0.0.1:6379> setbit signa 1 1
(integer) 0
127.0.0.1:6379> setbit signa 2 1
(integer) 0
127.0.0.1:6379> setbit signa 3 1
(integer) 0
127.0.0.1:6379> setbit signa 4 1
(integer) 0
127.0.0.1:6379> setbit signb 4 1
(integer) 0
127.0.0.1:6379> setbit signb 5 1
(integer) 0
127.0.0.1:6379> setbit signb 6 1
(integer) 0
#查看signa signb数量
127.0.0.1:6379> bitcount signa
(integer) 4
127.0.0.1:6379> bitcount signb
(integer) 3
#求signa与signb的交集并赋值在signc中
127.0.0.1:6379> bitop and signc signa signb
(integer) 1
127.0.0.1:6379> bitcount signc
(integer) 1
#求signa与signb的并集并赋值在signd中
127.0.0.1:6379> bitop or signd signa signb
(integer) 1
127.0.0.1:6379> bitcount signd
(integer) 6
#求signa与signb的差集(在signa中存在signb中不存在和signb中存在,signa中不存在的)并赋值在signf中,
127.0.0.1:6379> bitop xor signf signa signb
(integer) 1
127.0.0.1:6379> bitcount signf
(integer) 5
#给signaa赋值
127.0.0.1:6379> setbit signaa 1 1
(integer) 0
#将signaa取非存放到signnot中,因signaa只有第一位图为1,其余7个位图为0,取非的话就会有7个位图为1,所以signnot求bitcount为7
127.0.0.1:6379> bitop not signnot signaa
(integer) 1
127.0.0.1:6379> bitcount signnot
(integer) 7
127.0.0.1:6379> del signnot
(integer) 1
127.0.0.1:6379> setbit signaa 7 1
(integer) 0
127.0.0.1:6379> bitop not signnot signaa
(integer) 1
127.0.0.1:6379> bitcount signnot
(integer) 6
#因signaa第10个比特位占用两个字节,故共用16个比特位,其中为1的有3个位图,取非后bitcount为13
127.0.0.1:6379> setbit signaa 10 1
(integer) 0
127.0.0.1:6379> bitop not signnot signaa
(integer) 2
127.0.0.1:6379> bitcount signnot
(integer) 13
使用场景
1.用户签到
很多网站都提供了签到功能,并且需要展示最近一个月的签到情况,这种情况可以使用 BitMap 来实现。根据日期 offset = (今天是一年中的第几天) % (今年的天数),key = 年份:用户id
2.统计活跃用户
以登录日期为key;重复登录要去重;进行or或运算(有1则1)
> setbit 20230201 1 1
0
> setbit 20230201 2 1
0
> setbit 20230201 7 1
0
> setbit 20230202 2 1
0
> setbit 20230202 7 1
0
#统计20230201 ~ 20230202 活跃过的用户
> bitop or dest1 20230201 20230202
1
> BITCOUNT dest1
3
#统计连续两天活跃的用户总数:
> bitop and dest2 20230201 20230202
1
> BITCOUNT dest2
2
3.统计用户是否在线
如果需要提供一个查询当前用户是否在线的接口,也可以考虑使用 BitMap 。即节约空间效率又高,只需要一个 key,然后用户 id 为 offset,如果在线就设置为 1,不在线就设置为 0