DevTools

Cheatsheet Elasticsearch

Motor de busca e análise distribuído para logs, métricas e pesquisa full-text

Voltar às linguagens
Elasticsearch
91 cards encontrados
Categorias:
Versões:

Cluster e Índices


9 cards
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


9 cards
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 mudou

if_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


10 cards
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_after

from é 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, lte

range 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


9 cards
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 índice

Podes 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: 1710500000000

Campos 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-insensitive

fields 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


9 cards
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


9 cards
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


9 cards
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_size

request_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


9 cards
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


9 cards
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 literais

dissect é 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


9 cards
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=**.disk

Cluster 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.