wiki/HowtoElasticsearch.md
2016-11-06 18:25:40 +01:00

18 KiB
Raw Blame History

"snapshots" : [ { "snapshot" : "snapshot_201403190415", "indices" : [...], "state" : "SUCCESS", "start_time" : "2014-03-19T03:15:03.380Z", "start_time_in_millis" : 1395198903380, "end_time" : "2014-03-19T03:16:33.381Z", "end_time_in_millis" : 1395198993381, "duration_in_millis" : 90001, ... "snapshot" : "snapshot_201403201222", "indices" : [...], "state" : "SUCCESS", "start_time" : "2014-03-20T11:22:07.441Z", "start_time_in_millis" : 1395314527441, "end_time" : "2014-03-20T11:22:56.176Z", "end_time_in_millis" : 1395314576176, "duration_in_millis" : 48735, "failures" : [ ], "shards" : { "total" : 86, "failed" : 0, "successful" : 86


Pour supprimer un snapshot :

$ curl -s -XDELETE "localhost:9200/_snapshot/foo/snapshot_test"


### Sauvegarde via snapshots

On peut ainsi créer régulièrement des snapshots pour les sauvegardes.

Pour créer un snapshot toutes les heures, et en conserver 24 en permanence (notion de snapshots "roulants") :

~~~{.bash}
$ date=$(date +%H)
$ curl -s -X DELETE "127.0.0.1:9200/_snapshot/foo/h${date}" | grep -v acknowledged..true
$ curl -s -X PUT "127.0.0.1:9200/_snapshot/foo/h${date}?wait_for_completion=true" -o /tmp/es_snapshot_h${date}.log

Plus classiquement pour avoir un snapshot par jour :

$ date=$(date +%Y-%m-%d)
$ curl -s -XDELETE "localhost:9200/_snapshot/foo/snapshot_${date}" | grep -v acknowledged..true
$ curl -s -XPUT "localhost:9200/_snapshot/foo/snapshot_${date}?wait_for_completion=true" -o /tmp/es_snapshot_${date}.log

On peut ensuite purger les snapshots vieux de plus de 10 jours ainsi :

$ cd /home/backup-elasticsearch/foo
$ for i in $(ls -1d snapshot-* | head -n -10 | sed s'/snapshot-snapshot_//g'); do curl -s -XDELETE "localhost:9200/_snapshot/foo/snaps
hot_${i}"; done

cluster

https://www.elastic.co/guide/en/elasticsearch/reference/2.4/modules-cluster.html

Si l'on compare à d'autres services (MySQL, PostgreSQL, MongoDB..) la gestion d'un cluster Elasticsearch est vraiment simple. Il faut lancer plusieurs instances Elasticsearch sur un réseau avec le même cluster.name et un node.name différent, et il suffitd'indiquer une (ou plusieurs) adresse(s) IP qui va permettre à l'instance de communiquer avec un (ou plusieurs) autre(s) nœud(s) :

cluster.name: foo
node.name: bar0
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["192.0.2.42"]

En démarrant un 2ème nœud bar1 on verra ainsi dans les logs de l'instance master bar0 que le cluster passe de YELLOW à GREEN :

[INFO ][o.e.c.s.ClusterService   ] [bar0] added {{bar1}{_jwXmQsAQEyseSOc4pG2IA}{PTpsbMBAQEKTs_OFgW_RYw}{192.0.2.42}{192.0.2.42:9301},}, reason: zen-disco-node-join[{bar1}{_jwXmQsAQEyseSOc4pG2IA}{PTpsbMBAQEKTs_OFgW_RYw}{192.0.2.42}{192.0.2.42:9301}]
[WARN ][o.e.d.z.ElectMasterService] [bar0] value for setting "discovery.zen.minimum_master_nodes" is too low. This can result in data loss! Please set it to at least a quorum of master-eligible nodes (current value: [-1], total number of master-eligible nodes used for publishing in this round: [2])
[INFO ][o.e.c.r.a.AllocationService] [bar0] Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-data-2][0]] ...]).

On peut consulter le statut du cluster via la requête :

$ curl 'http://localhost:9200/_nodes?pretty=true'

