0% encontró este documento útil (0 votos)
25 vistas120 páginas

Documentacion Elasticsearch Alumnos

Descargar como pdf o txt
Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1/ 120

Elasticsearch

Administración y uso
Ramón Rubio Hortelano

Version 3.0.3 2018-10-10


Contenidos
1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1. ¿Qué es?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Portfolio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3. Conceptos básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3.1. Cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3.2. Nodo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3.3. Índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3.4. Tipo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3.5. Documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3.6. Shard y Réplicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4. Contenido del directorio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5. Configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Modelo distribuido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3. Operaciones básicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1. Inserción de índices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.2. Listar índices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.3. Insertar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4. Mostrar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.5. Actualizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.6. Borrar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.7. Procesos batch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.8. Borrado de índices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.9. Ejercicio en clase. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4. API de búsquedas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.1. Búsquedas por URI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.2. Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.3. Match Phrase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.4. Range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.5. Bool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.6. Ejercicios sobre análisis de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
5. Análisis de texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.1. Inverted Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.2. Analizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.2.1. Estándar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.2.2. Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2.3. Whitespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2.4. Language. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.3. Analizadores personalizados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.3.1. Filtro de caracteres. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.3.2. Tokenizers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.4. Token Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.4.1. Sinónimos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.5. Elección de analizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.6. Segmentos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6. Mappings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.1. ¿Que es un mapping?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.1.1. _uid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.1.2. _id . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.1.3. _type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.1.4. _source. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.2. Mappings dinámicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.3. Agregación de campos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.4. Especificaciones de analizadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.5. Plantillas dinámicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.5.1. match_mapping_type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.5.2. match y unmatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.5.3. match_pattern . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.5.4. path_match y path_unmatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6.6. Plantillas de índices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7. Búsquedas avanzadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
7.1. Consultas term-based . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
7.2. Filtros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
7.3. match_phrase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
7.4. match_phrase_prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.5. multi_match_query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
7.5.1. best_fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
7.5.2. most_fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.5.3. phrase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.6. fuzziness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
7.7. highlighting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7.8. more_like_this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
8. Resultado de consultas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.1. Boost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2. Algoritmos de búsqueda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.1. Query_then_fetch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
8.2.2. Dfs_query_then_fetch. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8.3. Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8.4. From / Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
8.5. Scroll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
8.6. Preferencias de ejecución. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
9. Modelo distribuido. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
9.1. Inicio de un nodo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
9.2. Creación de un índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
9.3. Shards, distribución de un índice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
9.4. Distribución de documentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
9.5. Replicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
9.6. Split Brain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
9.7. Tipos de nodos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
9.8. Desarrollo VS Producción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10. Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.1. API de actualizaciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.2. Actualizaciones por script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.3. Documentos parciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
10.4. Noop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
10.5. Upserts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
10.6. Update By Query. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
11. Delete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
11.1. Delete by Query . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
12. Agregaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
12.1. Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
12.2. Métricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
12.3. Rangos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
12.4. Rangos de fechas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
12.5. Términos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
12.6. Anidaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
13. Modelado de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
13.1. Uniones a nivel de aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
13.2. Desnormalización . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
13.3. Documentos anidados. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
13.4. Relaciones padre-hijo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
13.5. i18n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
13.5.1. Un lenguaje por documento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
13.5.2. Un lenguaje por campo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
13.5.3. Campos de lenguajes mixtos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Capítulo 1. Introducción
1.1. ¿Qué es?
Proyecto Open-Source altamente escalaba que permite búsquedas de texto optimizadas y ofrece
una analítica de todos sus datos. Generalmente se utiliza para ofrecer búsquedas de texto complejas
a nuestra aplicación.

1.2. Portfolio

1.3. Conceptos básicos


1.3.1. Cluster

Un cluster es una colección de uno o mas nodos ( servidores ) que contienen toda la información.
Un cluster se identifica por su nombre, por defecto "elasticsearch". Cada nodo solo puede tener un
cluster y se une a él mediante su nombre.

1.3.2. Nodo

Es un servidor que forma parte del cluster donde se guarda toda la información. Un nodo se
identifica por su nombre. Cada nodo tiene un “cluster_name”, por defecto “elasticsearch”, y todos
los nodos con el mismo nombre se unen automáticamente al mismo cluster.

1.3.3. Índice

Colección de documentos con características similares. Se identifican por su nombre, siempre en


minúsculas, y su nombre es el que se usa para indexar, buscar, borrar, filtrar…

1.3.4. Tipo

Dentro de un índice, se pueden definir un solo tipo. Un tipo es una categoría/partición de un índice.

1
Anteriormente, se podían definir múltiples tipos, pero estamos en época de
transición, y desaparecerán en la versión 7 de Elasticsearch. Ahora no es posible
 crear más de un tipo por índice, no como en la versión 5.x donde se podía activar
la función de múltiples tipos desde el fichero de configuración

1.3.5. Documento

Es una unidad de información, representada en formato JSON, que puede ser indexada. Dentro de
un índice podemos guardar tantos documentos como queramos, siempre que tengan asignados un
tipo y este a su vez un índice.

1.3.6. Shard y Réplicas

Un índice puede almacenar gran cantidad de datos, que pueden exceder los límites de un nodo.
Para resolver este problema elasticsearch divide esta información en trozos, llamados shards. Cada
shard es completamente funcional e independiente y puede ser almacenado en cualquier nodo del
cluster.

Para proporcionar alta disponibilidad ( control a fallos ), elasticsearch crea réplicas de estos shards.
Por defecto se crea una réplica por cada shard aunque podemos cambiarlo dinámicamente ==
Instalación

Para poder instalar elasticsearch es necesario tener instalado Java8 (06/2017), se recomienda la
versión 1.8.0_131 o posterior. Para instalarlo solo se necesita descargar la última versión de
elasticsearch o bien descargarse el proyecto de su página de Github. Una vez instalado usaremos los
paquetes precompilados RPM, DEB o bien el zip/tar

Para instalarlo en Red Hat, importamos la clave de firmas pública.

La máquina virtual suministrada ya posee el repositorio, no es necesario crear el


 repositorio, solo se necesita instalar el software con el comando yum que aparece
más adelante.

2
$ sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

Creamos el fichero de repositorios en /etc/yum.repos.d

/etc/yum.repos.d/elasticsearch.repo

[elasticsearch-5.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

Para instalarlo:

[elasticsearch@localhost ~]$ sudo yum -y install elasticsearch

Si hemos usado los paquetes RPM para iniciar sería

[elasticsearch@localhost ~]$ sudo systemctl start elasticsearch


[elasticsearch@localhost ~]$ sudo systemctl enable elasticsearch
Created symlink from /etc/systemd/system/multi-user.target.wants/elasticsearch.service to
/usr/lib/systemd/system/elasticsearch.service.

En caso de haber descargado el zip/tar ejecutamos

$./elasticsearch

También podemos iniciarlo cambiando los nombres del cluster y el nodo, aunque se puede hacer
una vez iniciado igualmente.

$ ./elasticsearch --cluster.name my_cluster_name --node.name my_node_name

Una vez iniciado, podemos comprobar que el sistema está iniciado

3
[elasticsearch@localhost ~]$ curl 'http://localhost:9200/?pretty'
{
"name" : "oXhGnWQ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "zyBc8IT-T7iaIKK6kAl3iA",
"version" : {
"number" : "6.4.2",
"build_flavor" : "default",
"build_type" : "rpm",
"build_hash" : "04711c2",
"build_date" : "2018-09-26T13:34:09.098244Z",
"build_snapshot" : false,
"lucene_version" : "7.4.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}

1.4. Contenido del directorio


• bin Scripts necesarios para ejecutar elasticsearch y para la gestión de plugins.

• config Ficheros de configuración.

• lib Librerías usadas por elasticsearch

• modules Almacén de modulos de elasticsearch

• logs Ficheros con información de eventos y errores

• plugins Almacén de los plugins instalados

1.5. Configuración
Elasticsearch viene prácticamente configurado, preparado para entornos simples y su
configuración está muy bien documentada.

Podemos empezar a configurar editando el fichero elasticsearch.yml

/etc/elasticsearch/elasticsearch.yml

# por defecto elasticsearch


cluster.name: my-application
# por defecto nombre aleatorio de marvel
node.name: node-1
# Conviene habilitarla, bloquea la dirección del proceso a la RAM, evita swap
bootstrap.memory_lock: true
# Permite el tráfico proveniente en exclusiva de localhost
network.host: 10.0.2.15

4
Las directivas de Index no se pueden definir directamente en el fichero de
 configuración. Se deben definir con el servidor iniciado indicando cual va a ser su
resultado final.

curl -H 'Content-Type: application/json' -XPUT 'http://localhost:9200/_template/default' -d '{


"index_patterns": ["*"],
"order": -1,
"settings": {
"number_of_shards": "6",
"number_of_replicas": "1"
}
}'

Debemos tener en cuenta que elasticsearch, durante las indexaciones, poseyendo gran cantidad de
shards y réplicas, es imprescindible mantener por encima de 32.000 el límite de ficheros abiertos.
En Linux podemos encontrar esta configuración en el directorio /etc/security/limits.conf, y podemos
ver rápidamente el límite con el comando ulimit

Al estar desarrollado en java, debemos conocer el comportamiento de la memoria, ya que produce


un impacto directo en el rendimiento de la máquina virtual y de Elasticsearch

Para editar esta configuración debemos editar el fichero config/jvm.options si nos hemos
descargado el zip/rar o editar /etc/default/elasticsearch si hemos usado los paquetes para linux.

Debemos tener en cuenta la configuración de la variable -Xms/-Xmx que nos permite configurar la
memoria que podrá tener el proceso java de elasticsearch.

Podemos configurar la memoria mínima -Xms ( 2g por defecto ), y la memoria máxima -Xmx ( 2g
por defecto ). Normalmente le daremos el mismo valor a las dos variables ( la mitad de la memoria
RAM disponible ).

5
Capítulo 2. Modelo distribuido
Elasticsearch puede trabajar como un sistema standalone, pero para poder trabajar con gran
cantidad de datos es recomendable usar un Cluster de instancias.

Cada vez que se inicia una instancia de elasticsearch, se inicia un nodo. Una colección de estos
nodos conectados, se llama cluster. Si hemos iniciado un solo nodo, entonces tendremos un cluster
de elasticsearch con un solo nodo.

Por defecto elasticsearch es de naturaleza distribuida y realiza de manera automática todas las
operaciones de descubrimiento, balanceo de carga y comunicación entre sus nodos

Cada vez que añadimos un nuevo índice a nuestro nodo, elasticsearch crea por defecto 5 shards y 1
réplica por cada uno, y dependiendo de cuántos nodos dispongamos se encarga de balancearlos.

Aunque cada shard tenga su réplica, solo uno será primary. si el primary se cae, automáticamente
su réplica es promovida.

Elasticsearch intenta separar los shard en distintos nodos y sus réplicas para proporcionar alta
disponibilidad y que la caía de un nodo en nuestro sistema, no nos suponga una pérdida de datos.

Algunas de las operaciones que elasticsearch realiza de manera automática son

• Particionamiento en shards y su almacenamiento en uno o varios nodos.

• Balanceo de shards a través de nodos para aumentar el rendimiento en búsquedas globales.

• Duplicado de shards para la prevención de pérdida de datos.

• Enrutamiento de peticiones de cualquier nodo en el cluster.

• Aumento del cluster de forma dinámica y redistribución de shards en los nuevos miembros.

Todo ello sin necesidad de gestionarlo directamente. Sin embargo, algunos valores si son necesarios
asignar según la naturaleza de nuestros índices y de nuestros nodos.

Podemos ver el nombre del cluster y el estado en el que se encuentra.

6
[elasticsearch@localhost ~]$ curl 'http://localhost:9200/_cluster/health?pretty'
{
"cluster_name" : "elasticsearch",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 0,
"active_shards" : 0,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}

En la respuesta de cluster/health podemos ver el campo _status este campo indica el estado del
servidor.

• Si está en verde significa que está bien y el cluster es completamente funcional

• Si está en amarillo, todos los datos están disponibles, pero algunas réplicas no han podido ser
asignadas, el cluster es completamente funcional, aunque no puede garantizar alta
disponibilidad.

• Si está en rojo significa que algunos datos no están disponibles por alguna razón. Aunque el
estado sea rojo, el cluster es parcialmente funcional y puede seguir devolviendo respuestas de
los shards disponibles.

7
Capítulo 3. Operaciones básicas
Todas las APIs proporcionadas por elasticsearch siguen el mismo patrón de acceso

curl -X<REST Verb> <Node>:<Port>/<Index>/<Type>/<ID>

3.1. Inserción de índices


Para insertar un nuevo índice

[elasticsearch@localhost ~]$ curl -XPUT 'localhost:9200/customer?pretty'


{
"acknowledged" : true,
"shards_acknowledged" : true
}

En la creación del índice, en la versión 2.x no tenemos constancia de que el


 número de copias se ha iniciado para cada shard antes de la devolución de la
respuesta.

3.2. Listar índices


Para listar todos los índices del cluster

[elasticsearch@localhost ~]$ curl -XGET 'localhost:9200/_cat/indices?pretty'


yellow open customer 6ldUqwTqTnKKvQuOHtfEKQ 6 1 0 0 1.5kb 1.5kb

• Indica en orden la salud, el estado, el nombre del índice, el identificador, numero de primary
shards, número de réplicas, documentos indexados, número de documentos eliminados,
Ramaño del almacenamiento utilizado, total de almacenamiento utilizado de los shards y
réplicas.

• Los documentos almacenados y eliminados se cuentan a nivel de Apache Lucene, de esa forma
también indicará todos los documentos ocultos, como los documentos anidados.

Si se desea realizar las operaciones a nivel de Elasticsearch, podemos llamar al API


 de Count o cat count

3.3. Insertar
Para insertar documentos

8
[elasticsearch@localhost ~]$ curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '{"name": "John Doe"}' -H 'Content
-Type: application/json'
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}

Insertar documentos sin id

[elasticsearch@localhost ~]$ curl -XPOST 'localhost:9200/customer/external?pretty' -d '


{
"name": "John Doe"
}' -H 'Content-Type: application/json'
{
"_index" : "customer",
"_type" : "external",
"_id" : "mO6wT2YB94c_BbBzeums",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}

3.4. Mostrar
Mostrar un documento

9
[elasticsearch@localhost ~]$ curl -XGET 'localhost:9200/customer/external/1?pretty'
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"name" : "John Doe"
}
}

