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
| Tipo | Vantagens | Desvantagens | Quando usar |
|---|---|---|---|
| Nested | Busca independente por objeto, boa performance | Atualizar um item requer reindexar o documento pai | Arrays de objetos com queries independentes |
| Join | Relacionamentos 1:N, atualização independente | Performance inferior, requer routing | Hierarquias profundas com pais/ filhos |
| Flattened | Schema dinâmico, sem mapeamento prévio | Sem busca por campos específicos | Metadados, 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.