为什么亿级数据量时要使用位图?位图和布隆过滤器有什么关系?

在这里插入图片描述

一、为什么要使用位图

我们先来看一个问题,假设我们有1千万个不同的整数需要存储,每个整数的大小范围是1到1亿。然后,给定任意一个整数X,我们需要判断X是否在刚才的1千万个整数内。这个问题该如何处理呢?

常规的做法肯定就是先考虑如何存储这1千万个整数,在Java中,int类型是4个字节,可以表示的范围区间是-2147483648~2147483647,所以每个整数都用int来表示是可行的。那么1千万个整数需要占用多少内存空间呢?两者相乘就是了,应该是4000万字节,也就是40MB。

而且如果我们存放的整数是是一亿个,每个整数大小范围是1到100亿怎么办?占用的内存空间将会是非常巨大的,是普通的计算机或者手机不能接受的。

所以我们需要使用位图这种数据结构来大大节省内存的使用量。

二、什么是位图

我们知道Byte表示字节,一个字节等于8bit,这里的bit就和位图有关系。在上面的例子中,我们不是要存放1千万个整数嘛,那就申请一个具有1千万个bit的数组,用每个bit(二进制位)来表示一个整数,当前bit为0表示不存在这个整数,为1表示该整数就存在。

虽然数量是1千万个,但是每个数的范围是1到1亿,所以我们需要1亿个bit,换算下来,就是12.5MB,和刚才的40MB相比,节省的不是一点点。

三、布隆过滤器

位图也不是万能的,倘若我们需要存放的1千万个整数的范围是1到100亿怎么办,按道理说,我们申请一个包含100亿个bit的数组就可以了,也是需要1.25GB,太大了,这也是很多电脑和手机承受不起的,那怎么办呢?

布隆过滤器就是让我们有办法在原来12.5MB的内存空间下,使用1亿个bit来存放原本需要100亿个bit才能解决的问题。我们的核心思想就是使用hash函数,把1到100亿大小的数值映射到1到1亿个bit内。

但是这肯定会造成冲突的,鸽巢理论就告诉过我们这一点了。那我们就使用多个不同的hash函数,来把同一个值映射到1到1亿bit中的不同位置上,如此,我们使用多个bit的值来表示一个数值是否存在。对于两个不同的数值来说,经过同一个hash处理得到的值可能会冲突,但是经过多个hash处理得到的多个值就不太可能全部冲突的。

img

上图:布隆过滤器的工作原理

当我们将某个整数放到内存中时,把它所有hash出来的bit都置为1;当我们需要判断给定的整数X是否已经存在时,就去读取所有的hash出来的bit值,只要有一个不是1,那么就说明这个值不存在;

但是如果所有hash出来的bit值都是1,也不能一定说明这个值X就是已经存在的,布隆过滤器会对结果为存在的情况发生误判。

img

上图:布隆过滤器发生误判的场景示意

当我们加入的数据越来越多,位图中为0的bit越来越少的时候,布隆过滤器发生误判的概率就会越来越高了。假设我们能提前知道总共有多少数据和数据的范围,我们可以通过调整hash函数的个数、位图的大小来减小误判发生的概率;假设我们并不能提前知道这些,那我们的位图就需要支持自动扩容,当为0的bit小于某个阈值的时候,我们就应该触发扩容位图的操作。

布隆过滤器在对某些可以容忍小概率误判的业务场景非常有效。

四、位图的常见使用场景

4.1 生成看似无规律却呈趋势递增的号段式ID

4.2 搜索引擎爬虫网页去重

4.3 大型网站每天UV数量统计

五、结语

下一篇会实战使用位图来实现抖音号淘淘号等需要生成看似无规律却呈趋势递增的号段式ID

猜你喜欢

转载自blog.csdn.net/weixin_42469135/article/details/127452337
今日推荐