ブルームフィルターを使用する利点は何ですか?


108

私はブルームフィルターについて読んでいますが、ばかげているように見えます。ブルームフィルターで達成できることは何でも、複数のスペースではなく1つのハッシュ関数を使用して、より少ないスペースで、より効率的に達成することができます。なぜブルームフィルターを使用するのですか?


5
ウィキペディアの記事を読みましたか?それは利点をかなりよく説明しています。en.wikipedia.org/wiki/Bloom_filter
Alex Budovski、

しかし、それはありそうにないようです。定数空間のk個のハッシュ関数は、定数空間の単一のハッシュ関数よりも衝突が多くなります。
頭痛

1
@アレックス私はウィキペディアの記事を読みました。私はそこで何が言われているのか理解していますが、なぜそれがより良いのかは分かりません。それが機能する理由は直感的です。なぜそれが有用であるかではありません。
頭痛

この作家は素晴らしい仕事をしていますmichaelnielsen.org/ddi/why-bloom-filters-work-the-way-they-do
dranxo

2
@dranxo、リンクされた記事jasondavies.com/bloomfilterの方が優れています。
Pacerier 2015

回答:


155

ウィキペディアから:

ブルームフィルターは、自己均衡バイナリ検索ツリー、トライ、ハッシュテーブル、または単純な配列やエントリのリンクリストなどのセットを表すために、他のデータ構造よりも強力なスペースの利点があります。これらのほとんどは、少なくともデータ項目自体を格納する必要があり、小さな整数の場合は少数のビットから、文字列などの任意のビット数までのいずれかを必要とする可能性があります(試行は例外です。プレフィックスが等しい要素)。リンクされた構造体は、ポインターに対して追加の線形スペースオーバーヘッドが発生します。一方、エラーが1%で最適値がkのブルームフィルターでは、要素のサイズに関係なく、要素あたり約9.6ビットしか必要ありません。この利点の一部は、配列から継承されたそのコンパクトさです。部分的にはその確率的性質から。1%の誤検知率が高すぎると思われる場合は、要素ごとに約4.8ビットを追加するたびに、10倍減らします。

私にはかなり明確です。

ブルームフィルターは要素自体を格納しません。これが重要なポイントです。ブルームフィルターを使用して要素が存在するかどうかをテストするのではなく、偽陰性を保証しないため、要素が存在しないかどうかをテストするために使用します。これにより、セットに存在しない要素(それらを検索するためのディスクIOなど)に対して余分な作業を行う必要がなくなります。

そして、すべてがハッシュテーブルのようなものよりも大幅に少ないスペースにあります(大きなデータセットの場合、ディスク上に部分的に配置される可能性があります)。ハッシュテーブルのような構造と組み合わせてブルームフィルター使用することもできますが、要素が存在する可能性があると確信できたら、

したがって、使用パターンの例は次のようになります。

ディスク上に大量のデータがあり、mの値を規定するエラー範囲(たとえば1%)を決定します。次に、最適なkが決定されます(記事に記載されている式から)。このディスクにバインドされたデータからフィルターを1回設定します。

これで、RAMにフィルターができました。一部の要素を処理する必要がある場合は、フィルターをクエリして、データセットに存在する可能性があるかどうかを確認します。そうでない場合、追加の作業は行われません。ディスクの読み取りなどは行われません(ハッシュやツリーなどの場合に行う必要があります)。

そうでなければ、フィルターが「はい、そこにあります」と言った場合、それが間違っている可能性が1%あるので、あなたが見つけるために必要な作業を行います。時間の99%は、それが本当になり作業が無駄になかったので、そこにあること。


2
はっきりしている場合は、答えてください。これは、同じサイズのセットの単一のハッシュ関数よりもスペース効率が良い可能性があるのはなぜですか?これは単により多くの衝突を作成します。すべてのハッシュ関数で1を使用できるように、個別のハッシュ関数での検索を回避します。単一のハッシュ関数を使用するよりも利点があることはわかりません。
頭痛

19
ハッシュ関数はデータではなくコードです。ハッシュ関数を何に使用しますか?ハッシュテーブル?その場合、テーブルには、ブルームフィルターとは異なり、任意のサイズのキーを格納する必要があります。抜粋はこれについて言及しています。
Alex Budovski、2011年

