Indexação e Atualização de Documentos com a API REST do Elasticsearch
Domine as operações básicas de Criar, Ler, Atualizar e Excluir (CRUD) no Elasticsearch usando a API REST. Este guia detalha as requisições HTTP precisas, endpoints e payloads JSON necessários para indexar novos documentos (com ou sem IDs especificados) e realizar atualizações parciais granulares em registros existentes. Aprenda exemplos práticos com `curl` para atualizações atômicas, modificações via script e ingestão eficiente de dados em lote.
Indexação e Atualização de Documentos com a API REST do Elasticsearch
Indexar e atualizar documentos com a API REST do Elasticsearch parece fácil à primeira vista: envie JSON para um endpoint e receba JSON de volta. As partes que importam em produção são mais específicas. Você está criando um novo documento ou substituindo um antigo? Você quer que o Elasticsearch gere o ID, ou precisa de um ID do seu sistema de origem? Você está fazendo uma atualização parcial ou está sobrescrevendo acidentalmente campos que pretendia manter?
Os exemplos abaixo usam localhost:9200, um índice chamado products e curl simples. Em um cluster real, você pode precisar também de HTTPS, autenticação e uma opção de certificado.
curl -u elastic:password --cacert http_ca.crt https://es.example.com:9200/
Criar um documento com ID automático
Use POST /{index}/_doc quando o Elasticsearch puder atribuir o ID do documento.
curl -X POST "localhost:9200/products/_doc" \
-H "Content-Type: application/json" \
-d '{
"sku": "mouse-x1",
"name": "Wireless Mouse X1",
"price": 25.99,
"in_stock": true,
"updated_at": "2026-05-24T09:30:00Z"
}'
Uma resposta bem-sucedida inclui um _id e um result de created.
{
"_index": "products",
"_id": "wI4aQZkB8xExample",
"_version": 1,
"result": "created"
}
IDs automáticos são adequados para dados de eventos, logs, registros de cliques e conteúdo somente de acréscimo. Eles não são ideais quando o mesmo item do mundo real pode chegar novamente mais tarde. Se a mesma atualização de produto for indexada duas vezes com IDs automáticos, você obtém dois documentos.
Indexar com seu próprio ID
Use PUT /{index}/_doc/{id} quando seu sistema de origem já possui um identificador estável.
curl -X PUT "localhost:9200/products/_doc/sku-mouse-x1" \
-H "Content-Type: application/json" \
-d '{
"sku": "mouse-x1",
"name": "Wireless Mouse X1",
"price": 25.99,
"in_stock": true,
"updated_at": "2026-05-24T09:30:00Z"
}'
Se o ID não existir, o Elasticsearch o cria. Se já existir, o Elasticsearch substitui o documento inteiro. Esse comportamento de substituição é útil para trabalhos de sincronização simples, mas também pode excluir campos que você esqueceu de enviar.
Por exemplo, se o documento existente tem category, brand e description, e seu próximo PUT envia apenas price, o _source armazenado se torna apenas os campos dessa nova requisição. Use PUT quando você estiver enviando o documento completo desejado.
Criar apenas se ausente
Se a criação duplicada seria um bug, use a operação de criação:
curl -X PUT "localhost:9200/products/_create/sku-mouse-x1" \
-H "Content-Type: application/json" \
-d '{
"sku": "mouse-x1",
"name": "Wireless Mouse X1",
"price": 25.99
}'
Se o ID já existir, o Elasticsearch retorna um conflito de versão em vez de sobrescrever o documento. Isso é útil para trabalhos de ingestão onde repetir uma mensagem não deve alterar um registro existente.
Atualizar campos parcialmente
Use POST /{index}/_update/{id} com um objeto doc quando você quiser alterar apenas alguns campos.
curl -X POST "localhost:9200/products/_update/sku-mouse-x1" \
-H "Content-Type: application/json" \
-d '{
"doc": {
"price": 22.49,
"in_stock": false,
"updated_at": "2026-05-24T10:15:00Z"
}
}'
O Elasticsearch busca o documento existente internamente, mescla os campos fornecidos e indexa a fonte alterada novamente. É uma atualização parcial do ponto de vista do usuário da API, não uma mutação no local no disco.
Se o documento pode ainda não existir, use doc_as_upsert:
curl -X POST "localhost:9200/products/_update/sku-keyboard-k90" \
-H "Content-Type: application/json" \
-d '{
"doc": {
"sku": "keyboard-k90",
"name": "Mechanical Keyboard K90",
"price": 129.99,
"in_stock": true
},
"doc_as_upsert": true
}'
Isso cria o documento com o conteúdo de doc se ele estiver ausente. Use isso quando seu feed upstream enviar registros de "estado atual" e você não se importar se esta é a primeira vez que o Elasticsearch vê o ID.
Atualizações com script
Scripts são úteis quando o novo valor depende do valor antigo. Um exemplo comum é incrementar um contador:
curl -X POST "localhost:9200/products/_update/sku-mouse-x1" \
-H "Content-Type: application/json" \
-d '{
"script": {
"source": "ctx._source.views = (ctx._source.views ?: 0) + params.count",
"params": {
"count": 1
}
}
}'
Mantenha os scripts pequenos e previsíveis. Eles são poderosos, mas também são mais fáceis de usar incorretamente do que uma atualização simples com doc. Para contadores de alto volume, pense cuidadosamente sobre a taxa de gravação, necessidades de refresh e se o Elasticsearch deve ser o sistema de registro.
Indexação e atualizações em lote
Para mais do que alguns documentos, use _bulk. O corpo da requisição é JSON delimitado por nova linha, e a nova linha final é importante.
cat bulk-products.ndjson
{"index":{"_index":"products","_id":"sku-mouse-x1"}}
{"sku":"mouse-x1","name":"Wireless Mouse X1","price":25.99,"in_stock":true}
{"update":{"_index":"products","_id":"sku-keyboard-k90"}}
{"doc":{"price":119.99,"in_stock":true},"doc_as_upsert":true}
{"delete":{"_index":"products","_id":"sku-old-cable"}}
Envie assim:
curl -X POST "localhost:9200/_bulk" \
-H "Content-Type: application/x-ndjson" \
--data-binary @bulk-products.ndjson
Use --data-binary, não -d simples, para que o curl preserve as novas linhas. Em seguida, inspecione a resposta. Uma requisição em lote pode retornar HTTP 200 enquanto itens individuais falharam.
curl -s -X POST "localhost:9200/_bulk" \
-H "Content-Type: application/x-ndjson" \
--data-binary @bulk-products.ndjson | jq '.errors, .items[] | select(.index.error or .update.error or .delete.error)'
Refresh e visibilidade
Um documento indexado nem sempre é pesquisável imediatamente. O Elasticsearch atualiza os índices periodicamente por padrão. Se você precisar ler o documento pelo ID, GET /products/_doc/sku-mouse-x1 pode encontrá-lo imediatamente. Se você precisar que ele apareça na pesquisa antes de continuar um teste, use refresh=wait_for:
curl -X PUT "localhost:9200/products/_doc/sku-mouse-x1?refresh=wait_for" \
-H "Content-Type: application/json" \
-d '{"sku":"mouse-x1","name":"Wireless Mouse X1","price":25.99}'
Não adicione refreshes forçados a cada gravação de produção sem medir o custo. Eles podem reduzir a taxa de transferência de indexação.
Uma regra prática
Use POST /_doc para dados somente de acréscimo, onde eventos duplicados são aceitáveis ou tratados em outro lugar. Use PUT /_doc/{id} quando a requisição contém o documento completo atual. Use _update quando você quiser alterar apenas certos campos. Use _create quando sobrescrever esconderia um problema de dados. Use _bulk quando o trabalho for mais do que alguns documentos.
A maioria dos bugs de indexação do Elasticsearch vem da escolha da forma de gravação errada. O endpoint deve corresponder aos seus dados de origem, ao seu comportamento de repetição e se o Elasticsearch está armazenando um registro completo ou uma cópia pesquisável do registro de outro sistema.
Verifique os mapeamentos antes de culpar a requisição de gravação
Às vezes, a gravação é bem-sucedida e o resultado da pesquisa ainda parece errado. Isso geralmente é um problema de mapeamento, não um problema de endpoint de indexação.
Verifique o mapeamento:
curl -s "localhost:9200/products/_mapping?pretty"
Se price foi indexado primeiro como texto porque um documento de teste inicial enviou "25.99" como string, as consultas de intervalo podem se comportar mal. Se sku precisa de correspondência exata e agregações, geralmente deve ser um campo keyword ou ter um subcampo keyword. Se os timestamps chegarem em formatos diferentes, alguns documentos podem ser rejeitados durante a indexação enquanto outros são bem-sucedidos.
Para sistemas previsíveis, crie o mapeamento do índice antes da primeira gravação:
curl -X PUT "localhost:9200/products" \
-H "Content-Type: application/json" \
-d '{
"mappings": {
"properties": {
"sku": { "type": "keyword" },
"name": { "type": "text" },
"price": { "type": "double" },
"in_stock": { "type": "boolean" },
"updated_at": { "type": "date" }
}
}
}'
O mapeamento dinâmico é conveniente para exploração. Para ingestão em produção, mapeamentos explícitos impedem que um primeiro documento ruim molde o índice.
Lide com conflitos e repetições deliberadamente
Atualizações concorrentes podem entrar em conflito. Se dois workers atualizarem o mesmo documento quase ao mesmo tempo, um pode ser baseado em uma versão mais antiga. Para repetições simples de atualização, o Elasticsearch suporta retry_on_conflict:
curl -X POST "localhost:9200/products/_update/sku-mouse-x1?retry_on_conflict=3" \
-H "Content-Type: application/json" \
-d '{
"doc": {
"price": 21.99
}
}'
Isso é útil para atualizações de baixo risco, mas não substitui uma propriedade clara. Se um sistema possui nomes de produtos e outro possui inventário, considere atualizar diferentes campos por meio de pipelines bem definidos. Se a ordem dos eventos for importante, inclua timestamps de origem e rejeite atualizações mais antigas em sua camada de ingestão ou com um script cuidadoso.
Leia após gravar durante a depuração
Ao testar um fluxo de indexação, busque o documento pelo ID imediatamente:
curl -s "localhost:9200/products/_doc/sku-mouse-x1?pretty"
Em seguida, pesquise por ele:
curl -s "localhost:9200/products/_search?pretty" \
-H "Content-Type: application/json" \
-d '{
"query": {
"term": {
"sku": "mouse-x1"
}
}
}'
Se GET por ID funciona, mas a pesquisa não, pense em refresh, mapeamento, analisador ou tipo de consulta. Se ambos falharem, pense em erro de indexação, índice errado, ID errado, autenticação ou roteamento.
Para aplicações, registre o índice alvo, o ID do documento, o status da resposta e os erros em nível de item do bulk. Você não precisa registrar todos os documentos completos para sempre, mas durante a implantação esses campos economizam horas.