Consultas Efectivas con Elastisearch

Niriana Blasco
Crehana
Published in
7 min readAug 1, 2020

En el post anterior vimos lo simple que fué pasar nuestros datos a elasticsearch usando la librería django-elasticsearch-dsl (por supuesto no es la única forma que existe de hacerlo, quizás si les interesa en otro post podríamos implementar otra solución sin usar ésta librería sino usando directamente el API de elasticsearch). Ahora llegó el momento tan esperado, vamos a profundizar en las búsquedas o consultas a elasticsearch. El corazón de ésta tecnología es la capacidad de hacer consultas más flexibles y más rápidas que una base de datos relacional.

Search:

El api de elasticsearch permite realizar consultas a través de una cadena de consulta simple como parámetro o usando un body en la solicitud (query DSL).

En el post anterior vimos cómo era usando una cadena simple de solicitud:

http://localhost:9200/item/_search&pretty&q=python

En esta consulta le indicamos a elasticsearch que busque todos los documentos cuyos campos coincidan con la palabra “python” dentro del índice “item”, como ya les comenté sólo traerá los 10 primeros documentos con mayor coincidencia, pero como no le indicamos en cuáles campos buscar, entonces buscará en todos los campos que contenga el documento.

Consulta DSL (Domain Specific Language):

Ésta consulta nos permite realizar búsquedas en elasticsearch y construyéndolas en formato JSON. Éste tipo de consultas consta de dos cláusulas: Leaf query o Compound query.

  • Leaf query: Busca un valor particular en un campo particular: match, term o range.
  • Compound query: Permite combinar varias consultas de una manera lógica (bool) ó para alterar su comportamiento(score).

Un ejemplo de leaf query, pero en este caso usaré postman para visualizar los datos de una mejor manera:

Vamos a detallar la consulta:

  • En la url hemos indicado que queremos buscar en el índice “item”, además a través del parámetro _source le indicamos que sólo queremos ver los campos id y name del documento book. Ésto optimiza la transferencia de datos.
  • En el body, agregamos la consulta en formato JSON, ésta consulta le dice a elasticsearch que queremos todos los documentos cuyo nombre sea python, en otras palabras, quiero todos los libros con el título o nombre python (en realidad, elasticsearch sólo me devolverá 10 resultados, a menos que indique un size mayor a 10).
  • Los resultados, vemos que hay 194 documentos que coinciden con la búsqueda, ordenados de acuerdo a su relevancia _score.

Ya sabemos cómo hacer consultas a elasticsearch, sin embargo los resultados y su posición tienen un significado. Básicamente las consultas a elasticsearch se construyen con filtros y métodos de ordenamiento. Hasta el momento hemos aplicado un filtro simple “match” y ningún método de ordenamiento. Elasticsearch ordena los resultados por defecto usando el score, así que necesitaremos un poco más de detalle para hablar sobre esto.

TF/IDF Relevance Algorithm

Las búsquedas en Elasticsearch usan un algoritmo denominado:
TF/IDF Relevance Algorithm

  • TF (Term frequency): Qué tan a menudo aparece el término de búsqueda en el campo de búsqueda.
  • IDF (Inverse document frequency): Qué tan a menudo aparece el término de búsqueda en el índice. Cuánto más a menudo aparece el término menor es el peso.
  • Field-lenght norm: La longitud del campo de búsqueda, entre menor es ésta longitud mayor es la relevancia.

Ahora que sabemos que hay detrás de las búsquedas podemos analizar un poco mejor los datos. Claro para ello elasticsearch nos proporciona una query:

“explain=true” , nos indica cómo el algoritmo calculó el score asociado a cada documento. Para profundizar les recomiendo revisar la documentación oficial, pues ésto se escapa del objetivo del post.

Consultas efectivas

Si nuestro objetivo es realizar consultas efectivas, lo primero que debemos tener claro es cuál o cuáles son los campos de búsqueda, ya que dependiendo de su naturaleza es necesario comunicárselo a elasticsearch.

Mappings:

Existen dos formas de enviar datos a Elasticsearch: la primera es indicarle a Elasticsearch el tipo de data que está almacenando:

  • Simple: text, keyword, date, long, double, boolean, ip.
  • Compuestos: object, nested.
  • Especializados: geo_point, geo_shape, completion.

