ブルームフィルタを例で理解する
(llimllib.github.io)- ブルームフィルタは、メモリ効率よく集合内の要素の存在有無を高速に確認できる確率的データ構造である
- 要素が集合に確実に存在しないか、存在するかもしれないかだけを示し、偽陽性の確率が存在する
- 基本構造ではビットベクタと複数のハッシュ関数を用い、各要素に対応するビットを 1 に設定する
- フィルタサイズとハッシュ関数の数によって誤差率と性能が決まり、用途に合わせて調整できる
- 推奨されるハッシュ関数や最適な設定方法、空間効率、実際の適用事例なども紹介されている
ブルームフィルタとは何か
- ブルームフィルタは、特定の要素が集合に存在するかどうかを高速かつメモリ効率よく判定するためのデータ構造である
- この効率性のために、ブルームフィルタは確率的データ構造となっており、検査結果は「集合に確実に存在しない」または「集合に存在するかもしれない」に分かれる
- ブルームフィルタの中核となる構造はビットベクタである
- 要素を追加するときは、各要素を複数回ハッシュして、そのインデックスのビットを 1 に設定する
- 各ハッシュ関数で得られたインデックスに対応するビットがすべて 1 の場合は「存在するかもしれない」と判定し、そうでなければ「確実に存在しない」と扱う
動作原理の例
- 複数のハッシュ関数(例: Fnv, Murmur)を通して、要素を複数のビットインデックスにマッピングする
- 要素を追加するときは、計算されたインデックスのビットを 1 に変更する
- 特定の要素の存在有無を調べる際、同じハッシュ関数で得られる対応インデックスがすべて 1 であれば「存在するかもしれない」とみなす
- もしひとつでも対応するビットが 0 なら、「集合に存在しない」と確実に判断できる
- このため、**偽陽性(フォールス・ポジティブ)**の可能性が生じる
高度なトピック
注意: 著者は実際に大規模サービスへブルームフィルタを適用した経験はない
ハッシュ関数の選択
- 独立性があり、一様分布を持つハッシュ関数が推奨される
- 暗号学的ハッシュ関数(sha1 など)は遅いため適していない
- 高速で単純なハッシュ関数の例としては、Murmur、xxHash、Fnv、HashMix などがある
- 実例では、md5 から murmur に変更した際に 800% 以上の速度向上を経験した
ブルームフィルタのサイズ決定
- フィルタサイズ(m) が大きいほど偽陽性率は低下する
- 偽陽性率は通常 (1-e^(-kn/m))^k で近似できる
- 期待要素数(n)、フィルタサイズ(m)、ハッシュ関数の数(k)を適切に決める必要がある
ハッシュ関数の数は?
- ハッシュ関数の数が多いほど速度は遅くなり、フィルタもより早く埋まる
- 少なすぎると偽陽性率が高くなる
- 理想的な k は (m/n)ln(2) で計算される
- 設計時は次の手順で進める:
- 期待要素数 n を見積もる
- ビット数 m を決める
- 最適な k を算出する
- 望む誤差率が出るか確認し、だめなら m を調整する
性能と空間効率
- ブルームフィルタでの要素追加/存在確認は O(k) の時間計算量を持つ
- 空間効率は、許容できる誤差率と要素範囲に応じて決まる
- 要素範囲をおおまかにでも予測できない場合は、ハッシュテーブルや拡張型ブルームフィルタのほうが適していることがある
活用事例
- 詳しい活用例は Wikipedia を参照
- C. Titus Brown は、ブルームフィルタのバイオインフォマティクスへの適用事例を示している
参考資料
- Broder, Mitzenmacher : Network Applications of Bloom Filters: A Survey — ブルームフィルタの概要論文
- Wikipedia – Bloom Filter
- Kirsch, Mitzenmacher: Less Hashing, Same Performance
- Almeida ほか: Scalable Bloom Filters
1件のコメント
Hacker News のコメント
"bloom"と"demonstrators "(末尾の空白を含む)が fnv: 7、murmur: 12 で衝突する