有防布隆过滤器吗?


25

一个布隆过滤器能够有效地跟踪是否处理过程中已经遇到的各种值。当有许多数据项时,布隆过滤器可以节省散列表上的大量内存。与哈希表共享的Bloom筛选器的主要功能是,如果某项不是新项,则始终显示“ not new”,但将项标记为“ not new”的可能性不为零。即使是新的。

是否有行为相反的“抗布鲁姆过滤器”?

换句话说:是否存在一个有效的数据结构,如果某项是新项,它会显示“ new”,但对于某些非新项也可能会显示“ new”?

保留所有先前看到的项(例如,在排序的链表中)可以满足第一个要求,但可能会占用大量内存。考虑到第二个要求放宽,我希望这也是不必要的。


对于那些更喜欢正式对待的人,如果Bloom过滤器认为是新的,则写,否则,写,如果确实是新的,写,而否则。b(x)=1xb(x)=0n(x)=1xn(x)=0

然后 ; ; ; ,对于某些。Pr[b(x)=0|n(x)=0]=1Pr[b(x)=0|n(x)=1]=αPr[b(x)=1|n(x)=0]=0Pr[b(x)=1|n(x)=1]=1α0<α<1

我在问:是否存在有效的数据结构,实现了函数且其值,因此 ; ; ; ?b0<β<1Pr[b(x)=0|n(x)=0]=βPr[b(x)=0|n(x)=1]=0P - [R [ b 'X = 1 | n x = 1 ] = 1Pr[b(x)=1|n(x)=0]=1βPr[b(x)=1|n(x)=1]=1


编辑:似乎以前在StackExchange上已经问过这个问题,如/programming/635728/cstheory/6596,其中包含“无法通过“可以花一些钱来完成”到“通过反转的值来做到这一点是微不足道的”。我还不清楚“正确”的答案是什么。什么明确的是,某种类型的LRU缓存机制(如ILMARI Karonen建议的一个)的作品相当好,很容易实现,并且获得在运行我的代码所花费的时间减少了50%。b


由于某种原因,我很想说这与缓存和缓存放置算法试图解决的问题非常相似。考虑使用最少使用(LFU)替换的缓存。从理论上讲是最佳的但不可能的替换算法将是驱逐您最长不会再次看到的算法,与缓存一样。我想缓存取决于一些关于分布性质的假设,这些假设可能通常不适用,但是值得考虑一下是否适用。
Patrick87

您可能对以下演讲感兴趣:基于满意度的集合成员资格过滤器
Kaveh 2014年

@Kaveh:感谢您的指点,会注意的。
安德拉斯·萨拉蒙

Answers:


12

遵循Patrick87的哈希概念,这是一种几乎可以满足您要求的实用构造—错误地将旧值误认为新值的可能性不为零,但可以轻易将其减小。

选择参数和;实际值可能是和。令为一个安全的密码哈希函数,产生(至少)位输出。k n = 128 k = 16 H n + knkn=128k=16Hn+k

令为位比特串的数组。该数组使用总共位存储过滤器的状态。(该数组的初始化方式并不重要;我们可以用零或随机位填充它。)2 ķ Ñ Ñ 2 ķa2k nn2k

  • 到一个新的值添加到过滤器,计算,其中,表示第一比特和表示下列的比特。令。xi k j n H x a i = jij=H(x)ikjnH(x)ai=j

  • 要测试是否已将值添加到过滤器中,请如上所述计算,然后检查。如果是,则返回true;否则,返回true。否则返回false。'xa i ' = j 'ij=H(x)ai=j

声明1:误报(=错误地声称已经看到新值)的概率为。通过增加,可以以适度的存储空间成本将其任意减小。特别是对于,该概率基本上可以忽略不计,实际上比由于硬件故障而导致误报的概率小得多。 Ñ Ñ 1281/2n+knn128

特别地,在已经检查了不同值并将其添加到过滤器之后,至少一个假阳性已经发生的概率为。例如,在和,以50%的概率获得假阳性所需的不同值的数量约为。N 2 - N / 2 n + k + 1 n = 128 k = 16 2 n + k / 2 = 2 72N(N2N)/2n+k+1n=128k=162(n+k)/2=272

声明2:假阴性(=先前误认为是新增加的值)的概率不大于,其中是添加到过滤器的不同值的数量(或更具体地说,是最近将测试的特定值添加到过滤器之后添加的不同值的数量)。 Ñ1(12k)N1exp(N/2k)<N/2kN


附言 为了使“微不足道的小”成为现实,使用当前已知的技术通常认为 128位加密是坚不可摧的。从此方案中获得误报的可能性与某人在首次尝试中正确猜出您的128位秘密密钥一样。(对于和,实际上它的可能性比这少65,000倍。)n = 128 k = 16n+k=128n=128k=16

但是,如果那仍然让您感到不合理的紧张,您可以随时切换到;它将使您的存储需求增加一倍,但是我可以安全地打赌,只要您愿意说出一笔总和,就不会有人看到的误报 —假设哈希函数始终没有中断。n = 256n=256n=256


1
不仅可以使这种可能性与硬件故障的可能性相当;也可以使它与有人在第一次尝试时猜测您的RSA密钥进行SSH登录的可能性具有可比性。IMO比前者更能传达您解决方案的实用性。
R.,

+1非常好-我的理解是,这样可以解决空间效率问题,方法是允许一些(很小的)机会在物品实际上是新货时错误地回答“不是新货”。非常实用,而且分析很好。
Patrick87

1
权利要求1仅说明体面的哈希函数具有较低的冲突概率。如果至少为50左右,则实际上已经是这样。对于我的应用程序,和可以与简单的64位,非加密安全但快速的哈希函数配合使用。n = 44 k = 20n+kn=44k=20
2014年

@AndrásSalamon:是的,尽管安全的加密哈希函数实际上提供了更强的保证:即,即使您试图故意寻找冲突输入,也不可能找到冲突输入。对于足够大的(例如,我上面建议的),这意味着即使假阳性的代价很高,即使有可能主动寻找对手,也不需要存储完整数据。当然,如果您不需要那么强大的保证,则可以接受更高的碰撞风险。n = 128nn=128
Ilmari Karonen 2014年

1
@Newtopian之所以指定密码哈希函数,是因为对于这些哈希函数,没有一种比暴力破解更有效地产生冲突的方法(即通过测试大量输入并选择发生冲突的输入),否则将考虑使用哈希损坏(例如,如今的MD5)。因此,对于密码哈希,我们可以很安全地假设冲突率与理想的随机哈希函数相同。使用通用哈希函数或带密钥的MAC(带有随机密钥)将使这种保证更加强大。
Ilmari Karonen

8

不,如果您想保证数据结构真的是新数据,那么就不可能拥有具有这些属性的高效数据结构(如果确实是新数据,则数据结构将说“新”(如果它实际上是新的;不允许出现假阴性)。任何此类数据结构都将需要保留所有数据以响应“不是新的”。有关正确的理由,请参阅pents90的cstheory答案

相反,Bloom过滤器可以保证以高效的方式将数据结构说成“不是新的”(如果不是新的)。特别是,Bloom筛选器比存储所有数据更有效:每个单独的项可能很长,但是Bloom筛选器的大小与项数(而不是它们的总长度)成比例。您问题的任何数据结构都必须与数据的总长度(而不是数据项的数量)成比例。


另请参阅接受的答案,因为这个问题同样存在

-1当您说不可能时,您应该确定您的意思。显然,有可能高效地做到这一点,而且还可能以低错误率做到这一点,因此在给定的实现中取得一定的平衡应该是可行的……尤其是,确切地解释其含义是有用的。 “有史以来所有数据”,因为严格来说这不是满足问题的要求。假阴性-答案应为“不是新的”时回答“新”,因此,不需要保留所有数据。
Patrick87

1
这个答案是完全合理的,似乎可以解决我的问题的实质,但也许不是精神。
安德拉斯·萨拉蒙

@DW感谢您抽出宝贵的时间来更新答案。尽管我仍然反对描述抗bloom过滤器效率低下时所使用的语言,但我倾向于现在将其作为答案,除了认为最好对所引用的“详细信息”进行详细说明之外。 ..暂时离开-1。清理了一些过时的注释。
Patrick87

@DW通过“假否定”,我打算在答案应该是“不是新的”时回答“新的”。(有些不符合直觉的说法是“不是新的”在这里是肯定的情况。)您无需保存“所有数据”就可以做到这一点,尽管我倾向于认为您确实需要保存整个元素(只是并非所有要素-除非您愿意接受假设的有意义的错误机会(根据此处对问题的其他回答,就可以了。)
Patrick87,2014年

6

哈希表呢?当您看到新项目时,请检查哈希表。如果该项目的现货为空,则返回“新”并添加该项目。否则,请检查该物品的位置是否被该物品占用。如果是这样,则返回“不是新的”。如果该地点被其他项目占用,则返回“新”并用新项目覆盖该地点。

如果您以前从未看过该项目的哈希,则肯定会始终正确获得“ New”。如果您只在看到同一项目时才看到该项目的哈希值,则肯定会始终正确获得“ Not New”。正确答案是“不是新的”时,唯一会得到“新”的信息是,如果看到项目A,然后看到项目B,然后又看到项目A,并且A和B都哈希到同一个东西。重要的是,您永远不会错误地获得“ Not New”。


1
我想这种忽略空间效率的问题,或者说效率远不如布隆过滤器有效,因为布隆过滤器实际上每个存储桶只需要一点点,并且每个存储桶需要的空间与代表项目。哦,好吧……除非宇宙是有限的(如在Wandering Logic的回答中那样),我认为您可能无法非常接近Bloom过滤器的空间效率。
Patrick87

就个人而言,我认为您的答案比我的要好。如果您希望概率大于50%,则布隆过滤器不仅只是每个存储区的一部分。它也是固定大小,一旦填满一半以上,误报的可能性就会急剧增加。没有方便的方法来扩展它,没有方便的方法将其用作缓存,也没有方便的方法来删除元素。我要一个哈希表的每个时间。
流浪逻辑

@WanderingLogic使用较小的饱和计数器而不是单个位可以支持删除(显然,以容量为代价,并且仅当计数器未达到最大值时)。
保罗·克莱顿

4

如果项目的范围是有限的,那么可以:只需使用Bloom Bloom过滤器来记录哪些元素不在集合中,而不是在集合中。(即,使用布隆过滤器代表感兴趣的集合的补充。)

一个有用的地方是允许进行有限形式的删除。您保留两个Bloom过滤器。他们开始是空的。插入元素时,将它们插入到Bloom过滤器A中。如果以后要删除某个元素,则将该元素插入到Bloom过滤器B中。无法取消删除。若要进行查找,请先在Bloom过滤器A中查找。如果找不到匹配项,则永远不会插入该项目(概率为1)。如果找到匹配项,则可能已(或可能未)插入元素。在这种情况下,您将在Bloom筛选器B中进行查找。如果找不到匹配项,则该项目将不会被删除。如果在布隆过滤器B中确实找到匹配项,则该项目可能已插入然后删除。

这并不能真正回答您的问题,但是,在这种有限的情况下,bloom过滤器B恰好执行了您要寻找的“抗bloom过滤器”行为。

Real Bloom筛选器研究人员使用更有效的方式表示删除,请参阅Mike Mitzenmacher的出版物页面


在这个问题中,我们正在处理项目,并且没有删除。在没有从bloom过滤器中删除项目的情况下,没有什么有意义的方式来存储赞美词
2014年

1
@乔:我同意这个问题通常是无法解决的,所以我的回答仅限于补数有限且很小的情况。
流浪逻辑

1

vi

一个示例可能是ip地址,并且您想知道每次出现从未见过的情况。但这仍然是一个有限集合,因此您知道可以期望什么。

实际的解决方案很简单:

  1. 将所有项目添加到计数布隆过滤器。
  2. 1
  3. 看到实际的新项目后,将其从过滤器中减去。

因此,您可能具有实际上是旧的但被识别为新的“误报”值。但是,对于新值,您将永远不会“不新鲜”,因为它的值仍将存在于所有插槽中,并且没有其他人可以将其取走。

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.