Elasticsearch for Data Engineers

Ce module présente Elasticsearch, le moteur de recherche et d’analytics distribué.


Prérequis

Niveau Compétence
✅ Requis Avoir suivi le module 08_intro_big_data_distributed
✅ Requis Comprendre les 5V du Big Data
✅ Requis Comprendre CAP
✅ Requis Connaître le format JSON

Objectifs du module

À la fin de ce notebook, tu seras capable de :

  • Comprendre l’architecture Elasticsearch (index, shards, replicas)
  • Utiliser Elasticvue pour interagir avec le cluster
  • Créer des index avec mapping approprié
  • Créer des Index Templates pour automatiser les mappings
  • Indexer, rechercher, modifier et supprimer des documents
  • Écrire des requêtes de recherche (match, bool, fuzzy, range)
  • Réaliser des agrégations analytiques

Version Elasticsearch

Ce cours utilise Elasticsearch 8.x (version recommandée : 8.12+).

Version Notes
8.x ✅ Recommandée — Sécurité par défaut, nouvelles fonctionnalités
7.x ⚠️ Encore supportée mais migration conseillée
6.x et avant ❌ Obsolète

💡 Les exemples de ce cours fonctionnent avec ES 7.x et 8.x. Pour ES 8.x, la sécurité est activée par défaut — nous la désactivons pour les tests locaux.


🎯 Elasticsearch dans l’écosystème Big Data

Tu as vu dans le module 08 les différents types de bases NoSQL. Elasticsearch est un moteur de recherche (Search Engine), parfois classé à part des bases NoSQL traditionnelles.

Position dans les types NoSQL

┌─────────────────────────────────────────────────────────────────┐
│                      BASES NoSQL                                │
├───────────┬───────────┬───────────┬───────────┬────────────────┤
│ Document  │ Clé-Valeur│  Colonnes │  Graphe   │ Search Engine  │
│           │           │           │           │                │
│  MongoDB  │   Redis   │ Cassandra │   Neo4j   │ ELASTICSEARCH  │
│           │           │           │           │     ◄───       │
└───────────┴───────────┴───────────┴───────────┴────────────────┘

Rappel : Les 5V

V Comment Elasticsearch répond
Volume Sharding horizontal (données réparties sur plusieurs nœuds)
Velocity Indexation temps réel, near real-time search
Variety Documents JSON flexibles, analyse full-text
Veracity Scoring de pertinence, recherche approximative
Value Recherche instantanée, dashboards Kibana

Rappel : CAP & BASE

Concept Elasticsearch
CAP AP (Availability + Partition tolerance) par défaut
BASE Eventually consistent (cohérence éventuelle)

Pourquoi Elasticsearch en Data Engineering ?

Cas d’usage Description
Logs & Monitoring Stack ELK (Elasticsearch, Logstash, Kibana)
Recherche full-text Moteur de recherche pour sites web, e-commerce
Analytics temps réel Dashboards et métriques en temps réel
Alerting Détection d’anomalies, alertes sur seuils

💡 ELK Stack = Elasticsearch + Logstash + Kibana — très utilisé en entreprise.


1. Concepts fondamentaux

Vocabulaire

SQL Elasticsearch Description
Database Cluster Ensemble de nœuds
Table Index Collection de documents
Row Document Une entrée (JSON)
Column Field Un champ du document
Schema Mapping Structure des champs

Shards & Replicas

Index "clients"
├── Primary Shard 0  ──────►  Replica Shard 0
├── Primary Shard 1  ──────►  Replica Shard 1
└── Primary Shard 2  ──────►  Replica Shard 2
Concept Rôle
Shard Partition des données (scalabilité)
Replica Copie d’un shard (haute disponibilité)

État du cluster

État Signification
🟢 Green Tous les shards OK
🟡 Yellow Primaires OK, replicas non alloués (1 seul nœud)
🔴 Red Données inaccessibles

2. Installation

Étape 1 : Télécharger Elasticsearch

👉 https://www.elastic.co/downloads/elasticsearch

  1. Télécharger le ZIP pour ton OS
  2. Dézipper dans un dossier (ex: C:\elasticsearch)
  3. Modifier config/elasticsearch.yml :
