概率数据结构:布隆过滤器

如果您有玻璃保护的书架,则可以保护书本免受灰尘和昆虫的侵害,但是如果需要,它将花费更多时间来访问这些书本。因为您首先需要滑动或打开玻璃板,然后才能拿到书本。另一方面,如果它是一个开放的书架,则可以使您更快地访问,但您将失去保护。同样,如果您按书名的书名顺序对书进行整理,则只要知道书名即可轻松搜索。但是,如果您的书架上有不同大小的箱子,并且根据它们的大小来组织书籍,那么看起来会不错,但是您可以急忙找到一本书吗?我不这么认为。

数据结构没有什么不同。它们就像您的应用程序的书架,您可以在其中组织数据。不同的数据结构将为您提供不同的便利和收益。要正确使用数据结构的功能和可访问性,您需要了解使用一种数据结构的权衡。

当主流数据结构(如列表,地图,集合,树等)主要用于获得有关数据是否存在的某些结果时,也许连同它们的出现次数等,概率数据结构将为您提供高效的内存更快的结果,但需要付出代价才能提供“可能的”结果而不是“确定的”结果。现在使用这种数据结构似乎并不直观,但是我将在本文中尝试说服您这些类型的数据结构具有其特定的用例,并且您可能会发现它们在某些情况下很有用。

在这篇文章中,我将讨论一种叫做'Bloom filter'的最流行的概率数据结构。将来,我将尝试写一些其他文章。

布隆过滤器

您知道哈希表如何工作吗?当您在简单数组或列表中插入新数据时,将不会从要插入的值中确定要在其中插入该数据的索引。这意味着“键(索引)”和“值(数据)”之间没有直接关系。结果,如果需要在数组中搜索值,则必须在所有索引中搜索。现在,在哈希表中,您可以通过对“值”进行哈希处理来确定“键”或“索引”。然后,将此值放在列表中的该索引中。这意味着“键”是由“值”确定的,每次您需要检查列表中是否存在该值时,只需对值进行哈希处理并在该键上进行搜索即可。它非常快,并且需要Big(O)表示形式的O(1)搜索时间。

 

现在,让我们考虑一下,您有大量的弱密码列表,它存储在某些远程服务器上。由于大小原因,无法一次将它们加载到内存/ RAM中。每次用户输入密码时,您都要检查它是否为弱密码之一,如果是,则要发出警告以将其更改为更强的密码。你能做什么?由于已经有了弱密码列表,因此您可以将它们存储在哈希表或类似的表中,并且每次想要匹配时,都可以检查给定的密码是否匹配。匹配可能很快,但是在磁盘上或通过远程服务器上的网络搜索它的成本将使其变慢。不要忘记,您需要为每个用户提供的每个密码执行此操作。我们如何降低成本?

好吧,布隆过滤器可以在这里为我们提供帮助。怎么样?在解释布隆过滤器的工作原理之后,我将回答它。好?

根据定义,Bloom过滤器可以检查值是“可能在集合中”还是“绝对不在集合中”“可能”“绝对不是” 之间的细微差别在这里至关重要。这就是“可能在集合中”的确切原因,它被称为概率论。使用智能词意味着可能会出现误报(有时会错误地认为该元素为正),而不会出现误报。别急,我们正在解释这实际上是什么意思。

Bloom过滤器实质上由长度为m的位向量或位列表(仅包含0或1位值的列表)组成,最初所有值均设置为0,如下所示。

 

图片来源:GeeksforGeeks

为了将项目添加到Bloom过滤器中,我们将其提供给k个不同的哈希函数,并将结果位置的位设置为“ 1”。如您所见,在哈希表中,我们将使用单个哈希函数,因此仅获得单个索引作为输出。但是对于Bloom Bloom过滤器,我们将使用多个哈希函数,这将为我们提供多个索引。

 

图片来源:GeeksforGeeks

如上例所示,对于给定的输入“怪胎”,我们的3个哈希函数将提供3个不同的输出-1、4和7。我们已对其进行了标记。

 

图片来源:GeeksforGeeks

对于另一个输入“书呆子”,哈希函数给我们3、4和5。您可能已经注意到,索引“ 4”已经被先前的“怪胎”输入标记了。保持您的想法,这很有趣,我们将在短期内讨论。

我们已经用两个输入填充了位向量,现在我们可以检查它是否存在。我们该怎么做? 
简单。就像我们在哈希表中一样。我们将使用3个散列函数对“搜索到的输入”进行散列,并查看保留的结果是什么。

 

图片来源:GeeksforGeeks

因此,搜索“ cat”时,我们的哈希函数这次给了我们1、3和7。并且我们可以看到所有索引都已标记为1。这意味着我们可以说“也许'cat'已经插入到我们的列表中”。但事实并非如此。那么,出了什么问题? 
实际上,没有错。事实是,这是“误报”的情况。Bloom过滤器告诉我们,似乎之前已经插入了“ cat”,因为应该已经用“ cat”标记了索引(尽管已经用其他不同的数据标记)了。
那么,如果是这样,它有什么帮助?好吧,让我们考虑一下,如果“ cat”给我们的输出为1、6、7而不是1、3、7,那会发生什么?我们可以看到,在3个索引中,6是'0',这意味着它没有被任何先前的输入标记。这显然意味着“ cat”以前从未插入过,如果已经插入,则不可能有6变为“ 0”,对吧?这样,bloom筛选器可以“确定”地判断数据是否不在列表中。

因此,简而言之:

  • 如果我们搜索一个值,并且看到该值的任何哈希索引为“ 0”,那么该值肯定不在列表中。
  • 如果所有哈希索引均为“ 1”,则“也许”搜索到的值在列表中。

它开始有意义吗?也许一点?

好了,现在,回到我们前面讨论的“密码”示例。如果我们使用这种类型的Bloom过滤器实施弱密码检查,您会看到,最初,我们将使用我们的密码列表标记Bloom过滤器,这将为我们提供一些带有标记为“ 1”的索引的矢量设置为0。由于Bloom筛选器的大小不会很大,并且将是固定大小,因此可以轻松地将其存储在内存中,并在必要时存储在客户端。这就是Bloom过滤器非常节省空间的原因。如果哈希表要求基于输入数据具有任意大小,则布隆过滤器可以在固定大小的情况下很好地工作。 
因此,每次用户输入密码时,我们会将其提供给哈希函数,并根据我们的位向量进行检查。如果密码足够强,bloom筛选器将向我们显示该密码肯定不在“弱密码列表”中,并且我们无需再进行任何查询。但是,如果密码看起来很弱,并且给我们一个“肯定”(可能是假肯定)结果,我们将把它发送到我们的服务器并检查我们的实际列表以进行确认。

如您所见,大多数情况下,我们甚至不需要向服务器发出请求或从磁盘读取数据来检查列表,这将大大提高应用程序的速度。以防万一,如果我们不想在客户端存储位向量,我们仍然可以将其加载到服务器内存中,这至少可以节省一些磁盘查找时间。还要考虑一下,如果您的Bloom过滤器误报率是1%(我们将在后面详细讨论错误率),这意味着在到服务器或磁盘的昂贵往返中,只有1%的查询是返回错误的结果,其他99%不会白费。 
还不错吧?

 

关于布隆过滤器如何工作的漂亮视觉模拟。图片来源:WikiPedia

布隆过滤器操作

基本的Bloom过滤器支持两种操作:testadd

测试用于检查给定元素是否在集合中。

添加只是将元素添加到集合中。

现在给您一个小测验。

根据到目前为止的讨论,是否可以从Bloom过滤器中删除项目?如果是,那怎么办?

休息2分钟,考虑解决方案。

有什么吗 没有?我帮你一下 在插入“怪胎”和“书呆子”之后,让我们带回位向量。

 

图片来源:GeeksforGeeks

 

图片来源:GeeksforGeeks

现在我们要从中删除“怪胎”。因此,如果我们从位向量中删除1、4、7(由“极客”标记)并将其转换为“ 0”,将会发生什么?您可以很容易地看到,下次我们搜索“书呆子”时,由于索引“ 4”将显示为“ 0”,因此可以肯定地告诉我们“书呆子”不在列表中,尽管实际上在列表中。这意味着在不引入假阴性的情况下就不可能去除。

那么,有什么解决方案?