3.5. Actualizar
Actualizar un documento

[elasticsearch@localhost ~]$ curl -XPOST 'localhost:9200/customer/external/1/_update?pretty' -d '


{
"doc": { "name": "Jane Doe", "age": 20 }
}' -H 'Content-Type: application/json'
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}

3.6. Borrar
Borrar un documento

10
[elasticsearch@localhost ~]$ curl -XDELETE 'localhost:9200/customer/external/1?pretty'
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 3,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}

Borrar un documento requiere mucha mas carga de CPU debido a que lleva asociadas otras
operaciones, es mucho menos costoso borrar el índice completo.

3.7. Procesos batch


Para lanzar un proceso batch

11
[elasticsearch@localhost ~]$ curl -H 'Content-Type: application/json' -XPOST
'localhost:9200/customer/external/_bulk?pretty' -d '
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
'
{
"took" : 6,
"errors" : false,
"items" : [
{
"index" : {
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1,
"status" : 201
}
},
{
"index" : {
"_index" : "customer",
"_type" : "external",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1,
"status" : 201
}
}
]
}

3.8. Borrado de índices


Para borrar un índice

[vagrant@localhost ~]$ curl -XDELETE 'localhost:9200/customer?pretty'


{
"acknowledged" : true
}

12
3.9. Ejercicio en clase
• Se debe importar una nueva base de datos que encontrareis en el fichero data.bulk

• Para ello usareis el entorno CMD e importareis el fichero por medio de una instrucción BULK

La importación de ficheros con curl implica el uso de la directiva --data-binary


 para evitar que se eliminen los saltos de línea

• Una vez importado, indicar el estado del índice generado

• Indica el número de documentos devueltos por defecto al consultar el índice y el tipo con la
terminación _search. Son todos? Porqué?

• Indica cual es el balance de la cuenta con id 735

13
Capítulo 4. API de búsquedas
Para realizar búsquedas en elasticsearch lo hacemos a través de su API _search. Podemos
realizarlas de dos maneras.

• REST request body. mandamos los parámetros de búsqueda a través de un body JSON

• REST request URI. mandamos los parámetros a través de la propia URL.

Para realizar las prácticas, se recomienda cargar el fichero de instrucciones


 data.bulk

4.1. Búsquedas por URI


Las búsquedas por URI permiten de forma sencilla realizar peticiones básicas sin necesidad de
construir un body

GET accounts/_search?q=firstname:M*
{
"took": 175,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 111,
"max_score": 1,
"hits": [
{
"_index": "accounts",
"_type": "account",
"_id": "265",
"_score": 1,
"_source": {
"account_number": 265,
"balance": 46910,
"firstname": "Marion",
"lastname": "Schneider",
"age": 26,
"gender": "F",
"address": "574 Everett Avenue",
"employer": "Evidends",
"email": "[email protected]",
"city": "Maplewood",
"state": "WY"
}

14
},
{
"_index": "accounts",
"_type": "account",
"_id": "551",
"_score": 1,
"_source": {
"account_number": 551,
"balance": 21732,
"firstname": "Milagros",
"lastname": "Travis",
"age": 27,
"gender": "F",
"address": "380 Murdock Court",
"employer": "Sloganaut",
"email": "[email protected]",
"city": "Homeland",
"state": "AR"
}
},
...
]
}
}

Incluso podemos filtrar los resultados

GET accounts/_search?q=firstname:M*&filter_path=hits.hits._source.firstname,hits.hits._source.lastname
{
"hits": {
"hits": [
{
"_source": {
"firstname": "Melissa",
"lastname": "Gould"
}
},
{
"_source": {
"firstname": "Marion",
"lastname": "Schneider"
}
},
...

• Por medio de URL se permite:

◦ q=<cadena de texto a buscar>

◦ df=<campo por defecto de búsqueda>

◦ analyzer=<nombre de analizador a aplicar>

15
◦ lowercase_expanded_terms=<true/false> (por defecto a true, terminos por defecto a
lowercase )

◦ default_operator=<OR|AND> (Por defecto OR)

◦ fields=<Campos almacenados separados por coma>

◦ sort=<campo:asc,campo2:desc> Permite los campos comunes e incluso _score

◦ timeout=<tiempo de ejecución de consulta>

◦ from=<numero inicial>

◦ size=<numero de elementos a devolver>

4.2. Matching
• Las búsquedas por coincidencias se pueden realizar también en el body y solo permiten la
consulta de un solo campo. Sin embargo, el campo es procesado con el motor de búsquedas

16
POST accounts/_search
{
"query": {
"match": {
"firstname": "Melissa"
}
}
}

"took": 15,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 4.742029,
"hits": [
{
"_index": "accounts",
"_type": "account",
"_id": "253",
"_score": 4.742029,
"_source": {
"account_number": 253,
"balance": 20240,
"firstname": "Melissa",
"lastname": "Gould",
"age": 31,
"gender": "M",
"address": "440 Fuller Place",
"employer": "Buzzopia",
"email": "[email protected]",
"city": "Lumberton",
"state": "MD"
}
}
]
}
}

• Si buscamos coincidencias múltiples para el mismo campo

17
POST accounts/_search
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1000,
"max_score": 1,
"hits": [
...

4.3. Match Phrase


• La búsqueda de una frase completa debe ser indicado por el operador:

POST accounts/_search
{
"query": {
"match_phrase": {
"address": "574 Everett Avenue"
}
}
}

4.4. Range
• Es posible definir rangos en las consultas para aplicar condiciones según el tipo de dato

18
POST accounts/_search
{
"query": {
"range": {
"age": {
"from": 20,
"to": 30
}
}
}
}
POST accounts/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 30
}
}
}
}

4.5. Bool
• Para hacer búsquedas booleanas, se definen las condiciones en el booleano con should, must o
must_not indicando si sebe cumplir todas o algunas de ellas

Condición must

POST accounts/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}

19
Condición should

POST accounts/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}

Condición must_not

POST accounts/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}

4.6. Ejercicios sobre análisis de texto


• Debemos buscar el número de personas entre 20 y 25 años que poseen más de 49000€ de
balance

• Indica el ID de la o las personas que viven en el "440 Fuller Place"

• Construye una consulta que muestre aquellos que posean como "lastname" "ortiz" o "jones"

20
Capítulo 5. Análisis de texto
5.1. Inverted Index
Elasticsearch usa una estructura llamada inverted index que permite búsquedas muy rápidas de
tipo full text. Consiste en una lista de palabras únicas que aparecen en cualquier documento. Una
forma muy simple de entenderlo es comprobar la operación de un indice invertido por medio de
dos documentos Documento1: El dia de la bestia Documento2: La bella y la bestia

Term D1 D2
El X
dia X
de X
la X X
bestia X X
La X
bella X
y X

• Si buscamos por "bella bestia"

Term D1 D2
bestia X X
bella X

Comprobamos que el documento 2 posee más hits que el primero. De hecho se producen una serie
de transformaciones al crear los índices * Paso a minúsculas todos los elementos * Paso a singular

Y de hecho, también se realiza lo que se llama un análisis en la consulta que realiza los mismos
cambios en la consulta generada para que sean "perfect match"

5.2. Analizadores
• Los analizadores permiten tokenizar un texto en términos prácticos para su uso en un inverted
index

• Normaliza los términos en formato estándar para mejorar las opciones de búsqueda.

• Un analizador posee tres funcionalidades

◦ Filtro de caracteres: La cadena es pasada por un filtro de caracteres. Permite por ejemplo
eliminar etiquetas html o transformar textos (& por and o similares)

◦ Tokenizador: Las cadenas son separadas en términos individuales. El más sencillo separa
por espacios o signos de puntuación.

◦ Filtros de token: Permite cambiar tokens, como poner en minúsculas, eliminar términos
como de, a o y, y agregar nuevos términos como los sinónimos.

21
• Para poder probar el resultado de cada analizador, podemos indicarlo con el endpoint _analyze

String String Tokens Tokens


Input CharacterFilters Tokenizer TokenFilters Output

• Elasticsearch, posee una serie de analizadores por defecto, y por medio del API de configuración
(settings) podemos crear nuevos analizadores a nivel de índice o cluster.

POST _analyze
{
"analyzer" : "standard",
"text" : "this is a test"
}

5.2.1. Estándar

• Uso por defecto. Para textos en cualquier lenguaje. Usa reglas de palabras definidas por el
Consorcio Unicode y elimina signos de puntuación.

• Pasa a minúsculas todas las palabras

22
POST _analyze
{
"analyzer" : "standard",
"text" : "function to delete(5)"
}
{
"tokens": [
{
"token": "pseudo",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "function",
"start_offset": 7,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "to",
"start_offset": 16,
"end_offset": 18,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "delete",
"start_offset": 19,
"end_offset": 25,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "3",
"start_offset": 26,
"end_offset": 27,
"type": "<NUM>",
"position": 4
}
]
}

5.2.2. Simple

• Todo lo que no sea letra es definido como token

23
POST _analyze
{
"analyzer" : "simple",
"text" : "Pseudo-function to delete(5)"
}
{
"tokens": [
{
"token": "pseudo",
"start_offset": 0,
"end_offset": 6,
"type": "word",
"position": 0
},
{
"token": "function",
"start_offset": 7,
"end_offset": 15,
"type": "word",
"position": 1
},
{
"token": "to",
"start_offset": 16,
"end_offset": 18,
"type": "word",
"position": 2
},
{
"token": "delete",
"start_offset": 19,
"end_offset": 25,
"type": "word",
"position": 3
}
]
}

5.2.3. Whitespace

• Solo considera los espacios o tabuladores como separadores

24
POST _analyze
{
"analyzer" : "whitespace",
"text" : "Pseudo-function to delete(3)"
}
{
"tokens": [
{
"token": "Pseudo-function",
"start_offset": 0,
"end_offset": 15,
"type": "word",
"position": 0
},
{
"token": "to",
"start_offset": 16,
"end_offset": 18,
"type": "word",
"position": 1
},
{
"token": "delete(3)",
"start_offset": 19,
"end_offset": 28,
"type": "word",
"position": 2
}
]
}

5.2.4. Language

• Permite definir el lenguaje del campo para realizar un analizador mas conciso

25
POST _analyze
{
"analyzer" : "english",
"text" : "Pseudo-function to delete(3)"
}
{
"tokens": [
{
"token": "pseudo",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "function",
"start_offset": 7,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "delet",
"start_offset": 19,
"end_offset": 25,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "3",
"start_offset": 27,
"end_offset": 28,
"type": "<NUM>",
"position": 4
}
]
}

5.3. Analizadores personalizados


