¡6 soluciones para la deduplicación de URL! (Con código de implementación detallado)

La eliminación de URL se encuentra a menudo en nuestro trabajo diario y entrevistas, como estas: Se
mj.png
puede ver que empresas de Internet conocidas como Alibaba, NetEase Cloud, Youku y Homework Gang han aparecido preguntas de entrevistas similares, y la eliminación de URL Más similares, como el juicio de listas blancas / negras de IP, etc., a menudo aparecen en nuestro trabajo, por lo que este artículo se centrará en el problema de eliminar URL duplicadas.

Ideas de deduplicación de URL

Independientemente del escenario comercial y la cantidad de datos, podemos utilizar los siguientes esquemas para lograr juicios repetidos de URL:

  1. Utilice la colección Set de Java para determinar si la URL está duplicada de acuerdo con el resultado de la adición (la adición exitosa significa que la URL no está duplicada);
  2. Use la colección Set en Redis para juzgar si la URL está duplicada de acuerdo con el resultado al agregar;
  3. Almacene las URL en la base de datos y luego utilice las instrucciones SQL para determinar si hay URL duplicadas;
  4. Establezca la columna URL en la base de datos como un índice único y juzgue si la URL está duplicada de acuerdo con el resultado cuando se agrega;
  5. Utilice el filtro Bloom de Guava para realizar juicios de URL;
  6. Utilice el filtro Bloom de Redis para realizar juicios de URL.

La realización concreta del esquema anterior es la siguiente.

Esquema de implementación de deduplicación de URL

1. Use la colección Set de Java para juzgar pesado

La colección Set es intrínsecamente no repetible. Solo se puede usar para almacenar elementos con valores diferentes. Si los valores son los mismos, la adición fallará. Por lo tanto, podemos determinar si la URL está duplicada agregando el resultado de la colección Set. El código de implementación es el siguiente:

public class URLRepeat {
    // 待去重 URL
    public static final String[] URLS = {
            "www.apigo.cn",
            "www.baidu.com",
            "www.apigo.cn"
    };
    public static void main(String[] args) {
        Set<String> set = new HashSet();
        for (int i = 0; i < URLS.length; i++) {
            String url = URLS[i];
            boolean result = set.add(url);
            if (!result) {
                // 重复的 URL
                System.out.println("URL 已存在了:" + url);
            }
        }
    }
}

El resultado de la ejecución del programa es:

La URL ya existe: www.apigo.cn

A partir de los resultados anteriores, se puede ver que el uso del conjunto Set puede realizar la función de evaluación de URL.

2.Desduplicación de la colección Redis Set

La idea de usar la colección Set de Redis es la misma que la idea de la colección Set de Java. Ambas se implementan usando la no repetibilidad de Set. Primero usemos el cliente de Redis redis-cli para implementar un ejemplo de juicio de URL:
image.png
Se puede ver en los resultados anteriores que cuando la adición es exitosa, significa que la URL no se repite, pero cuando la adición falla (el resultado es 0), significa que la URL ya existe.

Usemos código para implementar la deduplicación de conjuntos de Redis. El código de implementación es el siguiente:

// 待去重 URL
public static final String[] URLS = {
    "www.apigo.cn",
    "www.baidu.com",
    "www.apigo.cn"
};

@Autowired
RedisTemplate redisTemplate;

@RequestMapping("/url")
public void urlRepeat() {
    for (int i = 0; i < URLS.length; i++) {
        String url = URLS[i];
        Long result = redisTemplate.opsForSet().add("urlrepeat", url);
        if (result == 0) {
            // 重复的 URL
            System.out.println("URL 已存在了:" + url);
        }
    }
}

El resultado de la ejecución del programa anterior es:

La URL ya existe: www.apigo.cn

En el código anterior, usamos la RedisTemplate implementación en Spring Data.  Para usar RedisTemplate objetos en el proyecto Spring Boot,  primero debemos presentar el  spring-boot-starter-data-redis marco. La información de configuración es la siguiente:

<!-- 添加操作 RedisTemplate 引用 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Luego, debe configurar la información de conexión de Redis en el proyecto y configurar lo siguiente en application.properties:

spring.redis.host=127.0.0.1
spring.redis.port=6379
#spring.redis.password=123456 # Redis 服务器密码,有密码的话需要配置此项

Después de los dos pasos anteriores, podemos usar RedisTemplate objetos para operar Redis normalmente en proyectos Spring Boot  .

image.png

3. Deduplicación de la base de datos

También podemos utilizar la base de datos para realizar el juicio repetido de la URL. Primero, primero diseñamos una tabla de almacenamiento de URL, como se muestra en la siguiente figura:
image.png
El SQL correspondiente a esta tabla es el siguiente:

/*==============================================================*/
/* Table: urlinfo                                               */
/*==============================================================*/
create table urlinfo
(
   id                   int not null auto_increment,
   url                  varchar(1000),
   ctime                date,
   del                  boolean,
   primary key (id)
);

/*==============================================================*/
/* Index: Index_url                                             */
/*==============================================================*/
create index Index_url on urlinfo
(
   url
);

Entre ellos se  id encuentra una clave primaria autoincrementada, y el  url  campo se establece como un índice. La configuración del índice puede acelerar la consulta.

Primero agregamos dos datos de prueba a la base de datos, como se muestra en la siguiente figura:

image.png

Usamos la instrucción SQL para consultar, como se muestra en la siguiente figura:
image.png
Si el resultado es mayor que 0, significa que hay una URL duplicada, de lo contrario significa que no hay una URL duplicada.

4. Desduplicación de índices únicos

También podemos utilizar el índice único de la base de datos para evitar la duplicación de URL, su implementación es muy similar a la colección Set anterior.

Primero, establecemos un índice único para el campo URL y luego agregamos los datos de la URL. Si se puede agregar correctamente, significa que la URL no se repite, de lo contrario significa que se repite.

La implementación de SQL para crear un índice único es la siguiente:

create unique index Index_url on urlinfo
(
   url
);

5. Filtro de guayaba Bloom para eliminar

Bloom Filter (Filtro Bloom) 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 superan con creces el algoritmo general, pero la desventaja es que tiene una cierta tasa de reconocimiento erróneo y dificultad de eliminación.

La implementación principal del filtro Bloom es una matriz de bits muy grande y varias funciones hash. Suponga que la longitud de la matriz de bits es my el número de funciones hash es k.

Tome la figura anterior como ejemplo, el flujo de operación específico: suponga que hay 3 elementos {x, y, z} en el conjunto y el número de funciones hash es 3. Primero, inicialice la matriz de bits y establezca el bit 0 para cada bit en ella. Para cada elemento en el conjunto, los elementos se asignan a través de tres funciones hash a su vez, y cada asignación generará un valor hash, que corresponde a un punto en la matriz de bits, y luego la posición correspondiente a la matriz de bits se marca como 1 , Al consultar si el elemento W existe en el conjunto, el mismo método asigna W a 3 puntos en la matriz de bits por hash. Si uno de los tres puntos no es 1, se puede juzgar que el elemento no debe existir en el conjunto. Por el contrario, si los 3 puntos son 1, el elemento puede existir en el conjunto. Nota: No es posible juzgar si el elemento debe existir en la colección y puede haber una cierta tasa de errores de cálculo. Puede verse en la figura: Supongamos que un determinado elemento corresponde a los tres puntos 4, 5 y 6 a través del mapeo. Si bien estos 3 puntos son todos 1, es obvio que estos 3 puntos son las posiciones obtenidas al hacer hashing de diferentes elementos. Por lo tanto, esta situación muestra que aunque los elementos no están en el conjunto, pueden corresponder a todos 1. Esta es la tasa de error de juicio La razón de la existencia.

Podemos usar el marco de Guava provisto por Google para operar el filtro Bloom, de modo que primero podamos agregar la referencia de Guava en pom.xml, y la configuración es la siguiente:

<!-- 添加 Guava 框架 -->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>

Código de implementación para el juicio de URL:

public class URLRepeat {
    // 待去重 URL
    public static final String[] URLS = {
            "www.apigo.cn",
            "www.baidu.com",
            "www.apigo.cn"
    };

