ElasticSearch

Voir la vidéo

Dans ce tutoriel je vous propose de découvrir ElasticSearch et de faire un petit tour du propriétaire.

Qu'est-ce qu'elasticsearch

ElasticSearch est un moteur de recherche libre basé sur Lucene qui permet notamment des recherches poussées au sein de texte. Voici quelques points spécifiques :

  • ElasticSearch peut être distribué et plusieurs instances (nodes) peuvent communiquer entre-elles dans un même cluster.
  • Les données sont sauvegardées sous forme de documents JSON.
  • Schema free, lorsque l'on index un nouveau document, Elastic Search détèctera la structure et les types tout seul et construira les indexs pour rendre les données recherchables (on n'est pas obligé de créer le schéma avant d'enregistrer des données).
  • Facile à utiliser, pour communiquer avec ElasticSearch on pourra utiliser une API RESTful.
  • ElasticSearch permet des recherches full text puissantes, très puissantes.

Attention cependant, ElasticSearch ne peut pas être utilisé comme votre moteur de base de données principal (ne vous imaginez pas remplacer votre mysql ou mongodb par Elastic Search)

  • Mettre à jour partiellement des données est très très pénible. Par défaut, il faudra lui envoyer tout le document pour le mettre à jour.
  • On ne peut pas joindre des données. On peut cependant rechercher sur plusieurs types de données en même temps.

Un peu de terminologie

Avant de vous montrer quelques requêtes il est important de faire un point sur la terminologie utilisée. Afin d'être compris par le plus grand nombre on va faire l'analogie avec la structure des bases de données relationnelles.

Un index est un peu comme une base de données sur un SGBD relationnel. Chaque index dispose d'un mapping, qui permet de définir la structure des types.

Le mapping est similaire au schema definition dans une base de donnée relationnelle. La mapping peut être définit manuellement, mais aussi généré automatiquement quand les documents sont indexés.

Les types sont comme des tables dans un système relationnel. Chaque type contient une liste des champs disponibles pour les documents.

Les document sont comme les lignes dans une base de données relationnel. Ces documents sont stockés au format JSON et ont un index, un type et un id en plus des données.

Un node est une instance d'ElasticSearch qui appartient à un cluster. Plusieurs noeuds peuvent être lancés sur un même serveur mais il est conseillé d'avoir un noeud par serveur

Un shard est une instance de Lucene. Les shards sont gérés de manière automatique par Elasticsearch, un shard peut être primaire ou être un duplicatat. Les replica shards permettent d'améliorer les performances et d'éviter les erreurs en remplaçant une shard primaire en cas d'erreur.

Démarrer ElasticSearch

Elasticsearch fonctionne avec Java, aussi avant de commencer, vous devrez télécharger java et l'installer sur votre sysème. Si vous êtes sur MacOS ou Windows il vous suffit de vous rendre sur le site de Java, si vous êtes sur linux vous pouvez installer openjdk, par exemple sur debian :

sudo apt-get update
sudo apt-get install openjdk-7-jre-headless

Une fois java installé, il faut télécharger la librairie et lancer le binaire qui correspond à votre systême. Si vous le souhaitez vous pouvez aussi l'installer comme un service sur linux.

./bin/elasticsearch
Attention, ElasticSearch n'utilise pas d'authentification, donc votre serveur est accessible par tout le monde, donc configurez bien vos iptables et/ou la configuration network.bind_host d'elastic search

Une fois lancé on pourra communiquer avec ElasticSearch sur le port 9200 par défaut. Par exemple http://localhost:9200 nous donnera des informations sur le serveur.

Communiquer avec ElasticSearch

Comme précisé précédemment ElasticSearch utilise une API RESTful pour créer, supprimer et ajouter des informations. L'URL de base se présente de la manière suivante

http://localhost:9200/<index>/<type>

Si on souhaite par exemple créer un type tutorielsdans un index grafikart on devra appeller cette URL en POST en lui envoyant les donnéer à enregistrer.

curl -XPOST "http://localhost:9200/grafikart/tutoriels" -d'
{
   "title": "Facebook API Data PHP",
   "category": "PHP",
   "tags": [
      "Facebook",
      "API"
   ],
   "duration": 60
}'

En réponse à cette requêtes on récupère un JSON nous donnant notamment l'id du nouvel enregistrement

{
   "_index": "grafikart",
   "_type": "tutoriels",
   "_id": "AU0EmKLJhqdI0jUWPoir",
   "_version": 1,
   "created": true
}

Si on souhaite récupérer l'enregistrement il suffitra de faire une requête GET

curl -XGET "http://localhost:9200/grafikart/tutoriels/AU0EmKLJhqdI0jUWPoir"

De la même façon en cas de suppression