# Désactiver la sécurité pour les tests
xpack.security.enabled: false
  1. Lancer Elasticsearch :
# Windows
.\bin\elasticsearch.bat

# macOS / Linux
./bin/elasticsearch
  1. Vérifier : ouvrir http://localhost:9200 dans le navigateur

Étape 2 : Installer Elasticvue

Elasticvue est une interface graphique pour Elasticsearch — beaucoup plus simple que les commandes curl !

Options d’installation :

Option Lien
App Web (recommandé) https://app.elasticvue.com
Extension Chrome Chrome Web Store
Extension Firefox Firefox Add-ons
App Desktop elasticvue.com

3. Guide Elasticvue — Prise en main

3.1 Connexion au cluster

  1. Ouvrir Elasticvue
  2. Cliquer sur “Add Cluster”
  3. Remplir :
    • Name : Local (ou ce que tu veux)
    • URI : http://localhost:9200
  4. Cliquer “Connect”

✅ Tu devrais voir le statut du cluster (🟢 Green ou 🟡 Yellow)


3.2 Interface principale

┌─────────────────────────────────────────────────────────────┐
│  Elasticvue                                    [Cluster: Local] │
├─────────────┬───────────────────────────────────────────────┤
│             │                                               │
│     Home    │   Cluster Health: 🟢 Green                    │
│             │   Nodes: 1                                    │
│     Indices │   Indices: 3                                  │
│             │   Documents: 1,234                            │
│     Search  │                                               │
│             │                                               │
│     REST    │   ◄── C'est ici qu'on écrit les requêtes !    │
│             │                                               │
│     Settings│                                               │
│             │                                               │
└─────────────┴───────────────────────────────────────────────┘

Onglets importants :

Onglet Usage
Indices Voir/créer/supprimer des index
Search Rechercher visuellement dans un index
REST Écrire des requêtes (comme Kibana Dev Tools)

3.3 Utiliser la console REST

L’onglet REST permet d’exécuter des requêtes Elasticsearch avec une syntaxe simple.

Format des requêtes

MÉTHODE /chemin
{
  "corps": "de la requête en JSON"
}

Exemple pas à pas

┌──────────────────────────────────────────────────────────────┐
│  REST Query                                        [▶ Run]  │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  GET /clients/_search                                        │
│  {                                                           │
│    "query": {                                                │
│      "match": { "pays": "France" }                          │
│    }                                                         │
│  }                                                           │
│                                                              │
├──────────────────────────────────────────────────────────────┤
│  Response (200 OK)                                           │
│  {                                                           │
│    "hits": {                                                 │
│      "total": { "value": 2 },                                │
│      "hits": [...]                                           │
│    }                                                         │
│  }                                                           │
└──────────────────────────────────────────────────────────────┘

Raccourcis utiles

Raccourci Action
Ctrl + Enter Exécuter la requête
Ctrl + / Commenter une ligne
Ctrl + Space Autocomplétion

4. Créer un index et insérer des données

4.1 Créer l’index clients

Dans l’onglet REST, copier-coller :

PUT /clients
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "nom": { "type": "text" },
      "email": { "type": "keyword" },
      "pays": { "type": "keyword" },
      "age": { "type": "integer" },
      "salaire": { "type": "float" }
    }
  }
}

✅ Réponse attendue : { "acknowledged": true }


4.2 Comprendre le mapping

Type Usage Recherche full-text Agrégation
text Texte analysé ✅ Oui ❌ Non
keyword Valeur exacte ❌ Non ✅ Oui
integer, float Nombres Range ✅ ✅ Oui
date Dates Range ✅ ✅ Oui
boolean true/false ✅ Oui

💡 Règle : Utilise keyword pour les champs sur lesquels tu veux faire des agrégations (GROUP BY).


Index Templates — Automatiser les mappings

Pourquoi utiliser des templates ?

Quand tu gères des logs ou des données temporelles, tu crées souvent des index par jour ou par mois :

logs-2024-01-01
logs-2024-01-02
logs-2024-01-03
...

