一文了解布隆过滤器

目录html

1、问题引入python

2、诞生背景git

3、BF 简介及原理github

4、BF 经常使用操做redis

5、BF 优缺点及应用场景算法

6、应用场景数组

7、特殊状况缓存

8、Python实现简单的布隆过滤器算法网络

9、总结数据结构

10、参考连接


1、问题引入

一个网站有 20 亿 url 存在一个黑名单中,这个黑名单要怎么存?若此时随便输入一个 url,你如何快速判断该 url 是否在这个黑名单中?而且需在给定内存空间(好比:500M)内快速判断出。

2、诞生背景

如上述问题,查询某个元素是否存在于一个大型或者超大型数据集(千万、亿级别)中,这是布隆过滤器诞生的技术背景。因为数组、链表、树等数据结构存储的数据量过大时,消耗的内存也会呈现线性增加,最终成为系统瓶颈;若是采用哈希表,其时间复杂度为O(1),可是哈希表须要消耗的内存依然很高,URL字符串经过Hash获得一个Integer的值,Integer占4个字节,那20亿个URL理论上须要:20亿*4/1024/1024/1024=7.45G的内存。那么,为了更快更省内存的解决问题,布隆过滤器应运而生。

3、BF 简介及原理

3.1 哈希函数

介绍布隆过滤器以前,先简单了解下哈希函数。

哈希函数是将任意大小的数据元素转换成特定大小结果的函数。转换后的结果称为哈希值或哈希编码。以下图所示分别输出哈希编码与哈希值:

哈希函数是实现哈希表和布隆过滤器的基础。

3.2 BF 简介

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它其实是一个很长的二进制向量和一系列随机映射函数。

3.3 BF 原理

布隆过滤器的核心是由长度为m的位向量(能够理解为位数组)与k个不一样的哈希函数组成。将数据(示例为:hash, Hash, HASH. 以下图)添加到布隆过滤器中,首先将数据输入到k个不一样的哈希函数,获得k个不一样的哈希值,而后在位向量中设置对应的结果位(对应图中的黄色位置)。

例如,将m设置为50,k设置为3。(注意,有时哈希函数会产生重叠位置,所以能够设置小于k的位置)。为了判断测试数据(图中右侧数据test)是否在过滤器中,咱们再次将其提供给k个哈希函数,获得k个不一样的哈希值并设置对应的结果位。

最终,咱们检查测试数据对应的结果位是否已经被设置(黄色)。若是存在没有设置的结果位,则表示该测试数据(test)确定不在集合中(图中测试结果出现蓝色位置)。不然,测试数据可能在集合中。

注意:若是k个查询结果位置所有为1,则可能在集合中。

为何时可能呢?由于多个元素通过 hash 获得的结果可能在集合的同一位置,其误判率取决于使用的 hash 算法。

4、BF 经常使用操做

4.1 添加元素

  1. 将须要添加的元素给k个哈希函数
  2. 获得对应于位向量上的k个位置
  3. 将这k个位置设为1

4.2 查询元素

  1. 将须要查询的元素给k个哈希函数
  2. 获得对应于位向量上的k个查询结果位置
  3.  判断结果:

    若是k个查询结果位置有一个为0(对应上图的蓝色位置;说明没有任何一个值映射到这个 bit 位上),则须要查询的元素确定不在集合中;

    若是k个查询结果位置所有为1,则可能在集合中。

4.3 删除元素

不支持直接删除元素。

缘由:没法分辨哈希碰撞;同一位被两个值共同覆盖,删除其中一个则将其位置 0,判断另外一个值时则直接返回 false(不存在);

解决方法:计数删除。可是计数删除须要额外存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。此时增长一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。

5、BF 优缺点及应用场景

优势:空间效率和查询时间都比通常的算法要好的多。

缺点:存在必定的误识别率和删除相对困难。

6、应用场景

一、黑名单(如开篇引入的问题)

二、URL去重(减小磁盘 IO读写或者网络请求,广泛用于网络爬虫URL去重,例如在scrapy-redis爬虫框架实现布隆过滤器过滤已经爬取过的网页)

三、单词拼写检查(判断单词是否存在于合理正确的单词库中)

四、Key-Value缓存系统的Key校验(防止Redis缓存击穿)

五、ID校验,好比订单系统查询某个订单ID是否存在,若是不存在就直接返回。

7、特殊状况

7.1 超过预期容量

        按照一万个元素设计,超过一万个后布隆过滤器准确率降低

        解决思路:

            a. 扩大存储原始数据

                元素超事后扩充位向量成一个更大的布隆过滤器(如位向量个数翻倍)

            b. 堆叠布隆过滤器个数 BF( scalable bloomfilter)

               超过一万个元素后再生成一个新的一万容量的布隆过滤器,查询时同时查询多个,但性能相对稍差。

7.2 布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小

7.3 哈希函数的个数也须要权衡

    个数越多则布隆过滤器bit位设置为1的速度越快,且布隆过滤器的效率越低;可是若是太少的话,误报率会变高。

8、Python实现简单的布隆过滤器算法

用Python模拟布隆过滤器的算法思路,主要函数以下,完整代码参见 GitHub

def get_positions(self, url):
        """
        返回url通过hash以后的位向量。此处采用三个hash函数构建。
        取余数,保证向量组的比特位索引小于bit_size
        :param url: 须要通过hash的数据
        :return: url所在位向量的位置
        """
        # hash(key, seed=0, signed=True)
        # 参数解释:
        # key: 须要hash的元素
        # seed: 种子参数,随机化函数的一种方法。采用不一样的种子参数,生成不一样的hash值,防止不一样数据的hash冲突
        # signed: 默认True
        # seed 参数解释参考:https://stackoverflow.com/questions/9241230/what-is-murmurhash3-seed-parameter
        position_one = mmh3.hash(url, 60) % self.bit_size
        position_two = mmh3.hash(url, 61) % self.bit_size
        position_three = mmh3.hash(url, 62) % self.bit_size
        return [position_one, position_two, position_three]

9、总结

本文首先由一个实际问题引入布隆过滤器的诞生背景,介绍了布隆过滤器的基本原理、经常使用操做、优缺点、应用场景及特殊状况,最后给出简单的Python代码实现。水平通常,能力有限,本文中若存在描述不清或描述有误的地方还望读者留言指出,不吝赐教。

10、参考连接

https://www.jasondavies.com/bloomfilter

http://www.javashuo.com/article/p-aenfkllo-mo.html

https://zhuanlan.zhihu.com/p/43263751