Big Data

Búsqueda en Elasticsearch

Te hablamos sobre el lenguaje de búsqueda en Elasticsearch, conocido como Query DSL.

Publicado el 19 de Febrero de 2019
Compartir

Búsquedas en Elasticsearch

Elasticsearch distingue entre dos tipos de búsquedas:

  • Las búsquedas que devuelven una puntuación o score, que se llaman queries. Están pensadas para búsquedas sobre campos de tipo frase, ya que este tipo de consultas lo que hacen es medir cuánto se parece una frase buscada a la almacenada.
  • Las búsquedas sin puntuación o filters. Estos filtros se utilizan para búsquedas binarias, en las que hay dos posibilidades, o se encuentra el valor o no se encuentra. Tienen la ventaja que son más rápidas y que se cachean en memoria. Este tipo de búsquedas se utilizan para campos que no sean de texto.

Características de las búsquedas en Elasticsearch

Destacamos algunas características importantes del funcionamiento de las búsquedas en Elasticsearch:

  • La API está unificada, ya que filter se usa dentro de query, así podemos tener una query por si sola o una query que además contenga un filtro.
  • Las frases se almacenan divididas en tokens y en minúscula. Por ejemplo, si introducimos un campo que vale “Pedro Santos González”, internamente se almacenarían tres tokens [“pedro”,”santos”,”González]. Al hacer la consulta sobre la frase “Pedro García”, el token “pedro” coincidiría, por lo que se asignaría una puntuación, aunque el texto no coincide exactamente.

Sintaxis de queries y filters

La sintaxis para hacer las queries utilizando Kibana es la siguiente:

GET índice/tipo/_search
{
“query”: {
<tipoClausula>:{<campoConsultado>:<valor>}
}
}
Se utiliza el verbo GET, tenemos que pasarle el índice, el tipo y el método search, y dentro metemos un
JSON con un campo query que tiene el tipo de cláusula y dentro el campo consultado y el valor.
La sintaxis los filters, suponiendo que vamos a tener una query con un filter es esta:
GET índice/tipo/_search
{
“query”: {
“bool”: {“filter”}: {
<tipoClausula>:{<campoConsultado>:<valor>}}
}}
}

}

Podemos hacer que la query dentro tenga un bool con el filter, y dentro del mismo tendríamos la misma sintaxis que para la query, es decir, el tipo de cláusula, el campo consultado y el valor.

Tipos de búsquedas

Las cláusulas comunes en las queries son:

  • Buscar que un campo sea igual a un valor, lo que se hace con term.
  • Comprobar si un texto tiene una palabra concreta (token), que se hace con match.
  • Comprobar si un texto contiene una lista de palabras y se respeta el orden dado, que se hace con match_phrase.
  • Hacer una búsqueda por rangos de campos numéricos, utilizando gt (para mayor estrictamente), gte (para mayor o igual), lt (para menor estrictamente) y lte (para menor o igual).

También podemos componer varias búsquedas sencillas, para lo que tenemos dos operadores:

  • El operador should, que es equivalente a OR en otros lenguajes. Se indican dos condiciones y basta con que se cumpla una de ellas para que devuelva resultados.
  • El operador must, que es equivalente a AND en otros lenguajes. Lo que hace es unir dos condiciones, es decir, se tienen que cumplir las dos al mismo tiempo para que devuelva resultados. También se pueden hacer agregaciones, como por ejemplo hacer una media, para lo que se utiliza aggs y como media avg.

Ejemplos de búsquedas

Como punto de partida vamos a tomar tres documentos de empleados, en los que hay tres campos, el nombre, la edad y la ciudad.

Introducimos estos datos en la consola de Kibana y los insertamos:


PUT empleados/empleado/1
{“nombre”:”Pedro Pérez”,”edad”:”25”,”ciudad”:”Burgos”}
PUT empleados/empleado/2
{“nombre”:”Pedro García”,”edad”:”35”,”ciudad”:”Madrid”}
PUT empleados/empleado/1
{“nombre”:”Juan Pérez”,”edad”:”41”,”ciudad”:”Madrid”}
Comprobamos que lo único que tenemos en el clúster son esos tres documentos anteriores, ejecutando
este código:
GET _search
{
“query”: {match_all”: {}}
}

Ahora vamos a empezar con los ejemplos de búsquedas.

Si queremos hacer consultas de la edad, podríamos buscar, por ejemplo, los empleados que tienen exactamente edad 25:


GET empleados/empleado/_search
{
“query”: {
“bool”: {“filter”: {
“term”: {“edad”: 25}
}}
}
}
Si queremos consultar los empleados que tienen una edad mayor o igual a 30, haríamos una búsqueda
de rangos:
GET empleados/empleado/_search
{
“query”: {
“bool”: {“filter”: {
“range”: {“edad”: {”gte”: 30}}
}}
}
}

En ambos casos lo metemos dentro de un bool filter para que la búsqueda sea más rápida y lo cachee.

Metemos ambas consultas en Kibana y las vamos a ejecutar.

La primera consulta devuelve un resultado, el empleado Pedro Pérez, que tiene 25 años y es de Burgos.

La segunda consulta devuelve dos empleados que cumplen esa condición, ya que tanto Pedro García como Juan Pérez tienen una edad mayor de 30 años.

Ejemplos de composición de consultas

En esta ocasión vamos a hacer una composición de consultas.

Si queremos buscar que se cumpla una condición o bien otra, utilizamos el should:


GET empleados/empleado/_search
{
“query”: {
“bool”: {“filter”: {
“bool”: {“should”:
[
“term”: {“ciudad”: {”burgos”} },
“range”: {“edad”: {”gt”: 40}} }
]
}
}}
}
}

Aquí realizamos una consulta de empleados cuya ciudad sea Burgos o bien que tengan una edad mayor de 40 años.

Introducimos esta consulta en Kibana, la ejecutamos y nos muestra dos resultados, uno es Pedro Pérez que vive en Burgos y tiene 25 años, y otro es Juan Pérez de 41 años y vive en Madrid.

También podemos hacer composición pero en la que sea necesario que se cumplan las dos condiciones al mismo tiempo. En este caso podemos buscar los empleados que vivan en Madrid y además tengan más de 40 años.


GET empleados/empleado/_search
{
“query”: {
“bool”: {“filter”}: {
“bool”: {“must”:
[
{“term”: {“ciudad”: {”madrid”} },
“range”: {“edad”: {”gt”: 40}} }
]
}
}}
}
}

Introducimos esta consulta en Kibana y al ejecutarla vemos que en este caso solo hay un único empleado que cumple las dos condiciones al mismo tiempo, Juan Pérez de 41 años y que vive en Madrid.

Ejemplos de consultas de tipo texto

Vamos a realizar ahora consultas sobre campos de tipo texto.

En primer lugar vamos a buscar empleados cuyo nombre contenga las palabras “Pérez” y “Pedro” utilizando un match.


GET empleados/empleado/_search
{
“query”: {“match”: {“nombre”:“Pérez Pedro”}}
}
En segundo lugar vamos además a chequear que la posición de esas dos palabras es la misma, utilizamos
match phrase.
GET empleados/empleado/_search
{
“query”: {“match_phrase”: {“nombre”:“Pérez Pedro”}}
}
Copiamos la primera consulta en Kibana y al ejecutarla vemos que devuelve una puntuación para las
consultas.
Copiamos la segunda y la ejecutamos vemos que no devuelve ningún resultado, ya que en este caso no
hay ningún empleado con esa posición, pero si cambiamos los tokens de orden, nos mostraría un
resultado.
También podríamos buscar los tokens utilizando bool y must para hacer una composición término a
término:
GET empleados/empleado/_search
{
“query”: {
“bool”: {“filter”: {
“bool”: {
“must”: [
{“term”: {“nombre”: ”pedro”}},
{“term”: {“nombre”: ”pérez”}}
]
}

}}
}
}
8- Ejemplos de consultas de valor medio - 6:47
Finalmente vamos a ver cómo consultar la media de edad de los empleados:
GET empleados/empleado/_search
{
“aggs” : {
“media-edad”: { “avg” : { “field” : “edad” } }
}
}

Copiamos esta consulta en Kibana y al ejecutarla calcula la media de edad de los empleados. Primero devuelve todos los hits y al final devuelve la agregación de la media.

Este curso de Elasticsearch te permitirá conocer a fondo la arquitectura de Elasticsearch para aprender a comunicar Java con este potente servidor de búsquedas basado en Lucene.
 
cursos-elasticsearch-busqueda

Recuerda que puedes comenzar este curso con tu suscripción de OpenWebinars. Si todavía no estás suscrito, aprovecha para hacerlo ahora.

Compartir este post

También te puede interesar...

Tecnología

Características de la arquitectura de Elasticsearch

19 Febrero 2019 Pedro Santos González
Artículos
Ver todos