Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

🔍 Elasticsearch – Installation, Querying & IntĂ©gration

Guide complet IDEO‑Lab pour maĂźtriser le moteur de recherche, de l'installation (Java, Linux) Ă  l'intĂ©gration (Python, PHP).

1.1

Vue d'ensemble

Moteur de recherche, NoSQL Document, Lucene.

Search NoSQL Lucene
1.2

Architecture

Cluster, NƓuds (Nodes), API REST.

Cluster Node API REST
1.3

Concepts : Index & Document

Index (BDD), Document (Ligne/JSON).

Index Document JSON
1.4

Concepts : Shards & Replicas

Scalabilité (Shards) & Haute Dispo (Replicas).

Shard Replica Scalability
2.1

Prérequis : Java (JDK)

Installation OpenJDK (inclus ou externe).

Java JDK JAVA_HOME
2.2

Installation Linux (apt/dnf)

DépÎt Elastic, elasticsearch.yml, systemd.

apt dnf systemd
2.3

Installation Docker (Dev)

docker run (single-node), Docker Compose.

Docker Compose Dev
3.1

Installation Kibana (UI)

L'interface web pour ES (Dev Tools).

Kibana ELK UI
3.2

API REST (curl)

Interagir avec curl, API _cat.

curl API _cat
3.3

Mapping (Schema)

text vs keyword, date, integer.

Mapping text keyword
4.1

Indexer un Document

PUT (ID fixe) vs POST (auto-ID).

PUT POST _doc
4.2

CRUD (Get, Update, Delete)

GET, DELETE, _update.

GET DELETE _update
4.3

Query DSL : match

match (full-text), term (exact).

_search match term
5.1

Query DSL : bool

must, should, filter (trĂšs important).

bool must filter
5.2

Agrégations (aggs)

terms (GROUP BY), date_histogram.

aggs terms date_histogram
5.3

Ingestion (ELK)

Logstash, Filebeat (ingestion de logs).

Logstash Filebeat Logs
6.1

Intégration Django (Python)

elasticsearch-dsl, Document, Search.

Python Django elasticsearch-dsl
6.2

Intégration PHP

elasticsearch-php (client officiel).

PHP Composer Client
6.3

Santé & Admin Cluster

_cluster/health, (green, yellow, red).

health yellow red
7.1

Backup (Snapshots)

_snapshot, _restore.

_snapshot _restore Backup
8.1

Cheat-sheet API REST

Commandes curl fréquentes.

cheat curl
1.1 Vue d'ensemble Elasticsearch
Un moteur de recherche distribué

Elasticsearch est un **moteur de recherche et d'analyse** distribué, open-source, construit sur **Apache Lucene**.

Il est souvent qualifié de base de données **NoSQL orientée document** (comme MongoDB), mais sa force principale est la **recherche full-text** (texte intégral) et l'analyse en temps réel.

Toutes les interactions se font via une API RESTful (JSON sur HTTP).

Cas d'usage (Stack ELK/Elastic)
  • Recherche de site web : La barre "Rechercher..." de votre site.
  • Logging & MĂ©triques : (Le 'E' de la stack ELK : Elasticsearch, Logstash, Kibana). Centralisation et analyse de logs serveur.
  • Analyse (BI) : AgrĂ©gation et visualisation de grands volumes de donnĂ©es.
  • APM : (Application Performance Monitoring).
ParallĂšle SQL vs Elasticsearch

Pour comprendre ES, voici une analogie (imparfaite) avec le monde SQL :

Monde SQLMonde ElasticsearchDescription
Database (BDD)IndexConteneur de données.
Table(Concept supprimé)Avant ES 7, c'était 'Type'.
Row (Ligne)DocumentUne entrée JSON.
Column (Colonne)Field (Champ)Une clé dans le JSON.
SchemaMappingDéfinit les types des champs.
SELECT * ... WHEREGET .../_search (Query DSL)La requĂȘte (JSON).
GROUP BYAggregationsAgrégats.
1.2 Architecture : Cluster & NƓuds (Nodes)
Les NƓuds (Nodes)

