Como ler esta página. Oito etapas, uma consulta por vez. Para cada uma: a consulta a digitar, a resposta exata do laboratório, e o que é preciso olhar nela. Digite você mesmo cada consulta (sem copiar e colar): é escrevendo
PUT,GET,_docque as palavras entram. Os blocos "Para entender bem" são opcionais; abra-os se uma etapa lhe deixar uma dúvida. Se o laboratório não estiver iniciado, volte à prática guiada: a seção Em resumo dá os comandos, kit incluído (https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr).
A prática guiada fez você carregar 504 cursos, 609 avaliações e 12.000 linhas de log de uma vez, com um script. Você viu os números, mas ainda não escreveu nada por conta própria. Aqui, você recomeça do zero: um índice vazio que você cria, uma primeira ficha que você guarda dentro, que você relê, que você completa, depois uma segunda, uma busca, uma exclusão. No fim, você sabe o que é um índice e um documento porque fabricou um, não porque lhe disseram.
Um índice é um armário. Um documento é uma ficha guardada no armário: um pequeno texto JSON com campos. Cada ficha tem um número, seu _id, que permite reencontrá-la diretamente sem buscar. Você não precisa declarar as colunas de antemão: a primeira ficha guardada cria o mapping (a planta do armário) sozinha.
| Elasticsearch | Banco SQL clássico | Nesta prática |
|---|---|---|
| índice | tabela | pratique-mini |
| documento | linha | {"titre": "Mon premier document"} |
| campo | coluna | titre, auteur, note |
_id | chave primária | 1, 2 |
| mapping | esquema da tabela (CREATE TABLE …) | criado automaticamente na etapa 3 |
_source | a linha tal como você a escreveu | o que GET _doc/1 lhe devolve |
Abra http://localhost:5601, menu ☰ → Management → Dev Tools. O painel da esquerda recebe as consultas, o da direita exibe a resposta. Você envia com Ctrl + Enter (Cmd + Enter no macOS) ou o botão ▶ à direita da linha.
Toda consulta tem a mesma forma: um verbo, um caminho, e às vezes um corpo JSON embaixo.
| Verbo | O que faz | Equivalente SQL |
|---|---|---|
GET | ler, sem mudar nada | SELECT |
PUT | criar, ou substituir inteiramente | CREATE TABLE, INSERT (ou substituir a linha) |
POST | agir: atualizar, buscar com um corpo | UPDATE |
DELETE | excluir | DROP TABLE, DELETE |
O caminho diz sobre o que agimos: pratique-mini (o armário), pratique-mini/_doc/1 (a ficha número 1 do armário), pratique-mini/_search (buscar no armário). As palavras que começam por _ são comandos do Elasticsearch, não nomes seus.
PUT pratique-miniO que a consulta pede: crie um índice que se chama pratique-mini. Nada mais: sem colunas, sem conteúdo.
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "pratique-mini"
}O que olhar: "acknowledged": true, "está feito", e o nome em eco. O selo no alto à direita da resposta diz 200 - OK.
pratique- na frente? Todos os índices que você cria neste curso carregam esse prefixo. Assim GET _cat/indices/pratique-*?v lista tudo o que é seu e nada mais, e cours, avis, acces permanecem intocados./. Pratique-Mini seria recusado.400 com resource_already_exists_exception: o armário já existe. Não é uma falha, é uma resposta.GET _cat/indices/pratique-mini?vO que a consulta pede: uma linha de resumo sobre este índice, com a linha de cabeçalho (?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 227bO que olhar: docs.count 0, o armário está vazio. E health yellow com rep 1: o Elasticsearch previu uma cópia de segurança (uma réplica) do seu índice em uma segunda máquina, e o laboratório só tem uma. A cópia não pode ser colocada em nenhum lugar, daí o amarelo. Os três índices do kit são verdes porque seu mapping fixa number_of_replicas: 0. Faça o mesmo, em uma consulta:
PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 0 }
}{
"acknowledged": true
}Redigite 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 227bO que olhar: green, rep 0. Seu uuid será diferente: é o identificador interno do índice, sorteado na criação.
GET _cluster/health dizia "status": "yellow" para todo o cluster: a cor do cluster é a pior cor dos seus índices. É a explicação da falha "yellow" do catálogo da lição 04.GET pratique-mini (sem _cat) devolve a ficha completa do índice: "mappings": { } (vazio, nenhuma ficha guardada) e "settings" com number_of_replicas.PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}O que a consulta pede: no armário pratique-mini, guarde uma ficha (_doc) número 1 que contém um campo titre.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}O que olhar: "result": "created" e "_version": 1: primeira versão da ficha 1. Equivalente SQL: INSERT INTO pratique_mini (id, titre) VALUES (1, 'Mon premier document'), exceto que nenhum CREATE TABLE foi necessário.
GET pratique-mini/_mapping: o campo titre está agora declarado do tipo text (para buscar palavras dentro) com um subcampo titre.keyword (para ordenar ou filtrar pelo valor exato). O Elasticsearch o deduziu do valor "Mon premier document", uma string.1 de _doc/1 foi você quem escolheu. Os documentos do kit fazem o mesmo (C0001, A00001…). Se você escrever POST pratique-mini/_doc sem número, o Elasticsearch inventa um _id de vinte caracteres; prático para logs, incômodo para uma ficha que você quer reencontrar à mão._shards, _seq_no, _primary_term são contabilidade interna (em quantos pedaços a escrita foi confirmada, qual número de ordem). Você não precisa deles neste curso.GET pratique-mini/_doc/1O que a consulta pede: dê-me a ficha número 1 de pratique-mini, diretamente, sem buscar.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}O que olhar: "found": true, e _source, sua ficha tal como você a escreveu, caractere por caractere. Equivalente SQL: SELECT * FROM pratique_mini WHERE id = 1.
Experimente uma ficha que não existe: GET pratique-mini/_doc/3.
{
"_index": "pratique-mini",
"_id": "3",
"found": false
}Sem erro, sem _source: "found": false, selo 404 - Not Found. O Elasticsearch entendeu a pergunta; a resposta é "não há nada nesse número".
POST pratique-mini/_update/1
{
"doc": {
"auteur": "Alice",
"note": 5
}
}O que a consulta pede: atualize (_update) a ficha 1 acrescentando a ela estes dois campos. O que não é mencionado (titre) permanece como está.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}O que olhar: "result": "updated", "_version": 2. Releia a ficha com 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"
}
}Três campos. O título continua lá. Equivalente SQL: UPDATE pratique_mini SET auteur = 'Alice', note = 5 WHERE id = 1, com a diferença de que em SQL as colunas auteur e note deveriam ter existido antes. Esta é a sua resposta-entregável: guarde-a.
doc no corpo quer dizer "eis os campos a fundir". Sem ela, _update não sabe o que fazer.GET pratique-mini/_mapping mostra agora auteur (text + keyword, como titre) e note do tipo long, um inteiro. O Elasticsearch adivinhou o tipo a partir de 5. Se você tivesse escrito "note": "5" entre aspas, ele teria declarado texto, e você não poderia mais calcular uma média sobre ele. É o assunto da lição sobre o mapping, no módulo 2._version conta as escritas nesta ficha, não as leituras: GET nunca o incrementa.PUT substitui tudoReenvie exatamente a consulta da etapa 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
}O que olhar: "result": "updated" (não created: a ficha 1 existia) e "_version": 3. Depois releia-a:
{
"_index": "pratique-mini",
"_id": "1",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}auteur e note desapareceram. PUT _doc/1 não modifica a ficha 1: ele a substitui pelo que você envia. Para completar sem perder, é POST _update/1 com doc. Guarde a regra com os dois verbos: PUT substitui, _update completa. Recoloque os dois campos com a consulta da etapa 5 antes de continuar (você obtém _version: 4).
PUT pratique-mini/_doc/2
{
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}Resposta: "_id": "2", "result": "created", "_version": 1. Depois conte:
GET pratique-mini/_count{
"count": 2,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
}
}Equivalente SQL: SELECT COUNT(*) FROM pratique_mini. Agora, veja tudo o que há dentro:
GET pratique-mini/_searchO que a consulta pede: busque em pratique-mini, sem critério, portanto tudo.
{
"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"
}
}
]
}
}O que olhar: hits.total.value: 2 (quantas fichas respondem) e depois hits.hits, a lista das fichas, cada uma com seu _id e seu _source. A ordem das duas pode variar: sem critério, todas têm o mesmo _score de 1.0. Equivalente SQL: SELECT * FROM pratique_mini.
Por fim, busque uma palavra:
GET pratique-mini/_search
{
"query": {
"match": {
"titre": "premier"
}
}
}O que a consulta pede: as fichas cujo campo titre contém a palavra 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"
}
}
]
}
}O que olhar: uma única ficha, a 1, e um _score que não é mais 1.0: é a relevância, "até que ponto esta ficha responde à pergunta". O módulo 3 é dedicado a esse número. Equivalente SQL aproximado: SELECT * FROM pratique_mini WHERE titre LIKE '%premier%', exceto que match encontraria também Premier com maiúscula, e o módulo 2 explicará por quê.
_count devolve 0 ou 1 logo após uma escrita? O Elasticsearch torna as novas fichas visíveis à busca a cada segundo, não no mesmo instante. Reexecute _count: está atualizado. GET _doc/1, por sua vez, é sempre imediato porque não busca, vai direto ao número. Se você quiser forçar a visibilidade imediata em um teste: PUT pratique-mini/_doc/2?refresh=true.took é o tempo da busca em milissegundos. timed_out: false: ela terminou dentro do prazo.GET com um corpo? É uma particularidade do Elasticsearch: a busca é uma leitura, portanto GET, mas a pergunta cabe em um corpo JSON. POST pratique-mini/_search com o mesmo corpo também funciona; os dois são aceitos.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
}O que olhar: "result": "deleted". GET pratique-mini/_count devolve 1 (após um segundo). Equivalente SQL: DELETE FROM pratique_mini WHERE id = 2.
Depois exclua o armário inteiro, fichas incluídas:
DELETE pratique-mini{
"acknowledged": true
}Prova de que ele não existe mais, 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
}O que olhar: a diferença em relação à etapa 4. Ficha ausente em um armário presente: "found": false, sem erro. Armário ausente: index_not_found_exception, 404. Os dois são respostas normais de um serviço que roda. Equivalente SQL: DROP TABLE pratique_mini.
GET _cat/indices/pratique-*?vResposta esperada: só a linha de cabeçalho. Nada seu ficou para trás no cluster, e GET _cat/indices/cours,avis,acces?v mostra ainda 504, 609, 12000.
pratique-mini e sabe por que ele estava amarelo, depois verde.PUT _doc/1 e a releu com GET _doc/1.auteur e note com POST _update/1 sem perder titre.PUT _doc/1 apagar os dois campos, e sabe dizer a regra: PUT substitui, _update completa._count disse 2, _search listou as duas fichas, match só guardou uma.pratique-* está vazio.GET pratique-mini/_doc/1 com três campos (etapa 5) como entregável.400 com Unexpected character ou was expecting double-quote to start field name → o JSON do corpo está malformado: cada nome de campo e cada texto entre aspas duplas ", uma vírgula entre os campos, nenhuma vírgula após o último. O Dev Tools sublinha o lugar.400 com resource_already_exists_exception em PUT pratique-mini → o índice já existe (você reexecutou a etapa 1). Continue na etapa 2, ou DELETE pratique-mini para recomeçar do zero.400 com no handler found for uri → erro de digitação em uma palavra com _: _serch, _doc/ esquecido, _udpate. O Elasticsearch valida o caminho antes de tudo o mais.405 com Incorrect HTTP method for uri [/pratique-mini/_update/1] and method [GET], allowed: [POST] → verbo errado para este caminho. A mensagem diz ela mesma qual é aceito.400 com [UpdateRequest] unknown field [titre] → você enviou os campos diretamente a _update, sem envolvê-los em "doc": { … }. Acrescente o envelope._count ou _search não veem a ficha que você acabou de escrever → aguarde um segundo e reexecute (veja "Para entender bem" da etapa 7). GET _doc/1 a vê imediatamente."result": "noop" em _update → os valores enviados já eram os da ficha; nada a mudar, _version não se moveu. Não é um erro."status": "yellow" persiste em GET _cluster/health após a etapa 2 → outro índice seu ainda tem rep 1. GET _cat/indices?v&health=yellow o aponta; aplique a ele o mesmo _settings, ou exclua-o..\labo.ps1 etat ou ./labo.sh etat, depois a lição 04.