Comment lire cette page. D'abord trois parties à taper dans l'ordre : les commandes, puis la question qui les concerne. Ouvre « Pour bien comprendre » si une commande n'est pas claire. Les réponses sont repliées juste avant les huit étapes : réponds avant de les ouvrir. Ensuite on révise les étapes en gros, puis tu les refais une par une : le titre reste visible, le détail s'ouvre au clic. Tape toi-même chaque requête (pas de copier-coller) : c'est en écrivant
PUT,GET,_docque les mots rentrent. Si le labo n'est pas démarré, retourne à la pratique guidée : la section En bref donne les commandes, kit compris (https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr).
La pratique guidée t'a fait charger 504 cours, 609 avis et 12 000 lignes de journal d'un coup, avec un script. Tu as vu les chiffres, mais tu n'as encore rien écrit toi-même. Ici, tu repars de zéro : un index vide que tu crées, une première fiche que tu ranges dedans, que tu relis, que tu complètes, puis une deuxième, une recherche, une suppression. À la fin, tu sais ce qu'est un index et un document parce que tu en as fabriqué un, pas parce qu'on te l'a dit.
Un index est une armoire. Un document est une fiche rangée dans l'armoire : un petit texte JSON avec des champs. Chaque fiche a un numéro, son _id, qui permet de la retrouver directement sans chercher. Tu n'as pas à déclarer les colonnes à l'avance : la première fiche rangée crée le mapping (le plan de l'armoire) toute seule.
| Elasticsearch | Base SQL classique | Dans cette pratique |
|---|---|---|
| index | table | pratique-mini |
| document | ligne | {"titre": "Mon premier document"} |
| champ | colonne | titre, auteur, note |
_id | clé primaire | 1, 2 |
| mapping | schéma de la table (CREATE TABLE …) | créé automatiquement à l'étape 3 |
_source | la ligne telle que tu l'as écrite | ce que GET _doc/1 te rend |
Ouvre http://localhost:5601, menu ☰ → Management → Dev Tools. Le panneau de gauche reçoit les requêtes, celui de droite affiche la réponse. Tu envoies avec Ctrl + Entrée (Cmd + Entrée sur macOS) ou le bouton ▶ à droite de la ligne.
Toute requête a la même forme : un verbe, un chemin, et parfois un corps JSON en dessous.
| Verbe | Ce qu'il fait | Équivalent SQL |
|---|---|---|
GET | lire, sans rien changer | SELECT |
PUT | créer, ou remplacer entièrement | CREATE TABLE, INSERT (ou remplacer la ligne) |
POST | agir : mettre à jour, chercher avec un corps | UPDATE |
DELETE | supprimer | DROP TABLE, DELETE |
Le chemin dit sur quoi on agit : pratique-mini (l'armoire), pratique-mini/_doc/1 (la fiche numéro 1 de l'armoire), pratique-mini/_search (chercher dans l'armoire). Les mots qui commencent par _ sont des commandes d'Elasticsearch, pas des noms à toi.
Trois parties, dans cet ordre. Tape chaque commande, lis la réponse à droite, puis réponds à la question. Les réponses sont plus bas, juste avant l'étape 1.
PUT pratique-miniGET _cat/indices/pratique-mini?vPUT pratique-mini/_doc/1
{
"titre": "Introduction à Docker",
"categorie": "DevOps",
"niveau": "débutant"
}POST pratique-mini/_doc
{
"titre": "Introduction à Kubernetes",
"categorie": "Cloud",
"niveau": "intermédiaire"
}PUT pratique-mini/_doc/3
{
"titre": "Introduction aux LLMs",
"categorie": "IA",
"niveau": "intermédiaire"
}Question 1. Quelle est la différence entre PUT et POST ?
Indice : GET pratique-mini/_search, et regarde le champ _id de chaque fiche.
Question 2. Peut-on modifier la structure en ajoutant un champ nouveau, par exemple langue, à un document ?
Pour le voir, tape :
POST pratique-mini/_doc/5
{
"titre": "Introduction à Kubernetes",
"categorie": "Cloud",
"niveau": "intermédiaire",
"langue": "fr"
}Question 3. Comment déclarer précisément les champs autorisés et leur type, pour refuser une donnée qui ne respecte pas le plan ?
PUT pratique-mini-strict
{
"mappings": {
"dynamic": "strict",
"properties": {
"titre": { "type": "text" },
"categorie": { "type": "keyword" },
"niveau": { "type": "keyword" },
"langue": { "type": "keyword" }
}
}
}PUT pratique-mini-strict/_doc/5
{
"titre": "Introduction à Kubernetes",
"categorie": "Cloud",
"niveau": "intermédiaire",
"langue": "fr"
}PUT pratique-mini-strict/_doc/6
{
"titre": "Introduction à Docker",
"categorie": "DevOps",
"niveau": "débutant",
"langue": "fr",
"prix": 100
}Cette dernière requête est refusée. Lis le message.
Question 4. Dans quels cas concrets utilise-t-on un mapping strict ?
PUT pratique-mini, sans corps. Tu crées l'armoire et rien d'autre : pas de champs, pas de fiche. Le nom est en minuscules. pratique- devant permet, plus tard, de lister uniquement tes index avec pratique-*.GET _cat/indices/pratique-mini?v. Une seule ligne de résumé. ?v (verbose) affiche les noms de colonnes. Tu y lis health (la couleur), status (open : on peut écrire), docs.count (le nombre de fiches), rep (le nombre de copies demandées en plus de l'original).PUT pratique-mini/_doc/1. _doc veut dire « une fiche ». Le 1 est dans le chemin : c'est toi qui choisis le numéro, le _id. Le corps JSON est la fiche : titre, categorie, niveau.POST pratique-mini/_doc. Le chemin s'arrête à _doc. Il n'y a pas de numéro. Le corps a la même forme que la fiche 1, avec d'autres valeurs.PUT pratique-mini/_doc/3. Encore un numéro choisi, le 3. Personne n'a créé la fiche 2 : les numéros ne se suivent pas tout seuls.POST pratique-mini/_doc/5 ajoute le champ langue. La fiche a un champ de plus que les précédentes. Par défaut, Elasticsearch accepte ce champ et l'ajoute au mapping (le plan de l'armoire) sans que tu aies à le déclarer. C'est le mapping dynamique.PUT pratique-mini-strict avec mappings. Cette fois le corps décrit le plan avant toute fiche. "dynamic": "strict" veut dire : refuse tout champ qui n'est pas dans properties. text sert à chercher des mots (titre). keyword sert à une valeur exacte (categorie, niveau, langue).PUT pratique-mini-strict/_doc/5 n'envoie que des champs déclarés. PUT pratique-mini-strict/_doc/6 ajoute prix, qui n'est pas dans properties. Lis le message d'erreur : il nomme le champ refusé.PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 1 }
}GET _cat/indices/pratique-mini?vQuestion 2.1. Quelle couleur observes-tu ?
PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 0 }
}GET _cat/indices/pratique-mini?vQuestion 2.2. Quelle couleur observes-tu ?
Question 2.3. Pourquoi la couleur passe-t-elle de jaune à vert quand le nombre de réplicas passe de 1 à 0 ? Que signifient ces deux états ?
Pour voir le rouge, un index dont la copie est exigée sur une machine qui n'existe pas :
PUT demo-red
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"index.routing.allocation.require._name": "noeud-inexistant"
}
}GET _cat/indices/demo-red?vQuestion 2.4. Quelle couleur observes-tu, et pourquoi ?
On retire la contrainte, puis on relit :
PUT demo-red/_settings
{
"index.routing.allocation.require._name": null
}GET _cat/indices/demo-red?vQuestion 2.5. Quelle couleur maintenant ?
number_of_replicas dit combien de copies Elasticsearch doit placer en plus de l'original. 1 en demande une. 0 n'en demande aucune. Le labo n'a qu'une machine : une copie ne peut pas être placée sur une deuxième machine qui n'existe pas.health de GET _cat/indices/...?v. Relis cette colonne après chaque PUT _settings, pas le badge HTTP : un réglage accepté répond acknowledged: true même quand la couleur change.PUT demo-red fixe trois réglages d'un coup. number_of_shards: 1 : un seul morceau. number_of_replicas: 0 : pas de copie. index.routing.allocation.require._name : « ce morceau ne peut aller que sur le nœud qui porte exactement ce nom ». noeud-inexistant n'est le nom d'aucune machine du labo.null retire la contrainte. Le morceau peut alors se placer sur la machine qui tourne.On repart d'une armoire vide. La partie 3 reprend pratique-mini de zéro : les fiches de la partie 1 disparaissent ici.
DELETE pratique-miniGET _cat/indices/pratique-*?vPUT pratique-miniGET _cat/indices/pratique-mini?vQuestion 3.1. Pourquoi la couleur est-elle jaune ?
PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 0 }
}GET _cat/indices/pratique-mini?vQuestion 3.2. Pourquoi la couleur est-elle verte ?
PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}GET pratique-mini/_doc/1GET pratique-mini/_doc/3À regarder : la fiche 1 répond "found": true. La fiche 3 répond "found": false : ce numéro n'existe pas.
POST pratique-mini/_update/1
{
"doc": {
"auteur": "Alice",
"note": 5
}
}Question 3.3. À quoi sert cette commande ?
Question 3.4. Quelle commande affiche les informations générales de l'index (couleur, état, nombre de documents, taille) ? Quelle commande affiche les documents (titre, catégorie, niveau, langue) ?
Question 3.5. Peut-on faire un PUT à la place de ce POST _update ? Risque-t-on d'écraser la fiche ?
Question 3.6. La commande suivante écrase-t-elle la fiche existante, et pourquoi ?
PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}Relis la fiche :
GET pratique-mini/_doc/1On remet les champs effacés :
POST pratique-mini/_update/1
{
"doc": {
"auteur": "Alice",
"note": 5
}
}Question 3.7. Ajoute une deuxième fiche (titre, auteur Bob, note 3), puis compte les fiches. Écris les commandes.
Question 3.8. Retrouve l'ensemble des fiches. Écris la commande.
Question 3.9. Retrouve la fiche dont le titre contient « premier ». Écris la commande.
Question 3.10. Supprime la fiche 2, puis l'index. Écris les commandes, puis vérifie avec GET _cat/indices/pratique-*?v.
Avant l'étape 1, supprime aussi les deux index de démonstration, sinon ils restent dans le labo :
DELETE pratique-mini-strictDELETE demo-redDELETE pratique-mini enlève cette armoire et toutes ses fiches. pratique-mini-strict et demo-red ne sont pas touchés : un DELETE vise le nom que tu écris, pas « tout ce que tu as créé ».GET _cat/indices/pratique-*?v. L'étoile veut dire « tout nom qui commence par pratique- ». Après le DELETE, pratique-mini ne doit plus être dans la liste. pratique-mini-strict y est encore.PUT pratique-mini recrée une armoire vide. Sans corps, Elasticsearch choisit ses réglages par défaut, dont le nombre de copies. C'est ce défaut que la question 3.1 te fait observer.GET pratique-mini/_doc/1 lit la fiche par son numéro, sans chercher. found vaut true quand le numéro existe. GET pratique-mini/_doc/3 vise un numéro que tu n'as pas créé : found vaut false, sans _source. Ce n'est pas une panne du labo.POST pratique-mini/_update/1 ne remplace pas la fiche. Le mot doc dans le corps veut dire « fusionne ces champs avec ceux qui sont déjà là ». auteur et note s'ajoutent. titre n'est pas dans le corps, il reste.GET _cat/indices/pratique-mini?v décrit l'armoire : couleur, état, nombre de fiches, taille. GET pratique-mini/_search décrit les fiches. Les deux ne répondent pas à la même question.PUT pratique-mini/_doc/1 avec seulement titre envoie une fiche entière vers un numéro qui existe déjà. Compare avec _update : l'un envoie « la fiche complète », l'autre envoie « les champs à ajouter ».POST _update remet auteur et note après ce PUT. Sans lui, la fiche 1 n'aurait plus que titre au moment d'ajouter la fiche 2._count renvoie un nombre. _search sans corps renvoie les fiches. _search avec query / match ne garde que les fiches dont le champ contient le mot demandé.DELETE pratique-mini/_doc/2 enlève une fiche. DELETE pratique-mini enlève l'armoire. DELETE pratique-mini-strict et DELETE demo-red enlèvent les deux index de démonstration, pour que l'étape 1 reparte d'un labo sans tes essais.Ouvre une solution après avoir répondu.
Question 1. Quelle est la différence entre PUT et POST ?
PUT range la fiche à l'adresse que tu as écrite. POST range une fiche et laisse Elasticsearch inventer l'adresse.
Imagine une armoire d'école. Chaque fiche a un numéro collé dessus, son _id. C'est ce numéro que tu tapes ensuite dans GET …/_doc/1.
PUT pratique-mini/_doc/1 dit : « range cette fiche dans le tiroir 1 ». Tu as choisi le 1. La fiche Docker porte donc "_id": "1". PUT pratique-mini/_doc/3 fait la même chose pour le tiroir 3. Personne n'a créé le 2 : les numéros ne se suivent pas tout seuls, c'est toi qui les donnes.
POST pratique-mini/_doc s'arrête à _doc. Il n'y a pas de numéro dans le chemin. Elasticsearch invente alors un _id long, du genre W8k3nYQBR…. C'est comme demander à la bibliothécaire : « range cette fiche où tu veux, et dis-moi le numéro après ».
Tape GET pratique-mini/_search et ouvre chaque _id :
"_id": "1" → le PUT de Docker ;"_id": "3" → le PUT des LLMs ;_id illisible → le POST de Kubernetes.Le même PUT une seconde fois sur _doc/1 remplace toute la fiche 1. Un second POST sans numéro ajoute une fiche de plus, avec un nouvel _id. C'est la différence à retenir : PUT = à cette adresse, POST = une fiche de plus.
Si tu corriges le titre de Docker, tu refais PUT pratique-mini/_doc/1 avec le nouveau JSON. La fiche 1 change, les autres ne bougent pas. Si tu ajoutes un quatrième cours avec POST pratique-mini/_doc, tu obtiens une quatrième fiche : tu ne touches pas aux trois premières.
Question 2. Peut-on ajouter un champ nouveau, par exemple langue, à un document ?
Oui. Par défaut, Elasticsearch accepte le champ et l'ajoute au plan de l'armoire, sans que tu recréés l'index.
Dans pratique-mini, tu n'as jamais déclaré de colonnes. Les trois premières fiches ont titre, categorie, niveau. Puis tu ranges la fiche 5 avec un champ de plus, langue: "fr". Elasticsearch ne dit pas « cette colonne n'existe pas ». Il dit « d'accord », et il ajoute langue au mapping.
C'est le mapping dynamique : le plan de l'armoire grandit tout seul à la première fiche qui apporte un champ nouveau. Tu n'as pas à faire DELETE puis PUT de l'index.
Les fiches 1 et 3 n'ont pas langue. Ce n'est pas une erreur. Une fiche n'est pas obligée d'avoir tous les champs des autres. Relis-les avec GET pratique-mini/_doc/1 : tu ne vois que les trois champs d'origine. Relis la 5 : tu vois les quatre.
Un catalogue de cours, même idée. Les premiers n'ont pas de prix. Un jour tu ranges un cours payant avec "prix": 49. Elasticsearch ajoute prix au mapping. Les anciens cours restent lisibles, simplement sans prix. C'est pratique pour commencer. C'est aussi le risque de la question 3 : n'importe quel champ mal nommé (prx, languee) entre de la même façon.
Question 3. Comment déclarer les champs autorisés et leur type, pour refuser une donnée hors plan ?
On crée l'index avec un mapping "dynamic": "strict" et une liste properties. Tout champ absent de cette liste est refusé.
pratique-mini acceptait tout. pratique-mini-strict est l'armoire inverse : le plan est écrit avant la première fiche.
"dynamic": "strict"veut dire : si un champ n'est pas dans properties, refuse la fiche entière. Pas « ignore le champ », pas « ajoute-le quand même ». Refuse.
La liste déclare quatre champs et leur type :
titre en text : on pourra chercher des mots dedans (« Docker », « Kubernetes ») ;categorie, niveau, langue en keyword : on comparera la valeur exacte (« DevOps », pas « devops quelque chose »).La fiche 5 passe : titre, categorie, niveau, langue. Rien de plus. La fiche 6 ajoute prix: 100. prix n'est pas dans le plan. Elasticsearch répond une erreur du genre strict_dynamic_mapping_exception et nomme le champ prix. La fiche n'est pas rangée.
Un formulaire d'inscription n'accepte que nom, e-mail, âge. Quelqu'un ajoute une case « salaire ». Le formulaire refuse. Le mapping strict fait la même chose pour une fiche JSON. Sans lui, le salaire entrerait, et le jour où tu veux calculer une moyenne d'âge, tu te retrouves avec un champ salaire que personne n'avait prévu.
Question 4. Dans quels cas concrets utilise-t-on un mapping strict ?
Dès qu'une donnée fausse, mal nommée ou imprévue ne doit pas entrer dans l'index.
Le mapping dynamique est confortable pour un atelier. En production, un champ de trop coûte cher : une recherche qui ne trouve plus, un tableau de bord qui mélange des types, une donnée sensible rangée dans un champ inventé par une faute de frappe.
Cas où le strict est le bon réflexe :
montant_bis créé par une typo ne doit pas entrer.notes_perso inventé par une appli tierce ne doit pas se ranger à côté.qte et l'équipe B quantite, tu ne pourras plus additionner les stocks.client_id, id_client, clientId). Le strict force un seul nom.Ce que le strict refuse, avec un exemple pour chacun :
"quantite": "beaucoup" dans un champ nombre. Tu ne pourras plus faire une moyenne."date_reception": "hier". Une date doit ressembler à 2026-09-21, pas à un mot."quantitee": 12 (deux e). Faute de frappe : le champ autorisé s'appelle quantite. Sans strict, tu aurais deux colonnes et la vraie resterait vide."age": 18.5 dans un champ entier. Un âge en demi-année n'est pas le type déclaré."actif": "oui" dans un booléen. Seuls true et false passent.emplacement alors que tous les autres en ont un, si tu as déclaré le champ comme obligatoire côté application — le mapping, lui, refuse surtout les champs en trop."numero_carte": "4111…" envoyé par erreur dans un index de catalogues. Le champ n'est pas prévu : la fiche est refusée, la donnée sensible n'est pas stockée.tmp, debug, test1) qui gonflent l'index pour rien.Règle simple. Atelier, exploration, tu laisses le dynamique. Index partagé, argent, santé, stocks, journaux : tu écris le plan, tu mets strict.
Question 2.1. Quelle couleur observes-tu ?
Jaune.
Après number_of_replicas: 1, la colonne health de GET _cat/indices/pratique-mini?v dit yellow. Tes fiches sont toujours là. Tu peux encore faire GET _doc/1. Jaune ne veut pas dire « cassé ». Ça veut dire : « l'original est là, la copie demandée n'est pas là ».
Exemple. Tu photocopies un dossier pour le mettre dans un deuxième bureau. Le deuxième bureau n'existe pas. Le dossier original est sur ton bureau : tu travailles. L'alarme est jaune parce que la photocopie n'a nulle part où aller.
Question 2.2. Quelle couleur observes-tu ?
Vert.
Après number_of_replicas: 0, la même commande montre green et rep 0. Tu n'as plus demandé de copie. Rien ne manque. Vert veut dire : « tout ce qui a été demandé est en place ».
Exemple. Tu ranges le dossier dans un seul tiroir, et tu n'as pas demandé de photocopie. Personne n'attend une deuxième machine. L'alarme redevient verte.
Question 2.3. Pourquoi la couleur passe-t-elle de jaune à vert quand les réplicas passent de 1 à 0 ?
Parce que le labo n'a qu'une machine. Avec 1 réplica, Elasticsearch doit poser une copie sur une autre machine. Cette machine n'existe pas. La copie manque → jaune. Avec 0 réplica, aucune copie n'est demandée. Rien ne manque → vert.
Les trois couleurs, dites simplement :
Exemple de tous les jours. Un devoir :
Dans le labo, on reste volontairement à 0 réplica. Une seule machine ne peut pas héberger à la fois l'original et sa copie : Elasticsearch refuse de poser les deux au même endroit. C'est pour ça que les index du kit (cours, avis, acces) sont verts : leur mapping fixe déjà number_of_replicas: 0.
Question 2.4. Quelle couleur observes-tu, et pourquoi ?
Rouge. Parce que l'original lui-même n'a nulle part où se poser.
demo-red dit : « ce morceau d'index ne peut aller que sur le nœud noeud-inexistant ». Aucune machine du labo ne s'appelle comme ça. Elasticsearch ne pose donc pas le shard principal. Sans original, la couleur est rouge. GET _cat/indices/demo-red?v le montre.
C'est différent du jaune. En jaune, tes fiches Docker et Kubernetes se lisaient encore. Ici, même l'armoire n'est pas placée. Ranger une fiche dans demo-red maintenant échouerait : il n'y a pas de tiroir physique.
Exemple. Tu expédies un colis à « 12, rue qui n'existe pas ». Le colis n'arrive nulle part. Ce n'est pas « en attente de photocopie ». C'est « jamais livré ».
Question 2.5. Quelle couleur maintenant ?
Vert.
null retire la contrainte de nom. Elasticsearch n'exige plus le nœud fantôme. Il pose le shard sur la machine du labo, celle qui tourne. L'original est en place, aucun réplica n'est demandé (number_of_replicas: 0) : tout ce qui est demandé est là → vert.
Exemple. Tu enlèves l'étiquette « livrer uniquement au bureau inexistant ». Le colis va au bureau réel. Il est arrivé.
Question 3.1. Pourquoi la couleur est-elle jaune ?
Parce qu'un PUT pratique-mini sans corps reprend les réglages par défaut, et le défaut demande 1 réplica.
Tu viens d'effacer l'index et de le recréer vide. Tu n'as envoyé aucun settings. Elasticsearch choisit alors : 1 shard, 1 réplica. Une seule machine ne peut pas héberger cette copie. Même situation qu'à la question 2.1, pour la même raison.
docs.count vaut 0 : l'armoire est vide. Jaune n'a rien à voir avec le nombre de fiches. Une armoire vide peut être jaune. Une armoire pleine aussi. La couleur parle des copies, pas du contenu.
Exemple. Tu achètes une armoire neuve. La notice dit « prévoir une copie de secours ». Tu n'as qu'une pièce. L'alarme est jaune dès la sortie du carton, avant d'y ranger la moindre feuille.
Question 3.2. Pourquoi la couleur est-elle verte ?
Parce que tu as dit number_of_replicas: 0. Plus de copie exigée, plus de manque, vert.
C'est le même geste que dans la partie 2, et le même que les index du kit. Sur une machine, c'est le réglage juste.
Exemple. Tu barres sur la notice la ligne « copie de secours ». L'alarme s'éteint. L'armoire est toujours vide, mais elle est verte.
Question 3.3. À quoi sert POST pratique-mini/_update/1 ?
À compléter la fiche 1 sans jeter ce qui est déjà écrit.
Le mot doc dans le corps veut dire « fusionne ces champs avec la fiche actuelle ». Tu envoies auteur et note. titre n'est pas dans le corps : il reste. Après un GET _doc/1, tu dois voir les trois.
Ce n'est pas un PUT. Un PUT dirait « voici la fiche entière, jette l'ancienne ». _update dit « ajoute ou change seulement ce que je t'envoie ».
Exemple. Une fiche élève a déjà « nom : Alice ». Tu ajoutes « note : 5 » avec _update. Le nom est toujours là. Si tu avais fait un PUT avec seulement { "note": 5 }, le nom disparaissait. C'est exactement le piège des questions 3.5 et 3.6.
Question 3.4. Quelle commande décrit l'armoire ? Quelle commande décrit les fiches ?
L'armoire :
GET _cat/indices/pratique-mini?vUne ligne. Tu y lis la couleur (health), si l'index est ouvert (status), le nombre de fiches (docs.count), la taille sur disque. Tu n'y lis aucun titre, aucun auteur. C'est la plaque sur la porte de l'armoire, pas les feuilles à l'intérieur.
Les fiches :
GET pratique-mini/_searchLe JSON des documents. Chaque hit a un _id et un _source : titre, et plus tard auteur, note. C'est ouvrir l'armoire et étaler les feuilles sur la table.
Exemple. Tu veux savoir « combien de dossiers, et est-ce vert ? » → _cat/indices. Tu veux savoir « qu'est-ce qu'il y a écrit sur la fiche d'Alice ? » → _search, ou GET …/_doc/1 si tu as déjà le numéro.
Question 3.5. Peut-on faire un PUT à la place de _update ? Y a-t-il un risque d'écraser ?
Oui, le PUT est accepté. Oui, il y a un risque : il remplace toute la fiche.
Elasticsearch ne refuse pas PUT pratique-mini/_doc/1. Le numéro 1 existe, le verbe est bon, le JSON est bon. La requête répond "result": "updated". Ça a l'air réussi.
Le piège est dans le corps. _update envoie seulement les champs à ajouter. PUT _doc/1 envoie la fiche complète. Tout ce qui n'est pas dans ce JSON disparaît.
Si tu copies le PUT de l'étape « premier document », le corps n'a que titre. auteur et note sont effacés, même si la requête « marche ».
Exemple. Tu corriges une fiche papier. _update, c'est ajouter une ligne au stylo. PUT, c'est jeter la fiche et en réécrire une nouvelle avec seulement ce que tu as sous les yeux. Si tu as oublié deux lignes, elles n'existent plus.
Question 3.6. Cette commande écrase-t-elle la fiche, et pourquoi ?
Oui. Parce que PUT _doc/1 ne fusionne pas : il remplace le document entier par le JSON envoyé.
Après le GET pratique-mini/_doc/1, _source ne contient plus que "titre": "Mon premier document". auteur et note ont disparu. "_version" a augmenté : Elasticsearch a bien écrit. Il a écrit moins que ce qu'il y avait.
Le POST _update qui suit n'est pas décoratif. Il remet auteur et note. Sans lui, la fiche 1 resterait incomplète pour la suite (deuxième fiche, recherche sur « premier »).
Règle à retenir, la même qu'à l'étape 6 : PUT remplace, _update complète.
Exemple. Même fiche Alice. Tu fais PUT avec seulement le titre. C'est comme photocopier une page blanche où tu n'as réécrit que le titre, puis jeter l'original. Relire la fiche le prouve : plus de note, plus d'auteur.
Question 3.7. Ajoute une deuxième fiche, puis compte.
Tu ranges une fiche nouvelle, donc un _id que tu choisis, ici 2. Un PUT est juste : le tiroir 2 est vide, tu ne risques pas d'écraser Alice.
PUT pratique-mini/_doc/2
{
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}Tu dois voir "result": "created" et "_id": "2". Puis :
GET pratique-mini/_countcount vaut 2 : Alice et Bob. _count ne montre pas les titres. Il répond seulement « combien ». Si tu viens d'écrire et que tu lis 1, attends une seconde et relance : la recherche (et donc _count) voit les nouvelles fiches avec un tout petit délai. GET _doc/2, lui, est immédiat.
Exemple. Deux dossiers dans l'armoire. Tu ne les ouvres pas. Tu dis juste « il y en a deux ». C'est _count.
Question 3.8. Retrouve l'ensemble des fiches.
GET pratique-mini/_searchSans corps, sans query. Elasticsearch comprend : « tout ». Tu obtiens hits.total.value: 2 et deux _source : Alice (fiche 1) et Bob (fiche 2). L'ordre des deux peut changer : sans critère, les deux ont le même score.
C'est la commande de la question 3.4, côté fiches. _cat te dirait encore docs.count 2, sans montrer Alice ni Bob.
Exemple. Tu ouvres l'armoire et tu sors toutes les feuilles, sans tri. Tu les as toutes, tu ne cherches pas un mot.
Question 3.9. Retrouve la fiche dont le titre contient « premier ».
GET pratique-mini/_search
{
"query": {
"match": {
"titre": "premier"
}
}
}match cherche un mot dans le champ titre. La fiche 1 a « Mon premier document » : le mot premier est dedans. La fiche 2 a « Deuxième document, écrit par Bob » : pas ce mot. Une seule hit, "_id": "1".
Ce n'est pas un GET _doc/1. Tu n'as pas besoin de connaître le numéro. Tu poses une question sur le texte. GET _doc/1 va droit au tiroir. _search + match parcourt les feuilles.
Exemple. Dans une bibliothèque : « donne-moi le livre numéro 1 » (_doc/1) contre « donne-moi les livres dont le titre contient premier » (match). Le second marche même si tu as oublié le numéro.
Premier avec une majuscule marcherait aussi : match sur un champ text ne tient pas compte de la casse. C'est pour plus tard, le module sur les analyseurs.
Question 3.10. Supprime la fiche 2, puis l'index.
D'abord la feuille, ensuite l'armoire. L'ordre compte pour comprendre les deux DELETE.
DELETE pratique-mini/_doc/2"result": "deleted". Bob n'est plus là. Alice est encore dans le tiroir 1. _count passe à 1. L'armoire existe toujours.
DELETE pratique-miniL'armoire entière disparaît, Alice comprise. GET pratique-mini/_doc/1 ne répond plus "found": false : il répond index_not_found_exception. Plus de tiroir, plus de fiche.
GET _cat/indices/pratique-*?vLa ligne pratique-mini n'y est plus. S'il reste pratique-mini-strict ou demo-red, les deux DELETE donnés juste avant l'étape 1 les enlèvent.
Exemple. Tu jettes la copie de Bob (_doc/2). Le classeur est encore dans l'étagère. Puis tu jettes le classeur (DELETE pratique-mini). Demander la copie d'Alice n'a plus de sens : le classeur n'est plus là. Ce n'est pas « fiche introuvable », c'est « armoire introuvable ».
Les index du kit (cours, avis, acces) ne commencent pas par pratique-. Ils ne sont pas touchés. Tu peux enchaîner avec l'étape 1 : un PUT pratique-mini neuf.
Les trois parties ci-dessus, c'était le premier passage : tu as tapé, tu as répondu. Maintenant on refait le même parcours, plus lentement. Voici les huit étapes, en gros. Ensuite tu les ouvres une par une.
PUT pratique-mini. Rien dedans. Pas de colonnes, pas de fiche.GET _cat/indices/pratique-mini?v : jaune, 1 réplica. Puis number_of_replicas: 0 : vert.PUT pratique-mini/_doc/1 avec un titre. Tu choisis le numéro 1.GET pratique-mini/_doc/1 : "found": true et _source. Un numéro qui n'existe pas : "found": false.POST pratique-mini/_update/1 : auteur et note s'ajoutent, titre reste. C'est le livrable.PUT _doc/1 qu'à l'étape 3. auteur et note disparaissent. PUT remplace, _update complète._count = 2, _search liste les deux, match sur « premier » ne garde que la 1.DELETE la fiche 2, puis DELETE l'armoire. pratique-* est vide.Ouvre chaque étape. Tape. Compare avec le JSON. C'est le même pratique-mini, repris depuis zéro.
PUT pratique-miniCe que la requête demande : crée un index qui s'appelle pratique-mini. Rien d'autre : pas de colonnes, pas de contenu.
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "pratique-mini"
}À regarder : "acknowledged": true, « c'est fait », et le nom en écho. Le badge en haut à droite de la réponse dit 200 - OK.
pratique- devant ? Tous les index que tu crées dans ce cours portent ce préfixe. Ainsi GET _cat/indices/pratique-*?v liste tout ce qui est à toi et rien d'autre, et cours, avis, acces restent intouchés./. Pratique-Mini serait refusé.400 avec resource_already_exists_exception : l'armoire existe déjà. Ce n'est pas une panne, c'est une réponse.GET _cat/indices/pratique-mini?vCe que la requête demande : une ligne de résumé sur cet index, avec la ligne d'en-tête (?v, verbose).
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open pratique-mini YHjAfGXBTwSZcl7CLcc2jw 1 1 0 0 227b 227b 227bÀ regarder : docs.count 0, l'armoire est vide. Et health yellow avec rep 1 : Elasticsearch a prévu une copie de secours (un réplica) de ton index sur une deuxième machine, et le labo n'en a qu'une. La copie ne peut être placée nulle part, d'où le jaune. Les trois index du kit sont verts parce que leur mapping fixe number_of_replicas: 0. Fais pareil, en une requête :
PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 0 }
}{
"acknowledged": true
}Retape GET _cat/indices/pratique-mini?v :
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
green open pratique-mini YHjAfGXBTwSZcl7CLcc2jw 1 0 0 0 227b 227b 227bÀ regarder : green, rep 0. Ton uuid sera différent : c'est l'identifiant interne de l'index, tiré au hasard à la création.
GET _cluster/health disait "status": "yellow" pour tout le cluster : la couleur du cluster est la pire couleur de ses index. C'est l'explication de la panne « yellow » du catalogue de la leçon 04.GET pratique-mini (sans _cat) rend la fiche complète de l'index : "mappings": { } (vide, aucune fiche rangée) et "settings" avec number_of_replicas.PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}Ce que la requête demande : dans l'armoire pratique-mini, range une fiche (_doc) numéro 1 qui contient un champ titre.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}À regarder : "result": "created" et "_version": 1 : première version de la fiche 1. Équivalent SQL : INSERT INTO pratique_mini (id, titre) VALUES (1, 'Mon premier document'), sauf qu'aucun CREATE TABLE n'a été nécessaire.
GET pratique-mini/_mapping : le champ titre est maintenant déclaré de type text (pour chercher des mots dedans) avec un sous-champ titre.keyword (pour trier ou filtrer sur la valeur exacte). Elasticsearch l'a déduit de la valeur "Mon premier document", une chaîne.1 de _doc/1, c'est toi qui l'as choisi. Les documents du kit font pareil (C0001, A00001…). Si tu écris POST pratique-mini/_doc sans numéro, Elasticsearch invente un _id de vingt caractères ; pratique pour des journaux, pénible pour une fiche que tu veux retrouver à la main._shards, _seq_no, _primary_term sont de la comptabilité interne (sur combien de morceaux l'écriture a été confirmée, quel numéro d'ordre). Tu n'en as pas besoin dans ce cours.GET pratique-mini/_doc/1Ce que la requête demande : donne-moi la fiche numéro 1 de pratique-mini, directement, sans chercher.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}À regarder : "found": true, et _source, ta fiche telle que tu l'as écrite, au caractère près. Équivalent SQL : SELECT * FROM pratique_mini WHERE id = 1.
Essaie une fiche qui n'existe pas : GET pratique-mini/_doc/3.
{
"_index": "pratique-mini",
"_id": "3",
"found": false
}Pas d'erreur, pas de _source : "found": false, badge 404 - Not Found. Elasticsearch a compris la question ; la réponse est « il n'y a rien à ce numéro ».
POST pratique-mini/_update/1
{
"doc": {
"auteur": "Alice",
"note": 5
}
}Ce que la requête demande : mets à jour (_update) la fiche 1 en y ajoutant ces deux champs. Ce qui n'est pas mentionné (titre) reste tel quel.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}À regarder : "result": "updated", "_version": 2. Relis la fiche avec GET pratique-mini/_doc/1 :
{
"_index": "pratique-mini",
"_id": "1",
"_version": 2,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}Trois champs. Le titre est toujours là. Équivalent SQL : UPDATE pratique_mini SET auteur = 'Alice', note = 5 WHERE id = 1, à la différence près qu'en SQL les colonnes auteur et note auraient dû exister avant. C'est ta réponse-livrable : garde-la.
doc dans le corps veut dire « voici les champs à fusionner ». Sans lui, _update ne sait pas quoi faire.GET pratique-mini/_mapping montre maintenant auteur (text + keyword, comme titre) et note de type long, un entier. Elasticsearch a deviné le type à partir de 5. Si tu avais écrit "note": "5" entre guillemets, il aurait déclaré du texte, et tu n'aurais plus pu calculer une moyenne dessus. C'est le sujet de la leçon sur le mapping, au module 2._version compte les écritures sur cette fiche, pas les lectures : GET ne l'incrémente jamais.PUT remplace toutRenvoie exactement la requête de l'étape 3 :
PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}{
"_index": "pratique-mini",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}À regarder : "result": "updated" (pas created : la fiche 1 existait) et "_version": 3. Puis relis-la :
{
"_index": "pratique-mini",
"_id": "1",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}auteur et note ont disparu. PUT _doc/1 ne modifie pas la fiche 1 : il la remplace par ce que tu envoies. Pour compléter sans perdre, c'est POST _update/1 avec doc. Retiens la règle avec les deux verbes : PUT remplace, _update complète. Remets les deux champs avec la requête de l'étape 5 avant de continuer (tu obtiens _version: 4).
PUT pratique-mini/_doc/2
{
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}Réponse : "_id": "2", "result": "created", "_version": 1. Puis compte :
GET pratique-mini/_count{
"count": 2,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
}
}Équivalent SQL : SELECT COUNT(*) FROM pratique_mini. Maintenant, vois tout ce qu'il y a dedans :
GET pratique-mini/_searchCe que la requête demande : cherche dans pratique-mini, sans critère, donc tout.
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "pratique-mini",
"_id": "2",
"_score": 1.0,
"_source": {
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}
},
{
"_index": "pratique-mini",
"_id": "1",
"_score": 1.0,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}
]
}
}À regarder : hits.total.value: 2 (combien de fiches répondent) puis hits.hits, la liste des fiches, chacune avec son _id et son _source. L'ordre des deux peut varier : sans critère, toutes ont le même _score de 1.0. Équivalent SQL : SELECT * FROM pratique_mini.
Enfin, cherche un mot :
GET pratique-mini/_search
{
"query": {
"match": {
"titre": "premier"
}
}
}Ce que la requête demande : les fiches dont le champ titre contient le mot premier.
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.3788134,
"hits": [
{
"_index": "pratique-mini",
"_id": "1",
"_score": 0.3788134,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}
]
}
}À regarder : une seule fiche, la 1, et un _score qui n'est plus 1.0 : c'est la pertinence, « à quel point cette fiche répond à la question ». Le module 3 est consacré à ce chiffre. Équivalent SQL approximatif : SELECT * FROM pratique_mini WHERE titre LIKE '%premier%', sauf que match trouverait aussi Premier avec une majuscule, et le module 2 t'expliquera pourquoi.
_count rend 0 ou 1 juste après une écriture ? Elasticsearch rend les nouvelles fiches visibles à la recherche toutes les secondes, pas à l'instant même. Relance _count : il est à jour. GET _doc/1, lui, est toujours immédiat parce qu'il ne cherche pas, il va droit au numéro. Si tu veux forcer la visibilité immédiate dans un test : PUT pratique-mini/_doc/2?refresh=true.took est le temps de la recherche en millisecondes. timed_out: false : elle a fini dans les délais.GET avec un corps ? C'est une particularité d'Elasticsearch : la recherche est une lecture, donc GET, mais la question tient dans un corps JSON. POST pratique-mini/_search avec le même corps marche aussi ; les deux sont acceptés.DELETE pratique-mini/_doc/2{
"_index": "pratique-mini",
"_id": "2",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}À regarder : "result": "deleted". GET pratique-mini/_count rend 1 (au bout d'une seconde). Équivalent SQL : DELETE FROM pratique_mini WHERE id = 2.
Puis supprime l'armoire entière, fiches comprises :
DELETE pratique-mini{
"acknowledged": true
}Preuve qu'elle n'existe plus, GET pratique-mini/_doc/1 :
{
"error": {
"root_cause": [
{
"type": "index_not_found_exception",
"reason": "no such index [pratique-mini]",
"resource.type": "index_or_alias",
"resource.id": "pratique-mini",
"index_uuid": "_na_",
"index": "pratique-mini"
}
],
"type": "index_not_found_exception",
"reason": "no such index [pratique-mini]",
"resource.type": "index_or_alias",
"resource.id": "pratique-mini",
"index_uuid": "_na_",
"index": "pratique-mini"
},
"status": 404
}À regarder : la différence avec l'étape 4. Fiche absente dans une armoire présente : "found": false, sans erreur. Armoire absente : index_not_found_exception, 404. Les deux sont des réponses normales d'un service qui tourne. Équivalent SQL : DROP TABLE pratique_mini.
GET _cat/indices/pratique-*?vRéponse attendue : la ligne d'en-tête seule. Rien à toi ne traîne dans le cluster, et GET _cat/indices/cours,avis,acces?v montre toujours 504, 609, 12000.
pratique-mini et tu sais pourquoi il était jaune, puis vert.PUT _doc/1 et relue avec GET _doc/1.auteur et note avec POST _update/1 sans perdre titre.PUT _doc/1 effacer les deux champs, et tu sais dire la règle : PUT remplace, _update complète._count a dit 2, _search a listé les deux fiches, match n'en a gardé qu'une.pratique-* est vide.GET pratique-mini/_doc/1 à trois champs (étape 5) comme livrable.400 avec Unexpected character ou was expecting double-quote to start field name → le JSON du corps est mal formé : chaque nom de champ et chaque texte entre guillemets doubles ", une virgule entre les champs, pas de virgule après le dernier. Dev Tools souligne l'endroit.400 avec resource_already_exists_exception sur PUT pratique-mini → l'index existe déjà (tu as relancé l'étape 1). Continue à l'étape 2, ou DELETE pratique-mini pour repartir de zéro.400 avec no handler found for uri → faute de frappe dans un mot en _ : _serch, _doc/ oublié, _udpate. Elasticsearch valide le chemin avant tout le reste.405 avec Incorrect HTTP method for uri [/pratique-mini/_update/1] and method [GET], allowed: [POST] → mauvais verbe pour ce chemin. Le message dit lui-même lequel est accepté.400 avec [UpdateRequest] unknown field [titre] → tu as envoyé les champs directement à _update, sans les envelopper dans "doc": { … }. Ajoute l'enveloppe._count ou _search ne voient pas la fiche que tu viens d'écrire → attends une seconde et relance (voir « Pour bien comprendre » de l'étape 7). GET _doc/1 la voit tout de suite."result": "noop" sur _update → les valeurs envoyées étaient déjà celles de la fiche ; rien à changer, _version n'a pas bougé. Ce n'est pas une erreur."status": "yellow" persiste dans GET _cluster/health après l'étape 2 → un autre index à toi a encore rep 1. GET _cat/indices?v&health=yellow le désigne ; applique-lui le même _settings, ou supprime-le..\labo.ps1 etat ou ./labo.sh etat, puis la leçon 04.