Fiche de référence Elasticsearch : commandes et conseils essentiels

Commandes Elasticsearch pour la recherche, l'indexation et l'analyse.

Sommaire

Elasticsearch est un puissant moteur de recherche et d’analyse distribué construit sur Apache Lucene. Ce mémo complet couvre les commandes essentielles, les meilleures pratiques et les références rapides pour travailler avec des clusters Elasticsearch.

elasticsearch

Note : La plupart des exemples de ce guide utilisent cURL pour les requêtes HTTP. Si vous êtes nouveau avec cURL ou si vous avez besoin d’une référence rapide pour les options avancées, consultez notre Mémo cURL pour des techniques détaillées de requêtes HTTP en ligne de commande.

Gestion du Cluster

Vérifier la Santé du Cluster

Toutes les commandes de cette section utilisent cURL pour interagir avec l’API REST d’Elasticsearch. Vous pouvez personnaliser ces requêtes avec des en-têtes supplémentaires, une authentification et d’autres options selon vos besoins.

# Vérification de santé basique
curl -X GET "localhost:9200/_cluster/health?pretty"

# Santé du cluster détaillée avec informations sur les shards
curl -X GET "localhost:9200/_cluster/health?level=shards&pretty"

# Vérifier les informations sur les nœuds
curl -X GET "localhost:9200/_cat/nodes?v"

# Vérifier les paramètres du cluster
curl -X GET "localhost:9200/_cluster/settings?pretty"

Opérations sur les Nœuds

# Lister tous les nœuds
curl -X GET "localhost:9200/_cat/nodes?v&h=name,node.role,heap.percent,ram.percent,cpu,load_1m"

# Statistiques des nœuds
curl -X GET "localhost:9200/_nodes/stats?pretty"

# Threads actifs (dépannage)
curl -X GET "localhost:9200/_nodes/hot_threads"

Gestion des Index

Créer et Supprimer des Index

# Créer un index
curl -X PUT "localhost:9200/my_index?pretty"

# Créer un index avec des paramètres
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  }
}
'

# Supprimer un index
curl -X DELETE "localhost:9200/my_index?pretty"

# Lister tous les index
curl -X GET "localhost:9200/_cat/indices?v"

# Statistiques d'un index
curl -X GET "localhost:9200/my_index/_stats?pretty"

Mappings d’Index

# Définir un mapping
curl -X PUT "localhost:9200/products" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "price": { "type": "float" },
      "created_at": { "type": "date" },
      "tags": { "type": "keyword" },
      "description": { 
        "type": "text",
        "analyzer": "english"
      }
    }
  }
}
'

# Récupérer le mapping
curl -X GET "localhost:9200/products/_mapping?pretty"

# Mettre à jour le mapping (ajouter un champ)
curl -X PUT "localhost:9200/products/_mapping" -H 'Content-Type: application/json' -d'
{
  "properties": {
    "category": { "type": "keyword" }
  }
}
'

Modèles d’Index (Templates)

# Créer un modèle d'index
curl -X PUT "localhost:9200/_index_template/logs_template" -H 'Content-Type: application/json' -d'
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 1
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date" },
        "message": { "type": "text" },
        "level": { "type": "keyword" }
      }
    }
  }
}
'

# Lister les modèles
curl -X GET "localhost:9200/_index_template?pretty"

Opérations sur les Documents (CRUD)

Créer des Documents

# Indexer un document avec un ID auto-généré
curl -X POST "localhost:9200/products/_doc?pretty" -H 'Content-Type: application/json' -d'
{
  "name": "Laptop",
  "price": 999.99,
  "tags": ["electronics", "computers"]
}
'

# Indexer un document avec un ID spécifique
curl -X PUT "localhost:9200/products/_doc/1?pretty" -H 'Content-Type: application/json' -d'
{
  "name": "Laptop",
  "price": 999.99
}
'

# Indexation en vrac (Bulk)
curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d'
{ "index": { "_index": "products", "_id": "1" }}
{ "name": "Laptop", "price": 999.99 }
{ "index": { "_index": "products", "_id": "2" }}
{ "name": "Mouse", "price": 29.99 }
'

Lire des Documents

# Obtenir un document par ID
curl -X GET "localhost:9200/products/_doc/1?pretty"

# Obtenir plusieurs documents
curl -X GET "localhost:9200/_mget?pretty" -H 'Content-Type: application/json' -d'
{
  "docs": [
    { "_index": "products", "_id": "1" },
    { "_index": "products", "_id": "2" }
  ]
}
'

