布隆过滤器gydF4y2Ba
bloom过滤器是一种gydF4y2Ba概率数据结构gydF4y2Ba这是基于gydF4y2Ba哈希gydF4y2Ba.它非常节省空间,通常用于将元素添加到gydF4y2Ba集gydF4y2Ba并测试一个元素是否在集合中。但是,元素本身不会被添加到集合中。相反,元素的散列被添加到集合中。gydF4y2Ba
在测试bloom过滤器中是否有元素时,可能会出现误报。它会说一个元素是gydF4y2Ba肯定不是gydF4y2Ba在这个集合中gydF4y2Ba这是可能的gydF4y2Ba元素在集合中。gydF4y2Ba
bloom滤镜很像gydF4y2Ba哈希表gydF4y2Ba它将使用哈希函数将一个键映射到一个bucket。但是,它不会将该键存储在该bucket中,而是简单地将其标记为已填充。因此,许多键可能映射到相同的已填充桶,从而产生误报。gydF4y2Ba
属性gydF4y2Ba
一个空的bloom过滤器是一个位数组gydF4y2Ba 比特,所有的比特一开始都被设为0。位数组是一种非常节省空间的数据结构,它将数组中的每个位置设置为0或1。gydF4y2Ba
一种布隆滤镜还包括一套gydF4y2Ba 哈希函数,用于哈希传入值。这些哈希函数的范围必须都是0到gydF4y2Ba .如果这些哈希函数匹配入值与位数组中的索引,bloom过滤器将确保数组中该位置的位为1。看看这张动图,它显示了字符串“Hello”和“Bloom”插入到3位和2个散列函数的Bloom过滤器中。gydF4y2Ba
在这个例子中,“Hello”被第一个哈希函数哈希为1,被第二个哈希函数哈希为3。所以,bloom过滤器确保索引1和3的位被翻转到1。然后,“Bloom”被哈希为1和2。bloom过滤器确保它们都是1(即使位置1已经有了1)。gydF4y2Ba
当查询在bloom过滤器中发生时,我们再次对所有的键进行哈希gydF4y2Ba 我们的哈希函数。然后我们检查所有的输出位,以确保它们都是1。如果它们中的任何一个是0,我们可以肯定地知道我们要搜索的键不在列表中。如果它们都是1,我们知道它可能是。gydF4y2Ba
假阳性gydF4y2Ba
让我们想想动图中bloom过滤器的假阳性。假阳性是指当我们查询bloom过滤器以查看某个单词是否在其中时,即使它不在,它也会告诉我们它在。想象一下,“House”也被哈希到两个索引1和3?如果我们在过滤器中输入“Hello”和“Bloom”,然后询问“House”是否在过滤器中,会发生什么?gydF4y2Ba
布鲁姆滤镜会告诉我们"豪斯"gydF4y2Ba可能gydF4y2Ba参与其中。这是因为插入“House”时将被激活的位已经被翻转为1。bloom过滤器也可能告诉我们一个百分比的确定性,但我们将在下一节中讨论。gydF4y2Ba
假阳性分析gydF4y2Ba
在构建bloom滤波器时,我们有两种参数选择,gydF4y2Ba 而且gydF4y2Ba .它们的选择应该尽可能地抑制假阳性的数量,同时仍然保持过滤器所需的空间要求。gydF4y2Ba
如果我们有bloom过滤器gydF4y2Ba 比特和gydF4y2Ba 哈希函数,某位在插入一次后仍为零的概率为gydF4y2Ba
之后,gydF4y2Ba 插入之后,它仍然为零的概率gydF4y2Ba 插入是gydF4y2Ba
也就是说假阳性的概率是gydF4y2Ba
因为我们要求的是gydF4y2Ba 不同的位被翻转为1。这个近似等于gydF4y2Ba
在这些方程中,提高k的值(哈希函数的数量)将使假阳性的概率降低。然而,如果k值太大,计算效率就不高。为了使这个方程最小化,我们必须选择最好的gydF4y2Ba .我们这样做是因为我们假设程序员已经选择了一个gydF4y2Ba 基于他们的空间限制,他们有一些想法,他们的潜力gydF4y2Ba 将。因此,gydF4y2Ba 使方程最小的值是gydF4y2Ba
时空复杂性gydF4y2Ba
bloom过滤器在时间和空间使用方面都非常有效。这些特征是如此重要,以至于为了维护它们而放弃了准确性。gydF4y2Ba
时间gydF4y2Ba
如果我们使用的是布隆滤镜gydF4y2Ba 比特和gydF4y2Ba 哈希函数,插入和搜索都需要gydF4y2Ba 时间。在这两种情况下,我们只需要通过所有哈希函数运行输入。然后我们检查输出位。gydF4y2Ba
操作gydF4y2Ba | 复杂性gydF4y2Ba |
插入gydF4y2Ba | |
搜索gydF4y2Ba |
请注意,这是少数几个时间复杂度完全不取决于其中元素数量的数据结构之一。这是因为元素从来没有真正进入结构,只有它们的散列。gydF4y2Ba
空间gydF4y2Ba
要真正理解布隆滤波器的空间复杂性,首先必须选择参数。你可以用它来做bloom滤镜gydF4y2Ba 它就是agydF4y2Ba哈希表gydF4y2Ba这忽略了碰撞。然而,你会有一个非常大的gydF4y2Ba 如果你想降低误报率。实际数据结构(保存数据的地方)的空间很简单gydF4y2Ba .gydF4y2Ba
复杂性gydF4y2Ba | |
空间gydF4y2Ba |
Python实现示例gydF4y2Ba
下面是一个python实现。为了简单起见,省略了位数组组件;这里它只是一个初始化为全0的数组。为了简洁起见,这里只写了两个哈希函数。此实现仅用于学术目的。gydF4y2Ba
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38gydF4y2Ba |
|
测试布鲁姆滤镜gydF4y2Ba
让我们使用gydF4y2Ba以上gydF4y2Ba看看一旦我们开始插入元素,bloom过滤器会是什么样子。gydF4y2Ba
1 2 3 4gydF4y2Ba |
|
正如您所看到的,数组只是将0中的一个翻转为1,因为我们在这个实例中只使用了一个哈希函数。gydF4y2Ba
1 2 3 4 5 6gydF4y2Ba |
|
这里是字符串gydF4y2Ba“没有办法”gydF4y2Ba
不散列到相同的索引gydF4y2Ba“你好”gydF4y2Ba
.但是,字符串gydF4y2Ba“通用电气”gydF4y2Ba
所做的事。让我们尝试更多的哈希函数。gydF4y2Ba
1 2 3 4gydF4y2Ba |
|
现在我们有两个索引变成了一个因为我们使用了两个哈希函数。gydF4y2Ba
1 2 3 4gydF4y2Ba |
|
现在我们使用了更多的哈希函数,出现假阳性的概率下降了。另外,我们已经认不出来了gydF4y2Ba“通用电气”gydF4y2Ba
作为假阳性。gydF4y2Ba