Cheatsheet Elasticsearch
Motor de busca e análise distribuído para logs, métricas e pesquisa full-text
Elasticsearch
Cluster e Índices
Estado do cluster
GET /_cluster/health GET /_cluster/health?level=indices GET /_cluster/stats // Status: green (ok), yellow (sem réplicas), red (shards faltam)
_cluster/health mostra o estado geral. green = tudo OK, yellow = réplicas não alocadas, red = shards primários em falta. Monitorizar constantemente.
Reindex
POST /_reindex
{
"source": { "index": "produtos-v1" },
"dest": { "index": "produtos-v2" }
}
// Com filtro:
POST /_reindex
{
"source": {
"index": "logs",
"query": { "range": { "data": { "gte": "2024-01-01" } } }
},
"dest": { "index": "logs-2024" }
}_reindex copia documentos entre índices. Útil para migrar mappings ou filtrar dados. Aceita query no source para copiar só um subconjunto. Operação assíncrona.
Component templates
PUT /_component_template/base-settings
{
"template": {
"settings": { "number_of_shards": 1 }
}
}
PUT /_index_template/logs
{
"index_patterns": ["logs-*"],
"composed_of": ["base-settings", "logs-mappings"]
}Component templates são blocos reutilizáveis de settings/mappings. composed_of combina vários num index template. Facilita manutenção e consistência entre índices.
Listar nós e índices
GET /_cat/nodes?v GET /_cat/indices?v&s=index GET /_cat/shards?v GET /_cat/allocation?v // Parâmetro v = mostra cabeçalhos // s = ordenar por campo
A API _cat é legível para humanos. ?v mostra cabeçalhos, &s=campo ordena. _cat/indices lista índices com tamanho, docs e saúde.
Index templates
PUT /_index_template/logs-template
{
"index_patterns": ["logs-*"],
"priority": 100,
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"mensagem": { "type": "text" }
}
}
}
}index_templates aplicam settings/mappings automaticamente a novos índices que correspondem ao index_patterns. Essencial para séries temporais (logs, métricas).
Criar índice
PUT /produtos
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}PUT /nome cria um índice. number_of_shards define partições primárias (fixo após criação). number_of_replicas são cópias para redundância (ajustável).
Shards e réplicas
// Ver distribuição de shards
GET /_cat/shards/produtos?v
// Mover shard manualmente
POST /_cluster/reroute
{
"commands": [{
"move": {
"index": "produtos", "shard": 0,
"from_node": "node1", "to_node": "node2"
}
}]
}Shards são partições horizontais do índice. Réplicas são cópias para alta disponibilidade. Shards primários são fixos na criação; réplicas são ajustáveis dinamicamente.
Gerir índices
GET /produtos/_settings
GET /produtos/_mapping
PUT /produtos/_settings
{ "number_of_replicas": 2 }
DELETE /produtos
POST /produtos/_close
POST /produtos/_open_settings e _mapping mostram configuração. DELETE apaga o índice. _close/_open desativa/reativa sem apagar (poupa recursos).
Rollover
POST /logs-000001/_rollover
{
"conditions": {
"max_age": "7d",
"max_docs": 10000000,
"max_primary_shard_size": "50gb"
}
}_rollover cria um novo índice quando condições são atingidas (idade, docs, tamanho). Usado com aliases e ILM para gestão automática de índices temporais.
Documentos
Indexar (auto-ID)
POST /produtos/_doc
{
"nome": "Portátil Pro",
"preco": 1299.99,
"tags": ["tech", "portátil"],
"stock": 15
}
// Resposta: { "_id": "abc123", "result": "created" }POST /indice/_doc indexa com ID automático. O documento é analisado e indexado para busca. result: "created" confirma a criação. Quase tempo real (refresh 1s).
Atualizar (script)
POST /produtos/_update/1
{
"script": {
"source": "ctx._source.stock -= params.qtd",
"params": { "qtd": 1 }
}
}
// Upsert com script:
POST /contadores/_update/views
{
"script": { "source": "ctx._source.total += 1" },
"upsert": { "total": 1 }
}script permite lógica em Painless. ctx._source acede aos campos. params evita hardcoding. upsert cria o doc se não existir.
Update by query
POST /produtos/_update_by_query
{
"query": {
"term": { "categoria": "informática" }
},
"script": {
"source": "ctx._source.desconto = 0.1"
}
}_update_by_query aplica um script a todos os documentos que correspondem. Útil para migrações e atualizações em massa. Assíncrono — verifica progresso com _tasks.
Indexar (ID manual)
PUT /produtos/_doc/1
{
"nome": "Rato Wireless",
"preco": 29.99
}
// Se já existe, sobrescreve (result: "updated")
// Para garantir criação apenas:
PUT /produtos/_create/1
{ "nome": "Rato" }PUT /indice/_doc/ID define o ID manualmente. Se existir, sobrescreve. _create falha se o documento já existir (evita overwrites acidentais).
Apagar documento
DELETE /produtos/_doc/1
// Apagar por query
POST /produtos/_delete_by_query
{
"query": {
"term": { "stock": 0 }
}
}DELETE /indice/_doc/ID remove um documento. _delete_by_query remove todos que correspondem à query. Operação assíncrona — usa wait_for_completion=false para não bloquear.
Obter documento
GET /produtos/_doc/1
// Só o source (sem metadata)
GET /produtos/_source/1
// Campos específicos
GET /produtos/_doc/1?_source=nome,preco
// Múltiplos documentos
POST /produtos/_mget
{ "ids": ["1", "2", "3"] }GET /indice/_doc/ID retorna documento + metadata (_version, _seq_no). _source filtra campos. _mget obtém vários numa chamada.
Bulk API
POST /_bulk
{"index": {"_index": "produtos", "_id": "1"}}
{"nome": "Teclado", "preco": 49}
{"index": {"_index": "produtos", "_id": "2"}}
{"nome": "Monitor", "preco": 299}
{"update": {"_index": "produtos", "_id": "1"}}
{"doc": {"preco": 45}}
{"delete": {"_index": "produtos", "_id": "2"}}_bulk executa múltiplas operações numa chamada. Formato: linha de ação + linha de dados. Ações: index, create, update, delete. Máx. recomendado: 5-15 MB por request.
Atualizar (parcial)
POST /produtos/_update/1
{
"doc": {
"preco": 999.99,
"em_promocao": true
}
}_update com "doc" faz merge parcial — só altera os campos indicados. Internamente faz get + reindex. Mais eficiente que reenviar o documento completo.
Optimistic concurrency
// Obter versão atual
GET /produtos/_doc/1
// → "_seq_no": 5, "_primary_term": 1
// Atualizar com versão
PUT /produtos/_doc/1?if_seq_no=5&if_primary_term=1
{
"nome": "Rato v2",
"preco": 34.99
}
// Falha com 409 se versão mudouif_seq_no e if_primary_term implementam controlo de concorrência optimista. Se outro processo alterou o documento, retorna 409 Conflict. Evita overwrites perdidos.
Busca e Filtros
match (full-text)
GET /produtos/_search
{
"query": {
"match": {
"nome": "portátil pro"
}
}
}match analisa o texto e busca por tokens. "portátil pro" → busca "portátil" OR "pro". Usa o analyzer do campo. Ideal para campos text com busca natural.
match_phrase e fuzzy
// Frase exata (ordem importa)
{ "match_phrase": { "nome": "portátil pro" } }
// Com slop (tolerância de distância)
{ "match_phrase": { "nome": { "query": "portátil rápido", "slop": 2 } } }
// Fuzzy (tolerar typos)
{ "match": { "nome": { "query": "portatil", "fuzziness": "AUTO" } } }match_phrase exige tokens na ordem exata. slop permite distância entre palavras. fuzziness: "AUTO" tolera erros de escrita (1-2 caracteres). Ótimo para UX de pesquisa.
Paginação (from/size)
GET /produtos/_search
{
"query": { "match_all": {} },
"from": 20,
"size": 10
}
// Limite padrão: from + size <= 10000
// Para mais, usar search_afterfrom é o offset, size o número de resultados. Limite: from + size ≤ 10000 (configurável via max_result_window). Para datasets grandes, usa search_after.
term (correspondência exata)
GET /produtos/_search
{
"query": {
"term": {
"status": "ativo"
}
}
}
// Múltiplos valores:
{ "terms": { "tags": ["tech", "gaming"] } }term busca o valor exato sem análise. Para campos keyword, boolean, number, date. terms aceita array (OR). Não usar em campos text.
multi_match
GET /produtos/_search
{
"query": {
"multi_match": {
"query": "portátil",
"fields": ["nome^3", "descricao", "tags^2"],
"type": "best_fields"
}
}
}multi_match busca em múltiplos campos. ^3 dá peso triplo ao campo. Tipos: best_fields (padrão), most_fields, cross_fields, phrase.
Query string e simple_query_string
{
"query_string": {
"query": "(portátil OR tablet) AND -usado",
"default_field": "nome"
}
}
// Versão segura (sem erros de sintaxe):
{
"simple_query_string": {
"query": "portátil +pro -usado",
"fields": ["nome", "descricao"]
}
}query_string suporta sintaxe Lucene (AND, OR, NOT, *, ~). simple_query_string é mais seguro — nunca lança erro de parse. Ideal para input direto do utilizador.
bool (combinar condições)
GET /produtos/_search
{
"query": {
"bool": {
"must": [{ "match": { "nome": "pro" } }],
"must_not": [{ "term": { "status": "esgotado" } }],
"should": [{ "term": { "tags": "promoção" } }],
"filter": [{ "range": { "preco": { "lte": 1500 } } }]
}
}
}bool combina queries: must (AND, com score), filter (AND, sem score, com cache), must_not (NOT), should (OR, opcional). O mais usado.
wildcard, prefix e exists
// Padrão com * e ?
{ "wildcard": { "codigo": "PRD-*" } }
// Prefixo
{ "prefix": { "nome": "port" } }
// Campo existe
{ "exists": { "field": "tags" } }
// Regex (usar com cuidado)
{ "regexp": { "codigo": "PRD-[0-9]+" } }wildcard usa * (qualquer sequência) e ? (um caractere). prefix busca pelo início. exists verifica presença do campo. regexp é poderoso mas lento.
range (intervalos)
{ "range": { "preco": { "gte": 100, "lte": 500 } } }
{ "range": { "data": { "gte": "2024-01-01", "lt": "2025-01-01" } } }
{ "range": { "idade": { "gt": 18 } } }
// Operadores: gt, gte, lt, lterange filtra por intervalo numérico ou temporal. Operadores: gt (maior), gte (maior ou igual), lt (menor), lte (menor ou igual). Funciona com datas ISO.
Ordenação (sort)
GET /produtos/_search
{
"query": { "match_all": {} },
"sort": [
{ "preco": "asc" },
{ "nome.raw": "desc" },
{ "_score": "desc" }
]
}sort ordena resultados. asc ou desc. Campos text precisam de subcampo keyword para ordenar. Ao usar sort, o _score é desativado por padrão.
Mappings
Definir mapping
PUT /produtos
{
"mappings": {
"properties": {
"nome": { "type": "text" },
"preco": { "type": "float" },
"tags": { "type": "keyword" },
"criado": { "type": "date" },
"ativo": { "type": "boolean" }
}
}
}mappings define o esquema do índice — tipos e comportamento de cada campo. Deve ser definido antes de indexar. Tipos errados causam problemas de busca irreversíveis.
Ver e atualizar mapping
GET /produtos/_mapping
// Adicionar novo campo (permitido):
PUT /produtos/_mapping
{
"properties": {
"categoria": { "type": "keyword" }
}
}
// ❌ Não é possível mudar tipo de campo existente
// Solução: reindex para novo índicePodes adicionar campos novos a um mapping existente. Mas não podes alterar o tipo de um campo já criado. Para mudar tipos, cria novo índice e usa _reindex.
Index e doc_values
// Desativar indexação (só armazenar):
"nota_interna": {
"type": "text",
"index": false
}
// Desativar doc_values (sem ordenação/agregação):
"descricao_longa": {
"type": "keyword",
"doc_values": false
}index: false exclui o campo da busca (poupa espaço). doc_values: false desativa ordenação/agregação. Otimiza armazenamento para campos que só precisam de ser retornados.
Tipos de campo
text // full-text (analisado, para busca) keyword // exato (não analisado, para filtros/ordenação) integer, long, float, double, short, byte boolean date // "yyyy-MM-dd" ou epoch ip // endereços IPv4/IPv6 geo_point // coordenadas geográficas nested // objetos independentes object // objeto achatado (padrão)
text é analisado (tokenizado) para busca full-text. keyword é exato — para filtros, agregações e ordenação. nested mantém objetos como documentos separados.
Date formats
"criado": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
}
// "strict_date_optional_time" (padrão)
// Aceita: "2024-03-15" ou "2024-03-15T10:30:00Z"
// epoch_millis: 1710500000000Campos date aceitam formatos configuráveis. || separa múltiplos formatos. epoch_millis aceita timestamp Unix em ms. O padrão é strict_date_optional_time.
Multi-fields
"nome": {
"type": "text",
"fields": {
"raw": { "type": "keyword" },
"lower": {
"type": "keyword",
"normalizer": "lowercase"
}
}
}
// nome → busca full-text
// nome.raw → ordenação/filtro exato
// nome.lower → filtro case-insensitivefields indexa o mesmo valor de formas diferentes. nome para busca, nome.raw para ordenação/agregação. Padrão essencial para campos que precisam de ambos os usos.
Nested vs Object
// object (padrão) - achatado, perde relação:
"comentarios": { "type": "object" }
// nested - cada elemento é independente:
"comentarios": {
"type": "nested",
"properties": {
"autor": { "type": "keyword" },
"texto": { "type": "text" }
}
}
// Query nested:
{ "nested": { "path": "comentarios", "query": { ... } } }object achata arrays — perde a relação entre campos do mesmo elemento. nested mantém cada objeto independente. Usa nested quando precisas de filtrar por combinação de campos.
Dynamic mapping
PUT /produtos
{
"mappings": {
"dynamic": "strict",
"properties": {
"nome": { "type": "text" }
}
}
}
// "true" (padrão): infere tipos automaticamente
// "false": ignora campos não mapeados
// "strict": rejeita campos não mapeados (erro)dynamic controla campos não previstos. true (padrão) infere tipos — arriscado em produção. strict rejeita campos desconhecidos. Recomendado: mapear explicitamente.
Normalizers
PUT /produtos
{
"settings": {
"analysis": {
"normalizer": {
"lowercase": {
"type": "custom",
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"properties": {
"codigo": { "type": "keyword", "normalizer": "lowercase" }
}
}
}normalizer aplica transformações a campos keyword na indexação (lowercase, asciifolding). Ao contrário de analyzer, opera no texto inteiro. Útil para filtros case-insensitive.
Agregações
terms (agrupar por valor)
GET /produtos/_search
{
"size": 0,
"aggs": {
"por_tag": {
"terms": { "field": "tags", "size": 20 }
}
}
}
// → buckets: [{key:"tech", doc_count:45}, ...]terms agrupa por valores distintos de um campo keyword. size: 0 no search evita retornar documentos. Retorna buckets com key e contagem. O mais usado.
stats e cardinality
"aggs": {
"estatisticas": {
"stats": { "field": "preco" }
},
"categorias_unicas": {
"cardinality": { "field": "categoria" }
}
}
// stats → count, min, max, avg, sum
// cardinality → contagem distinta (aproximada)stats retorna count, min, max, avg e sum de uma vez. cardinality conta valores distintos (como COUNT DISTINCT). É aproximada (HyperLogLog) — erro ~1%.
composite (paginação de aggs)
"aggs": {
"todos_grupos": {
"composite": {
"size": 100,
"sources": [
{ "cat": { "terms": { "field": "categoria" } } },
{ "marca": { "terms": { "field": "marca" } } }
],
"after": { "cat": "tech", "marca": "ASUS" }
}
}
}composite pagina agregações com after. Supera o limite de 10000 buckets do terms. Combina múltiplas fontes. Ideal para exportar todos os grupos de um dataset grande.
Métricas (avg, sum, min, max)
"aggs": {
"preco_medio": { "avg": { "field": "preco" } },
"total_stock": { "sum": { "field": "stock" } },
"mais_barato": { "min": { "field": "preco" } },
"mais_caro": { "max": { "field": "preco" } },
"valor_total": {
"script": { "source": "doc['preco'].value * doc['stock'].value" }
}
}Agregações de métrica: avg, sum, min, max. script permite cálculos custom. Funciona em campos numéricos. Retorna valor único por agregação.
range e histogram
"aggs": {
"faixas_preco": {
"range": {
"field": "preco",
"ranges": [
{ "to": 50 },
{ "from": 50, "to": 200 },
{ "from": 200 }
]
}
},
"histograma": {
"histogram": { "field": "preco", "interval": 50 }
}
}range agrupa em intervalos customizados. histogram usa intervalos fixos. Ambos retornam buckets com contagens. Útil para distribuições e relatórios por faixa.
date_histogram
"aggs": {
"vendas_mes": {
"date_histogram": {
"field": "criado",
"calendar_interval": "month",
"format": "yyyy-MM",
"min_doc_count": 0
}
}
}date_histogram agrupa por período temporal. calendar_interval: minute, hour, day, week, month, quarter, year. min_doc_count: 0 inclui períodos vazios. Essencial para séries temporais.
filter e filters
"aggs": {
"ativos": {
"filter": { "term": { "status": "ativo" } },
"aggs": { "media": { "avg": { "field": "preco" } } }
},
"por_status": {
"filters": {
"filters": {
"disponiveis": { "term": { "stock_gt": 0 } },
"esgotados": { "term": { "stock": 0 } }
}
}
}
}filter restringe uma agregação a documentos que cumprem condição. filters cria múltiplos buckets nomeados com condições diferentes. Mais eficiente que terms para poucos valores.
Agregações aninhadas
"aggs": {
"por_categoria": {
"terms": { "field": "categoria" },
"aggs": {
"preco_medio": { "avg": { "field": "preco" } },
"top_produto": {
"top_hits": { "size": 1, "sort": [{ "vendas": "desc" }] }
}
}
}
}Agregações podem conter sub-agregações (aggs dentro de aggs). Métricas são calculadas por bucket. top_hits retorna documentos representativos de cada grupo.
percentiles
"aggs": {
"latencia_percentis": {
"percentiles": {
"field": "tempo_resposta",
"percents": [50, 90, 95, 99]
}
},
"percentile_ranks": {
"percentile_ranks": {
"field": "tempo_resposta",
"values": [200, 500]
}
}
}percentiles mostra distribuição (p50, p90, p99). Essencial para latências. percentile_ranks diz que percentagem está abaixo de um valor. Aproximado (algoritmo t-digest).
Análise de Texto
Analyze API
POST /_analyze
{
"analyzer": "standard",
"text": "O Portátil Pro é muito rápido!"
}
// → ["o", "portátil", "pro", "é", "muito", "rápido"]
// Testar com analyzer do índice:
POST /produtos/_analyze
{ "field": "nome", "text": "Portátil Gaming" }_analyze mostra como o texto é tokenizado. Essencial para debug de busca. Testa com o analyzer do campo real usando POST /indice/_analyze com field.
Token filters
lowercase // minúsculas asciifolding // remove acentos (ã → a) stop // remove stop words stemmer // reduz à raiz (portuguese) synonym // sinónimos length // filtra por comprimento truncate // trunca tokens longos unique // remove tokens duplicados
Token filters transformam tokens após tokenização. asciifolding normaliza acentos. stemmer reduz palavras à raiz. synonym expande com sinónimos. Encadeiam-se em ordem.
Search analyzer vs Index analyzer
"nome": {
"type": "text",
"analyzer": "autocomplete",
"search_analyzer": "standard"
}
// Indexação: edge_ngram (gera prefixos)
// Busca: standard (busca token inteiro)
// "gat" → match em "gato", "gatinho"analyzer é usado na indexação, search_analyzer na busca. Separar permite indexar com ngrams mas buscar com token inteiro. Essencial para autocomplete eficiente.
Analyzers integrados
standard // unicode, lowercase (padrão) simple // só letras, minúsculas whitespace // separa por espaços (sem lowercase) stop // standard + remove stop words keyword // sem análise (texto inteiro = 1 token) english // stemming + stop words inglesas
standard é o padrão — tokeniza por Unicode e faz lowercase. keyword não analisa (texto inteiro). stop remove palavras comuns. Escolhe conforme o caso de uso.
Stemming (português)
"filter": {
"pt_stem": {
"type": "stemmer",
"language": "light_portuguese"
}
}
// "portáteis" → "portátil"
// "computadores" → "computador"
// "programação" → "program"
// Opções: "portuguese" (agressivo) ou "light_portuguese"stemmer reduz palavras à raiz. light_portuguese é menos agressivo (recomendado). Melhora recall (encontra plurais/conjugações). Pode reduzir precisão — testar sempre.
Analyzer personalizado
"settings": {
"analysis": {
"analyzer": {
"meu_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "pt_stem"]
}
},
"filter": {
"pt_stem": { "type": "stemmer", "language": "light_portuguese" }
}
}
}Analyzer custom combina tokenizer + filters. asciifolding remove acentos. light_portuguese faz stemming (portáteis → portátil). Ordem dos filters importa.
Synonyms
"filter": {
"meus_sinonimos": {
"type": "synonym",
"synonyms": [
"portátil, notebook, laptop",
"telemóvel, celular, smartphone",
"ecrã, tela, monitor"
]
}
}synonym expande tokens com equivalentes. "portátil" → busca também "notebook" e "laptop". Formato: valores separados por vírgula. Pode usar ficheiro externo com synonyms_path.
Tokenizers
standard // unicode word boundaries
whitespace // separa por espaços
keyword // sem tokenização (1 token)
pattern // regex custom: "[^\\p{L}\\d]+"
ngram // subsequências: "cat" → "ca", "at"
edge_ngram // prefixos: "gato" → "g", "ga", "gat"
path_hierarchy // "a/b/c" → "a", "a/b", "a/b/c"tokenizer divide o texto em tokens. standard é o mais usado. edge_ngram é ideal para autocomplete (prefixos). pattern usa regex custom para divisão.
Autocomplete (edge_ngram)
"settings": {
"analysis": {
"analyzer": {
"autocomplete": {
"tokenizer": "autocomplete_tokenizer"
}
},
"tokenizer": {
"autocomplete_tokenizer": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 15,
"token_chars": ["letter", "digit"]
}
}
}
}edge_ngram gera prefixos progressivos: "gato" → "ga", "gat", "gato". Ideal para autocomplete. Usa analyzer diferente na indexação (edge_ngram) e na busca (standard).
Performance
Filter vs Query (cache)
"bool": {
"filter": [
{ "term": { "status": "ativo" } },
{ "range": { "preco": { "lte": 100 } } }
],
"must": [
{ "match": { "nome": "portátil" } }
]
}filter não calcula score e é cacheado — muito mais rápido. Usa filter para condições exatas (status, range, term). must só para relevância full-text. Regra: filter por padrão.
Refresh e flush
// Forçar refresh (documentos ficam pesquisáveis) POST /produtos/_refresh // Flush (gravar segmentos em disco) POST /produtos/_flush // Ver segmentos: GET /_cat/segments/produtos?v // Refresh interval padrão: 1s (near real-time)
refresh torna documentos pesquisáveis (cria segmento em memória). Padrão: 1s. flush persiste em disco. Aumentar refresh_interval melhora throughput de escrita.
Profile API
GET /produtos/_search
{
"profile": true,
"query": {
"match": { "nome": "portátil" }
}
}
// → mostra tempo de cada fase:
// build_scorer, next_doc, advance, score, etc."profile": true detalha o tempo de execução de cada componente da query. Mostra shards, collectors e tempo por operação. Ferramenta essencial para diagnosticar queries lentas.
Source filtering
GET /produtos/_search
{
"_source": ["nome", "preco"],
"query": { "match_all": {} }
}
// Excluir campos grandes:
{ "_source": { "excludes": ["descricao_longa"] } }_source limita os campos retornados. Reduz largura de banda e memória. excludes remove campos pesados. Não afeta a busca — só o que é devolvido ao cliente.
Force merge
// Consolidar segmentos (só para índices read-only!) POST /logs-2024/_forcemerge?max_num_segments=1 // Ver segmentos antes/depois: GET /_cat/segments/logs-2024?v // ⚠️ NUNCA em índices ativos (muito I/O)
_forcemerge consolida segmentos num só. Melhora performance de busca. Só usar em índices que não recebem mais writes (após rollover). Operação pesada — executar em off-peak.
search_after (paginação profunda)
// Página 1:
GET /produtos/_search
{
"size": 100,
"sort": [{ "criado": "desc" }, { "_id": "asc" }],
"query": { "match_all": {} }
}
// Página 2 (usar último sort value):
{ "search_after": ["2024-06-15T10:00:00Z", "doc_99"] }search_after pagina além do limite de 10000. Usa os valores de sort do último documento como cursor. Mais eficiente que scroll. Requer sort com campo único (tiebreaker).
Routing
// Indexar com routing custom:
PUT /produtos/_doc/1?routing=tenant_42
{ "nome": "Produto", "tenant": "tenant_42" }
// Buscar só no shard do tenant:
GET /produtos/_search?routing=tenant_42
{
"query": { "match": { "nome": "produto" } }
}routing direciona documentos para um shard específico. Buscas com routing consultam só 1 shard em vez de todos. Essencial para multi-tenancy. Reduz latência drasticamente.
Bulk indexing otimizado
// Antes da ingestão em massa:
PUT /logs/_settings
{
"number_of_replicas": 0,
"refresh_interval": "30s"
}
// Após ingestão, restaurar:
PUT /logs/_settings
{
"number_of_replicas": 1,
"refresh_interval": "1s"
}Para bulk indexing: desativa replicas e aumenta refresh_interval. Reduz I/O drasticamente. Restaura após terminar. Usa batches de 5-15 MB com _bulk.
Request cache
// Ativar cache de resultados (padrão: só size=0)
GET /produtos/_search?request_cache=true
{
"size": 0,
"aggs": { "media": { "avg": { "field": "preco" } } }
}
// Limpar cache:
POST /produtos/_cache/clear
// Ver uso:
GET /_cat/nodes?v&h=name,request_cache_memory_sizerequest_cache guarda resultados de agregações no nó. Por padrão, só cacheia queries com size: 0. Invalidado automaticamente no refresh. Ideal para dashboards com dados pouco mutáveis.
Avançado
Aliases
POST /_aliases
{
"actions": [
{ "remove": { "index": "produtos-v1", "alias": "produtos" } },
{ "add": { "index": "produtos-v2", "alias": "produtos" } }
]
}
// Apps usam sempre o alias "produtos"
// Troca de índice é transparente (zero downtime)aliases são ponteiros para índices. Permite trocar de índice sem alterar código. Operações atómicas (remove + add numa chamada). Essencial para deploy sem downtime.
Reindex com transformação
POST /_reindex
{
"source": { "index": "antigo" },
"dest": { "index": "novo" },
"script": {
"source": """
ctx._source.nome_completo = ctx._source.nome;
ctx._source.remove('nome');
ctx._source.migrado = true;
"""
}
}_reindex com script transforma documentos durante a migração. Renomeia campos, adiciona flags, remove dados. Útil para evoluir mappings sem downtime.
Cross-cluster search
// Configurar cluster remoto:
PUT /_cluster/settings
{
"persistent": {
"cluster.remote.dc2.seeds": ["dc2-node1:9300"]
}
}
// Buscar em ambos:
GET /produtos,dc2:produtos/_search
{
"query": { "match": { "nome": "portátil" } }
}Cross-cluster search consulta múltiplos clusters Elasticsearch numa query. Configura com cluster.remote. Referencia como cluster:indice. Útil para multi-datacenter.
ILM (Index Lifecycle Management)
PUT /_ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": { "actions": {
"rollover": { "max_size": "50gb", "max_age": "7d" }
}},
"warm": { "min_age": "7d", "actions": {
"shrink": { "number_of_shards": 1 },
"forcemerge": { "max_num_segments": 1 }
}},
"delete": { "min_age": "30d", "actions": { "delete": {} } }
}
}
}ILM automatiza o ciclo de vida: hot → warm → cold → delete. rollover cria novo índice ao atingir limites. shrink e forcemerge otimizam no warm. Essencial para logs.
Percolator (alertas)
// Registar queries:
PUT /alertas/_doc/1
{ "query": { "match": { "mensagem": "erro crítico" } } }
// Verificar documento contra queries registadas:
GET /alertas/_search
{
"query": {
"percolate": {
"field": "query",
"document": { "mensagem": "Ocorreu um erro crítico no servidor" }
}
}
}percolator inverte a busca: regista queries e verifica documentos contra elas. Ideal para alertas e notificações. "Quais queries correspondem a este documento?"
Suggesters (sugestões)
GET /produtos/_search
{
"suggest": {
"correcao": {
"text": "portatil gaming",
"term": { "field": "nome", "size": 3 }
},
"frase": {
"text": "portatil gamming",
"phrase": { "field": "nome" }
}
}
}term suggester sugere correções por token. phrase suggester sugere frases completas (mais inteligente). completion suggester usa FST para autocomplete ultra-rápido.
Scripted fields
GET /produtos/_search
{
"query": { "match_all": {} },
"script_fields": {
"preco_com_iva": {
"script": { "source": "doc['preco'].value * 1.23" }
},
"desconto_pct": {
"script": { "source": "(doc['preco_antigo'].value - doc['preco'].value) / doc['preco_antigo'].value * 100" }
}
}
}script_fields calcula campos na hora com Painless. Não são indexados — calculados a cada query. Útil para valores derivados. Mais lento que campos pré-calculados.
Completion suggester
// Mapping:
"sugestao": {
"type": "completion",
"analyzer": "simple"
}
// Query:
GET /produtos/_search
{
"suggest": {
"auto": {
"prefix": "port",
"completion": { "field": "sugestao", "size": 5, "fuzzy": { "fuzziness": "AUTO" } }
}
}
}completion suggester é otimizado para autocomplete. Usa estrutura FST em memória — extremamente rápido. fuzzy tolera typos. Indexa sugestões num campo dedicado tipo completion.
Highlighting
GET /produtos/_search
{
"query": { "match": { "descricao": "portátil rápido" } },
"highlight": {
"pre_tags": ["<mark>"],
"post_tags": ["</mark>"],
"fields": {
"descricao": { "fragment_size": 150, "number_of_fragments": 3 }
}
}
}highlight retorna trechos com termos encontrados destacados. pre_tags/post_tags definem o markup. fragment_size controla o tamanho dos excertos. Essencial para UX de busca.
Pipelines e Ingestão
Criar pipeline
PUT /_ingest/pipeline/limpar-produtos
{
"description": "Normalizar dados de produtos",
"processors": [
{ "lowercase": { "field": "nome" } },
{ "trim": { "field": "nome" } },
{ "remove_null": { "field": "descricao" } },
{ "set": {
"field": "criado_em",
"value": "{{_ingest.timestamp}}"
}}
]
}Ingest pipelines transformam documentos antes de indexar. Processadores encadeiam-se em ordem. Criados com PUT /_ingest/pipeline/nome. Executados no nó de ingestão.
Grok (parse de logs)
{
"grok": {
"field": "mensagem",
"patterns": [
"%{IP:ip} - %{WORD:user} [%{HTTPDATE:data}] \"%{WORD:metodo} %{URIPATHPARAM:url}\" %{INT:status} %{INT:bytes}"
]
}
}
// Input: "192.168.1.1 - admin [10/Oct/2024:13:55:36] \"GET /api\" 200 1234"
// → { ip, user, data, metodo, url, status, bytes }grok extrai campos estruturados de texto não-estruturado com padrões. %{TIPO:campo} captura valores. Essencial para parse de logs. Pode ser lento — testar performance.
Listar e apagar pipelines
// Listar todos:
GET /_ingest/pipeline
// Ver um específico:
GET /_ingest/pipeline/limpar-produtos
// Apagar:
DELETE /_ingest/pipeline/limpar-produtos
// Testar processor individual:
POST /_ingest/pipeline/_simulate
{
"pipeline": { "processors": [{ "uppercase": { "field": "nome" } }] },
"docs": [{ "_source": { "nome": "teste" } }]
}GET /_ingest/pipeline lista todos. DELETE remove. _simulate inline testa processors sem criar pipeline. Útil para experimentação rápida.
Usar pipeline na indexação
// Documento único:
PUT /produtos/_doc/1?pipeline=limpar-produtos
{ "nome": " PORTÁTIL PRO " }
// Bulk:
POST /_bulk?pipeline=limpar-produtos
{"index": {"_index": "produtos"}}
{"nome": "TECLADO"}
// Pipeline padrão do índice:
PUT /produtos/_settings
{ "index.default_pipeline": "limpar-produtos" }Aplica com ?pipeline=nome na indexação. Ou define default_pipeline nas settings do índice para aplicar automaticamente. _simulate testa sem indexar.
Dissect (parse simples)
{
"dissect": {
"field": "mensagem",
"pattern": "%{ip} - %{user} [%{data}] \"%{metodo} %{url}\" %{status} %{bytes}"
}
}
// Mais rápido que grok (sem regex)
// Usa delimitadores literaisdissect é uma alternativa mais rápida ao grok para logs com formato fixo. Usa delimitadores literais em vez de regex. Menos flexível mas muito mais performante.
Simular pipeline
POST /_ingest/pipeline/limpar-produtos/_simulate
{
"docs": [
{ "_source": { "nome": " PORTÁTIL ", "preco": -5 } },
{ "_source": { "nome": "Rato", "descricao": null } }
]
}
// Mostra resultado de cada processor_simulate testa o pipeline com documentos de exemplo sem indexar. Mostra o output de cada processor. Essencial para debug. Revela erros antes de produção.
Enrich pipeline
// 1. Criar política de enrich:
PUT /_enrich/policy/geo-ip
{
"geoip": {
"source": { "index": "ips" },
"match_field": "ip",
"enrich_fields": ["pais", "cidade"]
}
}
// 2. Executar:
POST /_enrich/policy/geo-ip/_execute
// 3. Usar no pipeline:
{ "enrich": { "policy_name": "geo-ip", "field": "ip", "target_field": "geo" } }enrich adiciona dados de um índice de referência durante ingestão. Exemplo: adicionar geo-localização a partir de IP. Cria política, executa, e usa como processor.
Processors comuns
set // definir campo remove // remover campo rename // renomear campo lowercase // minúsculas uppercase // maiúsculas trim // remover espaços convert // mudar tipo (string → integer) split // string → array join // array → string gsub // regex replace
Processors básicos: set, remove, rename para reestruturação. lowercase, trim, gsub para limpeza. convert muda tipos. split/join para arrays.
Error handling (on_failure)
{
"processors": [
{
"grok": {
"field": "mensagem",
"patterns": ["%{IP:ip}"],
"on_failure": [
{ "set": { "field": "erro_parse", "value": "{{_ingest.on_failure_message}}" } },
{ "set": { "field": "ip", "value": "unknown" } }
]
}
}
]
}on_failure define o que fazer se um processor falhar. Evita rejeição do documento inteiro. Regista o erro em campo dedicado. Pode ter on_failure por processor ou ao nível do pipeline.
Segurança e Monitorização
API keys
POST /_security/api_key
{
"name": "app-readonly",
"expiration": "30d",
"role_descriptors": {
"readonly": {
"indices": [{
"names": ["produtos"],
"privileges": ["read"]
}]
}
}
}
// → { "id": "...", "api_key": "...", "encoded": "base64..." }API keys autenticam sem user/password. Define permissões granulares por índice. expiration limita validade. Usa header Authorization: ApiKey encoded. Ideal para apps e serviços.
Hot threads e tasks
// Threads mais ativas: GET /_nodes/hot_threads // Tasks em execução: GET /_tasks?actions=*search*&detailed=true // Cancelar task lenta: POST /_tasks/task_id:12345/_cancel // Stats por nó: GET /_nodes/stats/jvm,os,process
hot_threads mostra threads com mais CPU. _tasks lista operações em curso. _cancel termina queries lentas. _nodes/stats dá JVM, disco e processo por nó.
Diagnóstico de problemas
// Cluster vermelho:
GET /_cluster/health?level=shards
GET /_cluster/allocation/explain
// Rejeições de escrita:
GET /_nodes/stats/thread_pool
// → "write": { "rejected": 150 }
// Circuit breaker (memória):
GET /_nodes/stats/breaker
// Disk watermark:
GET /_cluster/settings?include_defaults=true&filter_path=**.diskCluster red → allocation/explain. Rejeições → verificar thread_pool. OOM → breaker stats. Disco cheio → disk watermark (85%/90%/95%). Abordagem sistemática de troubleshooting.
Roles e privilégios
POST /_security/role/app_writer
{
"indices": [{
"names": ["produtos", "produtos-*"],
"privileges": ["read", "write", "create_index"],
"field_security": { "grant": ["nome", "preco", "tags"] },
"query": { "term": { "tenant": "app1" } }
}],
"cluster": ["monitor"]
}roles definem permissões por índice e cluster. field_security limita campos visíveis. query restringe documentos (row-level security). Combina com API keys para multi-tenancy.
Snapshots (backup)
// Registar repositório:
PUT /_snapshot/meu_backup
{
"type": "fs",
"settings": { "location": "/mnt/backups" }
}
// Criar snapshot:
PUT /_snapshot/meu_backup/snap-2024-01?wait_for_completion=true
{ "indices": "produtos,logs-*" }
// Restaurar:
POST /_snapshot/meu_backup/snap-2024-01/_restore
{ "indices": "produtos" }snapshots são backups incrementais do cluster. Regista repositório (fs, S3, GCS). PUT cria snapshot, _restore repõe. Incremental — só guarda mudanças. Essencial em produção.
Cluster health detalhado
GET /_cluster/health?level=shards
GET /_cluster/allocation/explain
GET /_cluster/settings
GET /_cluster/pending_tasks
// Alocar shard não atribuído:
POST /_cluster/reroute
{
"commands": [{ "allocate_replica": {
"index": "produtos", "shard": 1, "node": "node2"
}}]
}_cluster/health?level=shards mostra estado por shard. allocation/explain explica por que um shard não está alocado. reroute força alocação manual. Essencial para troubleshooting.
Slow logs
PUT /produtos/_settings
{
"index.search.slowlog.threshold.query.warn": "10s",
"index.search.slowlog.threshold.query.info": "5s",
"index.search.slowlog.threshold.fetch.warn": "1s",
"index.indexing.slowlog.threshold.index.warn": "10s"
}Slow logs registam queries e indexing lentos. Níveis: warn, info, debug, trace. Thresholds em tempo. Logs em logs/nome_index_search_slowlog.log. Essencial para diagnóstico.
Monitorização de índices
GET /_cat/indices?v&s=store.size:desc GET /_cat/count/produtos?v GET /_stats GET /produtos/_stats // Top índices por tamanho: GET /_cat/indices?v&h=index,docs.count,store.size&s=store.size:desc&bytes=mb
_cat/indices com s=store.size:desc ordena por tamanho. _stats dá métricas detalhadas (indexing, search, merge). Monitorizar crescimento para planear capacidade.
Segurança (TLS e auth)
// elasticsearch.yml: xpack.security.enabled: true xpack.security.transport.ssl.enabled: true xpack.security.http.ssl.enabled: true xpack.security.http.ssl.keystore.path: http.p12 // Definir passwords: bin/elasticsearch-setup-passwords interactive // Autenticação básica: curl -u elastic:password https://localhost:9200
xpack.security ativa autenticação e TLS. transport.ssl encripta comunicação entre nós. http.ssl encripta cliente-servidor. Sempre ativar em produção. Nunca expor sem auth.