# Vérifier si un document existe
curl -I "localhost:9200/products/_doc/1"

Mettre à Jour des Documents

# Mettre à jour un document
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "price": 899.99
  }
}
'

# Mettre à jour avec un script
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "script": {
    "source": "ctx._source.price *= params.discount",
    "params": {
      "discount": 0.9
    }
  }
}
'

# Upsert (mettre à jour ou insérer)
curl -X POST "localhost:9200/products/_update/1?pretty" -H 'Content-Type: application/json' -d'
{
  "doc": {
    "price": 899.99
  },
  "doc_as_upsert": true
}
'

Supprimer des Documents

# Supprimer par ID
curl -X DELETE "localhost:9200/products/_doc/1?pretty"

# Supprimer par requête
curl -X POST "localhost:9200/products/_delete_by_query?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "old"
    }
  }
}
'

Requêtes de Recherche

Recherche Basique

# Correspondre tout
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  }
}
'

# Requête de correspondance (match)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": {
      "name": "laptop"
    }
  }
}
'

# Requête multi-correspondance
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "multi_match": {
      "query": "laptop gaming",
      "fields": ["name", "description"]
    }
  }
}
'

Requêtes de Niveau Terme

# Requête terme (correspondance exacte)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "term": {
      "tags": "electronics"
    }
  }
}
'

# Requête termes (plusieurs valeurs)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "terms": {
      "tags": ["electronics", "computers"]
    }
  }
}
'

# Requête de plage (Range)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "range": {
      "price": {
        "gte": 100,
        "lte": 1000
      }
    }
  }
}
'

# Requête d'existence
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "exists": {
      "field": "description"
    }
  }
}
'

Requêtes Booléennes

# Requête bool (must, should, must_not, filter)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "laptop" }}
      ],
      "filter": [
        { "range": { "price": { "gte": 500 }}}
      ],
      "should": [
        { "term": { "tags": "gaming" }}
      ],
      "must_not": [
        { "term": { "tags": "refurbished" }}
      ]
    }
  }
}
'

Recherche Avancée

# Requête joker (Wildcard)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "wildcard": {
      "name": "lap*"
    }
  }
}
'

# Requête floue (tolérance aux fautes de frappe)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "laptpo",
        "fuzziness": "AUTO"
      }
    }
  }
}
'

# Requête de préfixe
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "prefix": {
      "name": "lap"
    }
  }
}
'

Agrégations

Agrégations Métriques

# Moyenne, somme, min, max
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "avg_price": { "avg": { "field": "price" }},
    "max_price": { "max": { "field": "price" }},
    "min_price": { "min": { "field": "price" }},
    "total_sales": { "sum": { "field": "price" }}
  }
}
'

# Agrégation Stats
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": { "field": "price" }
    }
  }
}
'

Agrégations par Bâche (Bucket)

# Agrégation Terms (grouper par)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "popular_tags": {
      "terms": {
        "field": "tags",
        "size": 10
      }
    }
  }
}
'

# Agrégation Range
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 50 },
          { "from": 50, "to": 100 },
          { "from": 100 }
        ]
      }
    }
  }
}
'

# Histogramme de date
curl -X GET "localhost:9200/logs/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "logs_over_time": {
      "date_histogram": {
        "field": "timestamp",
        "calendar_interval": "day"
      }
    }
  }
}
'

Agrégations Emboîtées

# Agrégations emboîtées
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": { "field": "category" },
      "aggs": {
        "avg_price": {
          "avg": { "field": "price" }
        }
      }
    }
  }
}
'

Tri et Pagination

# Tri par champ
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "price": { "order": "desc" }},
    { "_score": { "order": "desc" }}
  ]
}
'

# Pagination avec from/size
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "from": 0,
  "size": 10,
  "query": { "match_all": {} }
}
'

# Search after (pour la pagination profonde)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "size": 10,
  "query": { "match_all": {} },
  "sort": [{ "price": "asc" }, { "_id": "asc" }],
  "search_after": [100, "product_123"]
}
'

Sélection de Champs et Mise en Évidence

# Sélectionner des champs spécifiques
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "_source": ["name", "price"]
}
'

# Mise en évidence (Highlighting)
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match": { "description": "gaming laptop" }
  },
  "highlight": {
    "fields": {
      "description": {}
    }
  }
}
'

Alias d’Index