3
kではなく、ハッシュ関数を1つだけ持つブルームフィルターについて考えます。ハッシュ関数を追加する利点は何ですか?これは単により多くの衝突を作成します。それとも私は間違っていますか?
頭痛

2
これは、Wikipediaの記事の「空間と時間の利点」の最後の段落と「誤検知の確率」セクションで回答されています。
Alex Budovski、2011年

4
クリックしただけです。どうもありがとう、これはしばらくの間私を悩ませてきました。誤検知は、a)すべてのハッシュ関数の衝突であるか、b)すべてのスペースが他の値で埋められている必要があるため、誤検知の数を減らします。そのときのサイズの選択は難しいプロセスだと思います。私が間違っている場合は訂正してください。みんなありがとう。
頭痛

156

アレックスはそれをかなりよく説明しました。それでもまだ十分に理解していない人のために、うまくいけば、この例が理解に役立つでしょう:

私がChromeチームのGoogleで働いていて、ユーザーが入力したURLが悪意のあるURLである場合にユーザーに通知する機能をブラウザーに追加するとします。したがって、約100万の悪意のあるURLのデータセットがあり、このファイルのサイズは約25MBです。サイズはかなり大きいので(ブラウザー自体のサイズと比較して大きい)、このデータをリモートサーバーに保存します。

ケース1:ハッシュテーブルでハッシュ関数を使用します。私は効率的なハッシュ関数を決定し、100万のURLをすべてハッシュ関数に通してハッシュキーを取得します。次に、ハッシュテーブル(配列)を作成します。ハッシュキーは、そのURLを配置するためのインデックスを提供します。そこで、ハッシュテーブルをハッシュしていっぱいにしたら、そのサイズを確認します。100万個すべてのURLをそのキーとともにハッシュテーブルに保存しました。したがって、サイズは少なくとも25 MBです。このハッシュテーブルは、そのサイズが原因で、リモートサーバーに格納されます。ユーザーが来て、アドレスバーにURLを入力したら、悪意があるかどうかを確認する必要があります。したがって、ハッシュ関数を介してURLを実行し(ブラウザー自体がこれを実行できます)、そのURLのハッシュキーを取得します。次に、そのハッシュキーを使用してリモートサーバーにリクエストを送信する必要があります。その特定のキーを持つ私のハッシュテーブルの特定のURLがユーザーが入力したものと同じかどうかを確認します。はいの場合は悪意のあるものであり、いいえの場合は悪意のないものです。したがって、ユーザーがURLを入力するたびに、それが悪意のあるURLであるかどうかを確認するためにリモートサーバーへの要求を行う必要があります。これには時間がかかり、ブラウザの速度が低下します。