解决的办法是我们不能在此简单的Bloom过滤器中支持Remove操作。但是,如果我们确实需要删除功能,则可以使用Bloom过滤器的一种变体,称为“ Counting bloom filter”。这个想法很简单。我们将不存储单个值,而是存储一个整数值,然后我们的位向量将是一个整数向量。这将增加尺寸,并花费更多的空间来提供给我们删除功能。我们将在插入值时不只是将位值标记为“ 1”,而是将整数值增加1。要检查元素是否存在,请在对元素进行哈希处理后检查相应的索引是否大于0。 
如果您很难理解“计数布隆过滤器”如何为我们提供“删除”功能,建议您拿一支笔和纸,将我们的布隆过滤器模拟为计数过滤器,然后尝试删除它。希望您会轻松获得它。如果失败,请重试。如果您再次失败,请发表评论,我将尽力描述。

布隆过滤器的大小和哈希函数的数量

您可能已经了解,如果Bloom筛选器的大小太小,很快所有的位字段都将变为1,然后我们的Bloom筛选器将为每个输入返回“ false positive”。因此,布隆过滤器的尺寸是一个非常重要的决定。较大的滤波器将具有较少的误报,而较小的将为零。因此,我们可以根据“误报错误率”将布隆过滤器调整为需要多少精度。 
另一个重要参数是“我们将使用多少个哈希函数”。我们使用的哈希函数越多,bloom过滤器将越慢,并且其填充越快。但是,如果数量太少,我们可能会遭受太多误报。

 

图片来源:Abishek Bhat关于绽放过滤器的文章

从上图可以看出,增加哈希函数k的数量将大大降低错误率p

我们可以根据过滤器的大小m,哈希函数数k以及插入的元素数n来计算误报率p,公式如下:

 

好像是WTF?不用担心,实际上我们实际上最需要确定我们的mk。因此,如果我们自己设置容错值p和元素数n,则可以使用以下公式来计算这些参数:

 

我还要在这里提到另一个重要的观点。由于使用Bloom筛选器的唯一目的是搜索速度更快,因此我们不能使用慢速哈希函数,对吗?加密散列函数(例如Sha-1,MD5)对于bloom过滤器不是一个好选择,因为它们有点慢。因此,从更快的哈希函数实现中更好的选择是murmurfnv系列哈希,Jenkins哈希和HashMix

应用领域

布隆过滤器仅用于测试集合中的成员资格。使用布隆过滤器的经典示例是减少对不存在的密钥的昂贵磁盘(或网络)查找。正如我们看到的那样,布隆过滤器可以在O(k)恒定时间内搜索密钥,其中k是哈希函数的数量,测试密钥的不存在将非常快。

如果该元素不在bloom过滤器中,那么我们可以确定不需要执行昂贵的查找。在另一方面,如果在布隆过滤器中,我们进行查找,我们可以期望它失败的时候一定比例(假阳性率)。

对于一些更具体的例子:

  • 在给定的示例中您已经看到,我们可以使用它来警告用户输入弱密码。
  • 您可以使用布隆过滤器,以防止用户访问恶意网站
  • 您可以先使用Bloom Bloom筛选器进行廉价的查找检查,而不是查询SQL数据库以检查是否存在具有特定电子邮件的用户。如果电子邮件不存在,那就太好了!如果确实存在,则可能必须对数据库进行额外的查询。您也可以执行同样的操作来搜索“用户名已被使用”
  • 您可以根据网站访问者的IP地址保留一个Bloom过滤器,以检查您网站的用户是“回头用户”还是“新用户”。“回头用户”的一些误报不会伤害您,对吗?
  • 您还可以使用Bloom Bloom过滤器来跟踪字典单词,从而进行拼写检查
  • 想知道Medium如何使用bloom filter来确定用户是否已经阅读帖子吗?阅读有关此文章的令人震惊,令人震惊的真棒

您是否仍然认为将不再需要布隆过滤器?好吧,我们不会使用我们在日常生活中学到的所有算法。但是也许有一天它可能会节省您的时间。谁知道?学习新事物永远不会有害,对吗?

附上演示地址:https://www.jasondavies.com/bloomfilter/

演示图:

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值