Redis之Bitmap

Bitmap是什么:

Redis 的位图(bitmap)是由多个二进制位组成的数组,只有两种状态,0和1, 数组中的每个二进制位都有与之对应的偏移量(从 0 开始),通过这些偏移量可以对位图中指定的一个或多个二进制位进行操作。

Bitmap能解决什么问题:

Bitmap是用一个bit 位来存放某种状态,适用于大规模数据,但是前提是统计的这个大数据量每个的状态只能有两种,因为每一个bit位只能表示两种状态,在大量数据的快速排序、查找、去重bitmap很有优势。

Bitmap带来了什么问题:

1.数据碰撞。比如将字符串映射到 BitMap 的时候会有碰撞的问题,那就可以考虑用 Bloom Filter 来解决,Bloom Filter 使用多个 Hash 函数来减少冲突的概率。

2.数据稀疏。又比如要存入(10,8887983,93452134)这三个数据,我们需要建立一个 99999999 长度的 BitMap ,但是实际上只存了3个数据,这时候就有很大的空间浪费,碰到这种问题的话,可以通过引入 Roaring BitMap 来解决。

Bitmap原理:

BitMap 的基本原理就是用一个 bit 来标记某个元素对应的 Value,而 Key 即是该元素。由于采用一 个bit 来存储一个数据,因此可以大大的节省空间。

计算机分配给内存的最小单元是bit,1Byte=8bit, 1个整数类型为4Byte=32bit。

Bitmap场景:快速查找 去重   排序    签到 打卡


在20亿个随机整数中找出某个数m是否存在其中,并假设32位操作系统,4G内存。
计算机分配给内存的最小单元是bit,在Java中,int占4字节,1字节=8位(1 byte = 8 bit)。
如果每个数字用int存储,那就是20亿个int,因而占用的空间约为 (2000000000*4/1024/1024/1024)≈7.45G
如果按位存储就不一样了,20亿个数就是20亿位,占用空间约为 (2000000000/8/1024/1024/1024)≈0.23G

 

表示{1,2,4,6}这几个数,每一位表示一个数,0表示不存在,1表示存在,这正符合二进制:
这样我们可以很容易表示{1,2,4,6}这几个数:
在这里插入图片描述
那如果要表示{12,13,15}怎么办呢?当然是在另一个8位上表示了:
在这里插入图片描述
变成一个二维数组了,1个int占32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32] 即可存储,其中N表示要存储的这些数中的最大值,于是乎:
tmp[0]:可以表示0~31
tmp[1]:可以表示32~63
tmp[2]:可以表示64~95
总结:
给定任意整数M,那么M/32就得到下标,M%32就知道它在此下标的哪个位置。

添加

这里有个问题,我们怎么把一个数放进去呢?例如,想把5这个数字放进去,怎么做呢?

首先,5/32=0,5%32=5,也是说它应该在tmp[0]的第5个位置,那我们只需要把第5位数字设置位1即可,删除同理将第五位数字设置位0接口。

 

字符串映射

BitMap 也可以用来表述字符串类型的数据,但是需要有一层Hash映射,如下图,通过一层映射关系,可以表述字符串是否存在。

当然这种方式会有数据碰撞的问题,但可以通过 Bloom Filter 做一些优化。

BitMap如何使用:

网上很多使用教程。

问题:

去重:

https://www.cnblogs.com/chenfx/p/15710156.html

签到:

https://blog.csdn.net/qq_31905135/article/details/124032880

用户量统计:

https://blog.csdn.net/qq_37200262/article/details/122051753

总结

  1. bigmap 基于最小的单位bit进行存储,最大优势是非常省空间;
  2. 设置时候时间复杂度O(1)、读取时候时间复杂度O(n),操作是非常快的;
  3. 二进制数据的存储,进行相关计算的时候非常快,也能方便扩容;
  4. 不要给一个很短的 bigmap 设置很长位的偏移量的值,这样有可能堵塞。

 

posted @ 2022-10-16 20:57  爵士灬  阅读(1499)  评论(0编辑  收藏  举报