如果一个黑名单网站包含100亿个黑名单网页,每个网页最多占64B,设计一个系统,判断当前的URL是否在这个黑名单当中,要求额外空间不超过30GB,允许误差率为万分之一。
布隆过滤器其中重要的实现就是位图的实现,也就是位数组,并且在这个数组中每一个位置只占有1个bit,而每个bit只有0和1两种状态。如上图bitarray所示!bitarray也叫bitmap,大小也就是布隆过滤器的大小。
我们可以创建一个整型的数组 int[] arr = new int[1000]
,每个int占4个字节,一个字节8位,所以长度为1000的intArray可以表示长度为32000
的bitArray,如果要把某个bit位描黑怎么办呢,我们可以先定位到这个位所在的整数(假如要把第30000个位置描黑):
int index = 30000;
int intIndex = index / 32; // 937
int bitIndex = index % 32; // 16
// 1左移 16位然后或上当前数,原来数 16位置就变为 1
arr[intIndex] = (arr[intIndex] | (1 << bitIndex));
则应该是:第937个桶的第16个位置应该被描黑(变为1)
假设一种有k个哈希函数,且每个哈希函数的输出范围都大于m,接着将输出值对k取余(%m),就会得到k个[0, m-1]的值,由于每个哈希函数之间相互独立,因此这k个数也相互独立,最后将这k个数对应到bitarray上并标记为1(涂黑)。
等判断时,将输入对象经过这k个哈希函数计算得到k个值,然后判断对应bitarray的k个位置是否都为1(是否标黑),如果有一个不为黑,那么这个输入对象则不在这个集合中,也就不是黑名单了!如果都是黑,那说明在集合中,但有可能会出现全部都在黑名单中国的情况,由于当输入对象过多,而集合也就是bitarray过小,则会出现大部分为黑的情况,那样就容易发生误判!因此使用布隆过滤器是需要容忍错误率的,即使很低很低!
相关计算公式:
假设输入对象个数为n,bitarray大小(也就是布隆过滤器大小)为m,所容忍的误判率p和哈希函数的个数k。计算公式如下:(小数向上取整)
由于我们计算的m和k可能是小数,那么需要经过向上取整,此时需要重新计算误判率p!
假设一个网页黑名单有URL为100亿,每个样本为64B,失误率为0.01%,经过上述公式计算后,需要布隆过滤器大小为25GB,这远远小于使用哈希表的640GB的空间。