当您考虑可以确定Int是否在恒定时间内具有99%的确定性的集合中时,Bloom过滤器看起来确实很棒。但是散列也是如此,唯一的区别在于,在散列中,大多数时候您只访问一次内存。使用Bloom过滤器时,您需要在完全遥远的地方每个请求访问它们约7次,因此每个请求将有多个缓存未命中。
我想念什么吗?
k
哈希,则可能是k
每次读取都有高速缓存未命中。另一方面,哈希表可确保您在大多数情况下都会得到0个高速缓存未命中的答案-无论如何,冲突很少发生。
当您考虑可以确定Int是否在恒定时间内具有99%的确定性的集合中时,Bloom过滤器看起来确实很棒。但是散列也是如此,唯一的区别在于,在散列中,大多数时候您只访问一次内存。使用Bloom过滤器时,您需要在完全遥远的地方每个请求访问它们约7次,因此每个请求将有多个缓存未命中。
我想念什么吗?
k
哈希,则可能是k
每次读取都有高速缓存未命中。另一方面,哈希表可确保您在大多数情况下都会得到0个高速缓存未命中的答案-无论如何,冲突很少发生。
Answers:
您缺少这两个数据结构如何处理哈希冲突。Bloom过滤器不存储实际值,因此所需的空间是指定数组的恒定大小。相反,如果您使用传统的哈希,它将尝试存储您提供的所有值,因此它会随着时间增长。
考虑一个简化的哈希函数(仅出于示例目的!)f(x) = x % 2
。现在,您输入以下整数:2, 3, 4, 5, 6, 7
。
标准哈希:给定值将被散列,而且我们有很多冲突的结束,由于f(2) = f(4) = f(6) = 0
和f(3) = f(5) = f(7) = 1
。尽管如此,哈希存储了所有这些值,它可以告诉您8
未存储在其中。它是如何做到的?它跟踪冲突并存储具有相同哈希值的所有值,然后在查询时,它还会对查询进行比较。因此,让我们在地图上查询8
:f(8) = 0
,以便将其放入我们已经插入的存储桶中,2, 4, 6
并需要进行3次比较,以告诉您这8
不是输入的一部分。
布隆过滤器:通常,每个输入值都针对k
不同的哈希函数进行哈希处理。再次,为简单起见,我们假设仅使用单个哈希函数f
。我们需要一个由2个值组成的数组,然后当遇到输入时,2
这意味着由于f(2) = 0
我们将位置的数组值设置0
为value 1
。同样的情况发生了4
和6
。类似地,3, 5, 7
每个输入都将数组位置设置1
为value 1
。现在我们查询if是否8
是输入的一部分:f(8) = 0
位置0
处的数组是1
,因此Bloom筛选器将错误地声明8
确实是输入的一部分。
为了更加现实,让我们考虑添加第二个哈希函数g(x) = x % 10
。这样,输入值2
将导致两个哈希值f(2) = 0
,g(2) = 2
并且两个对应的数组位置将被设置为1
。当然,数组现在至少应为size 10
。但是,当我们查询时,8
我们将检查数组8
由于的位置g(8) = 8
,并且该位置仍为0
。这就是为什么其他哈希函数可以减少误报的原因。
比较: Bloom过滤器使用k
哈希函数,这意味着最多可以k
访问随机数组位置。但是这个数字是准确的。相反,哈希仅保证您享有摊销后的固定访问时间,但可能会根据哈希函数和输入数据的性质而退化。因此,除了退化的情况外,通常更快。
但是,一旦发生哈希冲突,标准哈希将必须对照查询值检查存储值的相等性。这种相等性检查可能会非常昂贵,并且对于Bloom Bloom过滤器将永远不会发生。
就空间而言,布隆过滤器是恒定的,因为不需要使用比指定数组更多的内存。另一方面,由于必须跟踪冲突值,因此哈希值会动态增长,并且可能变得更大。
权衡:现在您知道什么便宜,什么不便宜,在什么情况下,您应该可以看到权衡。如果您想非常快速地检测到以前已经看到过某个值,但可以使用误报,则Bloom过滤器非常有用。另一方面,如果希望以无法准确判断运行时为代价来确保正确性,则可以选择哈希图,但是可以接受偶尔退化的情况,这种情况可能比平均速度慢得多。
同样,如果您在有限的内存环境中,则可能希望使用bloom筛选器以保证其内存使用率。
Bloom过滤器和哈希的用例是不同的,并且大多数情况下是不相交的,因此直接比较是没有意义的。此外,这将取决于实现的技术细节,因为有许多方法可以处理具有不同权衡的哈希冲突。
Bloom过滤器可以使用适度的内存以合理的概率(但不是完全正确)来回答元素是否在大型集中的集合中。庞大的元素多达数万亿。但是它们从来都不是精确的。您只能通过使用更多的内存或更多的哈希函数来减少误报的数量。
另一方面,哈希表是精确的,但它们需要存储集合。因此,数万亿个元素将需要TB的内存(而这仅仅是美国的数万亿美元)。他们还可以为每个元素存储额外的数据,而Bloom筛选器则不能。
因此,如果您使用缓慢的方法来获取大型集合(不适合内存或无法将其传输到客户端)的某个成员(涉及查询服务器,从磁盘中读取数据等)的数据,则可以使用布隆过滤器等),并希望避免对不在集合中的对象执行慢速操作。