La segunda forma es schemaless (sin esquemas), por ello es que podemos pasar datos sin especificar su tipo, en éste caso se hace el llamado a: dynamic mapping. Elasticsearch al explorar los datos hace una conversión usando algunas reglas como por ejemplo:

Estos son solo algunos de los tipos de datos que aplica dinámicamente Elasticsearch. Nuevamente regresando a nuestro ejemplo, podemos revisar el mapping de nuestros campos usando la url: http://localhost:9200/item/_mappings?pretty

En la imagen vemos claramente que el mapeo que hace la librearía django-elasticsearch-dsl viene de la declaración del campo en el modelo de la app (item/models.py), y los campos personalizados como price viene de su definición en documents.py.

Hay otros conceptos significativos al momento de realizar consultas usando elasticsearch: analyzer y tokenizer.

Analyzer:

Los analizadores son de gran utilidad porque permiten agregar flexibilidad a algunos campos para mejorar la experiencia del usuario durante las consultas. Si el usuario quiere buscar una palabra la consulta a elasticsearch debería considerar varias características: errores ortográficos, tildes, minúsculas, texto parcial o completo, entre otros. Para éstos casos elasticsearch tiene varios analizadores listos para usar y combinar.

  • Standard analyzer
  • Stop analyzer, elimina palabras, en nuestro texto analizado usando el analizador estándar solo divide el texto en palabras, lo que resultó en 5 palabras, con stop analyzer sólo quedaron 3 palabras porque elimina algunos artículos (‘a’, ‘to’), se puede configurar para agregar el lenguaje, por defecto es English.
  • Keyword analyzer, considerar el texto completo como palabra clave.

Existen muchos analizadores, no olviden reforzar los conocimientos con la documentación oficial.

Tokenizers:

De la documentación oficial:

A tokenizer receives a stream of characters, breaks it up into individual tokens (usually individual words), and outputs a stream of tokens. For instance, a whitespace tokenizer breaks text into tokens whenever it sees any whitespace. It would convert the text "Quick brown fox!" into the terms [Quick, brown, fox!].

  • lowercase tokenizer, convierte todas las palabras en minúsculas.
  • letter tokenizer, elimina cualquier caracter que no sea una letra
  • ngram tokenizer, divide las palabras en parciales por defecto la mínima cantidad de letras en una palabra es 1, por eso se muestra así:

Ya con estos conocimientos vamos a configurar en nuestro proyecto de shopping_cart un analizador con tokenizer para realizar un consulta efectiva. Lo primero que debemos hacer es ir a nuestro arhivo shopping_cart/item/documents.py y hacer algunas modificaciones:

  • Linea 3: importamos los métodos que necesitamos para definir un analyzer y un tokenizer.
  • Linea 9–15: Definimos un tokenizer que deriva de Edge ngram, con un minimo de 3 caracteres y un máximo de 10 caracteres por palabra para la búsqueda.
  • Linea 12: token_chars, le indica al tokenizer que tipo de caracteres debe incluir en un token.
  • Linea 17–21: Definimos un analizador: nombre “search_engine”, le decimos que usará el tokenizador que se definió recientemente y con los filtros de minúsculas y caracteres ascii.

Vamos a probar nuestro analizador:

El texto que elasticsearch indexará permitirá su búsqueda con todas las palabras o tokens generados: [“muy”, “fac”, “faci”, “facil”]. Ahora recordemos que al inicio cuando consultábamos los libros sólo podíamos colocar palabras completas como: “python”, vamos a ver el mismo ejemplo colocando una parte de esa palabra:

En el ejemplo hicimos varias consultas, tanto con palabras completas como parcialmente.

Conclusión:

Si, lo sé! nos extendimos un poco, y aún así hay mucho más por descubrir. Sin embargo un paso a la vez, en este post hemos visto muchas características que podemos agregar a nuestros índices de elasticsearch para potenciar las búsquedas y que arrojen los resultados más coherentes posibles, de esta manera le podríamos garantizar una gran experiencia al usuario.

--

--