Tengo el siguiente problema: tengo una base de datos que contiene más de 2 millones de registros. Cada registro tiene un campo de cadena X y quiero mostrar una lista de registros para los cuales el campo X contiene una cadena determinada. Cada registro tiene un tamaño de aproximadamente 500 bytes.
Para hacerlo más concreto: en la GUI de mi aplicación tengo un campo de texto donde puedo ingresar una cadena. Sobre el campo de texto tengo una tabla que muestra los (primeros N, por ejemplo, 100) registros que coinciden con la cadena en el campo de texto. Cuando escribo o elimino un carácter en el campo de texto, el contenido de la tabla debe actualizarse sobre la marcha.
Me pregunto si hay una manera eficiente de hacer esto usando estructuras de índice apropiadas y / o almacenamiento en caché. Como se explicó anteriormente, solo quiero mostrar los primeros N elementos que coinciden con la consulta. Por lo tanto, para N lo suficientemente pequeño, no debería ser un gran problema cargar los elementos coincidentes de la base de datos. Además, el almacenamiento en caché de elementos en la memoria principal puede acelerar la recuperación.
Creo que el problema principal es cómo encontrar los elementos coincidentes rápidamente, dada la cadena de patrón. ¿Puedo confiar en algunas instalaciones de DBMS o tengo que construir un índice en memoria yo mismo? ¿Algunas ideas?
EDITAR
He realizado un primer experimento. He dividido los registros en diferentes archivos de texto (como máximo 200 registros por archivo) y coloqué los archivos en diferentes directorios (utilicé el contenido de un campo de datos para determinar el árbol de directorios). Termino con aproximadamente 50000 archivos en aproximadamente 40000 directorios. Luego ejecuté Lucene para indexar los archivos. Buscar una cadena con el programa de demostración Lucene es bastante rápido. Dividir e indexar tomó unos minutos: esto es totalmente aceptable para mí porque es un conjunto de datos estáticos que quiero consultar.
El siguiente paso es integrar Lucene en el programa principal y usar los hits devueltos por Lucene para cargar los registros relevantes en la memoria principal.
fuente
Respuestas:
En lugar de poner sus datos dentro de la base de datos, puede guardarlos como un conjunto de documentos (archivos de texto) por separado y mantener el enlace (ruta / url, etc.) en la base de datos.
Esto es esencial porque la consulta SQL por diseño será muy lenta tanto en la búsqueda de subcadenas como en la recuperación.
Ahora, su problema se formula como tener que buscar los archivos de texto que contienen el conjunto de cadenas. Hay dos posibilidades aquí.
Coincidencia de subcadenas Si sus blobs de texto son una sola picadura o palabra (sin espacios en blanco) y necesita buscar subcadenas arbitrarias dentro de ella. En tales casos, debe analizar cada archivo para encontrar los mejores archivos posibles que coincidan. Uno usa algoritmos como el algoritmo Boyer Moor. Vea esto y esto para más detalles. Esto también es equivalente a grep, porque grep usa cosas similares en su interior. Pero aún puede hacer al menos más de 100 grep (el peor de los casos, 2 millones) antes de regresar.
Búsqueda indexada Aquí está asumiendo que el texto contiene un conjunto de palabras y la búsqueda está limitada a longitudes de palabras fijas. En este caso, el documento se indexa sobre todas las posibles apariciones de palabras. Esto a menudo se llama "búsqueda de texto completo". Hay varios algoritmos para hacer esto y varios proyectos de código abierto que se pueden usar directamente. Muchos de ellos también admiten búsquedas con comodines, búsquedas aproximadas, etc., como se muestra a continuación:
a. Apache Lucene: http://lucene.apache.org/java/docs/index.html
b. OpenFTS: http://openfts.sourceforge.net/
c. Sphinx http://sphinxsearch.com/
Lo más probable es que si necesita "palabras fijas" como consultas, el enfoque dos será muy rápido y efectivo.
fuente
La tecnología que está buscando es la indexación de texto completo. La mayoría de los RDBMS tienen algún tipo de capacidades integradas que podrían funcionar aquí, o podría usar algo como Lucene si quisiera ser más elegante y / o simplemente ejecutarlo en la memoria.
fuente
¿Has considerado un trie ? Básicamente, usted construye un árbol utilizando prefijos comunes, por lo que todas las palabras que comienzan con las mismas letras son elementos secundarios del mismo nodo. Si vas a admitir la coincidencia en cualquier subcadena, entonces tendrás que generar algún tipo de índice permutado y construir tu trie a partir de eso. Sin embargo, eso puede terminar eliminando sus requisitos de almacenamiento.
fuente
Me gustaría agregar, además de la respuesta de Wyatt Barnett, que una solución RDBMS con indexación de texto completo en la columna adecuada funcionará, pero si desea utilizar un caché local de registros recuperados previamente, entonces necesita un plan para utilizar estos registros en caché a su ventaja.
Una opción es recopilar los identificadores únicos de estos registros que EXPLÍCITAMENTE no desea recuperar de la consulta e incluirlos, posiblemente en a
NOT IN
o aNOT EXISTS
.Sin embargo, una advertencia: usar
NOT IN
oNOT EXISTS
tiende a no ser barato y PUEDE influir negativamente en el rendimiento de su consulta o en el plan de consulta, según el motor de base de datos que esté utilizando. Ejecute un plan de explicación en su consulta final para asegurarse de que se estén utilizando todos sus índices en las columnas afectadas.Tampoco hace daño hacer una comparación de rendimiento entre los dos enfoques para ver cuál es más rápido. Es posible que se sorprenda al descubrir que mantener un caché local y filtrarlos de su consulta explícitamente puede tener un rendimiento peor que una consulta finamente ajustada que recupera todos los registros.
fuente
Por si acaso te lo perdiste. Si utiliza Lucene para su base de datos en lugar de la búsqueda de texto compatible con DB, tendrá que ser extremadamente cuidadoso al modificar su DB. ¿Cómo se asegura de que puede tener atomicidad cuando tiene que hacer cambios tanto en la base de datos como en los recursos externos (Lucene)? Sí, se puede hacer, pero habrá mucho trabajo.
En resumen, está perdiendo el soporte transaccional de DB si coloca a Lucene en su esquema de datos.
fuente
¿Has considerado la esfinge? http://sphinxsearch.com si puede usar una herramienta de terceros, esto sería ideal para lo que está tratando de lograr, es mucho más eficiente en la búsqueda de texto completo que cualquier RDBMS que yo haya usado personalmente.
fuente
Es algo extraño que ninguna de las respuestas presentara el término "índice invertido" , la tecnología que subyace a todas las soluciones similares a Apache Lucene y otras.
El índice invertido es un mapeo de palabras a documentos ("índice invertido a nivel de registro") o incluso ubicaciones precisas de palabras dentro del documento ("índice invertido a nivel de palabra").
Las operaciones lógicas AND y OR son triviales de implementar. Si tiene ubicaciones precisas de palabras, es posible buscar palabras adyacentes, haciendo posible la búsqueda de frases.
Entonces, piense en un índice que contenga tuplas (palabra, archivo, ubicación). Cuando tiene, por ejemplo, ("invertido", "foo.txt", 123), simplemente verifica si ("índice", "foo.txt", 124) es parte del índice para buscar la frase completa "índice invertido" .
Si bien no le recomiendo que vuelva a implementar un motor de búsqueda de texto completo desde cero, es útil saber cómo funcionan tecnologías como Apache Lucene.
Por lo tanto, mi recomendación es aprender cómo funcionan los índices invertidos y elegir una tecnología que los use, como Apache Lucene. Entonces al menos tienes una sólida comprensión de lo que se puede hacer y lo que no se puede hacer.
fuente