# Créer un alias
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
  "actions": [
    { "add": { "index": "products_v1", "alias": "products" }}
  ]
}
'

# Basculer l'alias vers un nouvel index (sans interruption)
curl -X POST "localhost:9200/_aliases?pretty" -H 'Content-Type: application/json' -d'
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" }},
    { "add": { "index": "products_v2", "alias": "products" }}
  ]
}
'

# Lister les alias
curl -X GET "localhost:9200/_cat/aliases?v"

Réindexation

# Réindexer d'un index à un autre
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "old_products"
  },
  "dest": {
    "index": "new_products"
  }
}
'

# Réindexer avec une requête
curl -X POST "localhost:9200/_reindex?pretty" -H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "products",
    "query": {
      "range": {
        "price": { "gte": 100 }
      }
    }
  },
  "dest": {
    "index": "expensive_products"
  }
}
'

Snapshots et Sauvegardes

# Enregistrer un dépôt de snapshot
curl -X PUT "localhost:9200/_snapshot/my_backup?pretty" -H 'Content-Type: application/json' -d'
{
  "type": "fs",
  "settings": {
    "location": "/mount/backups/my_backup"
  }
}
'

# Créer un snapshot
curl -X PUT "localhost:9200/_snapshot/my_backup/snapshot_1?wait_for_completion=true&pretty"

# Restaurer un snapshot
curl -X POST "localhost:9200/_snapshot/my_backup/snapshot_1/_restore?pretty"

# Lister les snapshots
curl -X GET "localhost:9200/_snapshot/my_backup/_all?pretty"

# Supprimer un snapshot
curl -X DELETE "localhost:9200/_snapshot/my_backup/snapshot_1?pretty"

Optimisation des Performances

Paramètres d’Index

# Désactiver le refresh pendant l'indexation en vrac
curl -X PUT "localhost:9200/products/_settings?pretty" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "-1"
  }
}
'

# Réactiver après l'indexation en vrac
curl -X PUT "localhost:9200/products/_settings?pretty" -H 'Content-Type: application/json' -d'
{
  "index": {
    "refresh_interval": "1s"
  }
}
'

# Fusionner les segments (Force merge)
curl -X POST "localhost:9200/products/_forcemerge?max_num_segments=1&pretty"

Nettoyage du Cache

# Effacer tous les caches
curl -X POST "localhost:9200/_cache/clear?pretty"

# Effacer un cache spécifique
curl -X POST "localhost:9200/products/_cache/clear?query=true&pretty"

Surveillance et Dépannage

# Tâches en attente
curl -X GET "localhost:9200/_cat/pending_tasks?v"

# Statistiques des pools de threads
curl -X GET "localhost:9200/_cat/thread_pool?v"

# Informations sur les segments
curl -X GET "localhost:9200/_cat/segments?v"

# Informations de récupération
curl -X GET "localhost:9200/_cat/recovery?v&h=index,stage,time"

# API des tâches
curl -X GET "localhost:9200/_tasks?detailed=true&pretty"

Exemples de Client Python

from elasticsearch import Elasticsearch

# Se connecter à Elasticsearch
es = Elasticsearch(['http://localhost:9200'])

# Indexer un document
doc = {
    'name': 'Laptop',
    'price': 999.99,
    'tags': ['electronics']
}
es.index(index='products', id=1, document=doc)

# Recherche
resp = es.search(index='products', query={'match': {'name': 'laptop'}})
for hit in resp['hits']['hits']:
    print(hit['_source'])

# Indexation en vrac
from elasticsearch.helpers import bulk

actions = [
    {
        '_index': 'products',
        '_id': i,
        '_source': {'name': f'Product {i}', 'price': i * 10}
    }
    for i in range(1000)
]
bulk(es, actions)

Exemples de Client JavaScript/Node.js

Le client JavaScript d’Elasticsearch offre une méthode sûre de typage pour interagir avec votre cluster. Pour les applications de production, envisagez d’utiliser TypeScript pour une meilleure sécurité de typage et l’auto-complétion. Consultez notre Mémo TypeScript pour les meilleures pratiques sur les définitions de types et les interfaces.

const { Client } = require('@elastic/elasticsearch');
const client = new Client({ node: 'http://localhost:9200' });

// Indexer un document
async function indexDoc() {
  await client.index({
    index: 'products',
    id: 1,
    document: {
      name: 'Laptop',
      price: 999.99
    }
  });
}

