首先说布隆过滤器的干嘛的
题目描述
- 一个网站有 100 亿 url 存在一个黑名单中,每条 url 平均 64 字节。这个黑名单要怎么存?若此时随便输入一个 url,你如何快速判断该 url 是否在这个黑名单中?假如允许万分之一的概率出错(这个出错代表宁可错杀三千不可漏掉一个)
思路
- 1.用一个HashSet 但是我们计算一下需要的内存大小:100亿 * 64 / 1024 / 1024 / 1024 = 640GB(不算乱七八糟的变量什么的)
- 2.用布隆过滤器,思路就是把所有的URL经过K个哈希算法得到K个哈希码值,然后用K个哈希码值去 % bit数组的大小(m 单位bit),然后把这些位置置为1(描黑),这个叫做进入了布隆过滤器,然后把所有的url都经过这样的处理。之后把想要判断的url放进布隆过滤器中,看是否全部描黑了(都匹配上了)那么这个就是黑名单里的,有一个不满足那就不是。我们用一个bit数组来存储,需要我们自己用int类型的数组实现一个位数组:
public class BitArray {
public static void main(String[] args) {
int[] arr = new int[1000];
int index = 30000;
int intIndex = index / 32;
System.out.println(intIndex);
int bitIndex = index % 32;
System.out.println(bitIndex);
arr[intIndex] = (arr[intIndex] | (1 << bitIndex));
}
}
- 下面的是我画的帮助理解的图
- 你会问我那么这里的 申请的bit数组大小m怎么确认?哈希函数个数怎么确认?
- (1)计算数组大小:
m
=
−
n
∗
ln
p
(
ln
2
)
2
m = - \frac {n * \ln p}{(\ln 2)^2}
m=−(ln2)2n∗lnp 其中n为样本量即100亿, p为误差概率即0.0001 最后:
m
=
−
10000000000
∗
ln
0.0001
(
ln
2
)
2
=
22.3
G
B
m = - \frac {10000000000 * \ln 0.0001}{(\ln 2)^2} = 22.3GB
m=−(ln2)210000000000∗ln0.0001=22.3GB 这就是我们需要的内存大小,比640GB小的多的多了
- (2)计算哈希函数个数:
K
=
ln
2
∗
m
n
K = \ln 2 * \frac {m}{n}
K=ln2∗nm m,n都是上面所求的,直接向上取整,直接带入
K
=
ln
2
∗
23
∗
1024
∗
1024
∗
1024
∗
8
10000000000
=
13
K = \ln 2 * \frac {23 * 1024 * 1024 * 1024 * 8}{10000000000} = 13
K=ln2∗1000000000023∗1024∗1024∗1024∗8=13
现在需要的哈希函数个数就是13个,然后由于m向上取整了,需要我们进行重新计算误差率p
p
=
(
1
−
e
−
n
∗
K
m
)
K
p = (1 - e ^ {- \frac {n * K}{m}}) ^K
p=(1−e−mn∗K)K 最后的结果是十万分之6左右。。比之前还低