Entrevista - Como determinar rapidamente se um elemento está em um conjunto?

Como determinar rapidamente se um elemento está em um conjunto? Este tópico é uma pergunta que muitas vezes faço durante entrevistas recentemente, e pessoas diferentes têm muitas respostas diferentes para essa pergunta.

Hoje quero apresentar uma solução que poucos vão mencionar, ou seja, com a ajuda do filtro Bloom.

1. O que é o filtro Bloom?

O filtro Bloom foi proposto por um irmão chamado Bloom em 1970.

Na verdade, pode ser considerado como uma estrutura de dados que consiste em um vetor binário (ou matriz de bits) e uma série de funções de mapeamento aleatório (funções de hash).

Sua vantagem é que a eficiência do espaço e o tempo de consulta são muito melhores do que o algoritmo geral, e a desvantagem é que possui uma certa taxa de reconhecimento falso e é difícil de excluir.

foto

2. Princípio de implementação

Venha com uma foto

foto

 A ideia principal do algoritmo do filtro Bloom é usar n funções de hash para obter diferentes valores de hash, mapeá-los para diferentes posições de índice do array (o comprimento desse array pode ser muito longo) de acordo com o hash e em seguida, defina o valor no bit de índice correspondente para 1.

Para julgar se o elemento aparece no conjunto, é preciso usar k funções de hash diferentes para calcular o valor de hash e ver se o valor acima da posição do índice correspondente do valor de hash é 1. Se houver um que não seja 1, significa que o elemento não existe na coleção.

Mas também é possível julgar que o elemento está no conjunto, mas o elemento não está, o 1 acima de todas as posições de índice deste elemento é definido por outros elementos, o que leva a uma certa probabilidade de erro de julgamento (é por isso que o acima pode viver em um conjunto) A causa raiz, porque haverá um certo conflito de hash).

Nota: Quanto menor a taxa de falsos positivos, menor o desempenho correspondente.

3. Função

Os filtros Bloom podem ser usados ​​para determinar se um elemento está ( provavelmente ) em um conjunto e, comparados a outras estruturas de dados, os filtros Bloom têm enormes vantagens no espaço e no tempo.

Observe a palavra acima: possivelmente. Fica aqui um suspense, que será analisado em detalhes a seguir.

  • Determine se os dados fornecidos existem

  • Impedir a penetração de cache (julgar se os dados solicitados são eficazes para evitar ignorar diretamente o banco de dados de solicitação de cache), etc., filtragem de spam de caixas de correio, funções de lista negra, etc.

4. Realização concreta

Após ler a ideia do algoritmo do filtro Bloom, então inicie a explicação da implementação específica.

Deixe-me dar um exemplo primeiro. Suponha que haja duas strings, Wangcai e Xiaoqiang. Eles passam pelo algoritmo de hash três vezes respectivamente, e então definem o valor da posição do índice do array correspondente (assumindo que o comprimento do array é 16) para 1 de acordo com o resultado do hash. , primeiro observe a frase "riqueza da prosperidade" :

foto

Após o hash de Wangjing três vezes, os valores são 2, 4 e 6, respectivamente. Em seguida, os valores do índice podem ser obtidos como 2, 4 e 6, respectivamente, de modo que o valor do índice (2, 4 , 6) da matriz é definido como 1. O restante é considerado como 0. Agora suponha que você precise procurar riqueza próspera. Após os mesmos três hashes, verifica-se que os valores das posições correspondentes aos índices 2 , 4 e 6 são todos 1, então pode-se julgar que pode existir riqueza próspera .

Em seguida, insira Xiaoqiang no filtro Bloom, o processo real é o mesmo que o acima, assumindo que os subscritos obtidos são 1, 3, 5

foto

Além da existência de Wangcai, Xiaoqiang é assim no filtro Bloom neste momento, e a matriz real combinando Wangcai e Xiaoqiang é assim:

foto

 Agora há um dado: 9527. Agora o requisito é julgar se 9527 existe. Suponha que os índices obtidos por 9527 após três hashes sejam: 5, 6 e 7. Acontece que o valor da posição com o subscrito 7 é 0, então pode ser determinado com certeza que 9527 não deve existir.

Então veio um  007 doméstico . Após três hashes, os índices obtidos são: 2, 3 e 5. Acontece que os valores correspondentes aos índices 2, 3 e 5 são todos 1, então pode ser julgado grosseiramente que o  007 doméstico possa existir. Mas, na verdade, após nossa demonstração agora, o doméstico 007 não existe de forma alguma. A razão pela qual o valor das posições do índice 2, 3 e 5 é 1 é porque outros dados são definidos.

Falando nisso, não sei se todos entendem o papel do filtro Bloom.

foto

 5. Implementação do código

Como programadores java, estamos muito felizes. Usamos muitos frameworks e ferramentas, e eles são basicamente encapsulados. Para filtros Bloom, usamos classes de ferramentas encapsuladas pelo google. Claro, existem outras maneiras que você pode explorar.

Primeiro adicione dependências

<!--布隆过滤依赖-->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>25.1-jre</version>
</dependency>

Implementação do código

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.Charset;

public class BloomFilterDemo {
    
    public static void main(String[] args) {
        /**
         * 创建一个插入对象为一亿,误报率为0.01%的布隆过滤器
         * 不存在一定不存在
         * 存在不一定存在
         * ----------------
         *  Funnel 对象:预估的元素个数,误判率
         *  mightContain :方法判断元素是否存在
         */
        BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 100000000, 0.0001);
        bloomFilter.put("死");
        bloomFilter.put("磕");
        bloomFilter.put("Redis");
        System.out.println(bloomFilter.mightContain("Redis"));
        System.out.println(bloomFilter.mightContain("Java"));
    }
}

 Explicações específicas foram escritas nos comentários. Neste ponto, acredito que todos devem entender o filtro Bloom e como usá-lo.

6. Combate real

Vamos simular um cenário onde a penetração de cache é resolvida por um filtro bloom.

Antes de tudo, você sabe o que é penetração de cache?

Penetração de cache significa que os usuários acessam dados que não estão no cache nem no banco de dados. Como o cache não existe, eles acessarão o banco de dados se a simultaneidade for alta. É fácil sobrecarregar o banco de dados

Como o filtro Bloom resolve esse problema? ele

O princípio é este: coloque todas as condições de consulta no banco de dados no filtro bloom, quando uma solicitação de consulta chegar, ela será verificada primeiro através do filtro bloom, e se for julgado que o valor da consulta solicitada existe, ela continuará check; Se for julgado que a consulta solicitada não existe, ela será descartada diretamente.

Seu código é o seguinte:

String get(String key) {
    String value = redis.get(key);     
    if (value  == null) {
        if(!bloomfilter.mightContain(key)){
            return null; 
        }else{
            value = db.get(key); 
            redis.set(key, value); 
        }    
    }
    return value;
}

7. Resumo

Este artigo detalha o que é um filtro bloom? qual é o efeito? O princípio de implementação e o filtro Bloom são explicados a partir de muitos aspectos do nível de código. Espero poder contribuir para o seu progresso de aprendizagem.

Acho que você gosta

Origin blog.csdn.net/qq_34272760/article/details/121198811
Recomendado
Clasificación