Introducción a Elasticsearch

Escrito por el , actualizado el .
software programacion planeta-codigo
Enlace permanente Comentarios

Elasticsearch es una potente herramienta que nos permite indexar una gran volumen de datos y posteriormente hacer consultas sobre ellos soportando entre otras muchas cosas búsquedas aproximadas, facetas y resaltado. Un uso puede ser hacer consultas de texto completo, al estar los datos indexados los resultados se obtienen de forma muy rápida.

Elasticsearch

Continuando con la forma de como dar solución a la búsquedas en las entidades de dominio en esta entrada profundizaré en la solución que comentaba de usar Elasticsearch. Elasticsearch se basa en Lucene pero expone su funcionalidad a través de una interfaz REST recibiendo y enviando datos en formato JSON y oculta mediante esta interfaz los detalles internos de Lucene. Esta interfaz permite que pueda ser utilizada por cualquier plataforma no solo Java, puede usarse desde Python, .NET, PHP o incluso desde un navegador con JavaScript. Es persistente, es decir, que lo que indexemos en ella sobrevivirá a un reinicio del servidor.

Como comentaba en el artículo anterior de búsquedas sobre entidades de dominio ES nos puede servir para hacer búsquedas a texto completo pero también podemos hacer otra serie de cosas adicionales que no podemos con una base de datos relacional aunque soporte en su lenguaje SQL búsqueda a texto completo, por ejemplo, resaltado (highlight) y facetas (facets), también permite hacer búsquedas vagas (fuzzy) y soporta diferentes analizadores según el idioma de la propiedad en que se busque. El indexar y desindexar los datos en elasticsearch para que luego puedan ser buscados es responsabilidad nuestra y además de insertarlos o eliminarlos en la base de datos debemos hacer lo mismo en ES ya sea haciéndolo en ambos sitios a la vez o mediante un proceso de fondo que se encargue de ello.

La instalación de ES es muy sencilla, basta con descargar el zip de su distribución, descomprimirlo e iniciarlo con el siguiente comando:

1
2
$ elasticsearch

script-1.sh

Después de unos segundos deberemos ver algo como lo siguiente.

Elasticsearch usa sus propios conceptos y aunque no es una base de datos relacional algunos pueden ser similares. Lo que en en una base de datos relacional es un esquema en ES es un índice, lo que en la primera es una tabla en ES es un tipo, continuando una fila en ES es un documento y finalmente una columna es una propiedad en ES.

La documentación de Elasticsearch es un documentación de referencia probablemente pero para aprender a sacarle el máximo provecho probablemente debamos buscar algún manual o libro que nos lo explique de una forma más didáctica. Algunas opciones son el libro Exploring Elasticsearch y el tutorial Elasticsearch.

Veamos como crear y borrar un índice, para ello utilizaremos la herramienta curl:

1
2
$ curl -XPUT 'http://localhost:9200/blogbitix'
$ curl -XDELETE 'http://localhost:9200/blogbitix'
script-2.sh

Aunque Elasticsearch es orientado a documentos y estos no tienen que adherirse a un esquema como en una base de datos relacional, podemos instruir a Elasticsearch como queremos que haga las búsquedas sobre los campos del documento. Para ello definimos la correspondencia (mapping). A continuación pondré el caso hipotético de un tipo libro que tiene las propiedades de nombre y descripción en varios idiomas, una serie de etiquetas para catalogarlo y una cantidad.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ curl -XPUT 'http://localhost:9200/blogbitix/libro/_mapping' -d '{
    "properties" : {
        "nombre" : {
            "type" : "object",
            "properties" : { 
                "es": { "type" : "string", "index" : "analyzed", "analyzer" : "spanish" },
                "en": { "type" : "string", "index" : "analyzed", "analyzer" : "english" }
            }
        },
        "descripcion" : {
            "type" : "object",
            "properties" : { 
                "es": { "type" : "string", "index" : "analyzed", "analyzer" : "spanish", "store": "yes" },
                "en": { "type" : "string", "index" : "analyzed", "analyzer" : "english", "store": "yes" }
            }
        },
        "etiquetas" : {
            "type" : "object",
            "properties" : { 
                "es": { 
                    "type" : "multi_field",
                    "fields" : {
                        "term" : { "type" : "string", "index" : "analyzed", "analyzer" : "spanish" },
                        "untouched" : {"type" : "string", "index" : "not_analyzed"}
                    }
                },
                "en": { 
                    "type" : "multi_field",
                    "fields" : {
                        "term" : { "type" : "string", "index" : "analyzed", "analyzer" : "english" },
                        "untouched" : {"type" : "string", "index" : "not_analyzed"}
                    }
                }
            }
        },
        "cantidad" : { "type" : "long" }
    }
}
}'
script-3.sh

Con la siguiente petición podemos ver el mapeo de un tipo.

1
2
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_mapping?pretty=true'

script-4.sh

El mapeo no es necesario definirlo previamente pero es aconsejable para ciertas propiedades sino queremos que ES tome valores por defecto o haga suposiciones, a continuación insertamos los documentos. Cada documento tiene un identificativo que deberemos asignarle y para indexarlo básicamente proporcionamos un JSON con las propiedades del documento. Elasticsearch se encargará de indexarlo para que una búsqueda posterior se ejecute rápidamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
$ curl -XPUT 'http://localhost:9200/blogbitix/libro/1' -d '{
    "nombre" : {
        "es": "PlugIn Tapestry",
        "en": "PlugIn Tapestry"
    },
    "descripcion" : {
        "es": "Desarrollo de aplicaciones y páginas web con Apache Tapestry",
        "en": "Development of applications and web pages with Apache Tapestry"
    },
    "etiquetas" : {
        "es": ["libro", "tecnologia", "tapestry", "java", "español"],
        "en": ["book", "tecnology", "tapestry", "java", "spanish"]
    },
    "cantidad" : 1000
}'