ケース2:ブルームフィルターを使用します。100万のURLのリスト全体が、複数のハッシュ関数を使用してブルームフィルターを介して実行され、それぞれの位置は、0の巨大な配列で1としてマークされます。ブルームフィルター計算機(http://hur.st/bloomfilter?n=1000000&p=0.01を使用して、1%の誤検知率が必要だとしましょう。)、必要なブルームフィルターのサイズはわずか1.13 MBです。配列のサイズが巨大であっても、ハッシュテーブルの場合のように1または0のみを格納し、URLは格納しないため、この小さなサイズが予想されます。この配列はビット配列として扱うことができます。つまり、1と0の2つの値しかないため、バイトの代わりに個別のビットを設定できます。これにより、スペースを8分の1に削減できます。この1.13 MBブルームフィルターは、サイズが小さいため、Webブラウザー自体に格納できます!! したがって、ユーザーが来てURLを入力すると、必要なハッシュ関数を(ブラウザー自体で)適用し、ブルームフィルター(ブラウザーに保存されている)のすべての位置を確認します。いずれかの位置の値が0の場合、このURLは悪意のあるURLのリストに定義されておらず、ユーザーは自由に進むことができます。したがって、サーバーを呼び出さなかったため、時間を節約できました。値1は、URLが悪意のあるURLのリストに含まれている可能性があることを示しています。これらのケースでは、リモートサーバーを呼び出し、その上で、最初のケースと同様に、ハッシュテーブルを含む他のハッシュ関数を使用して、URLが実際に存在するかどうかを取得して確認できます。ほとんどの場合、URLは悪意のあるURLである可能性が低いため、ブラウザの小さなブルームフィルタがそれを認識し、リモートサーバーへの呼び出しを回避することで時間を節約します。一部の場合にのみ、ブルームフィルターによってURLが悪意のある可能性があると通知された場合にのみ、サーバーに呼び出しを行います。その「MIGHT」は99%正しいです。これらのケースでは、リモートサーバーを呼び出し、その上で、最初のケースと同様に、ハッシュテーブルを含む他のハッシュ関数を使用して、URLが実際に存在するかどうかを取得して確認できます。ほとんどの場合、URLは悪意のあるURLである可能性は低いため、ブラウザの小さなブルームフィルタがそれを認識し、リモートサーバーへの呼び出しを回避することで時間を節約します。一部の場合にのみ、ブルームフィルターによってURLが悪意のある可能性があると通知された場合にのみ、サーバーに呼び出しを行います。その「MIGHT」は99%正しいです。これらのケースでは、リモートサーバーを呼び出し、その上で、最初のケースと同様に、ハッシュテーブルを含む他のハッシュ関数を使用して、URLが実際に存在するかどうかを取得して確認できます。ほとんどの場合、URLは悪意のあるURLである可能性が低いため、ブラウザの小さなブルームフィルタがそれを認識し、リモートサーバーへの呼び出しを回避することで時間を節約します。一部の場合にのみ、ブルームフィルターによってURLが悪意のある可能性があると通知された場合にのみ、サーバーに呼び出しを行います。その「MIGHT」は99%正しいです。ブラウザーの小さなブルームフィルターはそれを計算し、リモートサーバーへの呼び出しを回避することで時間を節約します。一部の場合にのみ、ブルームフィルターによってURLが悪意のある可能性があると通知された場合にのみ、サーバーに呼び出しを行います。その「MIGHT」は99%正しいです。ブラウザーの小さなブルームフィルターはそれを計算し、リモートサーバーへの呼び出しを回避することで時間を節約します。一部の場合にのみ、ブルームフィルターによってURLが悪意のある可能性があると通知された場合にのみ、サーバーに呼び出しを行います。その「MIGHT」は99%正しいです。

したがって、ブラウザーで小さなブルームフィルターを使用することで、入力されたすべてのURLに対してサーバー呼び出しを行う必要がないため、時間を大幅に節約できました。

単一のハッシュ関数を持つハッシュテーブルが、ブルームフィルターとはまったく異なる目的で使用されていることがわかります。うまくいけば、これはあなたの疑問を解消します:)

編集

Pythonでの悪意のあるURLテストのタスクにブルームフィルターを実装しました。コードはここにあります-https://github.com/tarunsharma1/Bloom-Filter コードは非常に理解しやすく、詳細な説明はreadmeファイルに記載されています。


3
ユースケースシナリオをありがとう。
Squiggs。

1
ハッシュ化と0または1の値の関連付けの一部を取得できませんでした。配列を使用していて、それらに0と1を格納している場合、テストを実行するときにURLのハッシュ値をどのように検索しますか。 ?
ディバインドラゴン

1
つまり、基本的にハッシュ関数と呼ばれるものを使用します。これはURLを文字列として受け取り、数値を提供します。この数値を使用して、対応する配列のインデックス値を1に設定します。さまざまなハッシュ関数がいくつか存在します。しかし重要なことは、同じURLがハッシュ関数を通過するたびに、同じ番号を生成する必要があるということです。ハッシュ関数の例としては、URL内のすべての文字のASCII値を合計することができます。ブルームフィルターでは、多くのハッシュ関数を使用し、これらすべての配列のインデックス値を1に設定します。これで疑問が解消されたことを願っています。
Tarun 2015