• Si los analizadores no son suficientes, podemos crear nuestros analizadores personalizados.

• Para ello debemos indicar los siguientes apartados:

5.3.1. Filtro de caracteres

• Indicamos cual es el filtro de caracteres inicial

• Haremos un ejemplo más adelante.

26
No es ejectutable, se crean en los índices

PUT char-filter
{
"settings": {
"analysis": {
"char_filter": {
"lol_to_genial": {
"type": "mapping",
"mappings":["lol=> genial "]
}
}
}
}
}

• Podemos usar tantos como queramos, de tal forma que podemos crear los char_filter y luego
aplicar los que queramos a la vez.

• Por ejemplo existe un html_strip que elimina las etiquetas de html

• Su uso en el char_filter sería

"char_filter": ["html_strip","lol_to_genial"]

• Algunos de los filtros son:

• html_strip: Elimina elementos de html como <head/> y decodifica entidades html como
&uacute;

POST char-filter/_analyze
{
"tokenizer": "keyword",
"char_filter": [ "html_strip","lol_to_genial" ],
"text": "<p>I&apos;m so <b>happy</b> lol!</p>"
}

 El tokenizer keyword permite devolver el texto tal cual sin dividir la información

Con las versiones 2 no posee la misma llamada, y en casos no funciona


 correctamente, ya que se manda una instrucción por método GET enviando un
body con información.

27
GET _analyze
{
"tokenizer" : "keyword",
"filter" : ["lowercase"],
"char_filter" : ["html_strip"],
"text" : "this is a <b>test</b>"
}

• mapping: Reemplaza cualquier ocurrencia de la cadena especificada por el reemplazo, como en


el ejemplo mostrado anteriormente

• pattern: Reemplaza un patron por el reemplazo indicado, usa patrones basados en soporte
Java.

 Un mal patrón puede llegar a interrumpir la ejecución de la instancia.

• Está formado por un patrón, el reemplazo y un flag

"char_filter": {
"my_char_filter": {
"type": "pattern_replace",
"pattern": "(\\d+)-(?=\\d)",
"replacement": "$1_"
}
}

5.3.2. Tokenizers

• Se trata del separador en términos individuales.

• Podemos elegir los tokenizers que queramos.

Standard

• Tokenizador basado en gramática por medio del algoritmo de segmentación de texto unicode.
Funciona correctamente para la mayoría de los lenguajes

POST _analyze
{
"tokenizer": "standard",
"text": "Tokenizadores estándar, Hello everybody. I've a lot of things to show"
}

Letter

• Separa en términos cuando encuentra un carater que no es una letra

28
POST _analyze
{
"tokenizer": "letter",
"text": "Separamos por caracteres, en inglés, I've a problem with tokenizer"
}

Lowercase

• Paso a términos separando por aquellos que no son caracteres.

• Pasa a minúsculas de todos los términos.

• Más eficiente que letter tokenizer con el token filter de lowercase. Realiza ambas operaciones
en un solo paso.

POST _analyze
{
"tokenizer": "lowercase",
"text": "LAS 5 PALABRAS PASAn a mInÚsCuLas"
}

Whitespace

POST _analyze
{
"tokenizer": "whitespace",
"text": "Separación por espacios"
}

UAX URL Email

• Tokenizador estándar que separa urls y direcciones de email

POST _analyze
{
"tokenizer": "uax_url_email",
"text": "Correo electrónico [email protected]"
}

Classic

• Tokenizador basado en gramática correcto para lenguaje inglés. Posee heurística para el
tratamiento de acrónimos, correos electrónicos, nombres de compañías, y nombres de host.
separa y elimina signos de puntuación, pero si el punto no posee un espacio, se considera parte
del token

29
POST _analyze
{
"tokenizer": "classic",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."
}

NGram

• Permite generar términos a partir de palabras tomando por defecto un caracter y un máximo
de dos

PUT tokenizer-ngram
{
"settings": {
"analysis": {
"analyzer": {
"analyzer-ngram": {
"tokenizer": "tokenizer-ngram"
}
},
"tokenizer": {
"tokenizer-ngram": {
"type": "ngram",
"min_gram": 3,
"max_gram": 3,
"token_chars": [
"letter",
"digit"
]
}
}
}
}
}

POST tokenizer-ngram/_analyze
{
"analyzer": "analyzer-ngram",
"text": "3 Tristes Tigres"
}

Edge NGram

Muy util para definir búsquedas de tipo search-as-you-type. Por defecto separa los primeros
caracteres de cada término en términos de búsqueda.

30
PUT tokenizer-edge-ngram
{
"settings": {
"analysis": {
"analyzer": {
"analyzer-edge-ngram": {
"tokenizer": "tokenizer-edge-ngram"
}
},
"tokenizer": {
"tokenizer-edge-ngram": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 10,
"token_chars": [
"letter",
"digit"
]
}
}
}
}
}

• Probamos el resultado:

POST tokenizer-edge-ngram/_analyze
{
"analyzer": "analyzer-edge-ngram",
"text": "3 Tristes Tigres comen trigo en un trigal."
}

Keyword: Sin separador. Procesa la cadena completa tal cual

POST _analyze
{
"tokenizer": "keyword",
"text": "Texto sin procesar"
}

Pattern: Uso de un patrón para detectar los separadores

31
PUT tokenizer-pattern
{
"settings": {
"analysis": {
"analyzer": {
"analyzer-pattern": {
"tokenizer": "tokenizer-pattern"
}
},
"tokenizer": {
"tokenizer-pattern": {
"type": "pattern",
"pattern": "[,;:]"
}
}
}
}
}

POST tokenizer-pattern/_analyze
{
"analyzer": "analyzer-pattern",
"text": "Ruben,Gomez;Garcia:Profesor"
}

Path:

Permite generar terminos basados en paths o rutas

32
PUT analyzer-path
{
"settings": {
"analysis": {
"analyzer": {
"analyzer-path": {
"tokenizer": "tokenizer-path"
}
},
"tokenizer": {
"tokenizer-path": {
"type": "path_hierarchy",
"delimiter": "_",
"replacement": "/",
"skip": 2
}
}
}
}
}

POST analyzer-path/_analyze
{
"analyzer": "analyzer-path",
"text": "c_Archivos de Programa_software_artefactos"
}

5.4. Token Filters


• Acepta una lista de tokens y lo modifica. Existe una gran cantidad de filtros de tokens.

5.4.1. Sinónimos

• Los sinónimos permiten reemplazar el stream de tokens

• Para crear un filtro de tipo sinónimo debemos crear el filtro e indicar los sinonimos en un array
separado por cadenas

33
PUT /filter-sinonimos
{
"settings": {
"index" : {
"analysis" : {
"filter" : {
"mi_filtro_de_sinonimos": {
"type": "synonym",
"synonyms": [
"cabello,pelo",
"bonito,hermoso"
]
}
},
"analyzer" : {
"analyzer-sinonimos" : {
"filter" : [
"standard",
"lowercase",
"stop",
"mi_filtro_de_sinonimos"
],
"type" : "custom",
"tokenizer" : "standard"
}
}
}
}
}
}
POST filter-sinonimos/_analyze
{
"analyzer" : "analyzer-sinonimos",
"text": "cabello hermoso"
}

• Como la lista de sinónimos puede ser muy grande, se puede utilizar un almacenamiento relativo
al directorio de configuración de elasticsearch que permite almacenar los sinónimos en un
fichero.

34
PUT /filter-sinonimos-path/
{
"settings": {
"index" : {
"analysis" : {
"analyzer" : {
"analyzer-sinonimos-path" : {
"tokenizer" : "whitespace",
"filter" : ["synonym"]
}
},
"filter" : {
"synonym" : {
"type" : "synonym",
"synonyms_path" : "lista_sinonimos.txt"
}
}
}
}
}
}

• Si se realizan búsquedas con los sinónimos, los hits se preservan, ya que las posiciones son las
mismas

• La lista de sinónimos es relativa al directorio de configuración. Si Elasticsearch se ha instalado


por repositorio, este se encuentra en /etc/elasticsearch

/etc/elasticsearch/lista_sinonimos.txt

guapo,bonito,precioso
pelo,cabello

• Para probar el nuevo analizador:

POST filter-sinonimos-path/_analyze
{
"analyzer" : "analyzer-sinonimos-path",
"text": "Que cabello más hermoso, que guapo es el caballero"
}

5.5. Elección de analizadores


• La elección de los analizadores es más complejo de lo que parece. Los algoritmos de los
analizadores determinan que campos de una cadena se transforman en términos en un índice
invertido.

• Tenemos 10 tokenizers, 31 filtros de token, y tres filtros de caracteres por defecto en

35
Elasticsearch. Si se usan plugins, podemos agregar más.

• Por defecto, poseemos 8 analizadores estándar, que no son más que 8 combinaciones de
tokenizers, token filters y character filters.

• La forma de elegir un analizador pasa por práctica y tiempo.

• Dependiendo de las necesidades aplicaremos distintos analizadores

PUT /indice_con_sinonimos_tras_estudio
{
"settings": {
"analysis": {
"analyzer": {
"html-snowball-personalizado": {
"tokenizer": "standard",
"filter": [
"lowercase",
"stop",
"snowball"
],
"char_filter": ["html_strip"]
}
}
}
}
}

• Si probamos ahora nuestro índice, comprobaremos como nuestro analizador procesa nuestros
textos como deseamos

POST indice_con_sinonimos_tras_estudio/_analyze
{
"analyzer" : "html-snowball-personalizado",
"text": "estoy <em>muy<em> interesado con tu formacion"
}
{
"tokens": [
{
"token": "estoy",
"start_offset": 0,
"end_offset": 5,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "muy",
"start_offset": 10,
"end_offset": 17,
"type": "<ALPHANUM>",
"position": 1

36
},
{
"token": "interesado",
"start_offset": 18,
"end_offset": 28,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "con",
"start_offset": 29,
"end_offset": 32,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "tu",
"start_offset": 33,
"end_offset": 35,
"type": "<ALPHANUM>",
"position": 4
},
{
"token": "formacion",
"start_offset": 36,
"end_offset": 45,
"type": "<ALPHANUM>",
"position": 5
}
]
}

• También se debe tener en cuenta el tipo de búsqueda. Si buscamos en vez de palabras, frases,
también podemos optimizar las búsquedas de frases a costa de memoria y proceso.

• Podemos usar un analizador shingle que permite aumentar el rendimiento y aumenta la


calidad de los resultados.

• El secreto está en generar trozos de texto y crea grupos de frases. Se trata de un token filter
nGram que trabaja a nivel de palabra en vez de a nivel de caracter.

Propiedades de configuración del token shingle

max_shingle_size: 3
min_shingle_size: 1

• En este caso hace grupos de una, dos o tres palabras para las búsquedas, a costa de
almacenamiento y memoria de los índices.

• Otra opción sería usar por lenguaje natural

• En los casos que necesitemos el tratamiento de internacionalización, para casos avanzados,

37
como por ejemplo palabras compuestas, existe el plugin de descomposición

◦ word decompounder analysis plugin.

• Podemos usar el procedimiento de definición de un campo como index:not_analyzed, lo que


provoca que solo trate busquedas exactas del campo.

• Para búsquedas avanzadas de token, podemos usar los ngrams y edgengrams.

• Otra opción ofrecida por Elasticsearch es el plugin elasticsearch-analysis-phonetic, que permite


convertir el texto en tokens de texto fonético.

5.6. Segmentos
• Los Index Segments son mini-índices. Al realizar una búsqueda, Lucene realiza la búsqueda en
cada segmento, y tras buscar la información, fusiona los resultados.

• Al generar un índice de tipo texto, éste se alimenta con el resultado del analizador definido. Esto
provoca los mini-indices. El problema es que se puede tener demasiados mini-índices creados,
para eso Lucene puede fusionar esos segmentos según sus políticas. En esa fase, aquellos
documentos que hayan sido eliminados, son descartados. Por eso, a veces al agregar
documentos, el tamaño del índice puede disminuir.

• Se permite la manipulación de los merges por medio de configuración, o por medio del API de
optimización.

38
Capítulo 6. Mappings
6.1. ¿Que es un mapping?
El mapeo es el proceso por el cual definimos cómo es nuestro documento, qué campos contiene y
cómo está guardado en el índice. Definimos:

Que campos de tipo string deben ser tratados como “full text”. Que campos son de tipo numéricos,
fechas o geolocalizados. Cuando los valores en un documento deben ser indexados dentro del
campo _all. El formato de los campos tipo fecha. Definir reglas para el control del mapeo dinámico
de datos.

