Guavaを使ったJavaのブルームフィルタ

Guavaを使用したJavaでのBloom Filter

1. 概要

この記事では、Guavaライブラリのブルームフィルターコンストラクトについて説明します。 ブルームフィルターは、whether or not a given element is in a setの質問に答えるために使用できる、メモリ効率の高い確率的なデータ構造です。

ブルームフィルターを使用したThere are no false negativesであるため、falseを返す場合、要素がセットに含まれていないことを100%確信できます。

ただし、ブルームフィルターはcan return false positivesであるため、trueを返す場合、要素がセットに含まれている可能性が高くなりますが、100%確実ではありません。

ブルームフィルターがどのように機能するかをより詳細に分析するには、this tutorialを調べます。

2. メーベン依存

ブルームフィルターのGuavaの実装を使用するので、guava依存関係を追加しましょう。


    com.google.guava
    guava
    22.0

最新バージョンはMaven Centralにあります。

3. ブルームフィルターを使用する理由

ブルームフィルターはdesigned to be space-efficient and fastです。 それを使用するとき、specify the probability of false positive responses which we can acceptを実行でき、その構成に従って、ブルームフィルターは可能な限り少ないメモリを占有します。

このスペース効率により、要素の数が非常に多い場合でもthe Bloom filter will easily fit in memoryになります。 CassandraやOracleなどの一部のデータベースは、特定のIDのリクエストが入った場合など、ディスクまたはキャッシュに移動する前の最初のチェックとしてこのフィルターを使用します。

IDが存在しないことをフィルターが返す場合、データベースは要求のそれ以上の処理を停止し、クライアントに戻ることができます。 それ以外の場合は、ディスクに移動し、ディスク上で見つかった要素を返します。

4. ブルームフィルターの作成

最大500Integersのブルームフィルターを作成し、誤検出の1%(0.01)の確率を許容できると仮定します。

これを実現するために、GuavaライブラリのBloomFilterクラスを使用できます。 フィルターに挿入されると予想される要素の数と、必要な偽陽性の確率を渡す必要があります。

BloomFilter filter = BloomFilter.create(
  Funnels.integerFunnel(),
  500,
  0.01);

次に、フィルターにいくつかの数値を追加しましょう。

filter.put(1);
filter.put(2);
filter.put(3);

3つの要素のみを追加し、挿入の最大数を500と定義したため、ブルームフィルターはshould yield very accurate resultsです。 mightContain()メソッドを使用してテストしてみましょう。

assertThat(filter.mightContain(1)).isTrue();
assertThat(filter.mightContain(2)).isTrue();
assertThat(filter.mightContain(3)).isTrue();

assertThat(filter.mightContain(100)).isFalse();

名前が示すように、メソッドがtrueを返すときに、特定の要素が実際にフィルター内にあることを100%確信することはできません。

この例でmightContain()trueを返す場合、要素がフィルター内にあることを99%確信でき、結果が誤検出である確率は1%です。 フィルタがfalseを返す場合、要素が存在しないことを100%確信できます。

5. 過飽和ブルームフィルター

ブルームフィルターを設計するとき、it is important that we provide a reasonably accurate value for the expected number of elements。 それ以外の場合、フィルターは必要以上に高いレートで誤検知を返します。 例を見てみましょう。

1%の望ましい偽陽性確率と5に等しいいくつかの要素を期待してフィルターを作成したが、100,000個の要素を挿入したと仮定します。

BloomFilter filter = BloomFilter.create(
  Funnels.integerFunnel(),
  5,
  0.01);

IntStream.range(0, 100_000).forEach(filter::put);

予想される要素の数が非常に少ないため、フィルターはほとんどメモリを占有しません。

ただし、予想よりも多くのアイテムを追加すると、filter becomes over-saturated and has a much higher probability of returning false positive resultsは目的の1パーセントよりも多くなります。

assertThat(filter.mightContain(1)).isTrue();
assertThat(filter.mightContain(2)).isTrue();
assertThat(filter.mightContain(3)).isTrue();
assertThat(filter.mightContain(1_000_000)).isTrue();

以前は、mightContatin()メソッドreturned true even for a value that we didn’t insertをフィルターに挿入していることに注意してください。

6. 結論

このクイックチュートリアルでは、Guavaの実装を利用して、ブルームフィルターのデータ構造の確率的な性質を確認しました。

これらすべての例とコードスニペットの実装は、GitHub projectにあります。

これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。