Filtro Bloom em Java usando Goiaba

Filtro Bloom em Java usando Goiaba

*1. Visão geral *

Neste artigo, veremos a construção do filtro Bloom da biblioteca Guava. Um filtro Bloom é uma estrutura de dados probabilística com eficiência de memória que podemos usar para responder à pergunta* se um determinado elemento está ou não em um conjunto *.

*Não há falsos negativos* com um filtro Bloom; portanto, quando ele retorna _false_, podemos ter 100% de certeza de que o elemento não está no conjunto.

No entanto, um filtro Bloom pode retornar falsos positivos ; portanto, quando retornar true, há uma alta probabilidade de que o elemento esteja no conjunto, mas não podemos ter 100% de certeza.

Para uma análise mais aprofundada de como um filtro Bloom funciona, você pode acessar este tutorial.

*2. Dependência Maven *

Usaremos a implementação do filtro Bloom do Guava, então vamos adicionar a dependência guava:

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

A versão mais recente pode ser encontrada em Maven Central

===* 3. Por que usar o Bloom Filter? *

O filtro Bloom foi* projetado para ser eficiente em termos de espaço e rápido . Ao usá-lo, podemos *especificar a probabilidade de respostas falsas positivas que podemos aceitar e, de acordo com essa configuração, o filtro Bloom ocupará o mínimo de memória possível.

Devido a essa eficiência de espaço, o filtro Bloom caberá facilmente na memória , mesmo para um grande número de elementos. Alguns bancos de dados, incluindo Cassandra e Oracle, usam esse filtro como a primeira verificação antes de ir para o disco ou cache, por exemplo, quando uma solicitação de um ID específico é recebida.

Se o filtro retornar que o ID não está presente, o banco de dados poderá interromper o processamento da solicitação e retornar ao cliente. Caso contrário, ele será direcionado ao disco e retornará o elemento se ele for encontrado no disco.

*4. Criando um filtro Bloom *

Suponha que desejemos criar um filtro Bloom para até 500 Integers e que possamos tolerar uma probabilidade de um por cento (0,01) de falsos positivos.

Podemos usar a classe BloomFilter da biblioteca Guava para conseguir isso. Precisamos passar o número de elementos que esperamos inserir no filtro e a probabilidade de falso positivo positiva desejada:

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

Agora vamos adicionar alguns números ao filtro:

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

Adicionamos apenas três elementos e definimos que o número máximo de inserções será 500, portanto nosso filtro Bloom* deve gerar resultados muito precisos *. Vamos testá-lo usando o método _mightContain () _:

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

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

Como o nome sugere, não podemos ter 100% de certeza de que um determinado elemento esteja realmente no filtro quando o método retornar true.

Quando mightContain () _ retorna _true em nosso exemplo, podemos ter 99% de certeza de que o elemento está no filtro e há uma probabilidade de um por cento de que o resultado seja um falso positivo. Quando o filtro retorna false, podemos ter 100% de certeza de que o elemento não está presente.

*5. Filtro Bloom saturado em excesso *

Quando projetamos nosso filtro Bloom,* é importante fornecer um valor razoavelmente preciso para o número esperado de elementos *. Caso contrário, nosso filtro retornará falsos positivos a uma taxa muito maior que a desejada. Vamos ver um exemplo.

Suponha que criamos um filtro com uma probabilidade falso-positiva desejada de um por cento e esperamos alguns elementos iguais a cinco, mas inserimos 100.000 elementos:

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

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

Como o número esperado de elementos é muito pequeno, o filtro ocupará muito pouca memória.

No entanto, à medida que adicionamos mais itens do que o esperado, o filtro fica saturado demais e tem uma probabilidade muito maior de retornar resultados positivos falsos do que o percentual desejado:

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

Observe que o método mightContatin () _ retornou _true mesmo para um valor que não inserimos