1
C#などの従来のハッシュHashSet<String>テーブルは、ハッシュテーブルが完全にいっぱいである最良のシナリオで、要素要素ごとに16バイトを使用します。4バイトは、「バケット」からエントリテーブルのエントリにマッピングされます(配列でパックされた単一リンク)リスト)、キャッシュされたハッシュコード用に4バイト、「次の」ポインター用に4バイト、キーへのポインター用に4バイト。そして、それは文字列のサイズを数えていません。最悪の場合、40 Stringバイトです。64ビットアーキテクチャの場合、ポインタが8バイトに拡大すると、エントリの半分が使用されず、エントリあたり20バイトになります。
Qwertie 2017年

文字列自体をハッシュセットに保存する必要はありません。そのハッシュを値として保存して、ハッシュセットをはるかに小さくすることができます。次に、ハッシュサイズで遊ぶことができます-ハッシュサイズが大きいほど、偽陽性率は小さくなります。
user1028741

24

まず、ブルームフィルターとは何か、何が可能で何ができないのか、なぜそれが必要なのか、直感的な説明でどのように機能するのかを説明し、次にそれらが役立つ場合の例をいくつか示します。

したがって、標準のブルームフィルターは、次のことができる確率的データ構造です*


  • セットに要素を追加する
  • 要素が伝えることでセットであるかどうかを確認definitely not in the setpossibly in the set

これpossibly in the setがまさに確率論と呼ばれる理由です。スマートワードを使用するということは、偽陽性が発生する可能性があることを意味します(要素が陽性であると誤って判断する場合もあります)が、偽陰性は不可能です。

しかし、それはできません *

  • セットからアイテムを削除する
  • セット内に現在あるすべての要素のリストを提供します

* この缶のセットは、基本的なブルームフィルター用です。それはずっと前に作成された有用なデータ構造であるため、人々は他の有用な機能でそれを増強する方法を見つけました。


しかし、少し待ってください。あいまいな「可能性」なしに、またすべての制限なしにこれをすべて解決できる(削除できない、すべてを表示できない)データ構造がすでにわかっています。そして、それはセットと呼ばれています。そしてここにブルームフィルターの主な利点があります。それはスペース効率がよく、スペース定数です。

つまり、そこに格納する要素の数は問題ではなく、スペースは同じになります。はい、10^6要素のあるブルームフィルター(役に立たないブルームフィルター)は、要素のあるブルームフィルターと同じ量のスペースと、10^20要素のあるブルームフィルターと同じスペースを取り0ます。それではどのくらいのスペースが必要でしょうか?決めるのはあなた次第です(しかし、トレードがあります:要素が多いほど、possible in the set答えが不確かになります。

別のクールなことは、それが空間定数であることです。データをセットに保存するときは、実際にこのデータを保存する必要があります。したがって、保存this long string in the setする場合は、少なくとも27バイトのスペースを使用する必要があります。しかし、1%のエラーとk **の最適値の場合、要素ごとに〜9.6ビット(<2バイト)が必要になります(短いintであるか、テキストの巨大な壁であるかにかかわらず)。

別の特性は、すべての操作が一定の時間を費やしていることです。これは、セットの場合の償却一定時間とは完全に同じではありません(セットに衝突がある場合、O(n)時間の経過とともに悪化する可能性があることを忘れないでください)。

** kは、ブルームフィルターで使用されるハッシュ関数の値です。


ブルームフィルターのしくみについては説明しません(ウィキペディアの記事では、すべてを説明するのに非常に優れています)。ここでは、基本を簡単に説明します。

  • あなたは長さの空のビット配列を開始します m
  • k異なるハッシュ関数を選択します(独立性が高いほど良い)
  • 要素を追加する場合はk、この値のすべてのハッシュを計算し、対応するビットを1に設定します
  • 要素が存在するかどうかを確認する場合は、すべてのkハッシュも計算し、それらの少なくとも1つが設定されていない場合は、確かにセットに含まれていません。それ以外の場合は、セットに含めることができます。

この説明でさえ、なぜ確信が持てないのかを理解するには十分です(他のさまざまな値からすべてのビットを設定できます)。これは、それがどのように機能するかについての非常に素晴らしい視覚化です

ここに画像の説明を入力してください


では、ブルームフィルターはいつ役立つのでしょうか。短い答えは、誤検知が許容され、セットに何かが含まれているかどうかを確認する必要があるすべての場所ですが、そうでない場合でも、検証者への高価な呼び出しを除外することは、防御の最前線になる可能性があります。

以下は、より具体的な説明のリストです。

  • 悪意のあるWebサイトとブラウザの標準的な例は、ブルームフィルタについて人々が話すほとんどすべての場所で説明されています
  • 弱いパスワードです:考えられるすべての弱いパスワードの膨大なセットを用意する代わりに、小さなブルームフィルターでパスワードが確かに弱いかどうかを確認できます
  • 記事のリストとユーザーのリストがある場合は、ブルームフィルターを使用して、ユーザーが読んでいないユーザーの記事を表示できます。興味深いのは、フィルターを1つしか持てないことです(user_id + article_idの組み合わせが存在するかどうかを確認します)。
  • ビットコインはウォレットの同期にブルームフィルターを使用します
  • アカマイのWebサーバーはブルームフィルターを使用して、「ワンヒットワンダー」がディスクキャッシュに保存されるのを防ぎます。1ヒットワンダーとは、ユーザーが1度だけリクエストしたWebオブジェクトであり、アカマイがキャッシングインフラストラクチャの4分の3近くに適用したものです。ブルームフィルターを使用してWebオブジェクトの2番目の要求を検出し、そのオブジェクトを2番目の要求にのみキャッシュすることで、ワンヒットの不思議がディスクキャッシュに入るのを防ぎ、ディスクワークロードを大幅に削減し、ディスクキャッシュヒット率を向上させます(ブルームフィルターの例から取得) wikiの記事)