Problème : Sans template, chaque index utilise le mapping dynamique (Elasticsearch devine les types). C’est risqué !

Solution : Créer un Index Template qui s’applique automatiquement à tous les index correspondant à un pattern.


Créer un Index Template

PUT /_index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "priority": 1,
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date" },
        "level": { "type": "keyword" },
        "message": { "type": "text" },
        "service": { "type": "keyword" },
        "host": { "type": "keyword" },
        "response_time_ms": { "type": "integer" }
      }
    }
  }
}

Maintenant, tout index créé avec le pattern logs-* aura automatiquement ce mapping !


Tester le template

# Créer un index qui match le pattern
POST /logs-2024-01-15/_doc
{
  "timestamp": "2024-01-15T10:30:00Z",
  "level": "ERROR",
  "message": "Connection timeout to database",
  "service": "api-gateway",
  "host": "server-01",
  "response_time_ms": 5000
}
# Vérifier que le mapping a été appliqué
GET /logs-2024-01-15/_mapping

Lister les templates existants

GET /_index_template

Supprimer un template

DELETE /_index_template/logs_template

💡 Bonnes pratiques Index Templates

Pratique Explication
Toujours définir un mapping Ne pas laisser ES deviner les types
Utiliser keyword pour les agrégations level, service, hostkeyword
Utiliser text pour la recherche messagetext
Définir date explicitement Évite les erreurs de parsing
Nommer clairement logs_template, metrics_template
Utiliser priority Quand plusieurs templates matchent

4.3 Insérer un document

POST /clients/_doc
{
  "nom": "Alice Dupont",
  "email": "alice@email.com",
  "pays": "France",
  "age": 30,
  "salaire": 55000
}

4.4 Insérer plusieurs documents (Bulk)

POST /_bulk
{ "index": { "_index": "clients" } }
{ "nom": "Bob Martin", "email": "bob@email.com", "pays": "France", "age": 25, "salaire": 48000 }
{ "index": { "_index": "clients" } }
{ "nom": "Charlie Konan", "email": "charlie@email.com", "pays": "Côte d'Ivoire", "age": 35, "salaire": 62000 }
{ "index": { "_index": "clients" } }
{ "nom": "Diana Schmidt", "email": "diana@email.com", "pays": "Allemagne", "age": 28, "salaire": 51000 }
{ "index": { "_index": "clients" } }
{ "nom": "Eve Kouassi", "email": "eve@email.com", "pays": "Côte d'Ivoire", "age": 32, "salaire": 58000 }

⚠️ Attention : En bulk, chaque ligne doit être sur une seule ligne (pas de formatage JSON multi-lignes).


5. Requêtes de recherche

5.1 Afficher tous les documents

GET /clients/_search

SQL équivalent : SELECT * FROM clients


5.2 Filtrer avec match (full-text)

GET /clients/_search
{
  "query": {
    "match": { "nom": "Alice" }
  }
}

SQL équivalent : SELECT * FROM clients WHERE nom LIKE '%Alice%'


5.3 Filtrer avec term (exact match)

GET /clients/_search
{
  "query": {
    "term": { "pays": "France" }
  }
}

SQL équivalent : SELECT * FROM clients WHERE pays = 'France'

💡 Utilise term pour les champs keyword, match pour les champs text.


5.4 Filtrer par plage de valeurs (range)

GET /clients/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 25,
        "lte": 35
      }
    }
  }
}

SQL équivalent : SELECT * FROM clients WHERE age BETWEEN 25 AND 35

Opérateur Signification
gt > (greater than)
gte >= (greater than or equal)
lt < (less than)
lte <= (less than or equal)

5.5 Conditions multiples (bool)

La requête bool combine plusieurs conditions :

Clause Comportement SQL équivalent
must Toutes les conditions requises AND
should Au moins une condition OR
must_not Exclure NOT / !=
filter Comme must mais sans score WHERE (optimisé)

Exemple : Clients français de plus de 25 ans

GET /clients/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "pays": "France" } },
        { "range": { "age": { "gt": 25 } } }
      ]
    }
  }
}

SQL équivalent : SELECT * FROM clients WHERE pays = 'France' AND age > 25


