0. 起因
以前写爬虫的时候用过布隆过滤器(Bloom filter)作为判断和去重,今天在看RPC代码的时候发现也有布隆过滤器的身影。因为之前了解过,看到名字的瞬间就明了作者想要做什么,虽然细节记不清了。因此在这里做个记录,后面如果需要扣细节,心里懂得了原理看起来也方便。
1. 什么是布隆过滤器?
布隆过滤器是由布隆(Burton Howard Bloom)在1970年提出的一个可以高效的判断出给定元素“肯定不存在”或者“可能已经存在”的概率型数据结构,这个高效不仅体现在时间上,也体现在内存上。
基本的布隆过滤器支持判断和添加这两个操作,但是不支持删除。但是经过扩展,布隆过滤器也可以实现删除,例如counting filter。
对于判断操作,如果返回假则可以说明给定元素肯定不存在;而如果返回真,则只能说给定元素有可能已经存在了。
2. 应用场景
布隆过滤器一般用于去除一些不必要的检索操作,特别是当这种检索相当耗时的时候。例如,有一个很长的链表,如果检索一个不存在的元素,常规操作需要遍历整个链表。虽然可以结合红黑树等数据结构减少减速的数量,但随着元素数量的增减,时间也会越来越长。但是如果使用了布隆过滤器,就可以在相对固定的时间内知道某个元素不存在,免去了多于的耗时。
3. 原理
布隆过滤器的基本思想是哈希函数,对于一个良好的哈希函数,任意两个不同的对象的哈希值基本是不一样。
其算法如下:
- 首先选取k个hash函数,n可以是除0外的任意正整数,每个函数可以把key散列成为1个整数;
- 开辟个数组空间,以比特位(bit)为单位,每个位都初始化为0;
- 某个元素加入集合时,用选取的k个hash函数计算分别计算出k个哈希值应该都小于数组长度;
- 判断某个key是否在集合时,查询第三部计算出的哈希值所对应的数组元素是否为1,如果存在至少一个哈希值对应的元素为0,则元素不存在;如果全部哈希值对应的元素都为1,则该元素可能已经存在;
- 添加某个元素的时候,只需要将哈希值对应的数组元素都设置为1即可。
例如下面这个例子:
在内存中开辟了一片连续的数组空间,并使用三个不同的哈希函数对元素进行哈希操作。如图1所以,当布隆过滤其中已经存在a, b, c, d, e, f,
这几个元素的情况下,这时,需要判断元素1234567890qwer
是否已经存在,三个哈希函数得到的哈希值指向的数组元素都已经被设置成1,虽然此时1234567890qwer
肯定不存在,但是布隆过滤器返回的结果是元素已经存在,因此布隆过滤器存在一定误判的可能。
而图2中,对于n元素,三个哈希函数中只有一个哈希函数得出的结果指向的数组元素中为0,但这足以肯定的得出n不存在这个结论。
4. 哈希函数的数量和数组长度选择
既然是概率型数据结构,那么对于参数的选择肯定有一套对应的数学公式,布隆过滤器中涉及的哈希函数数量k,数组长度m,元素数量n以及误报率p的公式如图3所示,通过下面的公式,可以得到比较合理的参数:
至于公式怎么推导出来的,这里(wo)就(ye)不(bu)介(zhi)绍(dao)了。
首发于个人微信公众号TensorBoy。微信扫描上方二维码或者微信搜索TensorBoy并关注,及时获取更多最新文章!
C++ | Python | Linux | 原理 | 源码,有一起玩耍的么?