布隆过滤器

72 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

在处理海量数据的算法问题,我们可能遇到这样的问题:

比如这里有一个包含40亿无符号整数文件,但是我们范围是0~42亿,最大使用1gb,怎么找到文件里面没出现的数?

内存限制10MB怎么找到一个没有出现的数?

如果只能申请有限几个变量,怎么找到缺失?

看到这个数据量,是不是一下子脑子蒙了?离谱了,这要怎么做?

最简单做法是使用hash直接循环遍历,但是想也知道多离谱,粗略一看,至少要300多亿B内存。这就需要用到布隆过滤器了。因为hash内存和不同数出现有关。

什么是布隆过滤器?

image.png

百度一下,感觉好像懂了,又好像没懂。看完还是没多大概念。

只需要记住:我们可以把它看作由二进制向量(或者说位数组)和一系列随机映射函数(哈希函数)两部分组成的数据结构

布隆过滤器其实就是位数组。了解布隆过滤器之前,我们要了解hash底层原理。

image.png

通过hash可以把40亿数,基本上通过hash平均分到m长度文件里面。然后把缺失的m提出,把m当作a再次hash,最终解决该问题。

为什么通过hash就平均分了? image.png

在我看来,做hash其实和取随机数很类似,我们可以这样想,1-99里面,1出现了18次(1,11,21,31,41,51,61,71,81,91,12,13,14,15,16,17,18,19),2出现了19次(2,12,22,32,42,52,62,72,82,92,20,21,23,24,25,26,27,28,29),3出现了。。。。

也就是我们如果把1-99放入长度为10的数组链表里面,几乎每个数组对应长度相等(差的不多,当数据量足够大,理论上是相等的)。为什么?因为每个数字出现概率是相等的,大家公平竞争,哈哈。

解题思路

怎么把基本数据类型变成位图?

public static void fang() {
      int a=0;
//    a--->32bit(4字节,一个字节8bit)
      int[] arr=new int[10]; //32bit*10-》存储320bit的信息
//    arr[0] int 0-31
//    arr[1] int 32-63
//    ...
      int i=123;//拿到第123位的信息
      int numIndex=123/32;//定义到去哪个数寻找
      int bitIndex=123%32;//定义位
//    拿到状态
//    找到数,右移bit位,和1作与
      int s=((arr[numIndex]>>bitIndex) &1);
//    把当前位变1
      arr[numIndex]=arr[numIndex]|(1<<bitIndex);
//    把当前位变0
      arr[numIndex]=arr[numIndex]&(~(1<<bitIndex));
}

int[] arr=new int[10]:定义了数组,即需要模10才能既然数组。一个int类型,包含32bit,那么足够数组,就存储了320bit数据。

123/32,123%32:假设我们需要找i的信息,那么通过除32,我们可以知道是哪一个数组下标,然后通过模32,可以字段是下标里面的哪一位。

数组存储的不是值:是范围数。

做布隆过滤器,关键是数组长度怎么取

但是在平时问题里面,它会限制内存,那么我们就可以按照限制内存大小做数组。

那么10gb就很明显。再苛刻一点。只用3kb内存

3kb变成整数-》3kb/4 接近700多。和他相近的是2^9(512),所以我们数组一个下标对应范围1~42亿/512

这样第一次做完后,看到会有一个数组下标对应范围不够 42亿/512 再把他取出来。把他长度除512,再次得到不够的....如此循环,我们就可以找到缺失值了。

如果只能申请有限几个变量,怎么找到缺失?

使用二分法:(数组长度为2)

按照42亿/2 分左边右边,小的继续除2,往复循环。

布隆过滤器使用场景

解决黑名单问题,爬虫去重复。也就是:解决只有添加和查询,没有删除的集合。

当碰到有样本量和失误率的问题时候,我们可以看它:

  1. 是不是类似黑名单
  2. 可不可以有失误率,可以——》布隆过滤器模型
  3. 得到失误率