Cada campo del documento dentro de un índice tiene un tipo de dato, que puede ser

• Core datatypes: text, date, long, double, boolean, binary ( Base64 encoded )

• Complex datatypes: object, nested ( array de object )

• Geo datatypes: geo_point, geo_shape

• Specialized datatypes: ip ( long identifier to ip address ), completion ( auto-complete


suggestions ), token_count ( number of tokens in a string ).

Todos los campos, dentro de un mismo índice, tienen el mismo mapeo, ya que internamente están
guardados como el mismo campo.

Aunque no podemos tener dos tipos de datos distintos, si podemos tener un mapeo un poco distinto
para el mismo campo.

Ejemplo con un campo de tipo string analizado con el analizador por defecto

PUT usuarios
POST usuarios/usuario/_mapping
{
"properties": {
"name": {
"type": "text"
}
}
}

39
Ejemplo con un campo de tipo string no analizado

POST usuarios/usuario/_mapping
{
"properties": {
"cif": {
"type": "keyword"
}
}
}

Cada documento tiene unos metadatos asociados

{
"_index": “my_index",
"_type": "my_type",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"name": "John Smith"
}
}

Podemos mapear algunos de estos campos, por ejemplo si no queremos que nuestro índice tenga
habilitado el meta campo _all añadimos El campo _all es un elemento que permite la búsqueda de
todo el contenido sin saber en que campo en concreto se encuentra. Se trata de un campo de texto
que contiene todos los demás elementos. El campo _all es analizado, indexado pero no almacenado
ni devuelto. Las búsquedas de tipo _search?q= o de tipo query_string apuntan por defecto al campo
_all

Deshabilitar el campo _all en el mapping

{
"_all": {
"enabled": false
}
}

Podemos cambiar el tipo de analyzer; algoritmo que se utiliza para convertir un string en tokens,
en los cuales se basará la búsqueda.

40
POST usuarios/usuario/_mapping
{
"properties": {
"description": {
"type": "text",
"analyzer": "english"
}
}
}

Con el meta campo copy_to, podemos crear campos tipo _all, el parámetro redirige la salida de un
campo a otro, formando campos compuestos.

POST usuarios/usuario/_mapping
{
"properties": {
"nombre_completo": {
"type": "text"
},
"nombre": { "type": "text", "copy_to": "nombre_completo"},
"apellido1": { "type": "text", "copy_to": "nombre_completo"},
"apellido2": { "type": "text", "copy_to": "nombre_completo"}
}
}

• Para poder buscar por el campo, podemos aprovechar la directiva and de match:

POST usuarios/usuario
{
"apellido1":"Gomez",
"apellido2":"Garcia",
"nombre":"Ruben"
}
GET usuarios/usuario/_search
{
"query": {
"match": {
"nombre_completo": {
"query": "Ruben Gomez Garcia",
"operator": "and"
}
}
}
}

• Cada mapping tiene un número de elementos asociados que pueden ser utilizados para
controlar los metadatos

41
6.1.1. _uid

• identificador único de un documento

6.1.2. _id

• Por defecto cada documento está asociado a un id y un tipo, que por defecto no es indexado ni
almacenado

6.1.3. _type

• Permite mostrar el tipo de un campo. Indexado y no analizado

6.1.4. _source

• generado automáticamente y almacena el documento al completo. Por defecto es devuelto con


get o search. Puede ser deshabilitado, aunque es necesario para la mayoría de operaciones de
actualización.

{
"transaction" : {
"_source" : {
"enabled" : false
}
}
}

6.2. Mappings dinámicos


Por defecto elasticsearch viene con un mapeo dinámico de sus datos.

Las reglas de mapeo automático se pueden cambiar, podemos configurar el campo default mapping
para cambiar el mapeo por defecto de los campos, o configurar las reglas de mapeo dinámico.

6.3. Agregación de campos


• Si el mapping es dinámico, podemos agregar nuevos campos en el mapping original.

• Al crear un índice e insertar documentos, se autodetecta el mapping de la misma, sin embargo,


a veces no genera correctamente el mapping, asi que se aconseja generar un mapping específico
que coincida con el modelo de datos.

• Para agregar nuevos campos, es tan sencillo como indicar el tipo de documento y el campo
necesario, teniendo en cuenta que no debe existir con anterioridad.

42
PUT /transactions
{
"mappings": {
"internal" : {
"properties" : {
"description" : {
"type" : "text",
"analyzer": "english"
},
"date" : {
"type" : "date"
},
"ccc" : {
"type" : "text"
}
}
}
}
}

Agregación de un nuevo campo en nuestro mapping

PUT /transactions/internal/_mapping
{
"properties": {
"ccc_dest" : {
"type" : "keyword"
}
}

• Podemos evaluar el comportamiento del analizador a nivel de campo para comprobar como ha
sido procesado

43
GET /transactions/_analyze
{
"field": "ccc_dest",
"text" : "123-123-123-123"
}
{
"tokens": [
{
"token": "123-123-123-123",
"start_offset": 0,
"end_offset": 15,
"type": "word",
"position": 0
}
]
}

6.4. Especificaciones de analizadores


• Podemos especificar los analizadores según se definen los atributos como vimos anteriormente.

PUT /transactions
{
"mappings": {
"internal" : {
"properties" : {
"description" : {
"type" : "string",
"analyzer": "english"
},
"date" : {
"type" : "date"
},
"ccc" : {
"type" : "string"
}
}
}
}
}

6.5. Plantillas dinámicas


• Las plantillas dinámicas permiten definir mappings personalizados que pueden ser aplicados
para agregar dinámicamente campos basados en:

◦ El tipo de dato detectado por Elasticsearch

44
◦ El nombre del campo

◦ El path completo del campo

6.5.1. match_mapping_type

• Por ejemplo, podemos crear en un índice un mapping que cuando detecte longs los pase a
integers

Generación de un índice y creación de tipos

PUT /match-mapping/users/1
{
"name" : "Ruben",
"value" : 1
}
GET /match-mapping/users/_mapping
{
"match-mapping": {
"mappings": {
"users": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"value": {
"type": "long"
}
}
}
}
}
}

• Usando una plantilla dinámica

45
PUT /match-dynamic
{
"mappings": {
"users": {
"dynamic_templates": [
{
"de-long-a-integer": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
}
]
}
}
}

• Si ahora repetimos la inserción del usuario

46
PUT /match-dynamic/users/1
{
"name" : "Ruben",
"value" : 1
}
GET /match-dynamic/users/_mapping
{
"match-dynamic": {
"mappings": {
"users": {
"dynamic_templates": [
{
"de-long-a-integer": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
}
],
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"value": {
"type": "integer"
}
}
}
}
}
}

6.5.2. match y unmatch

• Permite definir un patrón que si coincide con el nombre del campo aplica la directiva que se
definal

• De forma inversa, podemos generar un patrón que si no coincide, aplica la directiva definida

47
PUT /match-unmatch-dynamic
{
"mappings": {
"users": {
"dynamic_templates": [
{
"longs-como-strings": {
"match_mapping_type": "string",
"match": "l_*",
"unmatch": "l_t*",
"mapping": {
"type": "integer"
}
}
}
]
}
}
}

• Si insertamos un campo que haga match en el mapping por defecto y en el apartado match, y
otro en el apartado unmatch

POST dynamic-match-unmatch/users
{
"l_name_chars":"1",
"l_text":"22"
}

• Podemos comprobar cual es el resultado del mapping, que ha sido alterado por el template

POST match-unmatch-dynamic/users
{
"l_name_chars":"1",
"l_text":"22"
}
GET match-unmatch-dynamic
{
"match-unmatch-dynamic": {
"aliases": {},
"mappings": {
"users": {
"dynamic_templates": [
{
"longs-como-strings": {
"match": "l_*",
"unmatch": "l_t*",
"match_mapping_type": "string",

48
"mapping": {
"type": "integer"
}
}
}
],
"properties": {
"l_name_chars": {
"type": "integer"
},
"l_text": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
},
"settings": {
"index": {
"creation_date": "1539021510217",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "wS8cJ3R5QYSGigcfR5z5uA",
"version": {
"created": "6040299"
},
"provided_name": "match-unmatch-dynamic"
}
}
}
}

6.5.3. match_pattern

• Permite definir con patrones los matching de aplicación

49
Matching de tipo numeros_12312

PUT dynamic-match-pattern
{
"mappings": {
"users": {
"dynamic_templates": [
{
"longs_como_strings": {
"match_mapping_type": "string",
"match_pattern": "regex",
"match": "^numeros_\\d+$",
"mapping": {
"type": "long"
}
}
}
]
}
}
}

• Comprobamos la inserción de un documento que cumpla la expresión regular

POST dynamic-match-pattern/users
{
"name" : "Ruben",
"numeros_123":"22150",
"numeros_223_texto":"22150"
}

• El resultado del mapping es el siguiente:

50
GET dynamic-match-pattern/users/_mapping
{
"dynamic-match-pattern": {
"mappings": {
"users": {
"dynamic_templates": [
{
"longs_como_strings": {
"match": "^numeros_\\d+$",
"match_mapping_type": "string",
"match_pattern": "regex",
"mapping": {
"type": "long"
}
}
}
],
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"numeros_123": {
"type": "long"
},
"numeros_223_texto": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}

6.5.4. path_match y path_unmatch

Como match, pero opera por medio de un path completo por medio del sistema de puntos

51
PUT dynamic-path-match
{
"mappings": {
"users": {
"dynamic_templates": [
{
"full_name": {
"path_match": "direccion.*",
"path_unmatch": "*.numero",
"mapping": {
"type": "text",
"copy_to": "direccion_completa"
}
}
}
]
}
}
}

• Si realizamos una inserción de prueba

POST dynamic-path-match/users
{
"nombre": "Ruben",
"direccion": {
"tipo" : "Calle",
"calle" : "Real",
"numero" : 3
}
}

• El mapping será el siguiente

GET dynamic-path-match/users/_mapping
{
"dynamic-path-match": {
"mappings": {
"users": {
"dynamic_templates": [
{
"full_name": {
"path_match": "direccion.*",
"path_unmatch": "*.numero",
"mapping": {
"copy_to": "direccion_completa",
"type": "text"
}

52
}
}
],
"properties": {
"direccion": {
"properties": {
"calle": {
"type": "text",
"copy_to": [
"direccion_completa"
]
},
"numero": {
"type": "long"
},
"tipo": {
"type": "text",
"copy_to": [
"direccion_completa"
]
}
}
},
"direccion_completa": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"nombre": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}

6.6. Plantillas de índices


• Permite definir plantillas que permitan la creación de nuevos índices.

53
• Las plantillas incluyen settings, mappings y un patrón que controla cuando debe aplicarse el
índice nuevo

 Solo sirve a la hora de crear el índice, si se cambia el template no aplica.

PUT _template/plantilla_nueva2
{
"index_patterns": "pl*",
"settings": {
"number_of_shards": 2
},
"mappings": {
"users": {
"_source": {
"enabled": false
},
"properties": {
"email": {
"type": "keyword"
},
"fecha_creacion": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z YYYY"
}
}
}
}
}

• Creamos un nuevo índice, y generamos un tipo llamado users

PUT plex-template
POST plex-template/users
{
"name":"ruben"
}

• Comprobamos que el índice posee los shards configurados y que el tipo users posee los nuevos
campos del template

54
Muestra del nuevo índice

GET plex-template/_settings
{
"plex-template": {
"settings": {
"index": {
"creation_date": "1499096928446",
"number_of_shards": "2",
"number_of_replicas": "1",
"uuid": "O8zp3IT_SHOIB2GhtK9w_w",
"version": {
"created": "5040299"
},
"provided_name": "plex-template"
}
}
}
}

55
Muestra del nuevo tipo

{
"plex-template": {
"mappings": {
"users": {
"_source": {
"enabled": false
},
"properties": {
"email": {
"type": "keyword"
},
"fecha_creacion": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z YYYY"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}

• Para obtener los templates:

56
GET _templates
{
"plex-template": {
"aliases": {},
"mappings": {
"users": {
"_source": {
"enabled": false
},
"properties": {
"email": {
"type": "keyword"
},
"fecha_creacion": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z YYYY"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
},
"settings": {
"index": {
"creation_date": "1499097328963",
"number_of_shards": "2",
"number_of_replicas": "1",
"uuid": "-vaoeuetQ6y6-KwllfKFug",
"version": {
"created": "5040299"
},
"provided_name": "plex-template"
}
}
}
}

Para borrar los templates

57
DELETE _template/plantilla_nueva
{
"acknowledged": true
}

58
Capítulo 7. Búsquedas avanzadas
• No solo podemos realizar búsquedas _search para buscar contenido en ciertos campos,
podemos aprovechar el API de elasticsearch para realizar una gran cantidad de peticiones más
avanzadas que las vistas hasta ahora. Algunas de ellas son las siguientes

7.1. Consultas term-based


• Una consulta term busca documentos que contiene el valor exacto

• Para realizar las consultas de tipo term_based, indica que toma la petición como si fuera un
término único

POST accounts/_search
{
"query": {
"term": {
"address": {
"value": "171 Putnam Avenue"
}
}
}
}
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 0,
"max_score": null,
"hits": []
}
}

• Como el campo está analizado, no sabe que la dirección es exactamente esa, lo ha separado en
términos individuales

59
Agregación de un nuevo campo como no analizado

POST accounts/account/_mapping
{
"properties": {
"message": {
"type": "keyword"
}
}
}
GET accounts/_mapping
{
...
"message": {
"type": "keyword"
}

Agregación de un documento en el campo keyword

GET accounts/_mapping
POST accounts/account/25/_update
{
"doc" : {
"message" : "toma mensaje"
}
}

• Si ahora probamos la misma consulta de tipo term

60
Consulta de tipo term

POST accounts/_search
{
"query": {
"term": {
"message": {
"value": "toma mensaje"
}
}
}
}
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "accounts",
"_type": "account",
"_id": "25",
"_score": 0.2876821,
"_source": {
"account_number": 25,
"balance": 40540,
"firstname": "Virginia",
"lastname": "Ayala",
"age": 39,
"gender": "F",
"address": "171 Putnam Avenue",
"employer": "Filodyne",
"email": "[email protected]",
"city": "Nicholson",
"state": "PA",
"message": "toma mensaje"
}
}
]
}
}

• En caso de realizar múltiples consultas, podemos dar mayor valor a uno de ellos en concreto

61
POST accounts/account/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"state": {
"value": "dc",
"boost": 2.0
}
}
},
{
"term": {
"age": 27
}
}
]
}
}
}

7.2. Filtros
El entorno de consulta depende de como se usan el contexto de consulta y el entorno de filtro

• Contexto de consulta: Una consulta busca las coincidencias. Este contexto calcula el _score,
como se aproxima a las coincidencias, relativo al resto de coincidencias

• Contexto de filtro: Un contexto busca coincidencias, pero no elabora el score, o coincide con lo
esperado o no.

62
POST accounts/account/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"state": {
"value": "dc"
}
}
},{
"term": {
"lastname": {
"value": "moran"
}
}
}

],
"filter": [
{
"term": {
"age": 27
}
}
]

}
}
}