curl -XDELETE "http://localhost:9200/grafikart/tutoriels/AU0EmKLJhqdI0jUWPoir"

Et enfin si vous souhaitez mettre à jour un enregistrepent il faudra renvoyer tout le document en utilisant la méthode PUT

curl -XPUT "http://localhost:9200/grafikart/tutoriels/AU0EmKLJhqdI0jUWPoir" -d'
{
    "title": "Facebok Data API PHP",
   "category": "PHP",
   "tags": [
      "Youtube",
      "API",
      "PHP"
   ],
   "duration": 600
}'

Voila pour l'API de base, en l'état ce n'est pas vraiment utile pour notre objectif, qui est de faire des recherches plus ou moins complexes. Dans le cas d'une recherche il faudra appeller la méthode _search.

Rechercher

Comme vu précédemment faire des recherche se fait avec la méthode _search qui prendra comme argument une clef query. Il existe des dixaines de manières d'effectuer des recherches, ces méthodes sont toutes décrites dans la documentation.

    curl -XGET "http://localhost:9200/grafikart/tutoriels/_search" -d'
    {
        "query": {
            "query_string": {
                "query": "Data API"
            }
        }
    }'

La méthode query_string permet d'effectuer une recherche rapide sur tous les termes (on peut sélectionner les champs à filtrer gràce à l'attribute fields).

Il est aussi possible de faire des recherches composées gràce notamment à la recherche booléenne.

curl -XGET "http://localhost:9200/grafikart/tutoriels/_search" -d'
{
    "query": {
        "bool": {
            "should": [{
                "query_string": {
                   "query": "Data api",
                   "fields": ["title"]
                }
            },{
                "fuzzy_like_this": {
                   "fields": ["title"],
                   "like_text": "Data api",
                   "max_query_terms": 5,
                   "boost": 0.5
                }
            }]
        }
    }
}'

A l'aide des mots clefs must, should et must_not on peut affiner la recherche pour l'adapter à nos besoins. En l'absence de must un résultat sera considéré comme viable si au moins une des demandes du should.

Enfin il est aussi possible d'utiliser les filtres. Ces derniers permettent de filtrer les résultats sans influencer le score et sont donc plus rapides. Si par exemple on recherche dans tous les tutoriels de moins d'une minute :

curl -XGET "http://localhost:9200/grafikart/tutoriels/_search" -d'
{
    "query" : {
        "filtered": {
            "query": {
                "query_string": {
                    "query": "Data API"
                }
            },
            "filter": {
                "range": {
                    "duration": {
                        "lte": 60
                    }
                }
            }
        }
    }
}'

On n'en a pas parlé jusqu'à maintenant mais qui dit recherche dit pertinence. Lorsque vous faites une recherche les résultats se verront assigné une valeur de _score. Cette valeur est automatiquement calculée en fonction du nombre de critères correspondant à la recherche demandée. Il est d'ailleurs possible de booster ou de réduire l'influence de certaines recherche en utilisant la clef boost. Il est d'ailleurs possible de rescorer les résultats déjà obtenus pour affiner encore plus la recherche, cette méthode permet aussi d'alléger les performancer car le score ne sera pas calculé sur tous les documents mais seulement les résultats de la première requête.

curl -XGET "http://localhost:9200/grafikart/tutoriels/_search" -d'
{
    "query": {
        "bool": {
            "should": [{
                "query_string": {
                   "query": "Data api",
                   "fields": ["title"]
                }
            },{
                "fuzzy_like_this": {
                   "fields": ["title"],
                   "like_text": "Data api",
                   "max_query_terms": 5,
                   "boost": 0.5
                }
            }]
        }
    },
    "rescore": {
        "window_size": 50,
        "query": {
            "rescore_query": {
                "match_phrase": {
                    "title": "Data api"
                }
            }   
        }
    }
}'

Comment l'intégrer dans mon application

Vous l'aurez compris Elastic Search est un outil qui va vous permettre d'avoir un véritable contrôle sur la manière d'effectuer une recherche. En général, on ne l'utilisera pas comme SGBD par défaut mais on réalisera une synchronisation entre les données de notre base de données classique et Elastic Search. Ensuite, lorsque l'on souhaitera effectuer une recherche on demandera à Elastic Search les résultats, et à partir des IDs on récupèrera les données sur notre base de donnée pricnipale.

Il existe d'ailleurs des librairies pour différents de languages pour communiquer plus simplement avec votre serveur ElasticSearch. Il est d'ailleurs possible avec les frameworks modernes d'effectuer la synchronisation de manière quasi automatique.

Si vous connaissez d'autres librairies n'hésitez pas à les partager je les ajouterais à cette liste.

Publié
Technologies utilisées
Auteur :
Grafikart
Partager