Fecha publicación: 12 jul 2021

MongoDb índices: Text Index I

Hay ocasiones en las que contamos con un campo de texto libre sobre el que queremos realizar búsquedas, por ejemplo:

  • Las opiniones de la estancia en un alquiler vacacional.
  • La descripción de la ficha de un producto.
  • El diagnóstico de un médico.
  • ...

Lo normal es que queramos realizar búsquedas por substrings... si buscamos rendimiento aquí ni los índices estándares nos van a ser de gran ayuda, ni, salvo casos contados, los filtros por expresiones regulares ¿Qué podemos hacer? Usar los índices de tipo text

Manos a la obra

Vamos a tirar de la base de datos de ejemplo de AirBnb (en vídeos anteriores, puedes encontrar los enlaces para poder descargártelas). En la colección ListingsAndReviews hay un campo de reviews en el que las personas que alquilan comentan que tal ha sido su experiencia en ese apartamento, imagínate que queremos encontrar la siguiente cadena de texto en las opiniones: "great location".

¿Qué podemos hacer? Una búsqueda por el texto completo no valdría, nos podríamos plantear usar expresiones regulares.

Lo primero antes de arrancar hacemos limpia de índices

use airbnb
db.listingsAndReviews.dropIndexes();

Y vamos a ver que tal se porta esta consulta (abrimos el explain tab para poder verlo):

db.listingsAndReviews.find({ "reviews.comments": /great location/ });

Búsqueda por substring sin indice

Nos da un tiempo bastante malo, vamos a probar a crear un índice estándar:

db.listingsAndReviews.createIndex({ "reviews.comments": 1 });

Y repetimos la búsqueda

db.listingsAndReviews.find({ "reviews.comments": /great location/ });

Es curioso nos da un tiempo hasta peor :-@:

Búsqueda por substring intento índice estándar

Aquí podemos ver como esta consulta tarda bastante tiempo en ejecutarse, ya que aunque usemos índices estándares, las búsqueda sobre expresiones regulares no van muy bien excepto las que buscan usando prefijos, el resto no dan buen rendimiento.

¿Qué podemos hacer? Crear un índice para búsquedas por texto en esa colección.

Volvemos a hacer limpia previa de índices:

db.listingsAndReviews.dropIndexes();

En nuestro caso creamos un índice por el campo reviews, fíjate que aquí no le indicamos si es ascendente o descendente, sino que directamente le decimos que es de tipo texto

db.listingsAndReviews.createIndex({ "reviews.comments": "text" });

Si te fijas esta operación tarda un poco, los índices para búsquedas en texto, tienen su coste.

Otro tema interesante a tener en cuenta es que este índice es por colección, podríamos añadir más campos a ese índice (por ejemplo imagínate una ficha de producto en el que tienes la descripción y la ficha técnica del producto, se podría indexar por ambos campos)

Para aprovechar el índice tenemos el filtro de la consulta, usamos $text y $search:

db.listingsAndReviews.find({ $text: { $search: "great location" } });

Si vemos los resultados de rendimiento podemos ver que hemos bajado de forma significativa los tiempos de respuesta.

Busqueda por substring usando índice de tipo text

Esto pinta bien, pero necesitamos afinarlo, en este tipo de búsquedas si tienes una cadena que ponga "bad location" te la va a dar por buena (realiza la búsqueda por palabras) y puede que te la ponga como primer resultado válido, también hay que tener en cuenta que igual podemos querer hacer la búsqueda sobre campos que tengan contenido en castellano, ¿Cómo podemos resolver ésto? En el siguiente vídeo veremos como.

¿Con ganas de aprender Backend?

En Lemoncode impartimos un Bootcamp Backend Online, centrado en stack node y stack .net, en él encontrarás todos los recursos necesarios: clases de los mejores profesionales del sector, tutorías en cuanto las necesites y ejercicios para desarrollar lo aprendido en los distintos módulos. Si quieres saber más puedes pinchar aquí para más información sobre este Bootcamp Backend.