7.3. match_phrase
• Analiza el texto y crea una consulta de tipo phrase fuera del texto analizado

63
POST accounts/_search
{
"query": {
"match_phrase": {
"address": "574 Everett Avenue"
}
}
}
{
"took": 21,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 9.961143,
"hits": [
{
"_index": "accounts",
"_type": "account",
"_id": "265",
"_score": 9.961143,
"_source": {
"account_number": 265,
"balance": 46910,
"firstname": "Marion",
"lastname": "Schneider",
"age": 26,
"gender": "F",
"address": "574 Everett Avenue",
"employer": "Evidends",
"email": "[email protected]",
"city": "Maplewood",
"state": "WY"
}
}
]
}
}

• Se puede definir que analizador se va a utilizar a la hora de procesar la consulta

64
POST accounts/_search
{
"query": {
"match_phrase": {
"address": {
"query" : "574 Everett Avenue",
"analyzer" : "standard"
}
}
}
}

7.4. match_phrase_prefix
• Se trata del mismo concepto que match_phrase, pero permite expandir el sufijo por medio de la
directiva max_expansions

• Es el resultado de la típica consulta "search as you type"

POST accounts/_search
{
"query": {
"match_phrase_prefix": {
"address": {
"query" : "574 Everett Ave",
"analyzer" : "standard",
"max_expansions": 10
}
}
}
}

7.5. multi_match_query
• Permite generar consultas de tipo multi-match contra distintos campos

• En query aparece el texto que se busca

• En fields indica cuales son los campos que se quieren buscar

65
GET /_search
{
"query": {
"multi_match" : {
"query": "toma mensaje",
"fields": [ "otro", "message" ]
}
}
}

• Podemos usar wildcards para buscar campos y ^ para lanzar un boost a un campo concreto

GET /_search
{
"query": {
"multi_match" : {
"query": "ayala",
"fields": [ "*name", "email^3" ]
}
}
}

• Existen distintos tipos de multi_match

7.5.1. best_fields

• Uso por defecto. Busca documentos que posean coincidencias, usa _score de la mejor
coincidencia. El objetivo es bucar muchas palabras en un campo:

GET /_search
{
"query": {
"multi_match" : {
"query": "virginia ayala",
"type": "best_fields",
"fields": [ "firstname","lastname" ],
"tie_breaker" : 0.3
}
}
}

• Para mejorar el _score podemos usar tie_breaker, que permite calcular:

◦ EL valor del mayor score

◦ El valor de todos los demás * 0.3 (el valor del tie_breaker)

• Permite aumentar el score dando un hit mayor

66
• Otra opción es usar el operador para el multimatch

GET /_search
{
"query": {
"multi_match" : {
"query": "virginia ayala",
"type": "best_fields",
"fields": [ "firstname","lastname" ],
"tie_breaker": 0.3,
"operator" : "or"
}
}
}

7.5.2. most_fields

• Usa un analizador como si fuera un campo inmenso. Busca cada palabra en cada campo. El
objetivo es buscar la misma palabra en distintos campos

GET /_search
{
"query": {
"multi_match" : {
"query": "ayala",
"type": "most_fields",
"fields": [ "lastname","email" ],
"tie_breaker": 0.3,
"operator" : "or"
}
}
}

7.5.3. phrase

• Usa un match_phrase en cada campo y combina los _score de cada uno.

GET /_search
{
"query": {
"multi_match" : {
"query": "171 Putnam Av",
"type": "phrase_prefix",
"fields": [ "address", "message" ]
}
}
}

67
• phase_prefix: Lanza un match_phrase_prefix en cada campo y combina los _score de cada
campo

7.6. fuzziness
• Permite buscar con un efecto de borrosidad. Se trata de un match de tipo fuzzy.

• Permite en busquedas de texto o tipo keyword

• Por defecto podemos definir un fuzziness de entre 0 y 2

• Podemos definirlo de forma manual o automática

◦ Manual: 0, 1 o 2

◦ Automática:

▪ Si el term posee de 0 a 2 caracteres, debe ser un match exacto.

▪ Si el term posee de 3 a 5 caracteres, se permite una edición

▪ Si el term posee más de 5 caracteres, se permiten dos ediciones

Ejemplo de fuzzy, por defecto posee borrosidad 0

POST accounts/_search
{
"query": { "fuzzy": { "firstname" : "Veras" }}
}

Ejemplo de fuzzy con borrosidad 2

POST accounts/_search
{
"query": {
"fuzzy" : {
"firstname" : {
"value" : "Veras",
"fuzziness" : 2
}
}
}
}

• Los parámetros posibles son:

68
GET /_search
{
"query": {
"fuzzy" : {
"lastname" : {
"value" : "vera",
"boost" : 1.0,
"fuzziness" : 2,
"prefix_length" : 0,
"max_expansions": 100
}
}
}
}

• fuzziness: es la distancia por defecto de búsqueda. Por defecto AUTO.

• prefix_length: Es el número de caracteres iniciales que no deben ser modificados. Por defecto 0

• max_expansions: Es el número de terminos que pueden expandirse. Por defecto 50.

7.7. highlighting
• Permite búsquedas resaltadas de forma automática.

GET /_search
{
"highlight": {
"fields": {
"address":{}
}
},
"query": {
"term": {
"address": {
"value": "scott"
}
}
}
}

• Como resultado, aparecerá a parte de los hits, un apartado con el campo resaltadas

69
{
"took": 100,
"timed_out": false,
"_shards": {
"total": 92,
"successful": 92,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 4.311029,
"hits": [
{
"_index": "accounts",
"_type": "account",
"_id": "573",
"_score": 4.311029,
"_source": {
"account_number": 573,
"balance": 32171,
"firstname": "Callie",
"lastname": "Castaneda",
"age": 36,
"gender": "M",
"address": "799 Scott Avenue",
"employer": "Earthwax",
"email": "[email protected]",
"city": "Marshall",
"state": "NH"
},
"highlight": {
"address": [
"799 <em>Scott</em> Avenue"
]
}
}
]
}
}

7.8. more_like_this
• Las consultas more_like_this buscan documentos que se parezcan

• Para conseguirlo, MLT selecciona un grupo representativo de términos, genera una consulta con
esos términos, ejecuta la consulta y devuelve los resultados.

70
GET /_search
{
"query": {
"more_like_this" : {
"fields" : ["city", "address"],
"like" : "marshall scott avenue",
"min_term_freq" : 0,
"max_query_terms" : 12
}
}
}

• Los parámetros que se pueden utilizar son:

◦ like: requerido, permite indicar texto, uno o muchos documentos.

◦ unlike: En conjunto con like, para definir los documentos que no se quieren buscar

◦ fields: lista de campos de análisis. Por defecto _all

◦ like_text: Texto para buscar los documentos similares a este.

71
Capítulo 8. Resultado de consultas
8.1. Boost
• El boost permite dar importancia a ciertos campos, unos por encima de otros

PUT prueba-boosting
{
"mappings": {
"peliculas": {
"properties": {
"titulo": {
"type": "text",
"boost": 2
},
"sinopsis": {
"type": "text"
}
}
}
}
}
POST prueba-boosting/peliculas
{
"titulo":"El tio de los anillos",
"sinopsis":"Pues va de unos arillos y el master que los lleva"
}
POST prueba-boosting/peliculas
{
"titulo": "El master de los arillos",
"sinopsis": "Pues va de unos arillos de cebolla que vende un tio"
}

• El elemento implicado en la búsqueda implicará el orden por defecto de los resultados y su


_score

GET prueba-boosting/_search?q=master
GET prueba-boosting/_search?q=tio

8.2. Algoritmos de búsqueda


8.2.1. Query_then_fetch

• Los algoritmos de búsqueda de ElasticSearch se pueden elegir.

• Por defecto se usa query_then_fetch

72
◦ La petición se procesa en dos fases. Primero la query avanza a todos los shards
involucrados.

◦ Cada shard ejecuta la query y genera una lista ordenada de resultados.

◦ Cada shard devuelve el resultado al nodo encargado de fusionar y ordenar las respuestas

◦ El nodo coordina y devuelve el documento desde los shards relevantes.

8.2.2. Dfs_query_then_fetch

• Realiza las mismas fases que el anterior, pero con una fase previa de evaluación de los scores
para mayor precisión

• La forma de alterar la petición para afinar el score es

GET prueba-boosting/_search?q=master&search_type=dfs_query_then_fetch

8.3. Sort
• Podemos ordenar los resultados por distintos campos.

• Se trata de un nuevo apartado agregable en el API de búsquedas

GET accounts/_search
{
"sort": [
{
"age":{
"order": "desc"
}
}
],
"query": {
"range": {
"age": {
"from": 30,
"to": 35
}
}
}
}

• Las ordenaciones por campos de texto (que no por _score) producen un consumo excesivo de
memoria, por lo cual no se recomiendan excepto en casos concretos. Para ello se debe activar la
opción de permitir usar consumo de disco para ordenar.

73
8.4. From / Size
• Las paginaciones se realizan desde las opciones From y Size

• Se pueden agregar en el cuerpo del mensaje o desde la url para mayor comodidad

• No se recomienda la devolución de gran cantidad de elementos, sino que se prefieren opciones


más elegantes como los cursores.

GET accounts/_search
{
"sort": [
{
"age":{
"order": "desc"
}
}
],
"from": 30,
"size": 10,
"query": {
"range": {
"age": {
"from": 30,
"to": 35
}
}
}
}

8.5. Scroll
• Permite el acceso al concepto de cursos a los documentos asociados a una consulta.

• Para ello creamos un scroll con fecha de caducidad