{
  "_nodes" : {
    "total" : 3,
    "successful" : 3,
    "failed" : 0
  },
  "cluster_name" : "foo",
  "nodes" : {
    "4Tt8FlV4TG2Hf_1T4EayQg" : {
      "name" : "bar0",
[...]

On voit ainsi qu'il y a 3 nœuds dans le cluster.

Si l'on coupe le master, un autre est élu :

[INFO ][o.e.d.z.ZenDiscovery     ] [bar2] master_left [{bar0}{4Tt8FlV4TG2Hf_1T4EayQg}{5nbXw3F5RWCWjUSiRzv9DA}{192.0.2.42}{192.0.2.42:9300}], reason [shut_down]
[WARN ][o.e.d.z.ZenDiscovery     ] [bar2] master left (reason = shut_down), current nodes: {{bar2}{5wUhAI79SsyY-DKv4va26Q}{_VQTiZXxTCi2KIsijyQBpg}{192.0.2.42}{192.0.2.42:9302},{bar1}{_jwXmQsAQEyseSOc4pG2IA}{_pQMtkFLSTe3p-eDHMkalw}{192.0.2.42}{192.0.2.42:9301},}
[INFO ][o.e.c.s.ClusterService   ] [bar2] removed {{bar0}{4Tt8FlV4TG2Hf_1T4EayQg}{5nbXw3F5RWCWjUSiRzv9DA}{192.168.0.133}{192.168.0.133:9300},}, reason: master_failed ({bar0}{4Tt8FlV4TG2Hf_1T4EayQg}{5nbXw3F5RWCWjUSiRzv9DA}{192.0.2.42}{192.0.2.42:9300})
[INFO ][o.e.c.r.a.AllocationService] [bar2] Cluster health status changed from [GREEN] to [YELLOW] (reason: [removed dead nodes on election]).
[INFO ][o.e.c.s.ClusterService   ] [bar2] new_master {bar2}{5wUhAI79SsyY-DKv4va26Q}{_VQTiZXxTCi2KIsijyQBpg}{192.168.0.133}{192.168.0.133:9302}, reason: zen-disco-elected-as-master ([0] nodes joined)
[INFO ][o.e.c.r.DelayedAllocationService] [bar2] scheduling reroute for delayed shards in [59.8s] (2 delayed shards)
[INFO ][o.e.c.r.a.AllocationService] [bar2] Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[.monitoring-es-2-2016.11.06][0]] ...]).

Principe de fonctionnement d'Elasticsearch

Basé sur le livre http://exploringelasticsearch.com/book

On utilisera l'outil cURL pour faire les requêtes. En plaçant à la fin d'une URI ?pretty=true on pourra obtenir un JSON formaté, plus lisible pour les humains.

Avec une base de données d'exemple

Nous allons utiliser une base de données d'exemple pour faire des tests.

Télécharger, https://github.com/andrewvc/ee-datasets/archive/master.zip, décompresser l'archive et exécuter le programme Java qui va injecter la BDD "movie_db" dans votre cluster ES.

$ java -jar elastic-loader.jar http://localhost:9200 datasets/movie_db.eloader

La BDD movie_db contient quelques noms de films, avec leurs informations associés (genre, date, acteurs, …).

Pour consulter tout son contenu :

$ curl http://localhost:9200/movie_db/_search?pretty=true

En créant une base de données

Opérations CRUD

