【发布时间】:2009-05-15 05:32:47
【问题描述】:
你更喜欢哪个,为什么?
它们都可以用来完成类似的任务,但我很好奇人们在实际应用中使用了什么以及他们这样做的理由。
【问题讨论】:
标签: algorithm filter hash bloom-filter
你更喜欢哪个,为什么?
它们都可以用来完成类似的任务,但我很好奇人们在实际应用中使用了什么以及他们这样做的理由。
【问题讨论】:
标签: algorithm filter hash bloom-filter
Bloom 过滤器和 Cuckoo 过滤器在类似的情况下使用,但有很多不同之处通常决定了哪个是更好的选择。
布隆过滤器在数据库引擎内部使用,尤其是 Apache Cassandra。原因正如其他发帖者所说,为了降低慢集操作的成本。基本上,任何“这可能存在或绝对不存在”的高成本操作都可以使用布隆过滤器来减少完成的检查次数。
当今 SaaS 模型的另一个常见示例是具有每次调用成本的远程 REST 服务。任何带有二进制答案的 API 调用(例如“此地址是否无效”)都可以使用布隆过滤器来消除 90% 以上的重复查询!请注意,由于 Bloom 和 Cuckoo 过滤器具有误报,因此它们对于“此地址是否有效”的逆运算没有用处
重要的是要记住,Bloom 和 Cuckoo 过滤器没有误报。这使得这些过滤器对于诸如“这绝对不是垃圾邮件或可能是垃圾邮件”之类的检查很有用,但对于不可接受误报的操作(例如检查用户权限)则无用。在这方面,它们在概念上可以被认为是缓存的对立面。 Bloom/Cuckoo 过滤器和缓存都主要用于通过布尔答案降低昂贵操作的成本,除了缓存没有误报,Bloom/Cuckoo 没有误报。
Cuckoo/Bloom 之间的显着差异包括:
组合。只要使用相同的参数创建布隆过滤器,就可以有效地合并它们。快速且带宽小。这就是为什么你会看到它们在大规模分布式系统中经常使用,交换 Bloom 过滤器很快。 Cuckoo 过滤器不容易组合,因此在这些情况下它们的用处不大。
假阳性率。 Cuckoo 过滤器更节省空间。这两种结构的许多用例都集中在低级网络上。在弱硬件上,对于相同的误报率,Cuckoo 过滤器的效率提高约 40% 可能很重要。参考实现,在 C++ 中,对每个桶中的项目进行排序以节省额外的空间,利用项目在桶中的位置来存储较小的指纹。我稍后会提到的其他库(包括我的)似乎没有这样做。如果有人使用我的库,我可能会添加它:)。
恒定的误报率。布隆过滤器的误报率越来越差,因为它们超过了设计的大小。您可以永远插入项目,但最终您的误报率将接近 100%。基于 Cuckoo 散列的 Cuckoo 过滤器具有一定的容量,其中插入实际上会失败。重复插入非随机项哈希可能会导致 Cuckoo 过滤器插入失败,可能远远低于其设计的填充水平。
速度。这是主观的,很大程度上取决于硬件,但 Cuckoo 过滤器在一般情况下通常更快(根据我的经验)。大多数布隆过滤器设计运行一个哈希函数两次。特别是在使用安全散列函数时,与只散列插入的项目一次的 Cuckoo 过滤器相比,这可能是一个很大的障碍。我看到的代码对 Bloom 和 Cuckoo 过滤器使用了各种散列函数。 Google 的 Guava Bloom 使用 Murmur3,许多其他实现使用 SHA1 或其他东西。如果您的用例可以利用散列冲突,请确保库使用安全散列。重要的是要知道 Bloom 过滤器的插入时间大致恒定,而 Cuckoo 过滤器的插入时间是恒定的 AVERAGE 情况。由于 Cuckoo 过滤器在容量的百分之几以内,插入速度会大大降低。即使这样,只有插入速度变慢,所有其他操作都是恒定的平均时间。
灵活性。布隆过滤器仅支持插入和包含。 Cuckoo 过滤器还支持删除和有限计数。在参考设计中,Cuckoo 过滤器可以确定一个项目被插入了多少次,最多 7 次。布隆过滤器只能确定是-否。 Cuckoo 过滤器还支持删除插入的项目,与 Bloom 相比,这在许多用例中是一个很大的优势。使用 Bloom 过滤器时,当过滤器“已满”(估计误报率超过阈值)时从头重新创建过滤器是非常标准的,因为您无法删除旧项目。请注意,当插入开始失败时,Cuckoo 过滤器仍然会重建过滤器,因此根据用例,这可能没有实际意义。在某些情况下,Cuckoo 过滤器更有用,因为您可以删除项目以保持在过滤器限制范围内,而不是重建。
支持。 Cuckoo 过滤器是许多语言的新的稳定库,根本不存在。
布隆过滤器的最大优势是它们在大多数语言中都有更成熟的库支持。布隆过滤器背后的数学原理也被科学家们更好地理解了。 Cuckoo 过滤器的大部分特性都是根据经验确定的,而 Bloom 过滤器具有坚实的数值基础。这不包括必须对其性能进行验证的实时和关键系统的 Cuckoo 过滤器,尽管实验证据表明 Cuckoo 过滤器在大多数情况下表现更好。
Shameless Plug:我是 Java 的 Cuckoo 过滤器库的开发人员。 CuckooFilter4J 。它缺少论文中使用的桶半排序,因此空间效率略低于参考实现。在项目自述文件中,我有指向我知道的其他实现的链接。哪种结构更好取决于您的用例,但主要取决于您的语言是否存在可靠的 Cuckoo 过滤器实现。
在生产环境中使用 Cuckoo/Bloom 过滤器之前,您绝对应该查看源代码。在编写自己的库之前,我通读了各种库……由于 32 位底层数组或明显的性能问题,其中许多库具有静默大小限制。大多数人的测试为零。 Google 的 Guava Bloom 实现具有迄今为止最好的代码质量和测试(并支持 64 位数组限制)。 Guava 的 Bloom 唯一的缺点是它没有使用安全哈希函数的选项并且不是多线程的。
在生产系统中,您可能需要多线程以提高速度。 Guava's Bloom 的答案是为每个线程制作不同的过滤器,并偶尔将它们组合起来。由于 Cuckoo 过滤器无法组合,因此我在 Cuckoo 过滤器库中添加了并发线程。我知道的另一个不是线程安全的或不是并发的。
【讨论】:
你更喜欢哪一种,葡萄酒还是奶酪?
bloom 过滤器适用于空间有限、查询成本高和大部分为否定查询 .
在这种情况下,bloom 过滤器具有每个键 8 位和 4 个哈希函数,可以为您提供 2.5% 的误报率;您处理查询的速度比以前快 40 倍,代价是 每个键 1 个字节。
另一方面,如果任何前面的条件不成立,哈希表作为缓存是有意义的,虽然它显然需要一个每个条目超过一个字节 :-)
如果是缓存,您甚至可以跳过 cuckoo hashing 的硬边缘情况。这也使得 cuckoo 哈希表(或除线性哈希之外的任何东西)的大小增加问题没有实际意义。
【讨论】:
我更喜欢杜鹃哈希。
我对在较高填充因子的布隆过滤器中可能出现的误报保持警惕。
在我们有非常大的哈希表并且遇到内存压力问题的应用程序中使用了布谷鸟哈希。
请参阅我的 eCollections 库 http://codeplex.com/ecollections,了解布谷鸟散列变体的实现。
亲切的问候,
【讨论】:
杜鹃过滤器。
“Cuckoo 过滤器:实际上比 Bloom 更好。” 范斌、大卫·安徒生、迈克尔·卡明斯基、迈克尔·米岑马赫 CoNext 2014。http://dx.doi.org/10.1145/2674005.2674994
来自一位作者的blog:
让我描述一下布谷鸟过滤器和论文中的一些内容。如果您想避免技术讨论,您只需要知道对于相当大的集合,对于与相应的布隆过滤器相同的误报率,布谷过滤器比布隆过滤器使用更少的空间,查找速度更快(但更慢插入/构造),并且令人惊讶的是还允许删除键(Bloom过滤器不能这样做)。如果您想查看代码,甚至有一个 github repository 为您提供杜鹃过滤器的代码。
【讨论】:
如果我可以容忍误报并且空间很重要,我会使用布隆过滤器,因为它占用的空间更少。否则,我使用哈希。
【讨论】: