ブルームフィルターは実際にはハッシュよりも高速ですか?


16

ブルームフィルターは、Intが一定の時間で99%の確実性でセットに含まれているかどうかを判断できると考えると、本当に見栄えがします。ただし、ハッシュも同様です。ただし、ハッシュでは、ほとんどの場合、メモリに1回しかアクセスしません。ブルームフィルターでは、完全に離れた場所でリクエストごとに約7回アクセスする必要があるため、リクエストごとに複数のキャッシュミスが発生します。

何か不足していますか?


完全に遠い場所は何ですか?mビットのみがあります。これはおそらく、単一のレジスタに収まるか、最悪の場合は単一のキャッシュラインに収まります。

1
@delnan AFAIKは、要素あたり約10ビットを使用します。そのため、数千の要素(つまり、巨大なデータストア)の場合、それは間違いなくキャッシュに収まりません。したがって、kハッシュを使用している場合は、k読み取りごとにキャッシュミスが発生している可能性があります。一方、ハッシュテーブルを使用すると、ほとんどの場合、キャッシュミスが0の回答が得られることが保証されます。とにかく衝突はまれです。
MaiaVictor

期間はkビットです。すべての要素は同じ固定ビット数に影響するため、偽陽性率はエントリ数に依存します。

回答:


32

2つのデータ構造がハッシュの衝突をどのように扱うかが欠けています。ブルームフィルターは実際の値を保存しないため、必要なスペースは指定された配列の一定サイズです。代わりに、従来のハッシュを使用する場合、指定したすべての値を保存しようとするため、時間とともに成長します。

単純化されたハッシュ関数を考えてみましょう(例のためだけに!)f(x) = x % 2。ここで、次の整数を入力します2, 3, 4, 5, 6, 7

標準ハッシュ:与えられた値がハッシュ化され、我々は起因する衝突の多くで終わるf(2) = f(4) = f(6) = 0f(3) = f(5) = f(7) = 1。それにもかかわらず、ハッシュはこれらの値をすべて8保存し、保存されていないことを伝えることができます。それはどうやって?衝突を追跡し、すべての値を同じハッシュ値で保存し、クエリを実行すると、クエリをさらに比較します。それでは、クエリのマップましょう8f(8) = 0、それは我々がすでに挿入されているバケットに見ていきますので2, 4, 6、そのあなたを伝えるために3つの比較を行う必要がある8入力の一部ではありませんでした。

ブルームフィルター:通常、各入力値はk異なるハッシュ関数に対してハッシュされます。繰り返しますが、簡単にするために、単一のハッシュ関数のみを使用すると仮定しますf。その場合、2つの値の配列が必要です。入力2に遭遇するとf(2) = 0、位置の配列値をvalueに設定することを意味し0ます1。とについて4も同じことが起こり6ます。同様に、入力は3, 5, 7それぞれ配列の位置1をvalueに設定します1。次に8、入力の一部であるかどうかを照会します。f(8) = 0位置の配列0はです1。そのため、ブルームフィルターは8、入力の一部であると誤って主張します。

もう少し現実的にするために、2番目のハッシュ関数を追加することを考えてみましょうg(x) = x % 10。それと共に、入力値の22つのハッシュ値にリード線f(2) = 0及びg(2) = 2二つ対応する配列位置に設定されます1。もちろん、配列は少なくともsizeでなければなりません10。しかし、我々はを照会するとき8、我々は位置の配列をチェックする8原因にg(8) = 8、その位置はまだなります0。これが、追加のハッシュ関数が取得する誤検知を減らす理由です。

比較:ブルームフィルターは、kハッシュ関数を使用しkます。これは、アクセスされるランダムな配列位置までを意味します。しかし、その数字は正確です。ハッシュは代わりに償却された一定のアクセス時間を保証するだけですが、ハッシュ関数と入力データの性質によっては縮退する場合があります。そのため、通常は、縮退した場合を除いて高速です。

ただし、ハッシュの衝突が発生すると、標準ハッシュは保存された値とクエリ値の等価性をチェックする必要があります。この等価性チェックは、arbitrarily意的に高価になる場合があり、ブルームフィルターでは発生しません。

指定された配列よりも多くのメモリを使用する必要がないため、スペースに関してはブルームフィルターは一定です。一方、ハッシュは動的に増加し、衝突した値を追跡する必要があるため、はるかに大きくなる可能性があります。

トレードオフ:安価なものとそうでないもの、そしてどのような状況であるかがわかったので、トレードオフを確認できるはずです。ブルームフィルターは、値が以前に見られたことを非常に迅速に検出したいが、誤検出を伴う可能性がある場合に最適です。一方、ランタイムを正確に判断できないという代償を払って正確性を保証したい場合はハッシュマップを選択できますが、平均よりもはるかに低速な場合によっては縮退したケースを受け入れることができます。

同様に、限られたメモリ環境にいる場合、メモリ使用量の保証のためにブルームフィルターを好むかもしれません。


素晴らしい答え。これは私が混乱させていたものです。実際、すべてのデータ構造には最適なユースケースがあり、考慮事項はトレードオフに依存します。
リチャード

それは確かに適切な例で非常に良い説明です。では、値「k」をどのように使用しますか?値の総数に依存しますか?
itsraghz

5

ブルームフィルターとハッシュのユースケースは明確であり、ほとんどが互いに素であるため、直接比較することは意味がありません。それに加えて、異なるトレードオフでハッシュ衝突を処理する多くの方法があるので、実装の技術的な詳細に依存します。

ブルームフィルターは、適度なメモリを使用して、要素が巨大なセットのセットに含まれているかどうかを妥当な確率で答えることができますが、正確ではありません。巨大な、何兆もの要素。しかし、それらは決して正確ではありません。より多くのメモリまたはハッシュ関数を使用することによってのみ、誤検知の量を減らすことができます。

一方、ハッシュテーブルは正確ですが、セットを保存する必要があります。そのため、数兆個の要素にはテラバイトのメモリが必要になります(これはアメリカの兆にすぎません)。また、ブルームフィルターでは保存できない各要素の追加データも保存できます。

したがって、ブルームフィルターは、大きなセット(メモリに収まらない、またはクライアントに転送するのが実用的ではない)のメンバー(サーバーへのクエリ、ディスクからの読み取りなどを含む)のデータを取得する方法が遅い場合に使用されますまたはそのような)そして、セットにないオブジェクトに対して遅い操作を実行することを避けたい。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.