使用布隆过滤器的好处是什么?


108

我正在阅读绽放过滤器,它们看起来很傻。使用Bloom Bloom过滤器可以完成的任何事情,都可以使用单个哈希函数而不是多个哈希函数在更少的空间内更有效地完成,或者就是这样。为什么要使用布隆过滤器,它有什么用?


5
你读过维基百科的文章吗?它很好地解释了优点。en.wikipedia.org/wiki/Bloom_filter
亚历Budovski

@david似乎不太可能。恒定空间中的k个哈希函数将比恒定空间中的单个哈希函数具有更多的冲突。
头痛,2010年

1
@Alex我已经阅读了维基百科的文章。我了解那里所说的话,但我不明白为什么它会更好。它为什么起作用很直观。为什么没有用呢?
头痛,2010年


2
@dranxo,链接的文章jasondavies.com/bloomfilter更好。
Pacerier,2015年

Answers:


155

维基百科

与其他表示集的数据结构相比,Bloom筛选器在空间上具有很大的优势,例如用于自平衡二进制搜索树,尝试,哈希表或简单数组或条目的链接列表的集合。其中大多数要求至少存储数据项本身,这可能需要从少量位(对于小整数)到任意位数(例如对于字符串)而言的任何地方(尝试是例外,因为它们可以在具有相同前缀的元素)。链接的结构会为指针带来额外的线性空间开销。另一方面,具有1%误差和k的最佳值的Bloom滤波器每个元素仅需要9.6位-不管元素的大小如何。这种优势部分是由于其紧凑性(继承自数组,部分是由于其概率性质。如果1%的误报率似乎太高,则每次我们为每个元素增加4.8位时,我们将其降低十倍。

我很清楚

Bloom过滤器不存储元素本身,这是关键。您无需使用Bloom筛选器来测试是否存在某个元素,而是使用它来测试它是否肯定存在,因为它可以确保不会出现假阴性。这样,您就不必为集合中不存在的元素(例如,用于查找它们的磁盘IO)做额外的工作。

而且所有空间都比哈希表之类的要少得多(对于大型数据集,哈希表可能会部分地位于磁盘上)。尽管可以将Bloom过滤器与哈希表之类的结构结合使用,但是一旦确定该元素有出现的机会。

因此,示例使用模式可能是:

您在磁盘上有很多数据-您决定要确定的错误界限(例如1%),该界限规定了m的值。然后确定最佳k(根据文章中给出的公式)。您一次从此磁盘绑定数据填充过滤器。

现在,您已将筛选器放入RAM。当您需要处理某些元素时,可以查询过滤器以查看它是否有可能存在于数据集中。如果没有,则不会进行任何额外的工作。没有磁盘读取,等等。(如果它是哈希或树,则必须这样做)。

否则,如果过滤器显示“是的,则在其中”,则有1%的可能性是错误的,因此您必须进行必要的工作才能找出答案。99%的时间,它确实在那儿,所以这项工作并非一无是处。


2
如果清楚,请回答。在相同大小的集合上,这可能比单个哈希函数在空间效率上更高?这只会产生更多的碰撞。您将在搜索单独的哈希函数时四处弹跳,以确保所有哈希函数都为1。我不了解使用单个哈希函数的优势。
头痛,2010年

19
哈希函数是代码,而不是数据。您打算将hash函数用于什么?哈希表?在这种情况下,您的表将需要存储键,该键可以具有任意大小,这与Bloom筛选器不同。摘录提到了这一点。
Alex Budovski

3
考虑只有一个哈希函数而不是k的Bloom过滤器。添加更多哈希函数的好处是什么?这只会产生更多的碰撞。还是我错了?
头痛,2010年

2
维基百科文章“空间和时间优势”的最后一段以及“误报的概率”部分对此做出了回答。
Alex Budovski

4
它只是单击。非常感谢,这困扰了我一段时间。它减少了误报的数量,因为误报将需要a)是所有哈希函数的冲突,或者b)所有空格都已被其他值填充。我想,选择大小一定是一个棘手的过程。如果我错了,请纠正我,但我想我明白了。谢谢大家。
头痛,2010年

156

亚历克斯解释得很好。对于那些仍不太了解它的人,希望这个例子可以帮助您理解:

假设我在Chrome小组中为Google工作,并且想向浏览器添加一项功能,该功能可以通知用户输入的网址是否是恶意网址。因此,我有大约100万个恶意URL的数据集,此文件的大小约为25MB。由于大小很大(与浏览器本身的大小相比很大),因此我将这些数据存储在远程服务器上。

情况1:我将哈希函数与哈希表一起使用。我决定使用高效的哈希函数,并通过哈希函数运行所有100万个url以获取哈希键。然后,我创建一个哈希表(一个数组),其中哈希键将为我提供放置该URL的索引。因此,现在一旦对哈希表进行哈希处理并填满,就可以检查其大小。我已经将所有100万个URL及其密钥存储在哈希表中。因此大小至少为25 MB。由于哈希表的大小,该哈希表将存储在远程服务器上。当用户出现并在地址栏中输入URL时,我需要检查它是否是恶意的。因此,我通过哈希函数运行URL(浏览器本身可以执行此操作),并且获得了该URL的哈希键。现在,我必须使用该哈希键向远程服务器发出请求,检查具有特定键的哈希表中的特定URL是否与用户输入的URL相同。如果是,则表示是恶意的,如果不是,则表示不是恶意的。因此,每次用户输入URL时,都必须向远程服务器发出请求,以检查它是否为恶意URL。这将花费大量时间,从而使我的浏览器变慢。

情况2:我使用布隆过滤器。一百万个URL的整个列表通过使用多个哈希函数的Bloom筛选器运行,并且各个位置被标记为1(以0组成的庞大数组)。假设我们要使用布隆过滤器计算器将误报率设为1%(http://hur.st/bloomfilter?n=1000000&p=0.01),则所需的布隆过滤器的大小仅为1.13 MB。这样的小尺寸是可以预期的,因为即使数组的大小很大,我们也只存储1或0,而不存储哈希表中的URL。该数组可以视为位数组。也就是说,由于我们只有两个值1和0,因此可以设置单个位而不是字节。这样可以减少占用空间8倍。这个1.13 MB的bloom过滤器由于体积小,可以存储在Web浏览器中!因此,当用户出现并输入URL时,我们只需应用所需的哈希函数(在浏览器本身中),并检查Bloom过滤器(存储在浏览器中)中的所有位置。任何位置的0值都告诉我们该URL绝对不在恶意URL列表中,用户可以自由进行。因此,我们没有呼叫服务器,因此节省了时间。值为1表示URL可能在恶意URL列表中。在这些情况下,我们将调用远程服务器,在那儿,我们可以像在第一种情况中一样,使用带有某些哈希表的其他哈希函数来检索并检查URL是否实际存在。在大多数情况下,URL不太可能是恶意的,因此浏览器中的小型Bloom过滤器指出了这一点,从而避免了对远程服务器的调用,从而节省了时间。仅在某些情况下,如果Bloom筛选器告诉我们URL MIGHT是恶意的,则仅在这些情况下,我们才对服务器进行调用。那“ MIGHT”是99%正确的。在这些情况下,我们将调用远程服务器,在那儿,我们可以像在第一种情况中一样,使用带有某些哈希表的其他哈希函数来检索并检查URL是否实际存在。在大多数情况下,URL不太可能是恶意的,因此浏览器中的小型Bloom过滤器指出了这一点,从而避免了对远程服务器的调用,从而节省了时间。仅在某些情况下,如果Bloom筛选器告诉我们URL MIGHT是恶意的,则仅在这些情况下,我们才对服务器进行调用。那“ MIGHT”是99%正确的。在这些情况下,我们将调用远程服务器,在那儿,我们可以像在第一种情况中一样,使用带有某些哈希表的其他哈希函数来检索并检查URL是否实际存在。在大多数情况下,URL不太可能是恶意的,因此浏览器中的小型Bloom过滤器指出了这一点,从而避免了对远程服务器的调用,从而节省了时间。仅在某些情况下,如果Bloom筛选器告诉我们URL MIGHT是恶意的,则仅在这些情况下,我们才对服务器进行调用。那个“ MIGHT”是99%正确的。浏览器中的小布鲁姆过滤器可以识别出来,从而避免了对远程服务器的调用,从而节省了时间。仅在某些情况下,如果Bloom筛选器告诉我们URL MIGHT是恶意的,则仅在这些情况下,我们才对服务器进行调用。那个“ MIGHT”是99%正确的。浏览器中的小Bloom过滤器可以解决这一问题,从而避免了对远程服务器的调用,从而节省了时间。仅在某些情况下,如果Bloom筛选器告诉我们URL MIGHT是恶意的,则仅在这些情况下,我们才对服务器进行调用。那个“ MIGHT”是99%正确的。

因此,通过在浏览器中使用小的Bloom过滤器,我们节省了很多时间,因为我们不需要为输入的每个URL进行服务器调用。

我们可以看到,具有单个哈希函数的哈希表与bloom过滤器的用途完全不同。希望这可以消除您的疑虑:)

编辑

我已经为Python中的恶意URL测试任务实现了Bloom Bloom过滤器。可以在这里找到代码-https: //github.com/tarunsharma1/Bloom-Filter 该代码非常易于理解,并且自述文件中提供了详细说明。


3
感谢您的用例场景。
斯奎格斯。

1
我没有涉及散列和将值0或1关联的部分。如果我们使用数组,并在其中存储0和1,那么在执行测试时如何查找url的散列值?
divinedragon

1
因此,基本上,我们使用一种称为哈希函数的东西。该函数将URL作为字符串接收并给出一个数字。我们使用此数字并将相应的数组索引值设置为1。存在许多不同的哈希函数,但是重要的是,每次通过散列函数传递相同的URL时,它都必须生成相同的数字。哈希函数的一个示例可能是将URL中所有字符的ascii值相加。在Bloom过滤器中,我们使用许多哈希函数并将所有这些数组索引值设置为1。希望这消除了您的疑问。
塔伦(Tarun)2015年

1
HashSet<String>在哈希表完全充满的最佳情况下,常规的哈希表(例如C#)将在每个元素元素上使用16个字节:从“存储桶”到条目表中的条目(映射为数组的单链接数组)映射4个字节列表),4个字节(用于缓存的哈希码),4个字节(用于“下一个”指针),4个字节(用于指向键的指针)。这还不包括字符串大小。在最坏的情况下,它是40个字节:一旦String指针扩展到64位体系结构的8个字节,则有一半的条目未使用,每个条目20个字节。
Qwertie

您不必将String本身保存在哈希集中。您可以将其哈希保存为值,从而使哈希集更小。然后,您可以使用哈希大小-越大,则误报率越小。
user1028741

24

我将首先解释什么是bloom过滤器,它可以做什么,不能做什么,我们为什么需要它,显示它的工作原理的直观描述,然后举例说明它们何时有用。

因此,标准的布隆过滤器概率数据结构可以*


  • 将元素添加到集合
  • 通过告诉definitely not in the set或检查元素是否在集合中possibly in the set

possibly in the set就是为什么它被称为概率论的原因。使用智能词意味着错误肯定是可能的(在某些情况下它会错误地认为元素是肯定的),而错误否定是不可能的。

但却不能 *

  • 从集合中删除一个项目
  • 为您提供当前集合中所有元素的列表

* 这套可以/不能用于基本的布隆过滤器。因为它是很久以前创建的有用数据结构,所以人们发现了如何使用其他有用功能来对其进行扩充


但是,请稍等:我们已经知道一个数据结构可以在没有模糊的“可能”且没有所有限制的情况下回答所有这些问题(无法删除,无法显示全部)。它称为集合。布隆过滤器的主要优点是:空间效率高且空间常数

这意味着我们在那里存储多少元素都没有关系,空间将相同。是的,具有10^6元素的bloom过滤器(无用的bloom过滤器)将与具有元素的bloom过滤器占用相同的空间,并且与具有10^20元素的bloom过滤器占用相同的空间0。那么需要多少空间?由您决定(但是要权衡:您拥有的要素越多,possible in the set回答的不确定性就越大。

另一个很酷的事情是它是空间常数。将数据保存到集合中时,实际上必须保存此数据。因此,如果存储this long string in the set,则必须至少使用27个字节的空间。但是对于1%的错误和k **的最佳值,每个元素(无论是int的短文本还是巨大的文本墙)都需要〜9.6位(<2个字节)。

另一个特性是,所有操作都采用恒定时间,这与集合的情况下的分摊的恒定时间绝对不同(请记住,如果集合发生冲突,则O(n)时间可能会恶化)。

** k是布隆过滤器中使用的哈希函数的值


我不会描述布隆过滤器的工作原理(维基百科文章在解释所有内容方面做得很好)。在这里,我将简要介绍一下基本知识。

  • 您启动一个空的长度数组 m
  • 您选择k不同的哈希函数(越独立越好)
  • 如果要添加元素,则计算该k值的所有哈希并将相应的位设置为1
  • 如果要检查元素是否存在,则还要计算所有k哈希,如果没有设置至少其中之一,则肯定不在集合中。否则,它可以在集合中。

甚至这个描述也足以理解为什么我们不能确定(您可以从其他各种值中设置所有位)。这是一个很好的可视化工作原理

在此处输入图片说明


那么布隆过滤器什么时候有用?简短的答案是在任何地方都可以接受误报,并且您希望检查其中是否有东西,但是即使不是,也可以作为排除昂贵的要求验证者的第一道防线。

这是更具体的描述列表:

  • 人们几乎在谈论绽放过滤器的任何地方都描述了恶意网站和浏览器的标准示例
  • 是弱密码:您可以使用较小的Bloom过滤器来检查密码是否一定不是弱密码,而不是拥有大量所有可能的弱密码
  • 如果您有文章列表和用户列表,则可以使用Bloom筛选器显示用户尚未阅读的文章。有趣的是,您只能有一个过滤器(您检查是否有user_id + article_id的组合)
  • 比特币使用布隆过滤器进行钱包同步
  • Akamai的Web服务器使用Bloom过滤器来防止“一击打败”被存储在其磁盘缓存中。一击入奇的是用户一次请求的Web对象,Akamai发现这种对象应用于他们近四分之三的缓存基础结构。使用Bloom筛选器检测对Web对象的第二个请求并仅在其第二个请求上缓存该对象,可以防止一击式奇迹进入磁盘缓存,从而显着减少磁盘工作负载并提高磁盘缓存命中率(摘自Bloom筛选器中的示例)维基上的文章)

13

布隆过滤器在生物信息学中非常有用。与使用常规散列相比,它们可以更节省空间,尤其是当您使用的字符串的大小可以是亿万个字母且字母非常小的字母,例如{A,G,T,C}时。它们通常用于评估基因组中是否存在某种k-mer。这里有一个例子用于相关的事情

编辑:

多个哈希函数用于最小化误报。希望与所有其他可能值相比,在所有k哈希函数之间,每个值在位数组中将具有唯一的签名。但是,确实存在误报,但可以将其最小化到可管理的水平。使用此技术,您可以独立于元素的大小对哈希进行哈希处理。搜索它们时,请使用每个哈希函数,并检查以确保它们的位值均为1。

将此与人类基因组进行比较,在人类基因组中,元素大小的增加会显着增加哈希表的大小(表大小为4 * 4 k)。假设您使用2位/字母对元素进行编码。


1
抱歉,也许我误会了,但与常规哈希相比,它们如何在空间上更有效?字符串的哈希是固定长度的输出,您只需将该值设置为0或1。这也是Bloom过滤器会执行的操作,但是Bloom过滤器会在多个哈希函数上执行此操作。我在哪里误会?
头痛,2010年

仅存储单个哈希没有太大用处。这样就无法处理哈希冲突。大多数哈希表实现都有一种处理这种方法的方法,这会产生开销。例如,Python字典将密钥存储在散列旁边,并在发生冲突时开始线性探测。布隆过滤器将其切出,并尝试通过使用多个散列来将这样做固有的损害降到最低。
Bret Fontecchio 2014年

1
为什么不创建仅具有一个哈希函数的布隆过滤器?也许是“相对较大”的哈希函数。但不是很多而是一个
giorgim

7

如果Bloom过滤器返回某项是集合的成员,则很可能会出现误报。如果仅使用单个哈希函数来指示集合中的成员身份,则误报的概率将比使用多个哈希函数高。


需要对答案的内容进行认真的阐述:“ 假阳性的概率要高于使用多个哈希函数的概率 ” ...
Pacerier,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.