位图
😀
位图
位图,即大量bit组成的一个数据结构(每个bit只能是0和1),主要适合在一些场景下,进行空间的节省。
它是一个字符串类型的数据结构,实际上是对字符串的每个比特位进行操作。
例如一些大量的bool类型的存取,一个用户365天的签到记录,签到了是1,没签到是0,如果用普通的key/value进行存储,当用户量很大的时候,需要的存储空间是很大的。
在 Redis 的位图中,每个位可以设置为 0 或 1,并且可以将多个位组合在一起形成一个按位存储的数据结构。位图的长度是动态可变的,最大支持 2^32 - 1 个比特位。
使用位图可以实现一些常见的应用场景,例如:
统计用户的访问次数或活跃度。
进行布隆过滤器(Bloom Filter)等高效的数据结构的实现。
压缩和存储稀疏的布尔数据。
实现位图索引,用于高效地进行集合操作,如交集、并集和差集。
BitMap用法
相关操作命令
SETBIT key offset value:将指定偏移量 offset 处的位设置为给定的值 value(0 或 1)。
GETBIT key offset:获取指定偏移量 offset 处的位的值。
BITCOUNT key [start end]:计算给定范围内(默认整个位图)的位为 1 的数量。
BITOP operation destkey key [key …]:对多个位图执行逻辑操作(AND、OR、NOT、XOR),并将结果存储到目标位图 destkey 中。
例如,修改某个bit位上的数据:
- offset:要修改第几个bit位的数据
- value:0或1
如果要签到就可以利用上面的这个命令,例如这个月的第1、2、3、6、7、8几天签到了,就可以这样:最终Redis中保存的效果:1
2
3
4
5
6
7
8
9
10
11
12# 第1天签到
SETBIT bm 0 1
# 第2天签到
SETBIT bm 1 1
# 第3天签到
SETBIT bm 2 1
# 第6天签到
SETBIT bm 5 1
# 第7天签到
SETBIT bm 6 1
# 第8天签到
SETBIT bm 7 1
那如果我们要查询签到记录怎么办?
那就是要读取BitMap中的数据,可以用这个命令,这个命令比较复杂,是一个组合命令,可以实现查询、修改等多种操作。不过我们只关心读取,所以只看第一种操作,GET即可:
1 | BITFIELD key GET encoding offset |
- key:就是BitMap的key
- GET:代表查询
- encoding:返回结果的编码方式,BitMap中是二进制保存,而返回结果会转为10进制,但需要一个转换规则,也就是这里的编码方式
- u:无符号整数,例如 u2,代表读2个bit位,转为无符号整数返回
- i:有符号整数,例如 i2,代表读2个bit位,转为有符号整数返回
- offset:从第几个bit位开始读取,例如0:代表从第一个bit位开始
例如,我想查询从第1天到第3天的签到记录,可以这样:
可以看到,返回的结果是7. 为什么是7呢?
签到记录是 11100111,从0开始,取3个bit位,刚好是111,转无符号整数,刚好是7
签到案例
如果我们签到的话,保存到数据库需要多条数据。数据量多了的话就比较占用内存,所以这里我们可以优化一下,签到为1,没签到为0,只需要用1或者0来记录即可,Redis中提供了用二进制来存储的办法,BitMap结构,大概意思就是你存的时候,我用二进制来从左往右存,取的时候转换为十进制的数
我们用java取的时候,如果要查看连续签到几天,比如11010111,后面三个1是连续签到的,我们需要先把十进制转换为二进制,然后转换为字符串,之后反转,遇到第一个0就结束,然后就能知道是连续签到几天了
计算连续签到天数
1 | String key = 签到记录的key的前缀,比如sign:uid:110:202301 |