考虑这么一个问题:不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL占用64B。现在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单上,请设计该系统。不涉及从黑名单里删除URL,只考虑往黑名单里添加URL并进行查询。
如果使用哈希表,内存空间需要100亿*64字节=640G(10亿字节(byte)是1G),空间就爆掉了。此时就轮到布隆过滤器登场了。
布隆过滤器应用场景:黑名单 爬虫去重
布隆过滤器优势:节省内存(30G以内),查询速度快
布隆过滤器劣势:存在一定失误率
但布隆过滤器的失误率是可以容忍的,一是可以通过设计人为的把失误率控制的很低;二是就算失误了不会误报已经在黑名单里的URL。布隆过滤器只会把正常的URL当成黑名单系统里的,但不会误报已经在黑名单里的URL。形象点说就是“宁可错杀三千不会放过一个”
在讲解布隆过滤器原理之前先讲位图。
位图是bit类型的数组。int类型4字节即32bit,所以长度100的int类型数组可以看出长度3200的bit数组。假如要找1782位比特,那么在int数组里下标是1782/32,在下标里存的int数字里第几个比特位?即1782%32的计算结果,从而把整型数组操作转换成比特类型数组操作。
布隆过滤器即大位图,假设是长度为m的bit数组,那么占用m/8位字节(Byte),
URL加黑名单过程:开始时m位比特都是0(白)的状态,该URL通过哈希函数f1得到一个哈希值,然后%m,得到0~m-1上某个位置,将该位置描黑(变成1),再用哈希函数f2得到一个哈希值,再描黑,再用哈希函数f3同样处理(f1、f2、f3是独立的哈希函数),假设一共用了k个哈希函数,那么描黑了k个位置(某个位置重复了就重复了,但一旦描黑就没有描白的时候)完成后可以说该URL加入了位图里。对下一个URL同样处理,用k个哈希函数描黑k个位置……一直做100亿个,位图中有相当多位置被描黑了。
如何查某个URL在不在黑名单里?把待查的URL用K个哈希函数算出对应的哈希值,再把该哈希值%m,把K个位置的状态都拿出来,如果全黑,就说这个URL属于黑名单系统,如果有一个是白,就不属于黑名单系统。如果m很小,100亿个URL之后所有位图都是黑的,那么不论查谁都在黑名单里;如果m取的大一些,失误率就会降低。
但布隆过滤器需要准备多少个bit位和单样本的大小无关。一个URL经过K个哈希函数得到K个哈希值,对m取模后去相应的大比特map中描黑,只要保证哈希函数能接收单样本这种类型的参数就可以了,与样本是64字节还是128字节无关。所以影响失误率的重要参数就是样本量N和位图比特数组长度m。
布隆过滤器三公式:出处
1.确定m:对于输入的数据量n(这里是100亿)和失误率p(这里是万分之一),布隆过滤器的大小m:m = - (nlnp) / (ln2ln2)
2.确定K:K假如很少,例如只有一个哈希函数,相当于每个数据只采集了一个特征点,只把一个位置描黑,查的时候也只用一个哈希函数,特征点不够,失误率虽然不至于很高但有一定的量,如果K很大,例如用10万个哈希函数去把10万个位置描黑,m的空间会接近耗尽,查什么URL都是黑的,失误率非常高。需要的哈希函数的个数k:k = ln2 * m/n = 0.7 * m/n
3.因为前两步中公式1公式2都会进行向上取整,所以公式3算出的实际的失误率与比预期失误率要低
布隆过滤器在Hadoop中的应用:Hadoop中的分布式文件系统,是由许多小文件组成的,如何查询一个数据在哪个文件里?首先不可能记录每个小文件的索引,这样做占用空间太大了。所以每个小文件里都搞一个布隆过滤器,当Hadoop想知道某个key在哪个文件里,就查每一个布隆过滤器,文件a的布隆过滤器会说明你这个key在我这个文件里,但可能会有误报;文件c的布隆过滤器会说明你这个key在我这个文件里,但可能会有误报……如果失误率很低,哪怕有几万个分布式文件,最终可能算出来只有3个文件里可能含有这个key。那么就只用把这3个小文件遍历一遍,就知道key在哪个小文件里了。通俗点讲,如果一个文件真的含有key,那么它的布隆过滤器会说这个key属于我;但因为有失误率,可能会发生一个文件不含有这个key,它还是会说这个key属于我;可是这也没关系,多查一遍就可以,反正失误率很低,需要遍历的文件很少。
网友评论