13

ブルームフィルターは、バイオインフォマティクスで非常に便利です。特に、使用している文字列のサイズが非常に小さなアルファベットの数億の文字、つまり{A、G、T、C}である場合は、通常のハッシュを使用するよりもスペース効率が高くなります。それらは通常、特定のk-merがゲノムに存在するかどうかを評価するために使用されます。ここに関連する何かに使用されるものの例があります

編集:

複数のハッシュ関数は、誤検知を最小限に抑えるために使用されます。すべてのkハッシュ関数の間で、各値は、他のすべての可能な値と比較して、ビット配列内に一意の署名を持つことになります。ただし、誤検知は存在しますが、管理可能なレベルに最小化できます。この技術を使用して、あなたは要素ハッシュ独立して自分のサイズのを。それらを検索するときは、各ハッシュ関数を使用して、ビット値がすべて1であることを確認します。

これを人間のゲノムと比較すると、要素のサイズが増加すると、ハッシュテーブルのサイズが大幅に増加します(テーブルサイズは4 * 4 kです)。これは、2ビット/文字を使用して要素をエンコードすることを前提としています。


1
申し訳ありませんが、私は誤解しているかもしれませんが、通常のハッシュと比べて、どのようにスペース効率を高めることができますか?文字列のハッシュは固定長出力であり、その値を0または1に設定するだけです。これは、ブルームフィルターが行うことでもありますが、ブルームフィルターは複数のハッシュ関数でそれを行います。どこで誤解していますか?
頭痛

単一のハッシュを保存するだけではあまり役に立ちません。その場合、ハッシュの衝突を処理する方法がありません。ほとんどのハッシュテーブルの実装には、これを処理する方法があり、オーバーヘッドが発生します。たとえばPython辞書は、ハッシュと一緒にキーを保存し、衝突時に線形プローブを開始します。ブルームフィルターはそれをカットし、複数のハッシュを使用することで、そうすることによるダメージを最小限に抑えようとします。
Bret Fontecchio 2014年

1
なぜブルームフィルターを作成せず、ハッシュ関数を1つだけ持つのですか?多分「比較的大きな」ハッシュ関数。しかし、多くではなく1つ
Giorgim

7

ブルームフィルターがアイテムがセットのメンバーであることを返す場合、誤検知の可能性があります。セット内のメンバーシップを示すために単一のハッシュ関数のみが使用された場合、誤検出の確率は複数のハッシュ関数を使用するよりも高くなります。


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