$ curl -XPUT 'http://localhost:9200/blogbitix/libro/2' -d '{
    "nombre" : {
        "es": "Tapestry 5 - Desarrollo rápido de aplicaciones web en Java",
        "en": "Tapestry 5 - Rapid web application development in Java"
    },
    "descripcion" : {
        "es": "Una guía completa presentando Apache Tapestry y su aproximación inovadora para la construcción de aplicaciones web modernas",
        "en": "A comprehensive guide, introducing Apache Tapestry and its innovative approach to building modern web applications"
    },
    "etiquetas" : {
        "es": ["libro", "tecnologia", "tapestry", "java", "inglés"],
        "en": ["book", "tecnology", "tapestry", "java", "english"]
    },
    "cantidad" : 1000
}'

$ curl -XPUT 'http://localhost:9200/blogbitix/libro/3' -d '{
    "nombre" : {
        "es": "Tapestry in Action",
        "en": "Tapestry in Action"
    },
    "descripcion" : {
        "es": "Tapestry in Action e la introducción definitiva a Tapestry 3 escrito por Howard Lewis Ship, el creador de Tapestry",
        "en": "Tapestry in Action is the definitive introduction to Tapestry 3 written by Howard Lewis Ship, the creator of Tapestry"
    },
    "etiquetas" : {
        "es": ["libro", "tecnologia", "tapestry", "java", "inglés"],
        "en": ["book", "tecnology", "tapestry", "java", "english"]
    },
    "cantidad" : 1000
}'
script-5.sh

Con las anteriores peticiones hemos indexado 3 documentos, podemos ver los datos de cada uno de ellos con:

1
2
$ curl -XGET 'http://localhost:9200/blogbitix/libro/1'

script-6.sh

Una vez tenemos unos cuantos documentos indexados en ES podemos empezar a hacer búsquedas. Elasticsearch para hacer las búsquedas usa su propio lenguaje de DSL, no es sencillo y la documentación de ES no es muy útil para aprender a como usarla. Pondré algunos ejemplos simples, probablemente no reales y no representativos de todo el potencial que puede ofrecer ES. El primero es una búsqueda por una determinada palabra.

1
2
3
4
5
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_search?pretty=true' -d '{
    "query" : {
        "fuzzy" : { "descripcion.es": "tapestry" }
    }
}'
script-7.sh

Una búsqueda similar a la anterior pero con más condiciones, exigiendo que no tenga unas palabras en concreto y algunas que deberían tener haciendo que ES valore más los documentos que las tengan.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_search?pretty=true' -d '{
    "query" : {
        "bool" : {
            "must" : {
                "fuzzy" : { "descripcion.es": "tapestry" }
            },
            "must_not" : {
                "query_string" : {
                    "fields" : ["descripcion.es"],
                    "query" : "\"tapestry 3\""
                }
            },
            "should" : [{ 
                "match" : {
                    "descripcion.es" : {
                        "query" : "guía",
                        "type" : "phrase"
                    }
                }
            }]
        }
    }
}'
script-8.sh

Además de búsquedas ES puede ofrecernos más funcionalidades como las facetas con las que podemos obtener un sumatorio de los resultados. En la siguiente consulta buscamos los documentos con una determinada palabra y además le pedimos a ES que nos devuelva cuantos documentos hay que cumplan ese criterio en cada etiqueta. Esto probablemente es lo que usen en la tienda de Amazon cuando muestran cuantos elementos hay en las diferentes categorizaciones. Aunque en Amazon solo muestran las categorías de los elementos buscados probablemente podrían mostrar cuantos elementos hay en cada una de esas categorías.

1
2
3
4
5
6
7
8
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_search?pretty=true' -d '{
    "query" : {
        "fuzzy" : { "descripcion.es": "tapestry" }
    },
    "facets": {
        "etiquetas": { "terms": { "field": "etiquetas.es.untouched" } }
    }
}'
script-9.sh

Categorías de productos (facets) en Amazon

Otra de las funcionalidades que nos puede interesar es que ES nos ofrezca sugerencias para determinados términos, en el siguiente ejemplo solicitamos además de la búsqueda sugerencias para algunas palabras que tienen fallos de escritura.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_search?pretty=true' -d '{
    "query" : {
        "fuzzy" : { "descripcion.es": "tapestry" }
    },
    "suggest": {
        "suggest1" : {
            "text" : "tapestyr desarrallo",
            "term" : {
                "field" : "descripcion.es"  
            }
        }
    }
}'
script-10.sh

Finalmente, otra cosa que nos puede interesar es que ES nos resalte las palabras de determinados campos para destacar las coincidencias de los resultados de forma visual que se han encontrado. Esto necesita { store: “yes” } en la correspondencia de la propiedad.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ curl -XGET 'http://localhost:9200/blogbitix/libro/_search?pretty=true' -d '{
    "query" : {
        "query_string": {  
            "query": "Tapestry"
        }
    },
    "highlight" : {
        "fields" : {
            "descripcion.es" : { }
        }
    }
}'
script-11.sh

Estos son solo unos pocos ejemplos, ES seguro que puede ofrecer muchas cosas más que leyendo solo la documentación de referencia es difícil descubrir. Unos buenos libros que explican muchas de las posibilidades y opciones de forma más didáctica son Elasticsearch: The Definitive Guide y/o Elasticsearch Server, en algunos casos la documentación propia del proyecto es suficiente pero en el caso de Elasticsearch algunos libros como estos son casi necesarios para dominarlo.


Comparte el artículo: