Elasticsearch 2.0: ce qui change


Logo Elastic Une première bêta d'Elasticsearch 2.0 vient de sortir, c'est l'occasion de faire un premier bilan des changements. Il s'agit en effet d'une véritable V2 qui, sur certains aspects, rompt clairement avec le passé.

Cet article n'a pas vocation a énumérer de manière exhaustive les changements, la documentation fait cela bien mieux que moi, mais plutôt synthétiser les principaux changements.

Installation

Un premier changement se situe au niveau de la configuration réseau. Jusqu'ici, lorsqu'on démarrait des nœuds Elasticsearch, il se regroupaient d'eux mêmes en cluster, c'était épatant mais dangereux. Elasticsearch 2 fait un pas la sagesse avec une configuration par défaut plus raisonnable. Elle évitera de former des clusters inopinément :

  • Elasticsearch écoute sur l'adresse loopback (127.0.0.1), comme MySQL par exemple
  • Il ne découvre plus les autres membres de cluster par multicast. Le multicast qui était activé par défaut jusqu'ici, n'était de toutes façons pas recommandé en production.

La nouvelle configuration par défaut est parfaite pour le développement, elle l'est probablement moins pour la production. Il faudra donc, en plus du cluster.name et node.name positionner

  • network.host pour préciser sur quelle interface réseau écouter.
  • discovery.zen.ping.unicast.hosts pour donner une liste de nœuds à contacter pour rejoindre le cluster

Plus d'info

Indexation

Elastic l'avait annoncé depuis la V1.5, les Rivers allaient disparaître. C'est chose faite dans Elasticsearch 2, les Rivers ne sont plus. Pourtant, certaines rivières comme JDBC ou RabbitMQ étaient utiles et utilisées. Quelles solutions avons-nous pour remplacer les rivières?

  • Logstash, c'est la solution préconisée par Elastic. Il existe déjà de nombreux inputs (Twitter, RabbitMQ par exemple) et d'autres naissent régulièrement (JDBC par exemple)
  • Des utilitaires dédiés: la JDBC River est devenue le JDBC Importer et la river Wikipedia est dans Stream2Es
  • Une application spécifique, avec des frameworks comme Spring Batch, Spring Intégration ou Apache Camel qui disposent d'adaptateurs pour écrire dans Elasticsearch, il n'est pas très compliqué de transférer de la donnée dans Elasticsearch.
  • Une application distribuée spécifique, avec des frameworks comme Hadoop ou Spark et la librairie Elasticsearch Hadoop.

Mappings et analyse

C'était une mauvaise pratique dans Elasticsearch 1, c'est interdit dans Elasticsearch 2: Appliquer un mapping différent pour un même champ dans 2 types de documents d'un même index n'est plus permis. Par exemple, le mapping suivant n'est plus valide:

  "mappings": {
    "fr": {
      "properties": {
        "titre": {
          "type": "string",
          "analyzer": "french"
        }
      }
    },
    "en": {
      "properties": {
        "titre": {
          "type": "string",
          "analyzer": "english"
        }
      }
    }
  }

Autre mauvaise pratique, utiliser des points dans les noms de champs est aussi interdit dans cette nouvelle version.

Les pseudo-champs comme _id, _timestamp, _routing ne permettent plus de référencer un champ du document avec l'attribut path car celui-ci a disparu. Quant aux pseudo-champs _analyzer (analyseur par défaut) et _boost (document boost), que l'on positionnait aussi à la racine des mappings, ils ont aussi disparu. On les remplacera respectivement avec des dynamic_templates et des function_score queries.

La gestion des relations parent-enfants a été refondue. Pour cette raison, il est conseillé de ré-indexer les données pour tirer partie de ces nouvelles optimisations.

Dans Elasticsearch 1, supprimer le mapping pour un type de document entraînait la perte de tous les documents de ce type. Elasticsearch 2 ne permet plus la suppression de mapping, comme par exemple:

DELETE bibliotheque/_mapping/dvd

Enfin, les mappings et les templates d'index ne pourront plus être configurés sous forme de fichiers JSON placés dans les dossiers config/mappings ou config/templates Ils devront donc être déployés avec l'API REST.

Recherche

Dans le Query DSL d'Elasticsearch 1, on avait deux grands types d'opérateurs: les queries et les filters. Ces derniers étant particulièrement intéressants pour des raisons de performances (mise en cache, combinaisons booléennes efficaces...). On avait de ce fait un term query et term filter, une range query et un range filter... Avec Elasticsearch 2, et Lucene 5 en particulier, la distinction s'estompe.

Queries & Filters

Il n'y a plus qu'un seul type d'opérateur, mais il subsiste une signification différente en fonction du contexte d'utilisation. Pour mettre en œuvre les filtres, dans Elasticsearch 1, on utilisait généralement une query de type filtered. Dans Elasticsearch 2, ce type de query est toujours là mais devient obsolète. On utilisera à la place la nouvelle clause filter de la query bool, qui se comporte comme la clause must sauf que les opérateurs seront traités comme des filtres: Ils n'interviendront pas dans le calcul du score par exemple. Ainsi, la requête Elasticsearch 1 ...

{
  "query": {
    "filtered": {
      "query": {
        "match": {
          "titre": "spring"
        }
      },
      "filter": {
        "range": {
          "prix": {
            "gte": 50
          }
        }
      }
    }
  }
}

... deviendra avec Elasticsearch 2:

{
  "query": {
    "bool": {
      "must": {
        "match": {
          "titre": "spring"
        }
      },
      "filter": {
        "range": {
          "prix": {
            "gte": 50
          }
        }
      }
    }
  }
}

Les filtres and et or pouvaient être utilisés pour combiner des filtres. Ils deviennent obsolètes dans la V2, on utilisera à la place l'opérateur bool en toutes circonstances.

En ce qui concerne les recherches de type fuzzy, Elasticsearch 2 passe de la distance de Levenshtein à Damerau-Levenshtein. En résumé, les mots zenika et zeinka seront distants de 1 car il y a une permutation de 2 caractères adjacents, alors qu'ils étaient distants de 2 jusqu'ici. De plus, la fuzziness ne pourra plus être renseignée sous forme de pourcentage, les seules valeurs autorisées seront donc 0,1,2 et AUTO

Dans Elasticsearch 1, on pouvait référencer un champ en omettant son préfixe: par exemple le champ editeur.nom pouvait être abrégé nom dans les recherches. Pour éviter les amalgames, ce ne sera plus le cas avec Elasticsearch 2.

Plus d'info:

Agrégations

Les facettes qui ont été rendues obsolètes par l'avènement des agrégations ont été supprimées dans cette V2.

En plus des deux types d'agrégations déjà existants, metrics et bucket, un troisiéme type nommé pipeline fait son apparition. Son objectif est de calculer une agrégation, non pas sur des documents, mais sur des résultats d’agrégation. L'exemple suivant calcule l'amplitude de prix par éditeur:

{
  "aggregations": {
    "editeur": {
      "terms": { "field": "editeur.code" },
      "aggs": {
        "maxprix": {
          "max": { "field": "prix" }
        },
        "minprix": {
          "min": { "field": "prix" }
        },
        "ecartprix": {
          "bucket_script": {
            "buckets_path": {
              "minprix": "minprix",
              "maxprix": "maxprix"
            },
            "script": "maxprix - minprix"
          }
        }
      }
    }
  }
}

Les agrégations pipeline sont néanmoins au stade expérimental pour l'instant.

Les Field Datas sont une structure de données utilisée pour les agrégations, les tris et les scripts. Depuis Elastic 1, il était possible stocker ces field datas sur le disque au lieu d'occuper de la mémoire Java: on parle de Doc Values. Les Doc Values seront dorénavant activées par défaut pour presque tous les champs sauf ceux de type string analysée.

Plus d'info:

Messages d'erreur

Dans Elasticsearch 1, en cas d'erreur de syntaxe dans une requête, on obtenait un message d'erreur peu lisible:

{
  "error" : "SearchPhaseExecutionException[Failed to execute phase [query], all shards failed; shardFailures {[k2my_gmKTIS8kQ8bsVgHQA][bibliotheque][0]: SearchParseException[[bibliotheque][0]: from[-1],size[-1]: Parse Failure [Failed to parse source [{\"query\":{\"macht\":{\"titre\":\"spring\"}}}]]]; nested: QueryParsingException[[bibliotheque] No query registered for [macht]]; }{[k2my_gmKTIS8kQ8bsVgHQA][bibliotheque][1]: SearchParseException[[bibliotheque][1]: from[-1],size[-1]: Parse Failure [Failed to parse source [{\"query\":{\"macht\":{\"titre\":\"spring\"}}}]]]; nested: QueryParsingException[[bibliotheque] No query registered for [macht]]; }{[k2my_gmKTIS8kQ8bsVgHQA][bibliotheque][2]: SearchParseException[[bibliotheque][2]: from[-1],size[-1]: Parse Failure [Failed to parse source [{\"query\":{\"macht\":{\"titre\":\"spring\"}}}]]]; nested: QueryParsingException[[bibliotheque] No query registered for [macht]]; }{[k2my_gmKTIS8kQ8bsVgHQA][bibliotheque][3]: SearchParseException[[bibliotheque][3]: from[-1],size[-1]: Parse Failure [Failed to parse source [{\"query\":{\"macht\":{\"titre\":\"spring\"}}}]]]; nested: QueryParsingException[[bibliotheque] No query registered for [macht]]; }{[k2my_gmKTIS8kQ8bsVgHQA][bibliotheque][4]: SearchParseException[[bibliotheque][4]: from[-1],size[-1]: Parse Failure [Failed to parse source [{\"query\":{\"macht\":{\"titre\":\"spring\"}}}]]]; nested: QueryParsingException[[bibliotheque] No query registered for [macht]]; }]",
  "status" : 400
}

Dans Elasticsearch 2, l'erreur est beaucoup plus lisible car la chaîne d'exceptions est représentée en JSON:

{
  "error" : {
    "root_cause" : [ {
      "type" : "query_parsing_exception",
      "reason" : "No query registered for [macht]",
      "index" : "bibliotheque",
      "line" : 1,
      "col" : 11
    } ],
    "type" : "search_phase_execution_exception",
    "reason" : "all shards failed",
    "phase" : "query",
    "grouped" : true,
    "failed_shards" : [ {
      "shard" : 0,
      "index" : "bibliotheque",
      "node" : "L6GCrNrYTgWDurzr-05bEA",
      "reason" : {
        "type" : "query_parsing_exception",
        "reason" : "No query registered for [macht]",
        "index" : "bibliotheque",
        "line" : 1,
        "col" : 11
      }
    } ]
  },
  "status" : 400
}

Upgrade

La migration Elasticsearch 1 vers Elasticesearch 2 nécessite un redémarrage complet du cluster et donc une période d'indisponibilité.

Un plugin Elasticsearch Migration pourra être installé sur Elasticsearch 1 ou 0.90 pour évaluer les incompatibilités. Le plugin vérifie un certains nombre de règles sur la configuration, les mappings...

Avec le passage à Lucene 5.2, le format de fichier au niveau disque va changer. Cela signifie que d'une part un retour arrière nécessitera la restauration d'un snapshot. Et d'autre part, les fichiers au format Lucene 3.x (produits par les versions d'Elasticsearch antérieures à la 0.90) devront subir une transformation pour pouvoir être relus.

Plus d'info:

Conclusion

Les principales nouveautés d'Elasticsearch 2 sont le passage à Lucene 5, le rapprochement des queries et des filters, les agrégations de type pipeline et la suppression des rivers. D'autres changements rendent Elasticsearch moins permissif et obligent à plus de rigueur, ce qui permettra d'éviter les erreurs de configuration, les mauvaises pratiques et les problèmes.

Vos scripts sous stéroïdes avec Groovy


Au cours du cycle de vie d'une application, il y a beaucoup de besoins nécessitant la réalisation de scripts :

  • réaliser des opérations d'administration en ligne de commande
  • exécuter des actions de maintenance
  • effectuer des mises à jour sur des modèles de bases de données
  • etc, ....

Il existe au moins tout autant de façon de réaliser ces scripts :

  • en bash
  • en powershell (pour Windows)
  • en python
  • en PHP
  • en groovy
Lire la suite...

Métriques de web services REST avec Spring Boot


Lors d'une journée de conseil, un client m'a demandé entre autres comment effectuer des tests de performances sur des web services REST. Ces tests de performances pourraient ensuite être intégrés au processus d'intégration continue. Une des préoccupations étaient notamment d'instrumenter facilement les web services et d'avoir des métriques intéressantes (temps de réponse moyen, percentiles, etc). La question a finalement tourné court, puisqu'en moins de 10 minutes de live coding, l'objectif était rempli, grâce à Spring Boot et Metrics Dropwizard. Voyons comment !

Lire la suite...

DockerCon 2015 - La grande messe de Docker


global

Les 22 et 23 juin derniers s'est déroulée à San Francisco la DockerCon. Nous étions invités en tant que gagnants du Docker Hackathon de décembre et nous n'avons pas été déçus : ambiance joviale, talks de qualité et grandes annonces ont rendu cet événement exceptionnel.

Lire la suite...

NCrafts 2015, jour 1: Event Storming + My adventure with ELM


En tant qu'acteur du mouvement Software Craftsmanship, Zenika se devait d'être présent à la conférence NCrafts 2015. Nous ne l'avons pas regretté, les interventions étaient vraiment d'excellente qualité! Nous proposons un compte-rendu détaillé à ceux qui n'ont pas eu la chance de s'y rendre.

nscrafts2015.png

Lire la suite...

Gagnez deux places VIP pour le festival Rock en Seine


Vous êtes amateur de musique et souhaitez finir l'été sur une bonne note ? Participez à notre Grand Tirage au Sort et tenter de gagner deux places VIP pour le festival Rock en Seine !

Lire la suite...

NCrafts 2015, jour 1: Interaction driven design


En tant qu'acteur du mouvement Software Craftsmanship, Zenika se devait d'être présent à la conférence NCrafts 2015. Nous ne l'avons pas regretté, les interventions étaient vraiment d'excellente qualité! Nous proposons un compte-rendu détaillé à ceux qui n'ont pas eu la chance de s'y rendre.

nscrafts2015.png

Lire la suite...

World Cup Challenge sur CodinGame


Participez au prochain challenge de notre partenaire CodinGame : Code of the Rings.

code of the rings

Lire la suite...

Retour sur la première édition de la conférence Best Of Web


Vendredi 5 juin a eu lieu, à Paris, la conférence Best Of Web. Cette conférence permet, en une journée, de revoir les meilleures présentations de l'année données dans les différents meetups de la capitale : AngularJS, Backbone.js, Web Components, EmberJs, Node.js, Phonegap/Cordova, D3.js et Paris.js.
Bien évidemment, Zenika était partenaire de cette initiative, et deux consultants, Matthieu LUX et Emmanuel DEMEY, vont vous partager cette journée intense, techniquement parlant.

Lire la suite...

Simon Brown au #zlocalhost le mardi 7 juillet 2015


Zenika a le plaisir de recevoir Simon Brown qui viendra nous présenter son talk "Software architecture as a code" le mardi 7 juillet à partir de 19h.

slide.001.png

Lire la suite...

- page 1 de 49