    public static void main(String[] args) {
        // 创建一个布隆过滤器
        BloomFilter<String> filter = BloomFilter.create(
                Funnels.stringFunnel(Charset.defaultCharset()),
                10, // 期望处理的元素数量
                0.01); // 期望的误报概率
        for (int i = 0; i < URLS.length; i++) {
            String url = URLS[i];
            if (filter.mightContain(url)) {
                // 用重复的 URL
                System.out.println("URL 已存在了:" + url);
            } else {
                // 将 URL 存储在布隆过滤器中
                filter.put(url);
            }
        }
    }
}

El resultado de la ejecución del programa anterior es:

La URL ya existe: www.apigo.cn

6.desduplicación del filtro Redis Bloom

Además del filtro Bloom de Guava, también podemos usar el filtro Bloom de Redis para implementar el juicio de URL. Antes de usar, primero debemos asegurarnos de que la versión del servidor de Redis sea superior a 4.0 (solo admite filtros de floración por encima de esta versión) y habilitar la función de filtro de floración de Redis para que se use normalmente.

Tomando Docker como ejemplo, demostremos la instalación y activación del filtro de floración de Redis. Primero descargue el filtro de floración de Redis y luego encienda el filtro de floración cuando reinicie el servicio de Redis, como se muestra en la siguiente figura:
image.png

Uso del filtro Bloom Después de que el filtro Bloom
normalmente está activado, primero usamos el cliente Redis redis-cli para implementar el juicio de URL del filtro Bloom , el comando de implementación es el siguiente:
image.png

En Redis, no hay muchos comandos operativos para los filtros Bloom, incluidos principalmente los siguientes:

  • bf.add añadir elemento;
  • bf.exists determina si un elemento existe;
  • bf.madd agrega múltiples elementos;
  • bf.mexists juzgan si existen múltiples elementos;
  • bf.reserve establece la tasa de precisión del filtro Bloom.

A continuación, usamos código para demostrar el uso de los filtros Redis Bloom:

import redis.clients.jedis.Jedis;
import utils.JedisUtils;

import java.util.Arrays;

public class BloomExample {
    // 布隆过滤器 key
    private static final String _KEY = "URLREPEAT_KEY";
    
    // 待去重 URL
    public static final String[] URLS = {
            "www.apigo.cn",
            "www.baidu.com",
            "www.apigo.cn"
    };

    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedis();
         for (int i = 0; i < URLS.length; i++) {
            String url = URLS[i];
            boolean exists = bfExists(jedis, _KEY, url);
            if (exists) {
                // 重复的 URL
                System.out.println("URL 已存在了:" + url);
            } else {
                bfAdd(jedis, _KEY, url);
            }
        }
    }

    /**
     * 添加元素
     * @param jedis Redis 客户端
     * @param key   key
     * @param value value
     * @return boolean
     */
    public static boolean bfAdd(Jedis jedis, String key, String value) {
        String luaStr = "return redis.call('bf.add', KEYS[1], KEYS[2])";
        Object result = jedis.eval(luaStr, Arrays.asList(key, value),
                Arrays.asList());
        if (result.equals(1L)) {
            return true;
        }
        return false;
    }

    /**
     * 查询元素是否存在
     * @param jedis Redis 客户端
     * @param key   key
     * @param value value
     * @return boolean
     */
    public static boolean bfExists(Jedis jedis, String key, String value) {
        String luaStr = "return redis.call('bf.exists', KEYS[1], KEYS[2])";
        Object result = jedis.eval(luaStr, Arrays.asList(key, value),
                Arrays.asList());
        if (result.equals(1L)) {
            return true;
        }
        return false;
    }
}

El resultado de la ejecución del programa anterior es:

La URL ya existe: www.apigo.cn

para resumir

Este artículo presenta 6 soluciones de deduplicación de URL. Entre ellas, Redis Set, el filtro Redis Bloom, la base de datos y el índice único son adecuados para sistemas distribuidos. Si se trata de un sistema distribuido masivo, se recomienda utilizar el filtro Redis Bloom. Para lograr la deduplicación de URL, si se trata de una sola máquina con datos masivos, se recomienda utilizar Bloomer de Guava para lograr la deduplicación de URL .

Supongo que te gusta

Origin blog.csdn.net/qq_46388795/article/details/108511808
Recomendado
Clasificación