目录html
1、问题引入python
2、诞生背景git
3、BF 简介及原理github
4、BF 经常使用操做redis
6、应用场景数组
7、特殊状况缓存
9、总结数据结构
一个网站有 20 亿 url 存在一个黑名单中,这个黑名单要怎么存?若此时随便输入一个 url,你如何快速判断该 url 是否在这个黑名单中?而且需在给定内存空间(好比:500M)内快速判断出。
如上述问题,查询某个元素是否存在于一个大型或者超大型数据集(千万、亿级别)中,这是布隆过滤器诞生的技术背景。因为数组、链表、树等数据结构存储的数据量过大时,消耗的内存也会呈现线性增加,最终成为系统瓶颈;若是采用哈希表,其时间复杂度为O(1),可是哈希表须要消耗的内存依然很高,URL字符串经过Hash获得一个Integer的值,Integer占4个字节,那20亿个URL理论上须要:20亿*4/1024/1024/1024=7.45G的内存。那么,为了更快更省内存的解决问题,布隆过滤器应运而生。
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.1 添加元素
4.2 查询元素
若是k个查询结果位置有一个为0(对应上图的蓝色位置;说明没有任何一个值映射到这个 bit 位上),则须要查询的元素确定不在集合中;
若是k个查询结果位置所有为1,则可能在集合中。
4.3 删除元素
不支持直接删除元素。
缘由:没法分辨哈希碰撞;同一位被两个值共同覆盖,删除其中一个则将其位置 0,判断另外一个值时则直接返回 false(不存在);
解决方法:计数删除。可是计数删除须要额外存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。此时增长一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。
优势:空间效率和查询时间都比通常的算法要好的多。
缺点:存在必定的误识别率和删除相对困难。
一、黑名单(如开篇引入的问题)
二、URL去重(减小磁盘 IO读写或者网络请求,广泛用于网络爬虫URL去重,例如在scrapy-redis爬虫框架实现布隆过滤器过滤已经爬取过的网页)
三、单词拼写检查(判断单词是否存在于合理正确的单词库中)
四、Key-Value缓存系统的Key校验(防止Redis缓存击穿)
五、ID校验,好比订单系统查询某个订单ID是否存在,若是不存在就直接返回。
7.1 超过预期容量
按照一万个元素设计,超过一万个后布隆过滤器准确率降低
解决思路:
a. 扩大存储原始数据
元素超事后扩充位向量成一个更大的布隆过滤器(如位向量个数翻倍)
b. 堆叠布隆过滤器个数 BF( scalable bloomfilter)
超过一万个元素后再生成一个新的一万容量的布隆过滤器,查询时同时查询多个,但性能相对稍差。
7.2 布隆过滤器的长度会直接影响误报率,布隆过滤器越长其误报率越小
7.3 哈希函数的个数也须要权衡
个数越多则布隆过滤器bit位设置为1的速度越快,且布隆过滤器的效率越低;可是若是太少的话,误报率会变高。
用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]
本文首先由一个实际问题引入布隆过滤器的诞生背景,介绍了布隆过滤器的基本原理、经常使用操做、优缺点、应用场景及特殊状况,最后给出简单的Python代码实现。水平通常,能力有限,本文中若存在描述不清或描述有误的地方还望读者留言指出,不吝赐教。
https://www.jasondavies.com/bloomfilter