kb.erickguedes.com
Elasticsearch: Busca e Analytics

Modelagem de Dados

Aula 6 de 6

Modelagem de Dados no Elasticsearch

Diferente de bancos relacionais, o Elasticsearch é orientado a documentos e denormalizado. A escolha do tipo de campo e da estratégia de modelagem impacta performance, busca e escalabilidade.

Nested vs Join vs Flattened

`json // Nested — Objetos indexados independentemente PUT /pedidos { "mappings": { "properties": { "cliente": { "type": "keyword" }, "itens": { "type": "nested", "properties": { "produto": { "type": "keyword" }, "quantidade": { "type": "integer" }, "preco": { "type": "float" } } } } } }

GET /pedidos/_search { "query": { "nested": { "path": "itens", "query": { "bool": { "must": [ { "term": { "itens.produto": "notebook" } }, { "range": { "itens.quantidade": { "gte": 2 } } } ] } } } } }

// Join — Parent/Child PUT /empresa { "mappings": { "properties": { "relacionamento": { "type": "join", "relations": { "departamento": "funcionario" } }, "nome": { "type": "keyword" } } } }

PUT /empresa/_doc/1 { "nome": "Engenharia", "relacionamento": { "name": "departamento" } }

PUT /empresa/_doc/2?routing=1 { "nome": "João Silva", "departamento_id": 1, "relacionamento": { "name": "funcionario", "parent": "1" } }

// Flattened — Objeto como campo único PUT /logs { "mappings": { "properties": { "metadados": { "type": "flattened" } } } }

PUT /logs/_doc/1 { "mensagem": "Erro no servidor", "metadados": { "host": "server-01", "env": "production", "versao": "2.3.1" } } `

Comparação: Nested vs Join vs Flattened

TipoVantagensDesvantagensQuando usar
NestedBusca independente por objeto, boa performanceAtualizar um item requer reindexar o documento paiArrays de objetos com queries independentes
JoinRelacionamentos 1:N, atualização independentePerformance inferior, requer routingHierarquias profundas com pais/ filhos
FlattenedSchema dinâmico, sem mapeamento prévioSem busca por campos específicosMetadados, logs, dados semi-estruturados

EAV Pattern (Entity-Attribute-Value)

`json PUT /produtos_custom { "mappings": { "dynamic": false, "properties": { "sku": { "type": "keyword" }, "atributos": { "type": "nested", "properties": { "nome": { "type": "keyword" }, "valor": { "type": "keyword" } } } } } }

PUT /produtos_custom/_doc/1 { "sku": "NBT-001", "atributos": [ { "nome": "cor", "valor": "preto" }, { "nome": "tamanho_tela", "valor": "15.6" }, { "nome": "processador", "valor": "i7" } ] } `

Denormalização — Abordagem Recomendada

json PUT /orders { "mappings": { "properties": { "order_id": { "type": "keyword" }, "cliente": { "properties": { "id": { "type": "keyword" }, "nome": { "type": "text" }, "email": { "type": "keyword" } } }, "itens": { "type": "nested", "properties": { "produto_id": { "type": "keyword" }, "produto_nome": { "type": "text" }, "quantidade": { "type": "integer" }, "preco_unitario": { "type": "float" } } }, "total": { "type": "float" }, "data": { "type": "date" } } } }

Data Streams — Time-Series

`json PUT /_index_template/logs_stream { "index_patterns": ["logs-*"], "data_stream": {}, "template": { "settings": { "number_of_shards": 1 } } }

POST /logs-stream/_doc { "@timestamp": "2025-06-01T10:30:00Z", "message": "Request processed", "status": 200, "duration_ms": 45 }

GET /logs-stream/_data_stream/stats `

Reindex e Alias

`json POST /_reindex { "source": { "index": "produtos_v1" }, "dest": { "index": "produtos_v2" } }

POST /_reindex { "source": { "index": "produtos_v1", "query": { "term": { "categoria": "eletronicos" } } }, "dest": { "index": "eletronicos" } }

// Aliases — zero-downtime POST /_aliases { "actions": [ { "add": { "index": "produtos_v2", "alias": "produtos" } }, { "remove": { "index": "produtos_v1", "alias": "produtos" } } ] } `

Rollover

`json PUT /logs-write { "aliases": { "logs": { "is_write_index": true } } }

POST /logs/_rollover { "conditions": { "max_age": "7d", "max_size": "50gb" } } `

Shard Sizing — Regras Práticas

  • Tamanho ideal: 10GB–50GB por shard
  • Máximo recomendado: 100GB por shard
  • Número de shards: min( nós * 20, 1000 )
  • Throughput: ~20MB/s por shard para bulk indexing
  • Heap: 50% da RAM (máx 31GB por JVM)

Lab: Modelagem de E-commerce

`ash

1. Crie índice "produtos" com denormalização completa

2. Crie índice "pedidos" com nested items

3. Indexe dados de exemplo

4. Teste query nested e term

5. Crie alias "produtos-search" apontando para o índice

6. Simule reindex: copie dados para produtos_v2 com mapping modificado

7. Troque o alias para zero-downtime

curl -X POST "http://localhost:9200/_reindex"
-H "Content-Type: application/json"
-d '{"source": {"index": "produtos"}, "dest": {"index": "produtos_v2"}}' `

A modelagem correta — com denormalização, escolha adequada entre nested/join/flattened e shard sizing apropriado — determina o sucesso de um cluster Elasticsearch em produção.