Créer un index (équivalent d'une base de données) nommé planet :

$ curl -X PUT localhost:9200/planet
{"acknowledged":true,"shards_acknowledged":true}

Créer un type de donnée nommé « hacker » :

$ curl -X PUT localhost:9200/planet/hacker/_mapping -d '
{
    "hacker": {
        "properties": {
            "handle": {
                "type": "string"
            },
            "age": {
                "type": "long"
            }
        }
    }
}
'

Créer un document de type hacker avec l'ID 1 :

$ curl -X PUT localhost:9200/planet/hacker/1 -d '{"handle": "jean-michel", "age": 18}'
{"_index":"planet","_type":"hacker","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true

Voir son contenu :

$ curl localhost:9200/planet/hacker/1?pretty=true
{
  "_index" : "planet",
  "_type" : "hacker",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "handle" : "jean-michel",
    "age" : 18
  }
}

Mise à jour du champ âge :

$ curl -X POST localhost:9200/planet/hacker/1/_update -d '{"doc": {"age": 19}}'
{"_index":"planet","_type":"hacker","_id":"1","_version":2,"result":"updated","_shards":{"total":2,"successful":1,"failed":0}}

Suppression du document :

$ curl -X DELETE localhost:9200/planet/hacker/1
{"found":true,"_index":"planet","_type":"hacker","_id":"1","_version":3,"result":"deleted","_shards":{"total":2,"successful":1,"failed":0}}

Recherche basique

Recréons un index de test :

$ curl -X DELETE localhost:9200/planet
{"acknowledged":true}
$ curl -X PUT localhost:9200/planet -d '
{
    "mappings": {
        "hacker": {
            "properties": {
                "handle": {
                    "type": "string"
                },
                "hobbies": {
                    "type": "string",
                    "analyzer": "snowball"
                }
            }
        }
    }
}
'

Ajoutons quelques documents :

$ curl -X PUT localhost:9200/planet/hacker/1 -d '
{
    "handle": "mark",
    "hobbies": ["rollerblading", "hacking", "coding"]
}
'

$ curl -X PUT localhost:9200/planet/hacker/2 -d '
{
    "handle": "gondry",
    "hobbies": ["writing", "skateboarding"]
}
'

$ curl -X PUT localhost:9200/planet/hacker/3 -d '
{
    "handle": "jean-michel",
    "hobbies": ["coding", "rollerblades"]
}
'

Recherchons ceux qui ont pour hobby rollerblading :

$ curl -X POST localhost:9200/planet/hacker/_search?pretty=true -d '
{
    "query": {
        "match": {
            "hobbies": "rollerblading"
        }
    }
}
'

On obtiens 2 résultats, jean-michel et mark. Pourtant le hobby de jean-michel n'est pas rollerblading mais rollerblades, alors comment Elastic Search l'a trouvé ? C'est parce quil comprend que rollerblading et rollerblades sont très similaires ! Cela grâce à l'analyseur de type « snowball » que nous avons indiqué lors de la création du type hobbies. Cela indique à ES qu'il s'agit non pas d'une chaîne de caractère banale mais du texte Anglais (Gestion des autres langues ?).

FAQ

Erreur "failed to map segment from shared object: Operation not permitted"

Si vous obtenez une erreur du type :

[2016-06-15 14:53:05,714][WARN ][bootstrap                ] unable to load JNA native support library, native methods will be disabled.
java.lang.UnsatisfiedLinkError: /tmp/jna--1985354563/jna3461912487982682933.tmp: /tmp/jna--1985354563/jna3461912487982682933.tmp: failed
to map segment from shared object: Operation not permitted

C'est peut-être que vous avez votre partition /tmp en noexec, il faut alors changer le chemin comme indiqué sur #configuration-de-base

Lancer plusieurs instances sur un même système pour du test

Il faut définir 3 paramètres minimum pour lancer une instance Elasticsearch :

  • default.path.conf (répertoire de configuration)
  • default.path.data (répertoire pour les données)
  • default.path.logs (répertoire pour les logs)
# cp -pr /etc/elasticsearch /usr/local/etc/elasticsearch0
# mkdir -p /srv/es-data/bar0 /srv/es-log/bar0
# chown elasticsearch: /srv/es-data/bar0 /srv/es-log/bar0

Configuration via /usr/local/etc/elasticsearch0/elasticsearch.yml :

cluster.name: foo
node.name: bar0
node.master: true
node.data: true

On peut ensuite lancer cette nouvelle instance en ligne de commande :

# su -s /bin/sh elasticsearch
$ /usr/share/elasticsearch/bin/elasticsearch -Edefault.path.conf=/usr/local/etc/elasticsearch0 \
 -Edefault.path.data=/srv/es-data/bar0 -Edefault.path.logs=/srv/es-log/bar0

Note : si Elasticsearch nécessite une version de Java différent (Java 8 pour Elasticsearch 5.0), il suffit d'ajouter la variable JAVA_HOME en début de ligne de commande :

$ JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/jre/ /usr/share/elasticsearch/bin/elasticsearch [...]

Erreur "missing authentication token for REST request"

Si vous obtenez une erreur HTTP 401 Unauthorized avec le détail "missing authentication token for REST request...", c'est probablement que le plugin shield est activé.