sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo optimizar la búsqueda booleana de texto completo de MySQL? (¿O con qué reemplazarlo?) - C#

Primero, debe darse cuenta de que la compatibilidad con RDBMS para la indexación de texto completo es un truco para forzar una tecnología diseñada para permitir un acceso eficiente a datos estructurados para tratar con texto no estructurado. (Sí, eso es solo mi opinión. Si es necesario, puedo defenderlo ya que entiendo muy bien ambas tecnologías.;)

Entonces, ¿qué se puede hacer para mejorar el rendimiento de búsqueda?

Opción uno:"La mejor herramienta para la tarea"

La mejor manera de manejar la búsqueda de texto completo dentro de un corpus de documentos es usar tecnología específicamente diseñada para hacerlo, como SOLR (Lucene) de Apache o Sphinx de err, Esfinge.

Por razones que quedarán claras a continuación, recomiendo encarecidamente este enfoque.

Opción dos:precargue sus resultados

Cuando se construyen soluciones de búsqueda basadas en texto, el enfoque habitual es indexar todos los documentos en un solo índice de búsqueda y, si bien este podría ser el más conveniente, no es el único enfoque.

Suponiendo que lo que está buscando se puede cuantificar fácilmente en un conjunto de reglas conocidas, podría ofrecer un estilo de búsqueda más "guiado" que simplemente texto completo no calificado. Lo que quiero decir con esto es que, si su aplicación puede beneficiarse de guiar a los usuarios a los resultados, puede precargar varios conjuntos de resultados basados ​​en un conjunto conocido de reglas en sus propias tablas y, por lo tanto, reducir la mayor parte de los datos que se buscarán.

Si espera que la mayoría de sus usuarios se beneficien de un conjunto conocido de términos de búsqueda en un orden conocido, puede construir su interfaz de usuario de búsqueda para favorecer esos términos.

Entonces, suponiendo que la mayoría de los usuarios buscan una variedad de automóviles, puede ofrecer búsquedas predefinidas basadas en el modelo, el año, la condición, etc. Su interfaz de usuario de búsqueda se diseñaría como una serie de menús desplegables para "guiar" a los usuarios a resultados específicos.

O si la mayoría de las búsquedas serán por un tema principal específico (por ejemplo, "automóviles"), puede predefinir una tabla de solo aquellos registros que haya identificado previamente como relacionados con automóviles.

Ambos enfoques reducirían la cantidad de registros a buscar y, por lo tanto, aumentarían los tiempos de respuesta.

Opción tres:"Hazlo tú mismo"

Si no puede integrar una tecnología de búsqueda externa en su proyecto y la carga previa no es una opción, todavía hay formas de mejorar enormemente los tiempos de respuesta de las consultas de búsqueda, pero difieren según lo que necesita lograr y cómo espera que se realicen las búsquedas. .

Si espera que los usuarios busquen usando palabras clave o frases únicas y relaciones booleanas entre ellas, podría considerar construir su propio 'índice invertido ' de su corpus. (Esto es lo que ya hace la búsqueda booleana de texto completo de MySQL, pero hacerlo usted mismo permite un mayor control sobre la velocidad y la precisión de la búsqueda).

Para crear un índice invertido a partir de sus datos existentes:

Paso 1. Crea tres tablas

    // dict - a dictionary containing one row per unique word in corpus  
    create table dict (    
      id int primary key,  
      word varchar  
    )

    // invert - an inverted_index to map words to records in corpus  
    create table invert (    
      id int primary key,  
      rec_id int,  
      word_id int  
    )

    // stopwords - to contain words to ignore when indexing (like a, an, the, etc)
    create table stopwords ( 
      id int primary key,  
      word varchar  
    )

Nota:Esto es solo un boceto. Querrá agregar índices y restricciones, etc. cuando realmente cree estas tablas.

La tabla de palabras vacías se usa para reducir el tamaño de su índice a solo aquellas palabras que son importantes para las consultas esperadas de los usuarios. Por ejemplo, rara vez es útil indexar artículos en inglés, como 'a', 'an', 'the', ya que no aportan un significado útil a las búsquedas de palabras clave.