74
GET accounts/_search?scroll=1m
{
"sort": [
{
"age":{
"order": "desc"
}
}
],
"query": {
"range": {
"age": {
"from": 30,
"to": 35
}
}
}
}
{
"_scroll_id":
"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAABSFnIzZkFaamg1VHZXcW5ObkYtVm1sSmcAAAAAAAAAVRZyM2ZBWmpoNVR2V3FuTm5GLVZtbEpnAAAAAAAAAFEWcjNm
QVpqaDVUdldxbk5uRi1WbWxKZwAAAAAAAABUFnIzZkFaamg1VHZXcW5ObkYtVm1sSmcAAAAAAAAAUxZyM2ZBWmpoNVR2V3FuTm5GLVZtbEpn",
"took": 11,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
...

• Volvemos a consultar el scroll y ampliamos de nuevo el tiempo

GET _search/scroll
{
"scroll_id":
"DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAABSFnIzZkFaamg1VHZXcW5ObkYtVm1sSmcAAAAAAAAAVRZyM2ZBWmpoNVR2V3FuTm5GLVZtbEpnAAAAAAAAAFEWcjNm
QVpqaDVUdldxbk5uRi1WbWxKZwAAAAAAAABUFnIzZkFaamg1VHZXcW5ObkYtVm1sSmcAAAAAAAAAUxZyM2ZBWmpoNVR2V3FuTm5GLVZtbEpn",
"scroll":"1m"
}

• Devolverá resultados hasta que caduque el scroll (1 minuto por ejecución) o termine el flujo de
las respuestas

8.6. Preferencias de ejecución


• Podemos definir cuales son las preferencias de ejecución de la consulta. parámetro:preference

◦ _primary : Solo en shards primarios

◦ _primary_first : Primero en los shards primarios que están disponibles, sino otros
(deprecado en vesión 6.1.0, desaparece en la 7.0.0).

◦ _replica : Operaciones en las replicas exclusivamente (deprecado en vesión 6.1.0,


desaparece en la 7.0.0).

◦ _replica_first : Se ejecuta primero en las réplicas, si es posible (deprecado en vesión 6.1.0,

75
desaparece en la 7.0.0).

◦ _local : shards disponibles en el nodo consultado, si es posible

◦ _only_local : shards disponibles exclusivamente en local

◦ _only_nodes : (node_id,node_id2, ..). Solo en los nodos indicados

◦ _prefer_nodes : (node_id). En el nodo consultado y si no existen en otros.

◦ _shards : (1,2). Ejecuta en los shards con identificadores 1 y 2

• Para realizar las pruebas, solo necesitamos agregar la opción preference

GET accounts/_search?preference=_shards:2,3
{
"sort": [
{
"age":{
"order": "desc"
}
}
],
"query": {
"range": {
"age": {
"from": 30,
"to": 35
}
}
}
}

Es posible concatenar preferencias por medio del pipe | como el siguiente


 ejemplo: GET accounts/_search?preference=_shards:2,3|_local

76
Capítulo 9. Modelo distribuido
• Por defecto, Elasticsearch se construye para ser un servicio siempre disponib le y preparado
para el escalado según nuestras necesidades.

• El escalado puede venir por aumentar las características de la máquina (escalado vertical) o
iniciando nuevos nodos (escalado horizontal)

• El escalado vertical posee sus límites, mientras que el escalado horizontal permite un
crecimiento mas estable.

• ELasticsearch es un software distribuido por naturaleza, lo que permite manejar sin problemas
múltiples nodos para el escalado y la alta disponibilidad.

9.1. Inicio de un nodo


• Como por defecto, el inicio de un nodo de un cluster solo necesita que la dirección de
publicación esté en el mismo rango que el resto de los futuros miembros, y que el nombre del
cluster sea el mismo.

Configuración base para jvm.properties

# Xms represents the initial size of total heap space


# Xmx represents the maximum size of total heap space

-Xms512m
-Xmx512m

contenido de elasticsearch, directiva node.name

node.name: node-1

• Inicio de la ejecución del primer nodo del cluster elasticsearch

./elasticsearch

9.2. Creación de un índice


• La agregación de datos se inicia por medio de la creación de un índice, un espacio donde la
información está relacionada.

• Un índice no es más que un namespace que apunta a uno o más shards.

77
PUT nuevo-indice
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 2
}
}

9.3. Shards, distribución de un índice


• Un shard no es más que una unidad de trabajo. Básicamente es una instancia de lucene, con su
motor de búsqueda.

• Los shards es como elasticsearch redistribuye la información a traves del cluster. Se consideran
contenedores de datos.

• Los shards se consideran como primarios o replicas.

• La cantidad de shards indica cual va a ser el numero máximo de documentos almacenados en el


índice.

Por defecto, un shard primario puede almacenar Integer.MAX_VALUE - 128, sin


 embargo, depende del hardware, tamaño y complejidad de los documentos, la
forma de consulta y los tiempos de respuesta.

• Como recomendación, un shard no puede poseer más de 2^31 documentos, restricción de


Apache Lucene, mientras que el tamaño recomendado máximo de un shard es de 30 GB. Un
shard por indice y por nodo es una de las recomendaciones.

• Otra opción es colocar 3 shards por nodo, calculando, 3 nodos x 3 shards = 9 shards en total.

9.4. Distribución de documentos


• Los documentos se almacenan tanto en shards como en replicas. Por defecto, los documentos se
reparten entre todos los shards, y se copian a sus correspondientes réplicas, lo que permite
mantener la alta disponibilidad en el cluster.

9.5. Replicación
• Para realizar una replicación completa, debemos iniciar otras dos instancas de Elasticsearch.

• Para ello, iniciaremos un nodo más, con nombre node-2

• Repetimos el proceso de creación del nodo por medio de la descompresión.

No se debe copiar un elasticsearch ya iniciado, ya que sino, este se iniciará con el


 mismo id hash, y producirá errores de sincronización.

78
9.6. Split Brain
• El split-brain se produce en el caso de que la mitad del cluster (por defecto se vea
comprometida. El caso más común es en el cluster de dos nodos. En este caso, los dos nodos se
comunican por la capa de transporte. Si ese canal de transporte falla, puede haber un corte de
suministro. Por defecto en dos nodos, con que uno solo esté levantado, toma el control del
cluster y continúa dando servicio. Sin embargo en el caso del corte de suministro en la
comunicación, produce un efecto de separación de cerebros o split-brain.

• En este caso, ninguno de los dos nodos se ven entre sí, y en ese caso, los dos piensan que el nodo
contrario se ha caido. En caso de que esto ocurra (simulación que puede pasar en grandes
clusters de servidores) se vuelven clusters independientes, y si se realiza alguna modificación
en alguno de ellos, se descoordinarán y no podrán volver a unirse. Para evitar el split-brain se
recominda usar la siguiente directiva:

Configuración para un cluster de 8 nodos

discovery.zen.minimum_master_nodes: 5
# En caso de redes con latencia, se recomienda ampliar el timeout para evitar falsos positivos de nodos caidos.
discovery.zen.ping.timeout: 3s

De esta forma, el cluster con la mitad + 1 de nodos elegibles será el único que puede tomar el
control, evitando el efecto de split-brain.

9.7. Tipos de nodos


• Cada vez que se inicia una instancia de Elasticsearch, se inicia un nodo.

• Una colección de nodos es un cluster.

• Una sola instancia de un nodo es un cluster.

• Cada nodo puede gestionar HTTP y el tráfico de transporte por defecto. Esta última capa,
permite la comunicación entre nodos. El protocolo HTTP es el indicado para los clientes REST.

• Existen cuatro tipos de nodos básicos y uno extra en base al plugin X-Pack

1. node.master: nodo elegible como maestro (true por defecto). Permite que el nodo pueda ser
coordinador del cluster.

a. Es útil crear maestros elegibles que no posean carga excesiva, en caso de poseer clusters
grandes.

b. Poseen la capacidad de coordinación, enrutación de peticiones y la indexación de


peticiones de clientes a los nodos de datos.

configuración

node.master: true
node.data: false
node.ingest: false

1. node.data: (true por defecto) nodo que almacena y realiza operaciones con datos, como

79
búsquedas, agregaciones u operaciones CRUD

a. Es importante monitorizar cargas para agregar nuevos datanodes cuando sea necesario.

configuración

node.master: false
node.data: true
node.ingest: false

1. node.ingest: (true por defecto). Permite usar una cadena de ejecuciones para transformar y
enriquecer un documento antes de indexarlo. Muy útil en caso de que las transformaciones de
documentos sean extremas y de gran carga. Se trata de un conjunto de procesadores que se
ejecutan en orden y permiten la manipulación de documentos previamente a su indexación.
Desde agregar fechas, a reconstrucciones completas.

configuración

node.master: false
node.data: false
node.ingest: true
# Evita la búsqueda entre clusters (true por defecto)
search.remote.connect: false

1. tribe.*: coordinador que permite conectar a múltiples clusters y realizar búsquedas a través de
todos los clusters conectados.

◦ Es posible crear un nodo de coordinación que balancee las peticiones, gestione la enrutación
de recursos, gestion la fase de busqueda y reducción y distribuya el indexado en bloque.
(son como los balanceadores de carga inteligentes)

configuración

node.master: false
node.data: false
node.ingest: false
search.remote.connect: false

9.8. Desarrollo VS Producción


• Elasticsearch puede iniciarse en modo desarrollo o producción. Se considera en producción si
Elasticsearch se inicia y se puede conectar por medio de ips externas a otros nodos.

• Una vez iniciado, sea desarrollo o producción, se evaluan las características básicas de sistema
deseables para elasticsearch. Los mensajes vienen en forma de warnings para que apliquemos
los cambios.

• Para forzar estos controles en un nodo single,se usa la siguiente directiva:

80
es.enforce.bootstrap.checks: true

• Otra opción es usar las opciones de Java

ES_JAVA_OPTS=-Des.enforce.bootstrap.checks=true

• Por defecto, las configuraciones de Elasticsearch están definidas para desarrollo. En entornos de
producción, se deben modificar ciertas directivas.

• La primera es el tamaño de la memoria, que por defecto son 2GB. Se recomienda una
configuración de 30GB por instancia y servidor de elasticsearch.

• Por defecto, Elasticsearch apunta a Localhost para http y el transporte. Perfecto para pruebas
básicas o de concepto con elasticsearch. En producción, se debe definir la interfaz para que
todos los nodos se vean en la capa de transporte.

# dirección de protocolo http


http.host: 192.168.1.40
# dirección de protocolo de transporte
transport.host: 172.16.47.211

81
Capítulo 10. Updates
10.1. API de actualizaciones
El API de actualizaciones permite actualizar un documento por medio de un script. La operación
obtiene el documento del índice, ejecuta el script e indexa el resultado. Usa el versionado para
evitar conflitos de actualización Es imprescindible que se habilite el campo _source para ello. Al
terminar se realiza una reindexación completa del documento

10.2. Actualizaciones por script


• Una de las metodologías de actualización son las actualizaciones por script.

Agregación de un documento

PUT login
POST login/users/1
{
"username" : "Ruben",
"groups" : ["admin"],
"count_access" : 0
}

82
Agregación por scripting, usando "painless"

POST login/users/1/_update
{
"script" : {
"source": "ctx._source.count_access += params.hits",
"lang": "painless",
"params" : {
"hits" : 1
}
}
}
GET login/users/1
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"username": "Ruben",
"groups": [
"admin"
],
"count_access": 1
}
}

En las versiones anteriores (2.x) no es aceptado el tipo lang "painless", debemos


usar groovy para generar los scripts. Para que funcionen, debemos quitar el nodo
 lang y no usa la subetiqueta params, solo utiliza el nombre tag. El inline cambia a:
"inline": "ctx._source.count_access += hits",

Podemos agregar elementos a un array

83
POST login/users/1/_update
{
"script" : {
"source": "ctx._source.groups.add(params.tag)",
"lang": "painless",
"params" : {
"tag" : "operator"
}
}
}
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
GET login/users/1
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 3,
"found": true,
"_source": {
"username": "Ruben",
"groups": [
"admin",
"operator"
],
"count_access": 1
}
}

Agregación de nuevos campos al documento

POST login/users/1/_update
{
"script" : "ctx._source.password = \"madalena\""
}

Eliminar campos

84
POST login/users/1/_update
{
"script" : "ctx._source.remove(\"password\")"
}

10.3. Documentos parciales


• Podemos usar un lenguaje más sencillo por medio de la actualización de un partial document.

• Se trata de generar un documento que se fusione con los documentos coincidentes

POST login/users/1/_update
{
"doc" : {
"active" : true
}
}
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 24,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}

10.4. Noop
• Si el documento se fusiona con un origen, y no produce cambios, el resultado es noop (no
operation)

• Por lo tanto, el documento no aumenta de versión.

• Se puede observar al repetir una actualización

85
POST login/users/1/_update
{
"doc" : {
"active" : true
}
}
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 24,
"_shards": {
"total": 0,
"successful": 0,
"failed": 0
}
}

• En caso de que nos interese activamente que haga la sustitución aunque sea de tipo noop,
podemos deshabilitarlo

POST login/users/1/_update
{
"doc" : {
"active" : true
},
"detect_noop": false
}
{
"_index": "login",
"_type": "users",
"_id": "1",
"_version": 25,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}

10.5. Upserts
• Si realizamos una actualización de un documento y este no funciona, podemos aprovechar el
concepto de upsert.

• Si existe actualizo, si no existe lo creo. Es aplicable a todos los casos anteriores, aplicando la
opción upsert e indicando el documento que se va a generar por defecto

86
Ejemplo con script para generación de hits de usuarios no dados de alta previamente

POST login/users/luis/_update
{
"script" : {
"source": "ctx._source.count_access += params.hits",
"lang": "painless",
"params" : {
"hits" : 1
}
},
"upsert":{
"hits": 1
}
}
GET login/users/luis
{
"_index": "login",
"_type": "users",
"_id": "luis",
"_version": 1,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}

10.6. Update By Query


• Esta operación genera un snapshot del índice al comienzo e indexa al comienzo usando el
versionado interno.

• Si alguien modifica y cambia el versionado del documento, este produce un error en la


actualización al proceder al cambio

• Si todo es correcto, la versión se incrementa y los cambios se fusionan.

• No existe el rollback a la hora de realizar las operaciones de actualización. Si se produce un


error en la actualización

• Para realizar múltiples actualizaciones e intentar obviar los casos particulares, se puede
agregar la opción conflicts=proceed

• Las actualizaciones de este tipo, permiten lanzar las mismas consultas que con el API de
_update

• Permite actualizar en el índice sin necesidad de reindexar continuamente

87
POST accounts/_update_by_query
{
"script" : {
"source": "ctx._source.age += params.hits",
"lang": "painless",
"params" : {
"hits" : 1
}
},
"query": {
"range": {
"age": {
"from": 30,
"to": 35
}
}
}
}

88
Capítulo 11. Delete
• Permite borrar un documento JSON con un índice específico basado en su id

• Cada documento está indexado

• Permite el uso de enrutados, y si se indica y no se completa su valor, produce una excepción

• Permite el uso de parent. EL borrado de un parent no borra automáticamente el children. Para


ello es recomendado el uso del API de Delete Query

• Si se borra a un hijo, hay que indicarle el padre al que pertenece.

• Permite indicar la espera por shards activos, lo que obliga a que haya al menos un número
mínimo de shards

• Permite el uso de un timeout para interrumpir la operación en un tiempo de 1 minuto por


defecto.

DELETE login/users/luis
{
"found": true,
"_index": "login",
"_type": "users",
"_id": "luis",
"_version": 5,
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}

11.1. Delete by Query


• La forma más sencilla de borrado es delete_by_query

POST login/_delete_by_query
{
"query": {
"match": {
"count_access": 1
}
}
}

• Cuando se realiza la operación, genera un snapshot del índice, usando un sistema de versiones
interno. Si el documento cambia desde que el snapshot se realizó y la consulta es procesada,
produce un conflicto.

89
• Similar al update by query

 No disponible en versiones anteriores a la 5.x

90
Capítulo 12. Agregaciones
• El framework de agregaciones permite la cosntrucción de bloques llamados agregaciones que se
componen en orden para construir conjuntos de datos complejos

• Cada agregación se le considera como una unidad de trabajo que genera información a partir
de un conjunto de documentos

12.1. Tipos
• Existen distintos tipode de agregaciones:

◦ Bucketing: Agregación que genera buckets, donde cada uno está asociado a una clave y a un
criterio de documento. Todos los criterios son evaluados.

◦ Métricas: Agregaciones que computan métricas sobre un conjunto de documentos

◦ Matrices: Conjunto de agregaciones que operan en múltiples campos produciendo una


matriz de resultados. (Sin soporte de scripting)

◦ Pipeline: Agregaciones que agregan la salida de una agregación y sus métricas.

• Como dato a tener muy en cuenta, al ser un bucket un conjunto de documentos, se puede
asociar una agregación dentro de otra, produciendo la anidación de documentos.

• Las agregaciones poseen una estructura base:

"aggregations" : {
"<nombre_de_agregación>" : {
"<tipo_de_agregacion>" : {
<cuerpo_de_la_agregación>
}
[,"meta" : { [<cuerpo de metadatos>] } ]?
[,"aggregations" : { [<sub_agregaciones>]+ } ]?
}
[,"<nombre_de_segunda_agregacion>" : { ... } ]*
}

• Se permite el uso de aggs en vez de agregaciones como clave.

12.2. Métricas
• Computación de métricas basadas en valores extraidos de documentos o de otras agregaciones,
e incluso de scripts.

• Las agregaciones numéricas se consideran como caso específico de agregaciones.

• Algunas métricas relevantes son

91
POST /accounts/account/_search?size=0
{
"aggs" : {
"media" : { "avg" : { "field" : "balance" } }
}
}

• Podemos usar valores de script

POST /accounts/account/_search?size=0
{
"aggs" : {
"media-con-iva" : {
"avg" : {
"script" : {
"source" : "doc.balance.value * 1.21"
}
}
}
}
}

• Se puede calcular con proximidad la cardinalidad de un campo, esto es, aproximadamente,


cuantos elementos se tienen

POST /accounts/account/_search?size=0
{
"aggs" : {
"cardinalidad" : {
"cardinality" : {
"field" : "firstname.keyword"
}
}
}
}

• Podemos observar estadísticas avanzadas

92
POST /accounts/account/_search?size=0
{
"aggs" : {
"estadisticas" : {
"extended_stats" : {
"field" : "balance"
}
}
}
}
{ "aggregations": {
"estadisticas": {
"count": 1000,
"min": 1011,
"max": 49989,
"avg": 25714.837,
"sum": 25714837,
"sum_of_squares": 858626807735,
"variance": 197373965.79843104,
"std_deviation": 14048.984511288745,
"std_deviation_bounds": {
"upper": 53812.80602257749,
"lower": -2383.1320225774907
}
}
}
}

• Existen agregaciones simples para máximos y mínimos

POST /accounts/account/_search?size=0
{
"aggs" : {
"minimo" : {
"min" : {
"field" : "balance"
}
},
"maximo" : {
"max" : {
"field" : "balance"
}
}
}
}

• De la misma manera, de forma independiente, podemos buscar percentiles,stats,sum

93
12.3. Rangos
• Basado en generat buckets categorizados.

• Usa el soporte de rangos

POST accounts/account/_search?size=0
{
"aggs":{
"rango-de-balances": {
"range":{
"field":"balance",
"ranges": [
{"to":3000},
{"from":3000,"to":10000},
{"from":10000,"to":15000},
{"from":15000,"to":20000},
{"from":20000}
]
}
}
}
}

12.4. Rangos de fechas


• Las agregaciones de rengos se usan para valores de fecha. Los valores from y to se usan con
expresiones de tipo Date Math. Se puede definir fechas con formatos para que sea más cómodo

94
POST agregaciones/fechas
{ "date": "2017-01-01" }
POST agregaciones/fechas
{ "date": "2017-02-01" }
POST agregaciones/fechas
{ "date": "2017-03-01" }
POST agregaciones/fechas
{ "date": "2017-04-01" }
POST agregaciones/fechas
{ "date": "2017-05-01" }
POST /agregaciones/fechas/_search?size=0
{
"aggs": {
"range": {
"date_range": {
"field": "date",
"format": "MM-yyyy",
"ranges": [
{ "from": "01-2017", "to": "03-2017", "key": "primero" },
{ "from": "03-2017", "to": "06-2017", "key": "segundo" }
],
"keyed": true
}
}
}
}

12.5. Términos
• Se basan en el calculo de buckets de documentos

• Permite categorizar y generar buckets basados en términos

POST accounts/account/_search?size=0
{
"aggs":{
"primera-agregacion": {
"terms":{
"field":"gender.keyword"
}
}
}
}

12.6. Anidaciones
• Las anidaciones pertenecen a la categoría bucket

95
• Realizar agregaciones en anidaciones requieren indicar cual es el path del anidamiento

POST cuentas/cuenta/_search?size=0
{
"query" : {
"match" : { "ccc" : "214324322543535" }
},
"aggs" : {
"movimientos" : {
"nested" : {
"path" : "movimientos"
},
"aggs" : {
"maximo-movimiento" : { "max" : { "field" : "movimientos.valor" } }
}
}
}
}

96
Capítulo 13. Modelado de datos
• La base de datos de Elasticsearch permiten realizar operaciones no disponibles en bases de
datos tradicionales, pero eso no es gratuito.

• Las relaciones entre entidades no es tan obvia como estamos acostumbrados con SQL

• La idea de la normalización de la base de datos puede ser una catástrofe en Elasticsearch

• Elasticsearch está preparado para un escalado horizontal que debemos tener en cuenta

• Existen tres formas de relaciones:

◦ Uniones a nivel de aplicación

◦ Desnormalización de datos

◦ Anidación

◦ Relaciones padre-hijo

13.1. Uniones a nivel de aplicación


• Se pueden emular bases de datos relacionales implementando joins en la aplicación

• El objeto relacionado usa el identificador del objeto a relacionar.

PUT uniones-app-c/cliente/1
{
"nombre":"Roberto",
"descripcion": "Cliente majo"
}
PUT uniones-app-f/facturas/1
{
"codigo":"fmg-22",
"precio":22554.21,
"cliente":1
}

• La clave principal será el índice, el tipo y el id de documento

• En este caso, se realizarán dos consultas para obtener los datos relacionados.

• Si se quiere obtener las facturas del cliente por nombre, se consultará el nombre para obtener el
id, y con el id se buscará el cliente

• Ventajas:

◦ Normalización de datos

◦ Actualización de datos sin concurrencias con otros documentos

• Inconvenientes:

◦ Se realizan consultas extra para cumplir objetivos.

• Uso:

97
◦ Si la primera entidad pose un número de documentos pequeños

◦ Si la primera entidad no realiza muchos cambios

◦ Se recomienda cachear los resultados de la primera consulta para mostrar la segunda

13.2. Desnormalización
• Para aumentar el máximo de rendimiento en nuestras consultas, se desnormaliza para realizar
menos consultas y se elimina la necesidad de joins

PUT desnormalizacion-app-c/cliente/1
{
"nombre":"Roberto",
"pago":"paypal",
"descripcion": "Cliente majo"
}
PUT desnormalizacion-app-f/facturas/1
{
"codigo":"fmg-22",
"precio":22554.21,
"cliente":{
"id":1,
"nombre":"Roberto",
"pago":"paypal"
}
}

• La desnormalización es parcial. Se desnormaliza aquello que se necesite integrar para que la


consulta sea suficiente para obtener los documentos deseados

GET /desnormalizacion-app-f/facturas/_search
{
"query": {
"bool": {
"must": [
{ "match": { "codigo":"fmg-*" }},
{ "match": { "cliente.nombre": "Roberto"}}
]
}
}
}

• En desnormalización también se acepta el colapso de campos

◦ Un campo que va a ser el centro de una agregación, debe almacenarse en un campo de tipo
keyword para agrupar por el nombre completo.

• Para ello usamos el modelo no analizado dentro de los campos

98
PUT desnormalizacion-fields
PUT desnormalizacion-fields/facturas/_mapping
{
"properties": {
"cliente": {
"properties": {
"id": {
"type": "long"
},
"nombre": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"pago": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"codigo": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"precio": {
"type": "float"
}
}
}

• Por defecto, los campos ya se crean con ese formato de field de tipo keyword

99
Introducimos datos para probar las consultas

POST desnormalizacion-fields/facturas
{
"codigo":"fmg-21",
"precio":225234.21,
"cliente":{
"id":1,
"nombre":"Roberto",
"pago":"paypal"
}
}
POST desnormalizacion-fields/facturas
{
"codigo":"fmg-22",
"precio":1554.21,
"cliente":{
"id":2,
"nombre":"Luis",
"pago":"paypal"
}
}
POST desnormalizacion-fields/facturas
{
"codigo":"fmg-23",
"precio":23554.21,
"cliente":{
"id":3,
"nombre":"Alberto",
"pago":"Tarjeta de crédito"
}
}

• Probamos la consulta por medio del colapso de campos

100
GET /desnormalizacion-fields/facturas/_search
{
"size" : 0,
"query": {
"bool": {
"should": [
{ "match": { "codigo": "fmg-*" }},
{ "match": { "cliente.nombre": "luis" }}
]
}
}
,
"aggs": {
"formas-pago": {
"terms": {
"field": "cliente.pago.raw"
}
}
}
}

• En el resultado comprobamos la clasificación de claves

101
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"formas-pago": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "paypal",
"doc_count": 2
},
{
"key": "Tarjeta de crédito",
"doc_count": 1
}
]
}
}
}

