¿Qué es un filtro Bloom? ¡Vamos a ver!

 Filtro Bloom, solo mira el nombre, ¿no es solo un filtro? En primer lugar, todos conocen los filtros, como tamices, gasas y otras herramientas que se utilizan para filtrar partículas grandes. El uso de filtros puede filtrar algunas cosas no deseadas y finalmente obtener lo que queremos. Recuerde el anuncio de una determinada agua mineral, ¡todos los procesos pasan por más de 20 procesos de filtrado! ¡La piel de vaca explotó! ¡Quizás filtrar arena o cualquier otra cosa pueda considerarse como una capa de filtrado! [Sonrisa levemente: Jaja]

Hace unos días, cuando estaba mirando Redis, vi una estructura llamada BitMap. Después de terminar de leerlo, grité: ¡Buen chico, no es esta la raíz de los filtros Bloom! Entonces, silenciosamente golpeé una flecha en mi corazón y apunté al filtro Bloom.

Vamos, primero agrega una entrada de Baidu, muestra el número de palabras:

Bloom Filter (Bloom Filter) fue propuesto por Bloom en 1970. En realidad, es un vector binario muy largo y una serie de funciones de mapeo aleatorias . Los filtros Bloom se pueden usar para recuperar si un elemento está en una colección . Su ventaja es que la eficiencia del espacio y el tiempo de consulta son mucho mejores que el algoritmo general, pero la desventaja es que tiene una cierta tasa de reconocimiento erróneo y dificultad en el borrado.

Este tipo de explicación de entrada puede no ser muy clara para algunos amigos, así que hablemos de ello en un lenguaje sencillo.

El filtro Bloom, en términos simples, se usa para filtrar, ¿cómo filtrarlo? Primero, preparo una gran cantidad de segmentos, como de 0 a 100 millones, y luego cada número tiene un valor verdadero y falso correspondiente, el valor predeterminado es falso. Luego recibí una solicitud aquí con un parámetro, como Id. ¿Cómo lo filtro? Primero, primero hash todas las ID en la base de datos varias veces (hagámoslo 3 veces), luego habrá 3 valores hash, y luego cambiaré el valor del campo numérico correspondiente de estos 3 números a verdadero si la base de datos tiene 300.000 datos, pediré el hash 900.000 veces y luego cambiaré el valor del campo numérico correspondiente de estos hashes a verdadero. Por supuesto, puede haber duplicados. (Esto se hace con anticipación, al menos se ha hecho antes de que llegue la solicitud, jeje.)

Después de que llegó la solicitud, pedí el hash de los parámetros solicitados, um, también 3 veces, y luego verifiqué el valor correspondiente de este campo numérico, si es verdadero, déjelo pasar, si uno es falso, entonces estoy lo siento, usted La identificación obviamente no está en la base de datos, donde está el amor, el Señor no está esperando!

Por supuesto, si el hash se repite en un determinado segmento de datos, también puede haber un dato. Es muy afortunado. Aunque no está en la base de datos, el valor del hash es verdadero por 3 veces, y es también del filtro.

Por lo tanto, el filtro Bloom tiene tal característica que los existentes pasarán con seguridad y los que no existen pueden pasar.

Por favor, no levante la barra en este momento. El filtro es principalmente para interceptar cargas y ataques. Incluso si faltan algunos peces, después de que se procesa el código, el daño al servidor o la base de datos es casi insignificante. Esta pequeña cantidad de datos el procesamiento es aceptable.

Veamos un diagrama simple:

Diagrama esquemático del filtro Bloom

Como se muestra en la figura, el siguiente segmento de datos se prepara de antemano, y los datos se procesan previamente para modificar el verdadero y el falso en el segmento de datos. Cuando llega la solicitud, se juzga si filtrar los datos de acuerdo con el hash.

Bien, ha salido el diagrama modelo, ¿cómo lo implementamos?

¿Es para crear una matriz? Oye, da la casualidad de que este segmento de datos no es solo una matriz? Luego escriba verdadero y falso en los datos, para que la función no se realice.

Sí, la función se realiza y puede comprender del diagrama esquemático que este segmento de datos debe ser muy grande, de lo contrario se completará casualmente, todos son verdaderos, entonces, ¿qué más se necesita para filtrar? No digamos demasiado, ¡solo decenas de millones! ¿Está seguro de que desea crear una matriz o una lista de decenas de millones de niveles? No hablemos de si esto puede filtrar bien los ataques, ¡solo esta matriz de decenas de millones de niveles es suficiente para el servidor! Venga y venga, hagamos un pequeño cálculo por usted. Para crear un objeto en Java, hagamos el cálculo más pequeño, que es 16 Bytes, multiplicado por diez millones, que es 160 millones de Bytes, que es aproximadamente 1 GB.

Luego, debe realizar múltiples consultas y juicios en esta matriz de 1 GB y luego filtrar.

No hablemos de si puede reducir la presión sobre el servidor. Si hay más filtros Bloom de este tipo, ¡felicidades! ¡juego terminado! El servidor está caído directamente, entonces, ¡qué filtro se necesita!

Simplemente apague el servidor, ¡qué filtro se necesita!  !
Simplemente apague el servidor, ¡qué filtro se necesita! !

       Filtro Bloom: "Las matrices definitivamente no se pueden utilizar. ¡No necesitas matrices para matar en esta vida! ¡También somos un filtro disciplinado!"

        Dado que no necesita una matriz, ¿qué debería usar? La entrada de Baidu también decía: un vector binario muy largo .

Respecto al binario, involucra una parte de la parte inferior de la computadora, lo explicaré un poco aquí.

La programación de computadoras, eventualmente de lenguajes de alto nivel, como Java, C, C ++, etc., al lenguaje ensamblador y luego al lenguaje de máquina, eventualmente se transformará en dos números 0 y 1. La computadora solo reconoce estos dos números, ¿y si ... si no ...? ¡¿Dónde está el amor ?!

Las primeras computadoras grandes son en realidad un reconocimiento de agujeros perforados, pero después de generaciones de actualizaciones, las computadoras actuales ya no saben cuánto superan a sus antepasados, ya sea en almacenamiento o en potencia de cómputo.

De acuerdo, demasiada charla.

Todo el mundo está familiarizado con el almacenamiento, ¿verdad? Incluso si no conoce la capa inferior, siempre entrará en contacto con ella a menudo. Por ejemplo, cientos de gigabytes de películas de acción en un determinado disco duro, teléfonos móviles que utilizan decenas de MB de datos, etc., en realidad son la transmisión de los dos números 1 y 0.

Las unidades familiares son generalmente TB (1024GB), GB (1024MB), MB (1024KB), KB (1024B), B (Byte), entonces, ¿es B la unidad más pequeña?

¡NO! Este B (Byte) todavía está a cierta distancia de 1 y 0, es decir, bit, 1Byte = 8 bit, y bit es el lugar donde se almacenan 1 y 0 en la leyenda, y 1bit es un lugar donde se almacena 1 o 0 . Entonces, es obvio que 1Byte ocupa 8 bits, 1KB es 1024 * 8 = 8192 bits, 1MB es 8,388,608 bits, si cada bit representa un número, puede representar 8,388,608 (nivel de millones), y luego está representado por 1 y 0 Verdadero y falso, ¿no significaría que 1 MB puede representar más de 8 millones de segmentos de datos? Y puede localizar directamente un cierto número, devolver 0 y 1 directamente, y la velocidad es directamente O (1) ¿No es esto solo para los filtros Bloom? Oh, no, al contrario, ¿no debería el filtro Bloom simplemente hacer uso de este mecanismo de almacenamiento? Veamos un diagrama esquemático:

Diagrama esquemático del almacenamiento del filtro Bloom

Mira, solo se necesitan entre 10 y 20 millones de espacio para completar el filtro Bloom. ¿No es fragante? ¡Qué matriz quieres! El filtro Bloom es muy simple de entender, pero es un poco problemático si lo implementas de forma independiente. Sin embargo, ¡no te preocupes! Java está empaquetado, jeje, echemos un vistazo primero.

public class BloomTest {

    // 需要存储的数据,数据段的话是后台创建的,是根据下面的概率来的, 不用你管的,
    private static int dataAmount = 500000;

    // 百分比,就是漏网之鱼的概率,布隆过滤器总有一些不存在的数据能通过,
    //这个就是不存在的数据能通过的概率
    // 千分之一的概率
    private static double rate = 0.001;
    
    public static void main(String[] args) {

        // 本来想用Integer的,但是字段哪可能刚好是数字啊,字符串的可能更大,适应性更强,反正也是求hash,差别不大。
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()), dataAmount, 0.001);


        // 先塞数据吧
        for (int i = 0; i < dataAmount; i++) {
            String uuid = UUID.randomUUID().toString();
            bloomFilter.put(uuid);
        }
        //数据放好了,开始拦截呗,放50000数据过来呗,
        int number = 0;
        for (int i = 0; i < 50000; i++) {
            String uuid = UUID.randomUUID().toString();
            if (bloomFilter.mightContain(uuid)){
                number++;
            }
        }
        System.out.println("50000条数据误判的数据量为:"+number
                +"\n所占百分百:"+ new BigDecimal(number).divide(new BigDecimal(50000)));
    }
}

Puede ejecutar este método principal usted mismo, el porcentaje es cercano a 0.001, más o menos, el siguiente es el resultado de una de mis ejecuciones:

50000条数据误判的数据量为:51
所占百分百:0.00102

Process finished with exit code 0

  Por cierto, recuerde agregar dependencias al copiar el código, la dependencia maven de BloomFilter de Google (la versión depende de usted):

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

que tal eso? ¿Este filtro Bloom es muy cómodo de usar? ¿Es tan fácil? ¿Es realmente emocionante? Oye, pero mucha gente no los usa.

Este es un filtro Bloom para un solo servidor. Ahora, implementando el servicio, ¿sigue siendo independiente? ¡Me estás tomando el pelo! En un entorno distribuido, ¿tiene un filtro Bloom para cada máquina y la memoria no le cuesta dinero? ¿Eres un tirano? Entonces por favor.

Redis: "¿Entorno distribuido? Estoy familiarizado con él, ven, ven, déjame venir, jeje!".

¡Entonces, Redis está en el escenario! Algunos amigos implementan el filtro Bloom en Redis por sí mismos, pero hay encapsulación en la integración de Java Redis. Para simplificar, no construí la inyección de beans, pero escribí el método de prueba ya simple y luego pasé el método de construcción., Introduce redisson, y luego use el filtro Bloom directamente.

public class RedissonBloomTest {

    // 需要存储的数据,数据段的话是后台创建的,是根据下面的概率来的, 不用你管的,
    private static int dataAmount = 1000000;

    // 百分比,就是漏网之鱼的概率,布隆过滤器总有一些不存在的数据能通过,
    //这个就是不存在的数据能通过的概率
    // 千分之一的概率
    private static double rate = 0.001;

    // 客户端服务,spring中,应该是创建bean,然后直接注入的,我这边为了简单把Redisson在构造方法中初始化了
    RedissonClient redisson;

    public static void main(String[] args) {
        //获取redissonClient 服务
        RedissonClient redissonClient = new RedissonBloomTest().getRedisson();
        //获取(创建)布隆过滤器
        RBloomFilter<String> redisBloomFilter = redissonClient.getBloomFilter("RedisBloomFilter");
        //初始化布隆过滤器
        redisBloomFilter.tryInit(dataAmount, rate);
        // 代码copy过来

        // 先塞数据吧
        for (int i = 0; i < dataAmount; i++) {
            String uuid = UUID.randomUUID().toString();
            //这里塞数据就很慢了,建议少放点数据,生产中肯定要提前弄好,不然很容易出事故哦
            redisBloomFilter.add(uuid);
        }
        //数据放好了,开始拦截呗,放100000数据过来呗,
        int number = 0;
        for (int i = 0; i < 100000; i++) {
            String uuid = UUID.randomUUID().toString();
            if (redisBloomFilter.contains(uuid)){
                number++;
            }
        }
        System.out.println("100000条数据误判的数据量为:"+number
                +"\n所占百分百:"+ new BigDecimal(number).divide(new BigDecimal(100000)));

        redissonClient.shutdown();
    }

    static Config config = new Config();

    static {
        config.useSingleServer()
                .setAddress("redis://127.0.0.1:6379");
    }

    public RedissonBloomTest(){
        redisson = Redisson.create(config);
    }

    public static Config getConfig() {
        return config;
    }

    public RedissonClient getRedisson() {
        return redisson;
    }
}

Este es el resultado después de ejecutar:

100000条数据误判的数据量为:1847
所占百分百:0.01847

Este resultado parece ser un poco diferente de la tasa de error establecida. Observé el tamaño del filtro Bloom y lo comparé con los datos de Google de un millón. El tamaño del filtro Bloom es casi el mismo, todos los cuales son decenas de millones. Sin embargo, esta falsa probabilidad parece ser un poco diferente. (¡Si alguien lo ve, no dude en avisar!)

Es posible que este problema deba solucionarse un poco. Veamos las ventajas y desventajas de los filtros Bloom:

Excelente: simple, conveniente, fácil de filtrar grandes cantidades de datos

Deficiencia: Los datos deben ser ordenados y agregados con anticipación, y solo se pueden usar una vez. Si los datos básicos se eliminan o agregan, el filtro Bloom se restablecerá, lo cual es muy inconveniente.

También existe el escenario de aplicación del filtro Bloom:

1. La penetración de la caché se pregunta con frecuencia en las entrevistas; utilice el filtro Bloom para filtrar directamente

2. Elimine la duplicación de macrodatos. Por ejemplo, en un sistema de rastreador, debemos eliminar la duplicación de la URL.

3. El filtro Bloom también se usa comúnmente en la función de filtrado de correo no deseado. Debido a este filtro, algunos correos electrónicos normales generalmente se colocan en el directorio de correo no deseado. Esto se debe a un error de juicio, la probabilidad es Muy baja.

 

Es peligroso y peligroso, y solo publico este a fin de mes.

sin sacrificio, sin victoria ~

Si sientes que lo que escribiste es aceptable, dale un pulgar hacia arriba ~

Supongo que te gusta

Origin blog.csdn.net/zsah2011/article/details/115300961
Recomendado
Clasificación