Filtre Bloom en Java avec Guava

1. Vue d’ensemble

Dans cet article, nous examinerons la construction du filtre Bloom de la bibliothèque Guava . Un filtre de Bloom est une structure de données probabiliste, efficace en mémoire, que nous pouvons utiliser pour répondre à la question de savoir si un élément donné fait partie d’un ensemble

  • Il n’y a pas de faux négatifs ** avec un filtre de Bloom, donc quand il retourne false , on peut être sûr à 100% que l’élément n’est pas dans l’ensemble.

Cependant, un filtre de Bloom peut renvoyer des faux positifs . Ainsi, lorsqu’il renvoie true , la probabilité que l’élément se trouve dans l’ensemble est élevée, mais nous ne pouvons pas être sûrs à 100%.

Pour une analyse plus détaillée du fonctionnement d’un filtre Bloom, vous pouvez consulter this tutorial .

2. Dépendance Maven

Nous allons utiliser l’implémentation du filtre Bloom par Guava, ajoutons donc la dépendance guava :

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

La dernière version est disponible sur Maven Central. .

3. Pourquoi utiliser le filtre Bloom?

Le filtre Bloom est conçu pour être compact et rapide . Lors de son utilisation, nous pouvons spécifier la probabilité de réponses faussement positives que nous pouvons accepter et, selon cette configuration, le filtre de Bloom occupera aussi peu de mémoire que possible.

En raison de cette économie d’espace, le filtre de Bloom tiendra facilement dans la mémoire même pour un grand nombre d’éléments. Certaines bases de données, y compris Cassandra et Oracle, utilisent ce filtre comme première vérification avant de passer sur le disque ou le cache, par exemple, lorsqu’une demande pour un ID spécifique est reçue.

Si le filtre indique que l’ID n’est pas présent, la base de données peut arrêter le traitement de la demande et revenir au client. Sinon, il va sur le disque et renvoie l’élément s’il se trouve sur le disque.

4. Création d’un filtre de Bloom

Supposons que nous voulions créer un filtre Bloom pour un maximum de 500 Entiers et pouvoir tolérer une probabilité de faux positifs de 1% (0,01).

Nous pouvons utiliser la classe BloomFilter de la bibliothèque Guava pour y parvenir. Nous devons indiquer le nombre d’éléments que nous prévoyons insérer dans le filtre et la probabilité de faux positif souhaitée:

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

Ajoutons maintenant quelques chiffres au filtre:

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

Nous n’avons ajouté que trois éléments et nous avons défini que le nombre maximal d’insertions sera de 500. Notre filtre de Bloom devrait donc produire des résultats très précis . Essayons-le avec la méthode mightContain () :

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

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

Comme son nom l’indique, nous ne pouvons pas être sûrs à 100% qu’un élément donné est réellement dans le filtre lorsque la méthode retourne true .

Lorsque mightContain () renvoie true dans notre exemple, nous pouvons être certains à 99% que l’élément est dans le filtre et il existe une probabilité de 1% que le résultat soit un faux positif. Lorsque le filtre renvoie faux , nous pouvons être sûrs à 100% que l’élément n’est pas présent.

5. Filtre de floraison sursaturé

Lorsque nous concevons notre filtre de Bloom , il est important de fournir une valeur raisonnablement précise pour le nombre d’éléments attendu.

Sinon, notre filtre renverra les faux positifs à un taux beaucoup plus élevé que souhaité. Voyons un exemple.

Supposons que nous ayons créé un filtre avec une probabilité de faux positif souhaitée de 1% et un nombre d’éléments attendu égal à cinq, puis nous avons inséré 100 000 éléments:

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

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

Le nombre d’éléments requis étant si petit, le filtre occupera très peu de mémoire.

Cependant, à mesure que nous ajoutons plus d’éléments que prévu, le filtre devient sursaturé et présente une probabilité beaucoup plus grande de renvoyer des résultats faux positifs que le pourcentage souhaité:

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

Notez que la méthode mightContatin () a renvoyé true même pour une valeur que nous n’avions pas insérée ** dans le filtre auparavant.

6. Conclusion

Dans ce rapide tutoriel, nous avons examiné la nature probabiliste de la structure de données du filtre de Bloom, en utilisant l’implémentation de Guava .

Vous pouvez trouver la mise en œuvre de tous ces exemples et extraits de code dans le projet GitHub

Ceci est un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.