Un **NƓud** (Node) est une instance (un processus) d'Elasticsearch. C'est le "worker". Un nƓud peut avoir plusieurs rîles (master, data, ingest...).

Le Cluster

Un **Cluster** est un groupe d'un ou plusieurs nƓuds qui communiquent entre eux et partagent la charge de travail. Ils sont identifiĂ©s par le mĂȘme cluster.name (dans elasticsearch.yml).

L'API REST vous permet de parler Ă  n'importe quel nƓud, qui relaiera la requĂȘte au bon endroit.

SchĂ©ma d'un Cluster (3 NƓuds)
[Image d'un cluster Elasticsearch]
         (API REST, ex: Port 9200)
             |
             ▌
+-----------------------+
| NƓud 1 (Master Ă©ligible, Data) |
+-----------------------+
       ^ \
       |  \ (Communication interne)
       |   \
+------+...V---------------+
| NƓud 2 (Data)         |
+-----------------------+
       ^ \
       |  \
       |   \
+------+...V---------------+
| NƓud 3 (Data)         |
+-----------------------+
1.3 Concepts : Index & Document
Index (l'équivalent de la BDD)

Un Index est une collection de Documents qui ont une structure similaire (un "Mapping"). Ex: articles, logs-2025-11.

Document (l'équivalent de la Ligne)

Un Document est l'unité de base de l'information. C'est un simple objet JSON.

// Un Document dans l'index 'articles'
{
    "_index": "articles",
    "_id": "1", // L'ID unique
    "_source": { // Le JSON original
        "titre": "Elasticsearch et Python",
        "auteur": "Alice",
        "date_pub": "2025-11-01T10:00:00Z",
        "tags": ["python", "search"],
        "publie": true
    }
}
Index Inversé (Le secret de la vitesse)

Elasticsearch (via Lucene) utilise un Index Inversé pour la recherche full-text. Au lieu de mapper une page à des mots, il mappe des mots aux pages.

Documents (Entrée)
Doc 1: "the quick brown fox"
Doc 2: "a quick brown dog"
Index Inversé (Sortie, simplifié)
Terme   | Doc 1 | Doc 2
--------|-------|-------
a       |       | X
brown   | X     | X
dog     |       | X
fox     | X     |
quick   | X     | X
the     | X     |

Une recherche pour "quick dog" trouve instantanément les documents (Doc 2) via l'index, sans scanner le texte.

1.4 Concepts : Shards & Replicas (Scalabilité)
Shards (Scalabilité Horizontale)

Un index peut devenir trop gros pour un seul nƓud. ES vous permet de le diviser en morceaux appelĂ©s Shards (Partitions). C'est le mĂ©canisme de scalabilitĂ© horizontale.

Si vous crĂ©ez un index avec 3 Shards (P0, P1, P2), ES les rĂ©partit sur vos nƓuds. Quand vous recherchez, ES interroge les 3 Shards en parallĂšle et fusionne les rĂ©sultats.

Replicas (Haute Disponibilité)

Un Replica est une copie d'un Shard. Si un nƓud tombe, le replica (sur un autre nƓud) prend le relais. C'est le mĂ©canisme de haute disponibilitĂ© (HA).

SchĂ©ma (3 NƓuds, 1 Index, 3 Shards, 1 Replica)
[Image d'une architecture Shards/Replicas]
Index "articles" (3 Shards Primaires, 1 Replica)

+------------------+   +------------------+   +------------------+
| NƓud 1           |   | NƓud 2           |   | NƓud 3           |
|                  |   |                  |   |                  |
| +----+   +----+  |   | +----+   +----+  |   | +----+   +----+  |
| | P0 |   | R1 |  |   | | P1 |   | R2 |  |   | | P2 |   | R0 |  |
| +----+   +----+  |   | +----+   +----+  |   | +----+   +----+  |
|                  |   |                  |   |                  |
+------------------+   +------------------+   +------------------+

P0, P1, P2 = Shards Primaires (les "originaux")
R0, R1, R2 = Shards Replicas (les "copies")

Si le NƓud 2 tombe :

  • P1 est perdu.
  • ES promeut automatiquement R1 (sur NƓud 1) en nouveau Primaire P1.
  • Le cluster passe en statut "yellow" (donnĂ©es disponibles, mais un replica manque).
2.1 Prérequis : Installation Java (JDK)
Elasticsearch est Java

Elasticsearch est un programme Java. Il nécessite une Java Virtual Machine (JVM) pour s'exécuter.
NOTE : Depuis la version 8.x, Elasticsearch inclut sa propre version "bundlée" (intégrée) d'OpenJDK lors de l'installation (via apt/dnf/docker). Vous n'avez *généralement* plus besoin de l'installer séparément.

Cependant, si vous installez depuis un .tar.gz ou si vous devez forcer une version, voici comment installer le JDK.

Version Requise (minimum)
  • Elasticsearch 8.x : Java 17 (ou Java 21)
  • Elasticsearch 7.x : Java 11 (ou Java 8)
Ubuntu / Debian (OpenJDK 17)
sudo apt update
sudo apt install -y openjdk-17-jdk

# Vérifier
java -version
# openjdk version "17.0.x" ...

# (Optionnel) Définir JAVA_HOME
echo 'export JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64"' >> ~/.bashrc
source ~/.bashrc
RHEL / CentOS / Fedora (OpenJDK 17)
sudo dnf install -y java-17-openjdk-devel

# Vérifier
java -version
# openjdk version "17.0.x" ...

# (Optionnel) Utiliser 'alternatives'
sudo alternatives --config java
2.2 Installation Linux (apt/dnf)
1. Ubuntu / Debian (DépÎt Elastic)
# 1. Ajouter la clé GPG d'Elastic
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

# 2. Installer apt-transport-https
sudo apt-get install -y apt-transport-https

# 3. Ajouter le dépÎt (Ex: 8.x)
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

# 4. Installer
sudo apt-get update
sudo apt-get install -y elasticsearch
2. RHEL / CentOS / Fedora (DépÎt Elastic)
# 1. Ajouter la clé GPG
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

# 2. Créer le fichier .repo
sudo vi /etc/yum.repos.d/elasticsearch.repo

# Coller ceci dans le fichier :
[elasticsearch]
name=Elasticsearch repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

# 3. Installer
sudo dnf install -y elasticsearch
3. Configuration (elasticsearch.yml)

Le fichier de configuration principal est /etc/elasticsearch/elasticsearch.yml.

Par défaut (sécurité), ES n'écoute que sur localhost. Pour un cluster ou un accÚs distant (ex: dev) :

# /etc/elasticsearch/elasticsearch.yml

# Nom du cluster
cluster.name: ideo-lab-cluster

# Nom du nƓud
node.name: node-1

# Écouter sur toutes les interfaces (0.0.0.0)
network.host: 0.0.0.0
http.port: 9200

# Pour un cluster single-node (DEV)
discovery.type: single-node

# (Depuis 8.x, la sécurité est activée par défaut.
# Pour le dev, on peut la désactiver)
xpack.security.enabled: false
xpack.security.enrollment.enabled: false
xpack.security.http.ssl.enabled: false
4. Démarrage (systemd)
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

# Vérifier (peut prendre 30s)
curl http://localhost:9200
2.3 Installation Docker (Recommandé en Dev)
docker run (NƓud unique pour le dev)

La méthode la plus rapide pour démarrer un ES local (version 8.x).

docker run -d \
    --name es01 \
    -p 9200:9200 \
    -p 9300:9300 \
    -e "discovery.type=single-node" \
    -e "xpack.security.enabled=false" \
    -v es-data:/usr/share/elasticsearch/data \
    docker.elastic.co/elasticsearch/elasticsearch:8.11.1

# -p 9200: (API REST)
# -e "discovery.type=single-node": Mode dev
# -e "xpack.security.enabled=false": Désactive le mot de passe (DEV)
# -v es-data: Volume pour la persistance
docker-compose.yml (Stack ELK - ES + Kibana)

Permet de lancer Elasticsearch ET son interface graphique Kibana.

version: '3.8'
services:
  # 1. Le service Elasticsearch
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.1
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # Limite la RAM (dev)
    volumes:
      - es-data:/usr/share/elasticsearch/data
    ports:
      - "9200:9200"

  # 2. Le service Kibana (UI)
  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.1
    container_name: kibana
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200 # Lien vers ES
    depends_on:
      - elasticsearch

volumes:
  es-data:

Lancez docker compose up -d.
ES est sur http://localhost:9200.
Kibana est sur http://localhost:5601.

3.1 Interface UI : Kibana
L'interface de la Stack Elastic

Kibana est l'interface web officielle (le 'K' de ELK). C'est un outil de visualisation et de gestion.

Installation (Linux)
# (En supposant que le dépÎt Elastic 8.x est déjà ajouté)
sudo apt-get install kibana
# ou
sudo dnf install kibana
Configuration (kibana.yml)

Le fichier /etc/kibana/kibana.yml doit pointer vers ES.

# /etc/kibana/kibana.yml

server.port: 5601
server.host: "0.0.0.0" # Écouter sur toutes les interfaces

# Adresse d'Elasticsearch
elasticsearch.hosts: ["http://localhost:9200"]
Démarrage
sudo systemctl enable --now kibana
Dev Tools (L'outil indispensable)

L'outil le plus important de Kibana est les Dev Tools.

C'est une console (type Postman ou client curl) qui permet d'envoyer des requĂȘtes Ă  l'API REST d'ES, avec autocomplĂ©tion et formatage JSON.

Toutes les requĂȘtes de ce guide (GET _search, PUT /index) se font via cet outil.

Exemple (Console Dev Tools)
# Colonne de Gauche (RequĂȘte)
GET /_cluster/health

# Colonne de Droite (Réponse JSON)
{
  "cluster_name" : "ideo-lab-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  ...
}
3.2 API REST (curl) & API _cat
API REST

Tout dans Elasticsearch est une API REST. Les verbes HTTP ont un sens :

  • GET : Lire (_search, _doc, _cat).
  • POST : CrĂ©er (avec auto-ID) ou Actions (_search, _update).
  • PUT : CrĂ©er ou Mettre Ă  jour (avec ID fixe) (_doc/1, _mapping).
  • DELETE : Supprimer (_doc/1, /mon-index).
# Ping de base (GET)
curl -X GET "http://localhost:9200/"

{
  "name" : "node-1",
  "cluster_name" : "ideo-lab-cluster",
  ...
  "version" : { "number" : "8.11.1", ... }
}
API _cat (Monitoring simple)

L'API _cat (Compact and Aligned Text) est une API lisible par l'homme (pas JSON) pour le monitoring rapide.

# Santé du cluster (green, yellow, red)
curl "localhost:9200/_cat/health?v"
# v = verbose (ajoute les en-tĂȘtes)

# Lister les NƓuds
curl "localhost:9200/_cat/nodes?v"

# Lister les Index
curl "localhost:9200/_cat/indices?v"

# Lister les Shards (et leur état)
curl "localhost:9200/_cat/shards?v"

# Lister les Mappings
curl "localhost:9200/_cat/mappings?v"
3.3 Mapping (text vs keyword)
Le Mapping est le "Schema"

Le Mapping définit les champs de vos documents et leur type (date, integer...). Pour le texte, le choix est **critique**.

text (Analyzé)
  • Usage : Recherche Full-Text (corps d'article, description).
  • Analyse : ES applique un "Analyzer" :
    1. Met en minuscule (The Fox -> the fox).
    2. Retire les "stop words" (the, a...).
    3. Tokenize (quick fox -> [quick], [fox]).
  • Recherche : Une recherche "quick" trouvera "the quick brown fox".
  • Restrictions : Ne peut pas ĂȘtre utilisĂ© pour les AgrĂ©gations (aggs) ou le tri.
keyword (Non-analyzé)
  • Usage : Recherche exacte (Tags, Codes postaux, Statuts).
  • Analyse : Aucune. Le texte "Quick Fox" est stockĂ© tel quel.
  • Recherche : Une recherche "quick" ne trouvera pas "Quick Fox". Il faut chercher "Quick Fox" (exact).
  • Restrictions : Requis pour les AgrĂ©gations (aggs) et le tri.
Définition d'un Mapping (PUT sur un Index)

Il est fortement recommandé de définir son mapping avant d'indexer.

PUT /articles
{
  "mappings": {
    "properties": {
      
      "titre": {
        "type": "text" 
      },
      
      "date_pub": {
        "type": "date" 
      },
      
      "statut": {
        "type": "keyword" // Pour tri et aggs
      },
      
      "tags": {
        "type": "keyword" // Pour les tags (aggs)
      },
      
      "auteur_nom": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword", // Champ multiple (full-text ET exact)
            "ignore_above": 256
          }
        }
      }
      
    }
  }
}

-- Lire le mapping:
GET /articles/_mapping
4.1 Indexer un Document (POST vs PUT)
POST (Auto-ID)

Utilisez POST /index/_doc si vous n'avez pas d'ID unique (ex: logs). ES générera un ID unique.

POST /logs/_doc
{
  "timestamp": "2025-11-01T22:00:00Z",
  "level": "ERROR",
  "message": "Connexion BDD échouée"
}

-- Réponse (ES a généré _id)
{
  "_index" : "logs",
  "_id" : "aBc1dEf2gHi3...",
  "result" : "created",
  ...
}
PUT (ID Spécifique)

Utilisez PUT /index/_doc/id si vous avez déjà un ID (ex: ID de votre BDD SQL).

PUT /articles/_doc/1
{
  "titre": "Article sur Python",
  "auteur_id": 101,
  "tags": ["python", "tech"]
}

-- Réponse
{
  "_index" : "articles",
  "_id" : "1",
  "result" : "created", // (ou 'updated' si l'ID 1 existait)
  ...
}
4.2 CRUD (Get, Update, Delete)
GET (Lire un document)
GET /articles/_doc/1

-- Réponse
{
  "_index" : "articles",
  "_id" : "1",
  "found" : true,
  "_source" : {
    "titre": "Article sur Python", ...
  }
}
DELETE (Supprimer un document)
DELETE /articles/_doc/1

-- Réponse
{
  ...
  "result" : "deleted",
  "_id" : "1"
}
_update (Mise Ă  jour partielle)

Utilisez _update (avec POST) pour modifier un document sans écraser le reste.

POST /articles/_update/1
{
  "doc": {
    "titre": "Nouveau Titre (modifié)",
    "statut": "publie"
  }
}
-- (Laisse 'auteur_id' et 'tags' intacts)
_update (Script)
POST /articles/_update/1
{
  "script": {
    "source": "ctx._source.tags.add(params.new_tag)",
    "params": {
      "new_tag": "elasticsearch"
    }
  }
}
4.3 Query DSL : match (Recherche)
_search

Toute recherche utilise l'endpoint _search (GET ou POST) et un corps JSON (le "Query DSL").

match_all (Tout récupérer)
GET /articles/_search
{
  "query": {
    "match_all": {}
  },
  "size": 10,
  "from": 0
}
match (Full-Text)

Utilise l'Analyzer (cf 3.3). C'est la recherche "Google".

GET /articles/_search
{
  "query": {
    "match": {
      "titre": "python elasticsearch"
    }
  }
}
-- (Trouve "Article sur Python et Elasticsearch"
--  car 'et' est un stop-word et 'Python'/'Elasticsearch'
--  sont tokenizés)
term (Exact)

Recherche une valeur exacte (non-analyzĂ©e). Doit ĂȘtre utilisĂ© sur un champ keyword.

GET /articles/_search
{
  "query": {
    "term": {
      "tags.keyword": "python"
    }
  }
}
-- (Ne trouve que les tags 'python' exacts)
terms (Liste)
GET /articles/_search
{
  "query": {
    "terms": {
      "statut.keyword": ["publie", "archive"]
    }
  }
}
5.1 Query DSL : bool (La requĂȘte multi-critĂšres)
La requĂȘte bool

C'est le constructeur de requĂȘte le plus important. Il combine plusieurs requĂȘtes (AND, OR, NOT).

GET /articles/_search
{
  "query": {
    "bool": {
      
      "must": [
        { "match": { "titre": "python" } }
      ],
      
      "must_not": [
        { "term": { "statut.keyword": "archive" } }
      ],
      
      "should": [
        { "term": { "tags.keyword": "tech" } }
      ],
      
      "filter": [
        { "range": { "date_pub": { "gte": "2025-01-01" } } }
      ]
      
    }
  }
}
must vs filter (Concept Clé)

Les deux sont des conditions AND, mais leur but est différent.

must (RequĂȘte)
  • RĂ©pond Ă  : "À quel point ce document correspond-il ?"
  • Contexte : Recherche (Scoring).
  • Effet : Calcule un score de pertinence (_score). Plus le mot est rare/frĂ©quent, plus le score est Ă©levĂ©.
  • Usage : Pour la recherche "floue" (match).
filter (Filtre)
  • RĂ©pond Ă  : "Ce document correspond-il ? Oui/Non."
  • Contexte : Filtrage (Non-scoring).
  • Effet : Ne calcule pas de score. C'est beaucoup plus rapide et "cachable".
  • Usage : Pour les filtres exacts (term, range, statuts, tags).

Bonne Pratique : Mettez tout ce qui est exact (tags, statuts, dates, prix) dans la section filter, et gardez must uniquement pour la recherche full-text.

5.2 Agrégations (aggs)
Le "GROUP BY" d'Elasticsearch

Les agrégations (aggs) permettent de faire des statistiques sur vos données.

terms (Grouper par tag)

RequĂȘte : "Compte le nombre d'articles par tag".

GET /articles/_search
{
  "size": 0, // On ne veut pas les documents, juste les aggs
  "aggs": {
    "group_by_tags": {
      "terms": {
        "field": "tags.keyword" // DOIT ĂȘtre 'keyword'
      }
    }
  }
}

-- Réponse (simplifiée)
"aggregations": {
  "group_by_tags": {
    "buckets": [
      { "key": "python", "doc_count": 50 },
      { "key": "tech", "doc_count": 35 },
      ...
    ]
  }
}
Sous-Agrégations (Group by imbriqué)

RequĂȘte : "Grouper par tag, PUIS calculer la note moyenne par tag".

GET /articles/_search
{
  "size": 0,
  "aggs": {
    "group_by_tags": {
      "terms": { "field": "tags.keyword" },
      "aggs": {
        "avg_note": {
          "avg": { "field": "note" }
        }
      }
    }
  }
}
date_histogram (Séries temporelles)

RequĂȘte : "Compte le nombre d'articles par mois".

GET /articles/_search
{
  "size": 0,
  "aggs": {
    "articles_par_mois": {
      "date_histogram": {
        "field": "date_pub",
        "calendar_interval": "month"
      }
    }
  }
}
5.3 Ingestion (Logstash & Filebeat)
La Stack ELK (ou Elastic Stack)

Concerne l'ingestion de logs (ex: logs Nginx, syslogs).

  • Filebeat (Agent LĂ©ger) : Un agent (comme un DaemonSet K8s) qui "tail" (suit) les fichiers de logs et les envoie.
  • Logstash (ETL) : Un "pipeline" lourd (Java) qui reçoit les logs de Filebeat. Il peut Parser (ex: Grok), Transformer (ex: enrichir l'IP) et Charger dans Elasticsearch.
  • Elasticsearch (Base) : Stocke et indexe les logs.
  • Kibana (UI) : Visualise les logs (Dashboards).
Schéma de flux (Logs)
[Image d'une architecture ELK]

[Serveur Web 1] -> [Filebeat] ->-+
                                |
[Serveur Web 2] -> [Filebeat] ->-+
                                |
[Serveur DB 1]  -> [Filebeat] ->-+
                                |
                                ▌
                        +----------------+
                        | Logstash (ETL) |
                        | (Grok, Mutate) |
                        +----------------+
                                |
                                ▌
                   +-----------------------+
                   | Elasticsearch (Index) |
                   +-----------------------+
                                |
                                ▌
                        +----------------+
                        | Kibana (UI)    |
                        +----------------+
6.1 Intégration Django (Python)
1. Installation & Setup

La librairie elasticsearch-dsl est la référence pour l'intégration Django.

pip install elasticsearch
pip install elasticsearch-dsl
settings.py
# settings.py
INSTALLED_APPS = [
    ...
    "django_elasticsearch_dsl",
    ...
]

# Configurer la connexion
ELASTICSEARCH_DSL = {
    'default': {
        'hosts': 'localhost:9200'
    },
}

# (Optionnel) Auto-indexation
ELASTICSEARCH_DSL_SIGNAL_PROCESSOR = 'django_elasticsearch_dsl.signals.RealTimeSignalProcessor'
2. documents.py (Le "Mapping")

On définit un "Document" (mapping ES) lié à un "Model" Django.

# mon_app/documents.py
from django_elasticsearch_dsl import Document
from django_elasticsearch_dsl.registries import registry
from elasticsearch_dsl import analyzer, Text
from .models import Article

# Analyseur custom (ex: Ngrams pour autocomplétion)
html_strip = analyzer(
    'html_strip',
    tokenizer="standard",
    filter=["lowercase", "stop"],
    char_filter=["html_strip"]
)

@registry.register_document
class ArticleDocument(Document):
    # Champ custom
    auteur_nom = Text(analyzer=html_strip)

    class Index:
        # Nom de l'index dans ES
        name = 'articles'
    
    class Django:
        # ModĂšle Django Ă  lier
        model = Article
        
        # Champs du modĂšle Ă  inclure
        fields = [
            'titre',
            'date_pub',
            'statut',
        ]
    
    # Pour les champs 'related' (ex: Foreign Key)
    def prepare_auteur_nom(self, instance):
        return instance.auteur.get_full_name()
3. Indexation (manage.py)
# 1. Créer le mapping dans ES
python manage.py search_index --create

# 2. Indexer tous les articles existants
python manage.py search_index --populate

# (Si le 'Signal_Processor' est actif (cf 1),
# les 'save' et 'delete' sont auto-synchronisés)
4. Recherche (views.py)
from .documents import ArticleDocument
from elasticsearch_dsl import Q

def search_view(request):
    query_str = request.GET.get('q')
    
    # Construire la recherche
    q_object = Q(
        'bool',
        must=[
            Q('match', titre=query_str)
        ],
        filter=[
            Q('term', statut='publie')
        ]
    )
    
    s = ArticleDocument.search().query(q_object)
    
    # Ajouter une agrégation
    s.aggs.metric('par_auteur', 'terms', field='auteur_nom.keyword')
    
    # Exécuter
    response = s.execute()
    
    return render(request, 'search.html', {
        'hits': response.hits,
        'aggs': response.aggregations
    })
6.2 Intégration PHP (Client Officiel)
1. Installation (Composer)
composer require elasticsearch/elasticsearch
2. Connexion (ClientBuilder)
<?php
require 'vendor/autoload.php';

use Elasticsearch\ClientBuilder;

// Construire le client
$client = ClientBuilder::create()
    ->setHosts(['http://localhost:9200']) // Array d'hĂŽtes
    // ->setBasicAuthentication('user', 'pass') // Si sécurité active
    ->build();

// Ping
try {
    $info = $client->info();
    print_r($info);
} catch (Exception $e) {
    echo "Erreur de connexion: " . $e->getMessage();
}
?>
3. Indexer un document
$params = [
    'index' => 'articles',
    'id'    => 1,
    'body'  => [
        'titre' => 'Article sur PHP',
        'auteur' => 'Bob',
        'tags' => ['php', 'tech']
    ]
];

$response = $client->index($params);
print_r($response);
4. Lire (GET) un document
$params = [
    'index' => 'articles',
    'id'    => 1
];
$response = $client->get($params);

$source = $response['_source'];
echo $source['titre']; // "Article sur PHP"
5. Rechercher (_search)

Le corps de la requĂȘte (Query DSL) est un array PHP associatif.

$query = $_GET['q'] ?? '';

$params = [
    'index' => 'articles',
    'body'  => [
        'query' => [
            'bool' => [
                'must' => [
                    [ 'match' => [ 'titre' => $query ] ]
                ],
                'filter' => [
                    [ 'term' => [ 'tags.keyword' => 'tech' ] ]
                ]
            ]
        ],
        'aggs' => [
            'group_by_auteur' => [
                'terms' => [
                    'field' => 'auteur.keyword'
                ]
            ]
        ]
    ]
];

$response = $client->search($params);

$hits = $response['hits']['hits'];
$total = $response['hits']['total']['value'];

foreach ($hits as $hit) {
    echo $hit['_source']['titre'];
}

$aggs = $response['aggregations']['group_by_auteur']['buckets'];
print_r($aggs);
6.3 Santé & Administration Cluster
API _cluster/health

L'endpoint le plus important pour le monitoring.

GET /_cluster/health

{
  ...
  "status" : "yellow",
  "number_of_nodes" : 1,
  "unassigned_shards" : 3,
  ...
}
Les Statuts (Green, Yellow, Red)
StatutDescriptionImpact
GreenParfait. Tous les Shards Primaires ET Replicas sont alloués.OK.
YellowAttention. Tous les Shards Primaires sont allouĂ©s (le cluster est 100% fonctionnel), mais un ou plusieurs Replicas ne sont pas allouĂ©s (ex: NƓud 2 est tombĂ©, R1 est perdu).Risque (pas de HA).
RedPanne. Un ou plusieurs Shards Primaires ne sont pas alloués. Des données sont manquantes.Recherche partielle ou HS.
7.1 Backup (Snapshots)
1. Déclarer un "Repository"

On ne peut pas "juste" copier les fichiers. Il faut déclarer un "Repository" (ex: un dossier partagé (NFS) ou un bucket S3).

Ajouter à elasticsearch.yml (sur tous les nƓuds) :

path.repo: ["/mnt/backups/es"]
# Déclarer le repo (via API)
PUT /_snapshot/mon_repo_local
{
  "type": "fs",
  "settings": {
    "location": "/mnt/backups/es"
  }
}
2. Prendre un Snapshot (Backup)
# Lance le snapshot (non-bloquant)
POST /_snapshot/mon_repo_local/snapshot_20251101?wait_for_completion=true

# (wait_for_completion=true attend la fin)
3. Restaurer un Snapshot
# D'abord, fermer l'index (si on l'écrase)
POST /articles/_close

# Lancer la restauration
POST /_snapshot/mon_repo_local/snapshot_20251101/_restore

# Rouvrir l'index
POST /articles/_open
8.1 Cheat-sheet API REST (curl)
Monitoring (_cat)
GET /_cat/health?v
GET /_cat/nodes?v
GET /_cat/indices?v
GET /_cat/shards?v
Gestion d'Index
# Créer un index (avec mapping)
PUT /mon-index
{ "mappings": { ... } }

# Lire le mapping
GET /mon-index/_mapping

# Supprimer un index (DANGER)
DELETE /mon-index

# Fermer/Ouvrir (pour maintenance)
POST /mon-index/_close
POST /mon-index/_open

# RafraĂźchir (forcer l'indexation pour le search)
POST /mon-index/_refresh
CRUD (Document)
# Créer (ID auto)
POST /mon-index/_doc
{ "field": "value" }

# Créer/Remplacer (ID fixe)
PUT /mon-index/_doc/1
{ "field": "value" }

# Lire
GET /mon-index/_doc/1

# Lire (juste le _source)
GET /mon-index/_source/1

# Mettre Ă  jour (partiel)
POST /mon-index/_update/1
{ "doc": { "new_field": "new_val" } }

# Supprimer
DELETE /mon-index/_doc/1
Recherche (Query DSL)
# (Utiliser POST est mieux pour les grosses requĂȘtes)
POST /mon-index/_search
{
  "query": {
    "match_all": {}
  }
}

POST /mon-index/_search
{
  "query": {
    "match": {
      "description": "une recherche full text"
    }
  }
}

POST /mon-index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "description": "recherche" } }
      ],
      "filter": [
        { "term": { "statut.keyword": "publie" } },
        { "range": { "date": { "gte": "now-1M" } } }
      ]
    }
  },
  "aggs": {
    "group_by_statut": {
      "terms": { "field": "statut.keyword" }
    }
  }
}