Bloom-Filter in Java mit Guava

1. Überblick

In diesem Artikel betrachten wir das Bloom-Filter-Konstrukt aus der Guava -Bibliothek. Ein Bloom-Filter ist eine speichereffiziente, probabilistische Datenstruktur, mit der wir die Frage beantworten können, ob ein bestimmtes Element in einem Satz enthalten ist .

  • Es gibt keine falschen Negative ** mit einem Bloom-Filter. Wenn Sie also false zurückgeben, können Sie zu 100% sicher sein, dass das Element nicht in der Gruppe enthalten ist.

Ein Bloom-Filter kann jedoch falsch positive Ergebnisse liefern . Wenn er also true zurückgibt, besteht eine hohe Wahrscheinlichkeit, dass sich das Element in der Gruppe befindet.

Eine detailliertere Analyse der Funktionsweise eines Bloom-Filters finden Sie unter https://llimllib.github.io/bloomfilter-tutorial/Tutorial .

2. Maven-Abhängigkeit

Wir werden die Implementierung des Bloom-Filters von Guava verwenden. Fügen wir also die guava -Abhängigkeit hinzu:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>22.0</version>
</dependency>

Die neueste Version finden Sie unter Maven Central .

3. Warum Bloom-Filter verwenden?

Der Bloom-Filter ist platzsparend und schnell . Wenn Sie es verwenden, können wir die Wahrscheinlichkeit von falsch positiven Antworten angeben, die wir akzeptieren können , und gemäß dieser Konfiguration wird der Bloom-Filter so wenig Speicher wie möglich beanspruchen.

Aufgrund dieser Raumeffizienz passt der Bloom-Filter auch bei sehr vielen Elementen problemlos in den Speicher. Einige Datenbanken, einschließlich Cassandra und Oracle, verwenden diesen Filter als erste Prüfung, bevor sie auf die Festplatte oder in den Cache gehen, z. B. wenn eine Anforderung nach einer bestimmten ID eingeht.

Wenn der Filter zurückgibt, dass die ID nicht vorhanden ist, kann die Datenbank die weitere Verarbeitung der Anforderung stoppen und zum Client zurückkehren. Andernfalls geht es zur Festplatte und gibt das Element zurück, wenn es auf der Festplatte gefunden wird.

4. Bloom-Filter erstellen

Angenommen, wir möchten einen Bloom-Filter für bis zu 500 Integers erstellen, und wir können eine Wahrscheinlichkeit von 1% (0,01) für falsch positive Ergebnisse tolerieren.

Dazu können wir die BloomFilter -Klasse aus der Guava -Bibliothek verwenden. Wir müssen die Anzahl der Elemente übergeben, von denen wir erwarten, dass sie in den Filter eingefügt werden, und die gewünschte falsch positive Wahrscheinlichkeit:

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

Jetzt fügen wir dem Filter einige Zahlen hinzu:

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

Wir haben nur drei Elemente hinzugefügt, und wir haben festgelegt, dass die maximale Anzahl von Einfügungen 500 sein wird, sodass unser Bloom-Filter sehr genaue Ergebnisse liefern sollte . Testen wir es mit der Methode mightContain () :

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

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

Wie der Name vermuten lässt, können wir nicht zu 100% sicher sein, dass sich ein bestimmtes Element tatsächlich im Filter befindet, wenn die Methode true zurückgibt.

Wenn mightContain () in unserem Beispiel true zurückgibt, können wir zu 99% sicher sein, dass sich das Element im Filter befindet, und es besteht eine Wahrscheinlichkeit von ein Prozent, dass das Ergebnis falsch positiv ist. Wenn der Filter false zurückgibt, können wir zu 100% sicher sein, dass das Element nicht vorhanden ist.

5. Übersättigter Bloomfilter

Wenn wir unseren Bloom-Filter entwerfen, ist es wichtig, dass wir für die erwartete Anzahl von Elementen einen angemessen genauen Wert angeben.

Andernfalls liefert unser Filter falsche Ergebnisse mit einer viel höheren Rate als gewünscht. Sehen wir uns ein Beispiel an.

Nehmen wir an, wir hätten einen Filter mit einer gewünschten falsch-positiven Wahrscheinlichkeit von einem Prozent und erwarteten Elementen von fünf erstellt, aber dann 100.000 Elemente eingefügt:

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

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

Da die erwartete Anzahl von Elementen so klein ist, belegt der Filter nur wenig Speicher.

Wenn Sie jedoch mehr Elemente hinzufügen als erwartet, wird der -Filter übersättigt und die Wahrscheinlichkeit, falsch positive Ergebnisse zu erhalten, ist viel höher als das gewünschte ein Prozent.

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

Beachten Sie, dass die mightContatin () -Methode auch true für einen Wert zurückgegeben hat, den wir zuvor nicht in den Filter eingefügt haben.

6. Fazit

In diesem kurzen Tutorial haben wir die probabilistische Natur der Bloom-Filter-Datenstruktur unter Verwendung der Guava -Implementierung untersucht.

Die Implementierung all dieser Beispiele und Code-Snippets finden Sie im Projekt GitHub .

Dies ist ein Maven-Projekt, daher sollte es einfach sein, zu importieren und so wie es ist auszuführen.