• Ventajas

◦ Velocidad, ya que cada documento posee toda la información necesaria para poder
encontral lo necesario en las consultas

◦ No necesita de joins

• Invonvenientes

◦ En caso de actualización de la estructura principal, si afecta a algun campo cruzado, exige la


actualización de todos los documentos por duplicado, tantas veces como
desnormalizaciones, aunque se solventa con el api _bulk y con el scroll

◦ El índice es mayor ya que el documento _source para cada entrada es mayor y existen
mayor cantidad de campos indexados. No es un gran problema ya que los datos en disco
están comprimidos.

◦ En caso de alta concurrencia, esto es, mientras realizamos cientos, miles o millones de
actualizaciones, un usuario actualiza un documento. Puesto que elasticsearch no soporta
transacciones ACID, de múltiples documentos, debemos solucionar los problemas de
concurrencia. Para ello tenemos tres soluciones

102
▪ Concurrencia: Bloqueo global ( PUT /index/type/global/_create {} ) creación de un
documento. En este caso se crea bloqueo global, si y a hay uno da error. Al terminar
(DELETE /index/type/global). Debemos comprobar siempre si este documento existe o no
como operación previa

▪ Concurrencia: Bloqueo de documento. Mismo sistema con un bulk de ids de documentos

▪ Concurrencia: Bloqueo de arbol. Agregación de un documento de bloqueo a nivel de


documento por id.

13.3. Documentos anidados


• La gestión de documentos individuales son atómicas, podemos almacenar dentro del mismo
documento.

• La generación de un documento con un array de objetos (automático si está el mapping


dinámico activo), podemos agregar documentos sin problemas

PUT /embebidos/facturas/1
{
"codigo":"33fb1-23",
"etiquetas": [ "informatica", "ventas" ],
"productos": [
{
"titulo": "Ordenador",
"comentarios": "Modelo 3.214",
"valor":2425.21
},
{
"titulo": "Raton",
"comentarios": "Logitech v12",
"valor":225.11
},{
"titulo": "Monitor",
"comentarios": "LG 2131t2",
"valor":722.15
}
]
}

• Comprobamos el mapping generado

GET embebidos/facturas/_mapping
{
"embebidos": {
"mappings": {
"facturas": {
"properties": {
"codigo": {
"type": "text",

103
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"etiquetas": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"productos": {
"properties": {
"comentarios": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"titulo": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"valor": {
"type": "float"
}
}
}
}
}
}
}
}

• Pero debemos tener en cuenta las consecuencias del almacenamiento de la información de esta
forma

104
GET embebidos/facturas/_search
{
"query": {
"bool": {
"must": [
{ "match": { "productos.titulo": "Raton" }},
{ "match": { "productos.valor": 722.15 }}
]
}
}
}

• Si buscamos estas condiciones, los objetos anidados no son accesibles directamente, y su


actualización implica la actualización de todo el documento.

• Para ello existen los documentos anidados. Los documentos anidados se indexan de forma
independiente, y mantienen sus relaciones.

• Podemos ejecutar consultas de coincidencias dentro del mismo objeto anidado

• Unir el documento padre a los hijos es muy rápido, casi como si estuviera en el mismo
documento

• Para poder generar un objeto anidado, debemos construir el mapping

105
PUT /embebido-final
{
"mappings": {
"facturas": {
"properties": {
"codigo": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"etiquetas": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"productos": {
"type": "nested",
"properties": {
"titulo": { "type": "text" },
"comentarios": { "type": "text" },
"valor": { "type": "integer" }
}
}
}
}
}
}

• Volvemos a probar pero esta vez con elementos embebidos.

106
PUT /embebido-final/facturas/1
{
"codigo":"33fb1-23",
"etiquetas": [ "informatica", "ventas" ],
"productos": [
{
"titulo": "Ordenador",
"comentarios": "Modelo 3.214",
"valor":2425.21
},
{
"titulo": "Raton",
"comentarios": "Logitech v12",
"valor":225.11
},{
"titulo": "Monitor",
"comentarios": "LG 2131t2",
"valor":722.15
}
]
}

• La consulta a realizar en este caso es la siguiente

107
GET /embebido-final/facturas/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"codigo": "33fb1-23"
}
},
{
"nested": {
"path": "productos",
"query": {
"bool": {
"must": [
{
"match": {
"productos.titulo": "Raton"
}
},
{
"match": {
"productos.comentarios":"Modelo 3.214"
}
}
]
}
}
}
}
]
}}}

• Podemos comprobar como ahora no existe ese documento embebido

• Los documentos anidados se usan en caso de que no haya un documento principal claro, y con
un número controlado de elementos.

• Ventajas

◦ Permite almacenar documentos en distintos índices

◦ Se encuentran tan próximos que se realizan operaciones como si fuera un documento

◦ Se permite ordenaciones de documentos embebidos

◦ Se permiten agregaciones de documentos embebidos

◦ Se permiten agregaciones embebidas inversas para acceso al root.

• Inconvenientes

◦ La agregación, cambio o eliminación de un documento embebido indica que todo el

108
documento debe ser indexado, con un gran coste

◦ Las búsquedas devuelven el documento completo, no solo el documento anidado en


particular, aunque en un futuro se plantea hacerlo.

13.4. Relaciones padre-hijo


• En caso de que se quiera realizar una separación total entre documentos, pero relacionado, se
usa el tipo join

• Sustituye a los parent/child de versiones anteriores.

• Como los tipos ya no existen, no se puede generar más de un tipo por índice (y pronto
desaparecerán) tenemos la opción de join:

PUT empresas
{
"mappings": {
"_doc": {
"properties": {
"campo_join": {
"type": "join",
"relations": {
"cliente": "factura"
}
}
}
}
}
}

• Almacenamos la información de los padres e hijos

PUT empresas/_doc/1
{
"nombre": "Ruben",
"apellido1": "Gomez",
"campo_join": "cliente"
}
PUT empresas/_doc/2
{
"nombre": "Luis",
"apellido1": "Perez",
"campo_join": "cliente"
}

• Ahora, para insertar facturas:

109
PUT empresas/_doc/3?refresh&routing=1
{
"factura": "El caso es deber algo",
"campo_join": {
"name": "factura",
"parent": "1"
}
}
PUT empresas/_doc/4?refresh&routing=1
{
"factura": "El caso es deber otra cosa",
"campo_join": {
"name": "factura",
"parent": "1"
}
}
PUT empresas/_doc/5?refresh&routing=1
{
"factura": "El caso es deber algo a otro",
"campo_join": {
"name": "factura",
"parent": "2"
}
}

• La búsqueda de las facturas de un padre concreto será:

GET empresas/_search
{
"query": {
"parent_id":{
"type":"factura",
"id":1
}
}
}

• El resultado es todos los parents que posean estas coincidencias de los hijos, y no devuelve los
hijos de los padres.

• La búsqueda de los hijos desde los padres:

110
GET /empresa/facturas/_search
{
"query": {
"has_parent": {
"type": "cliente",
"query": {
"match": {
"nombre": "Alberto"
}
}
}
}
}

• Consideraciones finales

◦ A mayor numero de joins, peor rendimiento

◦ Cada generación de padres, necesitan su campo _id almacenado en memoria (mucha ram)

◦ Solo usarlo cuando hay pocos padres y muchos hijos

◦ No se deben usar multiples joins con padres e hijos en una consulta única

◦ Se deben mantener los ids de los padres pequeños para que se compriman en valores doc y
usen menos memoria.

13.5. i18n
• El uso de analizadores implica la generación de distintas soluciones a problemas de modelado
de datos.

• Los problemas de uso de multi idioma deben ser evaluados a la hora de construir nuestras
estructuras.

• Existen tres aproximaciones a la hora de solucionar el problema

• El hecho de unir distintos lenguajes en el mismo inverted index puede ser un problema real

◦ Las reglas de stemming para un idioma pueden ser totalmente distintos a las reglas de otros
idiomas.

◦ El uso de distintos stemmers a la vez contra el mismo campo, puede realizar el doble
stemming en un solo término, lo que produce errores de comprensión y de generación de
términos.

◦ Si un término aparece muchas veces, el score aumenta y si ordenamos por _score aparecerá
en un puesto superior. Esto produce que algunos idiomas, al tener menos términos o más
repetitivos o cortos, se potencien frente a otros. *EL uso de lenguajes también lleva a
distintos comportamientos según los deseos del cliente

◦ Un cliente busca en un idioma y mostramos resultados en el mismo idioma

◦ Un cliente busca en un idioma elegido y mostramos resultados en el idioma nativo

◦ Un cliente busca en un idioma elegido y mostramos resultados en el idioma elegido.

111
• Para solventar todas estas casuísticas, debemos resolverlos por medio de alguna de las
siguientes opciones:

13.5.1. Un lenguaje por documento

• Un lenguaje por documento requiere una configuración sencilla.

• Los documentos de distintos lenguajes se almacenan en distintos índices.

Definición de índice en español

PUT /services-es
{
"mappings": {
"extra": {
"properties": {
"name": {
"type": "string",
"fields": {
"i18n": {
"type": "string",
"analyzer": "spanish"
}
}
}
}
}
}
}

Definición de índice en inglés

PUT /services-en
{
"mappings": {
"extra": {
"properties": {
"name": {
"type": "string",
"fields": {
"i18n": {
"type": "string",
"analyzer": "english"
}
}
}
}
}
}
}

112
Definición de índice en francés

PUT /services-fr
{
"mappings": {
"extra": {
"properties": {
"name": {
"type": "string",
"fields": {
"i18n": {
"type": "string",
"analyzer": "french"
}
}
}
}
}
}
}

Introducción de datos

POST services-es/extra
{
"name":"Mensaje en español"
}
POST services-en/extra
{
"name":"Message in spanish"
}
POST services-fr/extra
{
"name":"Messaje en espagnol"
}

• Para hacer las consultas por idioma, usamos un índice distinto o buscamos en todos los índices:

113
GET /services-*/extra/_search
{
"query": {
"multi_match": {
"query": "mensaje en español",
"fields": [ "name","name.i18n" ] ,
"type": "most_fields"
}
},
"indices_boost": {
"services-en": 3,
"services-fr": 2,
"services-es": 1
}
}

13.5.2. Un lenguaje por campo

• Un campo se puede repetir indicando distintas traducciones.

• Es el mas sencillo de todos, y a pesar de estar en el mismo índice, no están en el mismo inverted
index

PUT /services-i18n
{
"mappings": {
"extra": {
"properties": {
"name": {
"type": "string"
},
"name_es": {
"type": "string",
"analyzer": "spanish"
},
"name_en": {
"type": "string",
"analyzer": "english"
},
"name_fr": {
"type": "string",
"analyzer": "french"
}
}
}
}
}

114
Agregamos un documento

POST services-i18n/extra
{
"name":"Mensaje por defecto",
"name_es":"Mensaje por defecto",
"name_en":"Default message",
"name_fr":"message par défaut"
}

Consulta de múltiples campos a la vez con boosting en el lenguaje por defecto.

GET /services-i18n/extra/_search
{
"query": {
"multi_match": {
"query": "defecto",
"fields": [ "name*", "name_es^3" ],
"type": "most_fields"
}
}
}

13.5.3. Campos de lenguajes mixtos

• Para un uso limitado de lenguajes, se usa la capacidad de multi-field. De esa forma se realiza un
análisis por campo.

• Interesante cuando no sabemos el idioma origen. Se permite las búsquedas multi-idioma.

115
PUT /services-multimapping
{
"mappings": {
"extra": {
"properties": {
"name": {
"type": "string",
"fields": {
"i18n-es": {
"type": "string",
"analyzer": "spanish"
},
"i18n-en": {
"type": "string",
"analyzer": "english"
},
"i18n-fr": {
"type": "string",
"analyzer": "french"
}
}
}
}
}
}
}

Introducción de información

POST services-multimapping/extra
{
"name":"texto en español"
}

GET /services-multimapping/extra/_search
{
"query": {
"multi_match": {
"query": "español",
"fields": [ "name.i18n*^2.5", "name" ],
"type": "most_fields",
"minimum_should_match": "75%"
}
}
}

• minimum_should_match permite filtrar los scores más bajos para evitar problemas

116

También podría gustarte