Por lo general, necesitará una lista de palabras vacías elaborada específicamente a las necesidades de su aplicación. Si nunca espera que los usuarios incluyan los términos "rojo", "blanco" o "azul" en sus consultas o si estos términos aparecen en todos registro de búsqueda, querrá agregarlos a su lista de palabras vacías.

Consulte la nota al final de este mensaje para obtener instrucciones sobre cómo usar su propia lista de palabras vacías en MySQL.

Véase también:

Paso 2. Construya el índice invertido

Para crear un índice invertido a partir de sus registros existentes, deberá (pseudocódigo):

    foreach( word(w) in record(r) ) {
      if(w is not in stopwords) {
        if( w does not exist in dictionary) {
          insert w to dictionary at w.id
        }
        insert (r.id, w.id) into inverted_index
      }
    }
Más sobre palabras vacías:

En lugar de usar una lista específica de palabras vacías, la prueba 'si (w no está en palabras vacías)' podría tomar otras decisiones en lugar de su lista de palabras inaceptables o como un complemento de la misma.

Es posible que su aplicación desee filtrar todas las palabras de menos de 4 caracteres o solo incluir palabras de un conjunto predefinido.

Al crear su propio índice invertido, obtiene un control mucho mayor y más detallado sobre la búsqueda.

Paso 3. Consulta el índice invertido usando SQL

Este paso realmente depende de cómo espera que se envíen las consultas a su índice.

Si las consultas van a ser 'codificadas', simplemente puede crear la declaración de selección usted mismo o si necesita admitir consultas ingresadas por el usuario, deberá convertir cualquier lenguaje de consulta que elija en una declaración SQL (normalmente se hace usando un analizador simple).

Suponiendo que desea recuperar todos los documentos que coincidan con la consulta lógica '(palabra1 Y palabra2) O palabra3', un posible enfoque podría ser:

CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS 
    ( SELECT rec_id, COUNT(rec_id) AS count 
      FROM invert AS I, dict AS D 
      WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2') 
      GROUP BY I.rec_id 
      HAVING count=2
    ) 
    UNION (
      SELECT rec_id, 1 AS count 
      FROM invert AS I, dict AS D
      WHERE I.word_id=D.id AND D.word='word3'
    );

SELECT DISTINCT rec_id FROM temp_results;

DROP TABLE temp_results;

NOTA:Esto es solo un primer paso desde la parte superior de mi cabeza. Confío en que existen formas más eficientes de convertir una expresión de consulta booleana en una declaración SQL eficiente y agradezco todas y cada una de las sugerencias para mejorar.

Para buscar frases, deberá agregar un campo al índice invertido para representar la posición en la que apareció la palabra dentro de su registro y tenerlo en cuenta en su SELECCIÓN.

Y finalmente, deberá actualizar su índice invertido a medida que agregue nuevos registros o elimine los antiguos.

Palabra final

La "búsqueda de texto completo" se incluye en un área de investigación muy amplia conocida como "Recuperación de información" o IR, y hay muchos libros sobre el tema, incluidos

Consulte Amazon para obtener más información.

Notas

Cómo usar su propia lista de palabras vacías en MySQL

Para usar su propia lista de palabras vacías en MySQL:

  1. Cree su propia lista de palabras vacías, una palabra por línea, y guárdela en una ubicación conocida de su servidor, por ejemplo:/usr/local/lib/IR/stopwords.txt

  2. Edite my.cnf para agregar o actualizar las siguientes líneas:
        [mysqld]  
        ft_min_word_len=1    
        ft_max_word_len=40  
        ft_stopword_file=/usr/local/lib/IR/stopwords.txt
    

    que establecerá la longitud mínima y máxima de las palabras legales en 1 y 40, respectivamente, y le indicará a mysqld dónde encontrar su lista personalizada de palabras vacías.

    (Nota:el ft_max_word_len predeterminado es 84, lo que creo que es bastante excesivo y puede causar que se indexen series de cadenas que no son palabras reales).

  3. Reiniciar mysqld

  4. Soltar y volver a crear todos los índices relacionados con el texto completo