Exemple : Clients français OU ivoiriens, mais PAS Bob

GET /clients/_search
{
  "query": {
    "bool": {
      "should": [
        { "term": { "pays": "France" } },
        { "term": { "pays": "Côte d'Ivoire" } }
      ],
      "minimum_should_match": 1,
      "must_not": [
        { "match": { "nom": "Bob" } }
      ]
    }
  }
}

SQL équivalent : SELECT * FROM clients WHERE (pays = 'France' OR pays = 'Côte d''Ivoire') AND nom != 'Bob'


5.6 Recherche floue (fuzzy)

Trouve des résultats même avec des fautes de frappe :

GET /clients/_search
{
  "query": {
    "fuzzy": {
      "nom": {
        "value": "Alise",
        "fuzziness": "AUTO"
      }
    }
  }
}

✅ Trouve “Alice” même si on tape “Alise” !

💡 Pas d’équivalent simple en SQL — c’est la force d’Elasticsearch.


📌 5.7 Trier et limiter les résultats

GET /clients/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "salaire": "desc" }
  ],
  "size": 3
}

SQL équivalent : SELECT * FROM clients ORDER BY salaire DESC LIMIT 3


6. Agrégations (GROUP BY)

6.1 Compter par catégorie (terms)

GET /clients/_search
{
  "size": 0,
  "aggs": {
    "par_pays": {
      "terms": { "field": "pays" }
    }
  }
}

SQL équivalent : SELECT pays, COUNT(*) FROM clients GROUP BY pays

💡 size: 0 = ne pas retourner les documents, seulement l’agrégation.


6.2 Métriques (sum, avg, min, max)

GET /clients/_search
{
  "size": 0,
  "aggs": {
    "salaire_moyen": { "avg": { "field": "salaire" } },
    "salaire_max": { "max": { "field": "salaire" } },
    "salaire_min": { "min": { "field": "salaire" } },
    "salaire_total": { "sum": { "field": "salaire" } }
  }
}

SQL équivalent : SELECT AVG(salaire), MAX(salaire), MIN(salaire), SUM(salaire) FROM clients


6.3 Stats complètes en une requête

GET /clients/_search
{
  "size": 0,
  "aggs": {
    "stats_salaire": {
      "stats": { "field": "salaire" }
    }
  }
}

Résultat : count, min, max, avg, sum en une seule requête !


6.4 Agrégations imbriquées (GROUP BY + métriques)

GET /clients/_search
{
  "size": 0,
  "aggs": {
    "par_pays": {
      "terms": { "field": "pays" },
      "aggs": {
        "salaire_moyen": { "avg": { "field": "salaire" } },
        "age_moyen": { "avg": { "field": "age" } }
      }
    }
  }
}

SQL équivalent :

SELECT pays, AVG(salaire) AS salaire_moyen, AVG(age) AS age_moyen
FROM clients
GROUP BY pays;

6.5 Filtrer avant d’agréger

GET /clients/_search
{
  "size": 0,
  "query": {
    "range": { "salaire": { "gte": 50000 } }
  },
  "aggs": {
    "par_pays": {
      "terms": { "field": "pays" }
    }
  }
}

SQL équivalent :

SELECT pays, COUNT(*)
FROM clients
WHERE salaire >= 50000
GROUP BY pays;

7. Modifier et supprimer

7.1 Mettre à jour un document (par ID)

POST /clients/_update/1
{
  "doc": {
    "salaire": 60000
  }
}

7.2 Mettre à jour par requête

POST /clients/_update_by_query
{
  "query": {
    "term": { "pays": "France" }
  },
  "script": {
    "source": "ctx._source.salaire += 1000"
  }
}

SQL équivalent : UPDATE clients SET salaire = salaire + 1000 WHERE pays = 'France'


7.3 Supprimer un document (par ID)

DELETE /clients/_doc/1

7.4 Supprimer par requête

POST /clients/_delete_by_query
{
  "query": {
    "range": { "age": { "lt": 18 } }
  }
}

SQL équivalent : DELETE FROM clients WHERE age < 18


7.5 Supprimer un index entier

DELETE /clients

