MongoDB, una de las principales bases de datos NoSQL, es bien conocido por su rápido rendimiento, esquema flexible, escalabilidad y excelentes capacidades de indexación. En el núcleo de este rápido rendimiento se encuentran los índices de MongoDB, que admiten la ejecución eficiente de consultas al evitar los análisis de colección completa y, por lo tanto, limitar el número de documentos que las búsquedas de MongoDB.
A partir de la versión 2.4, MongoDB comenzó con una función experimental que admite Búsqueda de texto completo utilizando Índices de texto. Esta característica ahora se ha convertido en una parte integral del producto (y ya no es una característica experimental). En este artículo vamos a explorar las funcionalidades de búsqueda de texto completo de MongoDB desde los fundamentos..
Si eres nuevo en MongoDB, te recomiendo que leas los siguientes artículos sobre Envato Tuts + que te ayudarán a entender los conceptos básicos de MongoDB:
Antes de entrar en detalles, veamos algunos antecedentes. La búsqueda de texto completo se refiere a la técnica de búsqueda de un base de datos de texto completo contra los criterios de búsqueda especificados por el usuario. Es algo similar a cómo buscamos cualquier contenido en Google (o, de hecho, cualquier otra aplicación de búsqueda) al ingresar ciertas palabras clave / frases de cadena y recuperar los resultados relevantes ordenados por su clasificación.
Aquí hay algunos escenarios más en los que veríamos una búsqueda de texto completo:
los gatos
en ellos; o para ser más complejos, todas las publicaciones que tengan comentarios que contengan la palabra los gatos
. Antes de continuar, existen ciertos términos generales relacionados con la búsqueda de texto completo que debe conocer. Estos términos son aplicables a cualquier implementación de búsqueda de texto completo (y no específica de MongoDB).
Las palabras de parada son las palabras irrelevantes que se deben filtrar de un texto. Por ejemplo: a, an, the, is, at, which, etc.
Detener es el proceso de reducir las palabras a su raíz. Por ejemplo: palabras como estar de pie, estar de pie, estar de pie, etc. tienen una base común..
Una clasificación relativa para medir cuál de los resultados de búsqueda es más relevante..
Antes de que MongoDB propusiera el concepto de índices de texto, modelaríamos nuestros datos para respaldar las búsquedas de palabras clave o usaríamos expresiones regulares para implementar dichas funcionalidades de búsqueda. Sin embargo, el uso de cualquiera de estos enfoques tenía sus propias limitaciones:
Aparte de estos enfoques, para aplicaciones más avanzadas y complejas centradas en la búsqueda, existen soluciones alternativas como Elastic Search o SOLR. Pero el uso de cualquiera de estas soluciones aumenta la complejidad arquitectónica de la aplicación, ya que MongoDB ahora tiene que hablar con una base de datos externa adicional..
Tenga en cuenta que la búsqueda de texto completo de MongoDB no se propone como un reemplazo completo de las bases de datos de motores de búsqueda como Elastic, SOLR, etc. Sin embargo, se puede usar efectivamente para la mayoría de las aplicaciones que se construyen con MongoDB hoy..
Con la búsqueda de texto completo de MongoDB, puede definir un índice de texto en cualquier campo del documento cuyo valor sea una cadena o una matriz de cadenas. Cuando creamos un índice de texto en un campo, MongoDB tokeniza y deriva el contenido de texto del campo indexado, y configura los índices en consecuencia.
Para entender mejor las cosas, ahora vamos a sumergirnos en algunas cosas prácticas. Quiero que sigas el tutorial conmigo probando los ejemplos en mongo shell. Primero crearemos algunos datos de muestra que usaremos a lo largo del artículo, y luego continuaremos para discutir conceptos clave..
A los efectos de este artículo, considere una colección mensajes
que almacena documentos de la siguiente estructura:
"subject": "Joe tiene un perro", "content": "Los perros son el mejor amigo del hombre", "likes": 60, "year": 2015, "language": "english"
Insertemos algunos documentos de muestra usando el insertar
comando para crear nuestros datos de prueba:
db.messages.insert ("subject": "Joe es dueño de un perro", "content": "Los perros son el mejor amigo del hombre", "likes": 60, "year": 2015, "language": "english" ) db.messages.insert ("subject": "Los perros comen gatos y los perros comen también palomas", "content": "Los gatos no son malvados", "likes": 30, "year": 2015, "language": "english") db.messages.insert ("subject": "Los gatos comen ratas", "content": "Las ratas no cocinan comida", "likes": 55, "year": 2014, "language": "english") db.messages.insert ("subject": "Rats eat Joe", "content": "Joe se comió una rata", "likes": 75, "year": 2014, "language": " Inglés")
Se crea un índice de texto muy similar a la forma en que creamos un índice regular, excepto que especifica el texto
palabra clave en lugar de especificar un orden ascendente / descendente.
Crear un índice de texto en el tema
campo de nuestro documento utilizando la siguiente consulta:
db.messages.createIndex ("subject": "text")
Para probar este índice de texto recién creado en el tema
campo, buscaremos documentos utilizando el $ texto
operador. Estaremos buscando todos los documentos que tengan la palabra clave. perros
en su tema
campo.
Dado que estamos realizando una búsqueda de texto, también estamos interesados en obtener algunas estadísticas sobre la relevancia de los documentos resultantes. Para ello utilizaremos el $ Meta: "textScore"
expresión, que proporciona información sobre el procesamiento de la $ texto
operador. También ordenaremos los documentos por su textScore
utilizando la ordenar
mando. Una mayor textScore
Indica una coincidencia más relevante..
db.messages.find ($ text: $ search: "dogs", score: $ meta: "toextScore"). sort (score: $ meta: "textScore")
La consulta anterior devuelve los siguientes documentos que contienen la palabra clave perros
en su tema
campo.
"_id": ObjectId ("55f4a5d9b592880356441e94"), "subject": "Los perros comen gatos y los perros también comen palomas", "content": "Los gatos no son malvados", "likes": 30, "year": 2015, "language": "english", "score": 1 "_id": ObjectId ("55f4a5d9b592880356441e93"), "subject": "Joe posee un perro", "content": "Los perros son el mejor amigo del hombre", " Me gusta ": 60," año ": 2015," idioma ":" inglés "," puntaje ": 0.6666666666666666
Como puede ver, el primer documento tiene una puntuación de 1 (ya que la palabra clave perro
aparece dos veces en su tema) en comparación con el segundo documento con una puntuación de 0,66. La consulta también ha ordenado los documentos devueltos en orden descendente de su puntuación.
Una pregunta que puede surgir en su mente es que si estamos buscando la palabra clave perros
, ¿Por qué el motor de búsqueda está tomando la palabra clave perro
(sin 's') en consideración? ¿Recuerda nuestra discusión sobre la derivación, donde las palabras clave de búsqueda se reducen a su base? Esta es la razón por la cual la palabra clave perros
se reduce a perro
.
La mayoría de las veces, utilizará la búsqueda de texto en varios campos de un documento. En nuestro ejemplo, habilitaremos la indexación de texto compuesto en la tema
y contenido
campos. Continúa y ejecuta el siguiente comando en mongo shell:
db.messages.createIndex ("subject": "text", "content": "text")
¿Funcionó esto? ¡¡No!! La creación de un segundo índice de texto le dará un mensaje de error que indica que ya existe un índice de búsqueda de texto completo. ¿Por que es esto entonces? La respuesta es que los índices de texto vienen con una limitación de solo un índice de texto por colección. Por lo tanto, si desea crear otro índice de texto, deberá eliminar el existente y volver a crear el nuevo..
db.messages.dropIndex ("subject_text") db.messages.createIndex ("subject": "text", "content": "text")
Después de ejecutar las consultas de creación de índice anteriores, intente buscar todos los documentos con palabras clave gato
.
db.messages.find ($ text: $ search: "cat", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
La consulta anterior generaría los siguientes documentos:
"_id": ObjectId ("55f4af22b592880356441ea4"), "subject": "Los perros comen gatos y los perros también comen palomas", "content": "Los gatos no son malvados", "likes": 30, "year": 2015, "language": "english", "score": 1.333333333333333335 "_id": ObjectId ("55f4af22b592880356441ea5"), "subject": "Cats eat rats", "content": "Ratas no cocinan comida", "me gusta ": 55," año ": 2014," idioma ":" inglés "," puntaje ": 0.666666666666666666
Puede ver que la puntuación del primer documento, que contiene la palabra clave gato
en ambos tema
y contenido
campos, es mas alto.
En el último ejemplo, ponemos un índice combinado en el tema
y contenido
campos. Pero puede haber escenarios en los que desee que cualquier contenido de texto en sus documentos pueda buscarse.
Por ejemplo, considere almacenar correos electrónicos en documentos de MongoDB. En el caso de los correos electrónicos, todos los campos, incluidos Remitente, Destinatario, Asunto y Cuerpo, deben poder buscarse. En tales situaciones, puede indexar todos los campos de cadena de su documento utilizando el PS
especificador de comodín.
La consulta sería algo como esto (asegúrese de que está eliminando el índice existente antes de crear uno nuevo):
db.messages.createIndex ("$ **": "texto")
Esta consulta configuraría automáticamente los índices de texto en cualquier campo de cadena en nuestros documentos. Para probar esto, inserte un nuevo documento con un nuevo campo ubicación
en eso:
db.messages.insert ("subject": "Birds can cook", "content": "Las aves no comen ratas", "likes": 12, "year": 2013, ubicación: "Chicago", "language" :"Inglés")
Ahora si intentas buscar texto con palabra clave chicago
(consulta a continuación), devolverá el documento que acabamos de insertar.
db.messages.find ($ text: $ search: "chicago", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
Algunas cosas en las que me gustaría centrarme aquí:
ubicación
campo después de insertar un nuevo documento. Esto se debe a que ya hemos definido un índice de texto en todo el documento utilizando el PS
operador.Puedes buscar frases como “pájaros inteligentes que aman cocinar”utilizando índices de texto. Por defecto, la búsqueda de frase hace un O busque todas las palabras clave especificadas, es decir, buscará documentos que contengan las palabras clave inteligente
, pájaro
, amor
o cocinar
.
db.messages.find ($ text: $ search: "pájaros inteligentes que cocinan", score: $ meta: "text Score"). sort (score: $ meta: "text Score ")
Esta consulta generaría los siguientes documentos:
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Los pájaros pueden cocinar", "el contenido": "Los pájaros no comen ratas", "me gusta": 12, "año": 2013, "ubicación": "Chicago", "idioma": "inglés", "puntaje": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "sujeto": "Los gatos comen ratas", "contenido": "Las ratas no cocinan "," me gusta ": 55," año ": 2014," idioma ":" inglés "," puntuación ": 0.6666666666666666
En caso de que desee realizar una búsqueda de frase exacta (lógica Y), puede hacerlo especificando comillas dobles en el texto de búsqueda.
db.messages.find ($ text: $ search: "\" cook food \ "", score: $ meta: "textScore"). sort (score: $ meta: "textScore ")
Esta consulta resultaría en el siguiente documento, que contiene la frase "cocinar alimentos" juntos:
"_id": ObjectId ("55f5289bb592880356441eab"), "subject": "Los gatos comen ratas", "content": "Las ratas no cocinan comida", "likes": 55, "year": 2014, "language": "Inglés", "puntuación": 0.6666666666666666
Prefijando una palabra clave de búsqueda con -
(signo menos) excluye todos los documentos que contienen el término negado. Por ejemplo, intente buscar cualquier documento que contenga la palabra clave rata
pero no contiene aves
utilizando la siguiente consulta:
db.messages.find ($ text: $ search: "rat -birds", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
Una funcionalidad importante que no revelé hasta ahora es cómo se ve detrás de la escena y cómo se eliminan las palabras clave de búsqueda, cómo se aplica, se niega la palabra, se niegan, etc.. $ explicar
al rescate. Puede ejecutar la consulta de explicación pasando cierto
como su parámetro, que le dará estadísticas detalladas sobre la ejecución de la consulta.
db.messages.find ($ text: $ search: "los perros que los gatos no comen comieron ratas \" los perros comen \ "-friends", puntuación: $ meta: "textScore"). sort ( puntuación: $ meta: "textScore"). explicar (verdadero)
Si nos fijamos en el planificador de consultas
objeto devuelto por el comando de explicación, podrá ver cómo MongoDB analizó la cadena de búsqueda dada. Observe que descuidó las palabras de alto como quien
, y provino perros
a perro
.
También puede ver los términos que descuidamos de nuestra búsqueda y las frases que usamos en el parsedTextQuery
sección.
"parsedTextQuery": "Terms": ["dog", "cat", "dont", "eat", "eat", "rat", "dog", "eat"], "negatedTerms": ["friend "]," frases ": [" los perros comen "]," frases negadas ": []
La consulta de explicación será muy útil ya que realizamos consultas de búsqueda más complejas y queremos analizarlas.
Cuando tenemos índices en más de un campo en nuestro documento, la mayoría de las veces un campo será más importante (es decir, más peso) que el otro. Por ejemplo, cuando busca en un blog, el título del blog debe ser de mayor peso, seguido del contenido del blog..
El peso predeterminado para cada campo indexado es 1. Para asignar pesos relativos para los campos indexados, puede incluir el pesos
opción mientras usa el createIndex
mando.
Entendamos esto con un ejemplo. Si intentas buscar el cocinar
palabra clave con nuestros índices actuales, dará lugar a dos documentos, los cuales tienen la misma puntuación.
db.messages.find ($ text: $ search: "cook", score: $ meta: "textScore"). sort (score: $ meta: "textScore")
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Los pájaros pueden cocinar", "el contenido": "Los pájaros no comen ratas", "me gusta": 12, "año": 2013, "ubicación": "Chicago", "idioma": "inglés", "puntuación": 0.666666666666666666 "_id": ObjectId ("55f5289bb592880356441eab"), "subject": "Los gatos comen ratas", "contenido": "Las ratas no cocinan "," me gusta ": 55," año ": 2014," idioma ":" inglés "," puntuación ": 0.6666666666666666
Ahora vamos a modificar nuestros índices para incluir pesos; con el tema
campo que tiene un peso de 3 contra el contenido
campo que tiene un peso de 1.
db.messages.createIndex ("$ **": "texto", "pesos": asunto: 3, contenido: 1)
Intenta buscar por palabra clave cocinar
ahora, y verá que el documento que contiene esta palabra clave en el tema
el campo tiene una puntuación más alta (de 2) que la otra (que tiene 0.66).
"_id": ObjectId ("55f5289cb592880356441ead"), "subject": "Los pájaros pueden cocinar", "el contenido": "Los pájaros no comen ratas", "me gusta": 12, "año": 2013, "ubicación": "Chicago", "idioma": "inglés", "puntaje": 2 "_id": ObjectId ("55f5289bb592880356441eab"), "sujeto": "Los gatos comen ratas", "contenido": "Las ratas no cocinan "," me gusta ": 55," año ": 2014," idioma ":" inglés "," puntuación ": 0.6666666666666666
A medida que los datos almacenados en su aplicación aumentan, el tamaño de sus índices de texto también sigue creciendo. Con este aumento en el tamaño de los índices de texto, MongoDB tiene que buscar en todas las entradas indexadas cada vez que se realiza una búsqueda de texto..
Como técnica para mantener su búsqueda de texto eficiente con índices crecientes, puede limitar el número de entradas de índice escaneadas usando condiciones de igualdad con un $ texto
buscar. Un ejemplo muy común de esto sería buscar todas las publicaciones realizadas durante un determinado año / mes, o buscar todas las publicaciones con una determinada categoría / etiqueta.
Si observa los documentos en los que estamos trabajando, tenemos un año
Campo en el que aún no hemos utilizado. Un escenario común sería buscar mensajes por año, junto con la búsqueda de texto completo que hemos estado aprendiendo..
Para esto, podemos crear un índice compuesto que especifique una clave de índice ascendente / descendente en año
seguido de un índice de texto en el tema
campo. Al hacer esto, estamos haciendo dos cosas importantes:
Suelte los índices que ya tiene y cree un nuevo índice compuesto en (año
, tema
):
db.messages.createIndex ("año": 1, "asunto": "texto")
Ahora ejecute la siguiente consulta para buscar todos los mensajes que se crearon en 2015 y contienen el los gatos
palabra clave:
db.messages.find (year: 2015, $ text: $ search: "cats", score: $ meta: "textScore"). sort (score: $ meta: "textScore" )
La consulta devolvería solo un documento coincidente como se esperaba. Si tu explique
esta consulta y mira el ejecuciónStats
, encontraras eso totalDocsExamined
para esta consulta fue 1, lo que confirma que nuestro nuevo índice se utilizó correctamente y que MongoDB solo tuvo que escanear un solo documento mientras ignoraba con seguridad todos los demás documentos que no estaban incluidos en 2015.
Hemos recorrido un largo camino en este artículo aprendiendo sobre índices de texto. Hay muchos otros conceptos que puedes experimentar con índices de texto. Pero debido al alcance de este artículo, no podremos discutirlos en detalle hoy. Sin embargo, veamos brevemente cuáles son estas funcionalidades:
$ idioma
operador. MongoDB actualmente soporta alrededor de 15 idiomas, incluyendo francés, alemán, ruso, etc..Teniendo en cuenta el hecho de que la búsqueda de texto completo de MongoDB no es un reemplazo completo de las bases de datos de motores de búsqueda tradicionales que se utilizan con MongoDB, se recomienda el uso de la funcionalidad nativa de MongoDB por los siguientes motivos:
Como la búsqueda de texto completo es una característica relativamente nueva en MongoDB, existen ciertas funcionalidades de las que carece actualmente. Los dividiría en tres categorías. Echemos un vistazo.
$ texto
expresión, no puedes usar $ texto
con $ ni
, no puedes usar el insinuación()
comando con $ texto
, utilizando $ texto
con $ o
necesita todas las cláusulas en tu $ o
Expresión a indexar, etc..La búsqueda de texto completo siempre ha sido una de las características más demandadas de MongoDB. En este artículo, comenzamos con una introducción de qué es la búsqueda de texto completo, antes de pasar a los conceptos básicos de la creación de índices de texto..
Luego exploramos la indexación compuesta, la indexación de comodines, las búsquedas de frases y las búsquedas de negación. Además, exploramos algunos conceptos importantes como el análisis de índices de texto, la búsqueda ponderada y la partición lógica de sus índices. Podemos esperar algunas actualizaciones importantes de esta funcionalidad en los próximos lanzamientos de MongoDB..
Te recomiendo que pruebes la búsqueda de texto y compartas tus pensamientos. Si ya lo has implementado en tu aplicación, comparte tu experiencia aquí. Finalmente, siéntase libre de publicar sus preguntas, pensamientos y sugerencias sobre este artículo en la sección de comentarios..