// Recherche
async function search() {
  const result = await client.search({
    index: 'products',
    query: {
      match: { name: 'laptop' }
    }
  });
  console.log(result.hits.hits);
}

// Indexation en vrac
async function bulkIndex() {
  const operations = [];
  for (let i = 0; i < 1000; i++) {
    operations.push({ index: { _index: 'products', _id: i } });
    operations.push({ name: `Product ${i}`, price: i * 10 });
  }
  await client.bulk({ operations });
}

Exemple TypeScript avec Typage Fort

import { Client } from '@elastic/elasticsearch';

interface Product {
  name: string;
  price: number;
  tags?: string[];
  created_at?: Date;
}

const client = new Client({ node: 'http://localhost:9200' });

async function indexProduct(product: Product, id: number): Promise<void> {
  await client.index<Product>({
    index: 'products',
    id: id.toString(),
    document: product
  });
}

async function searchProducts(query: string): Promise<Product[]> {
  const result = await client.search<Product>({
    index: 'products',
    query: {
      match: { name: query }
    }
  });
  
  return result.hits.hits.map(hit => hit._source as Product);
}

Meilleures Pratiques

Conception d’Index

  • Maintenir la taille des shards entre 20 et 50 Go pour des performances optimales
  • Utiliser la gestion du cycle de vie des index (ILM) pour les données séries temporelles
  • Concevoir soigneusement les mappings avant d’indexer des données
  • Utiliser les types de champs appropriés (keyword vs text, formats de date)
  • Désactiver _source pour les grands documents si non nécessaire

Optimisation des Requêtes

  • Utiliser des filtres plutôt que des requêtes lorsque le score n’est pas nécessaire
  • Privilégier les requêtes de niveau terme pour les données structurées
  • Utiliser la requête bool pour combiner efficacement plusieurs conditions
  • Implémenter la pagination avec search_after pour le paginage profond
  • Mettre en cache les filtres fréquemment utilisés

Performance d’Indexation

  • Utiliser l’API Bulk pour l’indexation par lots (1000-5000 documents par requête)
  • Désactiver le refresh pendant les opérations en vrac
  • Augmenter index.refresh_interval pendant une indexation intensive
  • Utiliser plusieurs threads/ouvriers pour une indexation parallèle
  • Envisager d’utiliser le routage pour une meilleure distribution des shards

Gestion du Cluster

  • Surveiller régulièrement la santé du cluster
  • Configurer correctement les répliques
  • Utiliser des nœuds maîtres dédiés pour les grands clusters
  • Mettre en place une stratégie de sauvegarde appropriée avec des snapshots
  • Surveiller l’utilisation de la heap JVM (garder en dessous de 75 %)

Sécurité

  • Activer l’authentification et l’autorisation (X-Pack Security)
  • Utiliser HTTPS pour les déploiements de production (configurer cURL avec les options --cacert, --cert, et --key pour SSL/TLS)
  • Implémenter un contrôle d’accès basé sur les rôles approprié
  • Appliquer régulièrement les mises à jour de sécurité et les correctifs
  • Chiffrer les données au repos et en transit

Cas d’Usage Courants

Recherche Texte Intégral

Elasticsearch excelle dans la recherche texte intégral avec des fonctionnalités telles que :

  • Calcul de pertinence (scoring)
  • Correspondance floue
  • Correspondance de phrases
  • Gestion des synonymes
  • Support multilingue Si vous évaluez si vous devez garder la recherche dans Postgres ou passer à un moteur de recherche dédié, cette comparaison PostgreSQL full text search vs Elasticsearch détaille les compromis pratiques.

Analyse de Logs (Stack ELK)

  • Collecter les logs avec Logstash/Filebeat
  • Indexer et rechercher les logs dans Elasticsearch
  • Visualiser avec des tableaux de bord Kibana
  • Configurer des alertes pour les anomalies

Recherche E-commerce

  • Recherche de catalogue de produits
  • Navigation par facettes avec agrégations
  • Auto-complétion et suggestions
  • Résultats de recherche personnalisés

Surveillance des Performances d’Application

  • Indexer les métriques d’application
  • Tableaux de bord de surveillance en temps réel
  • Détection d’anomalies
  • Analyse des tendances de performance

Liens Utiles

Ressources Officielles Elasticsearch

Mémos et Guides Connexes

S'abonner

Recevez de nouveaux articles sur les systèmes, l'infrastructure et l'ingénierie IA.