⚠️ Attention : Irréversible !


Cheatsheet Elasticsearch

Gestion des index

Action Requête
Créer un index PUT /mon_index
Supprimer DELETE /mon_index
Lister GET /_cat/indices?v
Voir mapping GET /mon_index/_mapping
Santé cluster GET /_cluster/health

CRUD Documents

Action Requête
Insérer POST /index/_doc
Lire (ID) GET /index/_doc/1
Mettre à jour POST /index/_update/1
Supprimer DELETE /index/_doc/1
Bulk POST /_bulk

Types de requêtes

Type Usage
match Full-text (champs text)
term Exact (champs keyword)
range Plage (nombres, dates)
bool Combiner (must, should, must_not)
fuzzy Tolérant aux fautes

Agrégations

Type SQL équivalent
terms GROUP BY
sum, avg, min, max Fonctions d’agrégation
stats Toutes les stats
cardinality COUNT(DISTINCT)

Exercices pratiques

Utilise l’onglet REST d’Elasticvue pour résoudre ces exercices.


Exercice 1 — Facile

Afficher tous les clients.

💡 Solution
GET /clients/_search

Exercice 2 — Facile

Trouver les clients de Côte d’Ivoire.

💡 Solution
GET /clients/_search
{
  "query": {
    "term": { "pays": "Côte d'Ivoire" }
  }
}

Exercice 3 — Intermédiaire

Trouver les clients avec un salaire entre 50000 et 60000, triés par âge décroissant.

💡 Solution
GET /clients/_search
{
  "query": {
    "range": {
      "salaire": { "gte": 50000, "lte": 60000 }
    }
  },
  "sort": [{ "age": "desc" }]
}

Exercice 4 — Intermédiaire

Calculer le nombre de clients par pays.

💡 Solution
GET /clients/_search
{
  "size": 0,
  "aggs": {
    "par_pays": {
      "terms": { "field": "pays" }
    }
  }
}

Exercice 5 — Avancé

Calculer le salaire moyen par pays, seulement pour les clients de plus de 25 ans.

💡 Solution
GET /clients/_search
{
  "size": 0,
  "query": {
    "range": { "age": { "gt": 25 } }
  },
  "aggs": {
    "par_pays": {
      "terms": { "field": "pays" },
      "aggs": {
        "salaire_moyen": { "avg": { "field": "salaire" } }
      }
    }
  }
}

Quiz


❓ Q1. Quelle requête crée un index ?

  1. POST /clients
  2. PUT /clients
  3. GET /clients
  4. CREATE /clients
💡 Réponse bPUT /index crée un nouvel index.

❓ Q2. Quelle est la différence entre text et keyword ?

  1. Aucune différence
  2. text est analysé (tokenisé), keyword est stocké tel quel
  3. keyword est plus rapide
  4. text est pour les nombres
💡 Réponse btext est découpé en tokens pour la recherche full-text, keyword reste intact pour les matchs exacts et agrégations.

❓ Q3. Quelle requête utiliser pour un GROUP BY ?

  1. match
  2. bool
  3. terms (dans aggs)
  4. range
💡 Réponse c — L’agrégation terms groupe les documents par valeur de champ.

❓ Q4. Que fait size: 0 dans une requête d’agrégation ?

  1. Supprime les données
  2. Retourne uniquement l’agrégation, pas les documents
  3. Limite à 0 résultat d’agrégation
  4. Erreur
💡 Réponse bsize: 0 évite de retourner les documents, seulement les résultats d’agrégation.

❓ Q5. Quelle requête permet de chercher “Alice” même si on tape “Alise” ?

  1. match
  2. term
  3. fuzzy
  4. range
💡 Réponse cfuzzy tolère les fautes de frappe.

📚 Ressources


➡️ Prochaine étape

Tu maîtrises maintenant les bases NoSQL (MongoDB et Elasticsearch) ! Passons au traitement distribué avec PySpark.

👉 Module suivant : 11_pyspark_for_data_engineering — PySpark pour le traitement Big Data


🎉 Félicitations ! Tu as terminé le module Elasticsearch pour Data Engineers.

Retour au sommet