đ 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).
Vue d'ensemble
Moteur de recherche, NoSQL Document, Lucene.
Search NoSQL LuceneArchitecture
Cluster, NĆuds (Nodes), API REST.
Cluster Node API RESTConcepts : Index & Document
Index (BDD), Document (Ligne/JSON).
Index Document JSONConcepts : Shards & Replicas
Scalabilité (Shards) & Haute Dispo (Replicas).
Shard Replica ScalabilityPrérequis : Java (JDK)
Installation OpenJDK (inclus ou externe).
Java JDK JAVA_HOMEInstallation Linux (apt/dnf)
DépÎt Elastic, elasticsearch.yml, systemd.
Installation Docker (Dev)
docker run (single-node), Docker Compose.
Installation Kibana (UI)
L'interface web pour ES (Dev Tools).
Kibana ELK UIAPI REST (curl)
Interagir avec curl, API _cat.
Mapping (Schema)
text vs keyword, date, integer.
Indexer un Document
PUT (ID fixe) vs POST (auto-ID).
CRUD (Get, Update, Delete)
GET, DELETE, _update.
Query DSL : match
match (full-text), term (exact).
Query DSL : bool
must, should, filter (trĂšs important).
Agrégations (aggs)
terms (GROUP BY), date_histogram.
Ingestion (ELK)
Logstash, Filebeat (ingestion de logs).
Logstash Filebeat LogsIntégration Django (Python)
elasticsearch-dsl, Document, Search.
Intégration PHP
elasticsearch-php (client officiel).
Santé & Admin Cluster
_cluster/health, (green, yellow, red).
Backup (Snapshots)
_snapshot, _restore.
Cheat-sheet API REST
Commandes curl fréquentes.
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 SQL | Monde Elasticsearch | Description |
|---|---|---|
| Database (BDD) | Index | Conteneur de données. |
| Table | (Concept supprimé) | Avant ES 7, c'était 'Type'. |
| Row (Ligne) | Document | Une entrée JSON. |
| Column (Colonne) | Field (Champ) | Une clé dans le JSON. |
| Schema | Mapping | Définit les types des champs. |
SELECT * ... WHERE | GET .../_search (Query DSL) | La requĂȘte (JSON). |
GROUP BY | Aggregations | Agrégats. |
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) |
+-----------------------+
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.
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 :
P1est perdu.- ES promeut automatiquement
R1(sur NĆud 1) en nouveau PrimaireP1. - Le cluster passe en statut "yellow" (donnĂ©es disponibles, mais un replica manque).
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
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
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 persistancedocker-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.
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,
...
}
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"
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" :
- Met en minuscule (
The Fox->the fox). - Retire les "stop words" (
the,a...). - Tokenize (
quick fox->[quick],[fox]).
- Met en minuscule (
- 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/_mappingPOST (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)
...
}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"
}
}
}_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"]
}
}
}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.
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"
}
}
}
}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) |
+----------------+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
})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);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)
| Statut | Description | Impact |
|---|---|---|
| Green | Parfait. Tous les Shards Primaires ET Replicas sont alloués. | OK. |
| Yellow | Attention. 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). |
| Red | Panne. Un ou plusieurs Shards Primaires ne sont pas alloués. Des données sont manquantes. | Recherche partielle ou HS. |
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
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/_refreshCRUD (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/1Recherche (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" }
}
}
}