-
Notifications
You must be signed in to change notification settings - Fork 3
06 ‐ Index Settings: Entendendo Mapping, Analyzers e Aliases
O mapping define como os campos de um documento são armazenados e indexados no Elasticsearch. É equivalente ao schema de uma tabela em um banco de dados relacional — mas com diferenças importantes: no Elasticsearch, o mapping pode ser definido explicitamente antes da indexação ou inferido automaticamente pelo próprio Elasticsearch ao receber o primeiro documento.
Definir o mapping explicitamente é uma boa prática em ambientes de produção. Sem isso, o Elasticsearch pode inferir tipos incorretos — por exemplo, tratar um campo de CEP como long em vez de keyword — e o mapping não pode ser alterado depois que os dados já foram indexados. Para mudar o tipo de um campo, é necessário reindexar os dados.
Os tipos mais usados no dia a dia:
| Tipo | Uso típico | Exemplo de valor |
|---|---|---|
text |
Texto livre — será analisado (tokenizado) para full-text search | "Produto de alta qualidade" |
keyword |
Valores exatos — usado para filtros, ordenação e agregações (ex: status, UF, ID) |
"SP", "ativo", "CA-2024-001"
|
integer |
Números inteiros de 32 bits. Faixa: -2.147.483.648 a 2.147.483.647 |
42, -10, 2024 (idade, ano, quantidade) |
long |
Números inteiros de 64 bits. Faixa muito maior que integer |
1704067200000 (timestamps Unix em milissegundos, IDs grandes) |
double |
Números decimais de 64 bits (alta precisão) |
19.99, -0.5, 3.14159 (preços, coordenadas, taxas) |
float |
Números decimais de 32 bits (menor precisão, ocupa menos espaço) |
1.5, 98.6 (métricas de sistema, onde precisão absoluta não é crítica) |
byte |
Inteiro de 8 bits. Faixa: -128 a 127 |
42 (flags, níveis de prioridade com poucos valores) |
short |
Inteiro de 16 bits. Faixa: -32.768 a 32.767 |
1000 (portas de rede, códigos pequenos) |
date |
Datas e timestamps |
"2024-05-01", "2024-05-01T10:30:00Z"
|
boolean |
Verdadeiro ou falso |
true, false
|
geo_point |
Coordenadas geográficas (latitude/longitude) | "-23.5505, -46.6333" |
nested |
Arrays de objetos com relacionamento interno preservado | Lista de itens de um pedido, cada um com nome e preço |
object |
Objeto JSON aninhado | { "rua": "Av. Brasil", "numero": 100 } |
Dica prática: na dúvida entre
integerelong, prefiralong— o custo de armazenamento é pequeno e evita problemas de overflow em campos que podem crescer. Entrefloatedouble, usedoublepara valores financeiros onde precisão importa, efloatapenas em métricas de monitoramento onde uma pequena perda de precisão é aceitável.
PUT /clientes
{
"mappings": {
"properties": {
"nome": { "type": "text" },
"idade": { "type": "integer" },
"email": { "type": "keyword" }
}
}
}É possível indexar o mesmo campo com dois tipos diferentes usando fields. Isso é útil quando você precisa tanto de full-text search quanto de filtros/ordenação no mesmo campo:
PUT /clientes
{
"mappings": {
"properties": {
"nome": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}Nesse exemplo, nome é indexado como text (para buscas por texto) e nome.raw como keyword (para ordenação e agregações exatas).
Todo documento no Elasticsearch possui, além dos campos definidos pelo usuário, um conjunto de campos especiais chamados meta fields. Eles são gerados e mantidos pelo próprio Elasticsearch e fornecem informações sobre o documento em si.
Os meta fields mais relevantes no dia a dia:
| Meta field | O que contém |
|---|---|
_id |
Identificador único do documento dentro do índice. Pode ser definido na indexação ou gerado automaticamente pelo Elasticsearch. |
_index |
Nome do índice ao qual o documento pertence. |
_source |
O conteúdo JSON original do documento, exatamente como foi indexado. É o que aparece nos resultados de busca. Pode ser desabilitado para economizar espaço, mas aí o documento não pode ser recuperado na íntegra. |
_routing |
Controla em qual shard o documento é armazenado. Por padrão, é calculado com base no _id. Pode ser customizado para garantir que documentos relacionados fiquem no mesmo shard. |
_meta |
Campo livre para armazenar metadados sobre o mapping — como versão, descrição ou informações de governança. Não é usado pelo Elasticsearch na busca. |
_seq_no |
Número de sequência do documento — incrementado a cada operação de escrita. Usado para controle de concorrência otimista. |
_primary_term |
Junto com _seq_no, identifica unicamente uma versão do documento. Útil para operações condicionais de update e delete. |
Exemplo: recuperar um documento e observar seus meta fields:
GET /clientes/_doc/1A resposta inclui _id, _index, _seq_no, _primary_term e o _source com os dados do documento.
Exemplo: desabilitar o _source (use com cautela — o documento não poderá ser recuperado na íntegra):
PUT /metricas
{
"mappings": {
"_source": {
"enabled": false
}
}
}Além do type, cada campo pode receber parâmetros adicionais que controlam como ele é indexado e armazenado:
| Parâmetro | Aplica a | O que faz |
|---|---|---|
index |
Todos | Se false, o campo é armazenado no _source mas não é indexado — não pode ser usado em buscas ou filtros. Útil para campos grandes que só precisam ser recuperados, não filtrados. |
store |
Todos | Se true, o campo é armazenado separadamente do _source. Raramente necessário — o _source já permite recuperar qualquer campo. |
doc_values |
keyword, numéricos, datas |
Estrutura de dados em disco usada para ordenação e agregações. Habilitado por padrão nesses tipos. Desabilitar economiza disco mas remove a capacidade de ordenar e agregar pelo campo. |
norms |
text |
Informações de comprimento do campo usadas no cálculo de score. Desabilitar ("norms": false) economiza memória em campos que são usados apenas como filtros, não para busca por relevância. |
copy_to |
Todos | Copia o valor do campo para outro campo virtual, permitindo fazer buscas em múltiplos campos como se fossem um só. |
fields |
Todos | Define sub-campos com tipos ou analyzers diferentes — o multi-field descrito acima. |
null_value |
keyword, numéricos |
Define um valor substituto para indexar quando o campo for null. Sem isso, campos nulos não são indexados e não aparecem em filtros. |
eager_global_ordinals |
keyword |
Pré-carrega os ordinals globais na memória ao reabrir o índice. Melhora o desempenho de agregações terms em campos de alta cardinalidade que são consultados com muita frequência. |
Exemplo combinando parâmetros:
PUT /pedidos
{
"mappings": {
"properties": {
"descricao": {
"type": "text",
"norms": false,
"copy_to": "busca_geral"
},
"status": {
"type": "keyword",
"null_value": "desconhecido"
},
"valor_bruto": {
"type": "double",
"index": false
},
"busca_geral": {
"type": "text"
}
}
}
}Nesse exemplo: descricao não usa norms (economiza memória); status indexa o valor "desconhecido" quando o campo vier nulo; valor_bruto é armazenado mas não indexado (só para recuperação); e o campo virtual busca_geral recebe cópias de outros campos para buscas combinadas.
Quando nenhum mapping é definido, o Elasticsearch infere os tipos automaticamente ao indexar o primeiro documento:
POST /clientes/_doc/1
{
"nome": "Maria",
"idade": 28
}O Elasticsearch inferirá nome como text (com subcampo keyword automático) e idade como long.
O comportamento do mapeamento dinâmico é controlado pelo parâmetro dynamic, com três valores possíveis:
| Valor | Comportamento |
|---|---|
true (padrão) |
Novos campos são detectados e adicionados ao mapping automaticamente |
false |
Novos campos são aceitos e armazenados no _source, mas não são indexados — não podem ser pesquisados |
strict |
Documentos com campos não mapeados são rejeitados com erro |
Exemplo com dynamic: strict:
PUT /clientes
{
"mappings": {
"dynamic": "strict",
"properties": {
"codigo": { "type": "integer" },
"nome": { "type": "text" }
}
}
}Com essa configuração, qualquer documento que contenha campos além de codigo e nome será rejeitado pelo Elasticsearch.
Permitem definir regras de mapeamento para campos novos com base em padrões de nome ou tipo. São aplicadas somente quando o mapeamento dinâmico está ativo e um campo novo é encontrado.
Exemplo — todos os campos do tipo string que comecem com logradouro devem ser indexados como keyword:
PUT /clientes
{
"mappings": {
"dynamic_templates": [
{
"logradouros_as_keywords": {
"match_mapping_type": "string",
"match_pattern": "regex",
"match": "^logradouro.*",
"mapping": {
"type": "keyword"
}
}
}
]
}
}Outro exemplo comum — tratar todos os campos de string como keyword por padrão:
PUT /clientes
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}A análise de texto é o processo que o Elasticsearch aplica sobre campos do tipo text no momento da indexação e da busca. Ela transforma o texto bruto em uma lista de termos (tokens) que serão armazenados no índice invertido.
Um analyzer é composto por três partes, aplicadas em sequência:
-
Character Filters: processam o texto bruto antes da tokenização. Podem remover ou substituir caracteres — por exemplo, remover tags HTML ou converter
&emand. -
Tokenizer: divide o texto em tokens. O tokenizer
standarddivide por espaços e pontuação, removendo a pontuação dos tokens resultantes. Cada analyzer tem exatamente um tokenizer. -
Token Filters: processam cada token gerado pelo tokenizer. Podem converter para minúsculas (
lowercase), remover stopwords (stop), aplicar stemming, adicionar sinônimos, entre outros.
O Elasticsearch vem com vários analyzers prontos para uso:
| Analyzer | O que faz |
|---|---|
standard |
Tokeniza por espaços e pontuação, converte para minúsculas. É o padrão para campos text. |
simple |
Tokeniza por qualquer caractere não-letra, converte para minúsculas |
whitespace |
Tokeniza apenas por espaços — preserva pontuação |
keyword |
Não tokeniza — trata o campo inteiro como um único token |
portuguese |
Analyzer com stemming e stopwords em português |
english |
Analyzer com stemming e stopwords em inglês |
A API _analyze permite testar como um texto será processado por um analyzer, sem precisar indexar nada:
GET /_analyze
{
"analyzer": "standard",
"text": "Texto para análise!"
}Testando apenas o tokenizer:
POST /_analyze
{
"tokenizer": "standard",
"text": "Quick brown fox."
}Testando um analyzer definido inline — útil para testar sem precisar de um índice criado:
POST /_analyze
{
"tokenizer": {
"type": "edge_ngram",
"min_gram": 3,
"max_gram": 10,
"token_chars": ["letter", "digit"]
},
"text": "GOL Linhas Aereas"
}Para testar um analyzer customizado de um índice específico (como
my_analyzer_ngram_3), usePOST /nome-do-indice/_analyze— mas o índice precisa existir e ter o analyzer configurado. Esse exemplo prático está no Lab 6.5, onde o índicefornecedoré criado com esse analyzer.
Normalizers são semelhantes aos analyzers, mas aplicados a campos do tipo keyword. A diferença principal: um normalizer sempre produz exatamente um token por entrada — ele transforma o valor sem dividi-lo. São usados para normalizar valores antes de armazená-los, como converter para minúsculas.
PUT /meu_index
{
"settings": {
"analysis": {
"normalizer": {
"meu_normalizer": {
"type": "custom",
"char_filter": [],
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"meu_campo_keyword": {
"type": "keyword",
"normalizer": "meu_normalizer"
}
}
}
}Com esse normalizer, o valor "BOA TARDE" será armazenado e indexado como "boa tarde", tornando as buscas case-insensitive nesse campo.
POST /meu_index/_doc/
{
"meu_campo_keyword": "BOA TARDE"
}GET /meu_index/_search
{
"size": 0,
"aggs": {
"meus_valores": {
"terms": {
"field": "meu_campo_keyword"
}
}
}
}Um alias é um nome alternativo que aponta para um ou mais índices. Para quem consome os dados (aplicações, dashboards, queries), o alias funciona exatamente como um índice — mas por trás pode estar apontando para um, vários índices ou até para um subconjunto filtrado de um índice.
Casos de uso comuns:
- Abstração de versão: renomear ou reindexar dados sem alterar o nome que as aplicações usam
- Alias multi-índice: fazer uma query em vários índices ao mesmo tempo por um único nome
- Alias filtrado: expor apenas um subconjunto de documentos de um índice (ex: apenas registros de um cliente específico)
- Write index: controlar em qual índice as escritas são direcionadas (usado pelo ILM)
POST /_aliases
{
"actions": [
{
"add": {
"index": "clientes",
"alias": "clientes_atuais"
}
}
]
}A partir desse momento, clientes_atuais pode ser usado no lugar de clientes em qualquer operação de leitura.
POST /_aliases
{
"actions": [
{
"add": {
"index": "clientes",
"alias": "clientes_adultos",
"filter": {
"range": {
"idade": { "gte": 18 }
}
}
}
}
]
}O alias clientes_adultos expõe apenas documentos de clientes com 18 anos ou mais. O filtro é aplicado automaticamente — quem usa o alias não precisa saber que ele existe.
POST /_aliases
{
"actions": [
{
"remove": {
"index": "clientes",
"alias": "clientes_atuais"
}
}
]
}GET /_cat/aliases?vNeste laboratório, vamos criar um índice clientes com um mapping explícito para campos conhecidos e um dynamic template para tratar automaticamente campos de endereço como keyword.
PUT /clientes
{
"mappings": {
"dynamic_templates": [
{
"logradouros_as_keywords": {
"match_mapping_type": "string",
"match_pattern": "regex",
"match": "^logradouro.*",
"mapping": {
"type": "keyword"
}
}
}
],
"properties": {
"codigo": {
"type": "integer"
},
"nome": {
"type": "text",
"fields": {
"keyword": { "type": "keyword" }
}
},
"sexo": { "type": "keyword" },
"estado_civil": { "type": "keyword" },
"data_nascimento": { "type": "date" },
"caracteristicas": { "type": "text" }
}
}
}Explicação dos campos:
-
codigo: número inteiro -
nome: texto livre com subcampokeywordpara ordenação e agregações -
sexoeestado_civil: valores exatos, sem análise de texto -
data_nascimento: campo de data -
caracteristicas: texto livre para full-text search -
dynamic_templates: qualquer campo novo que comece comlogradouroserá automaticamente indexado comokeyword
POST /clientes/_doc/1
{
"codigo": 123,
"nome": "João Silva",
"sexo": "masculino",
"estado_civil": "casado",
"data_nascimento": "1980-05-15",
"caracteristicas": "Amigável, extrovertido, atencioso",
"logradouro_principal": "Rua das Flores",
"logradouro_secundario": "Avenida das Arvores"
}Os campos logradouro_principal e logradouro_secundario não estão definidos no mapping — serão detectados pelo dynamic template e indexados como keyword automaticamente.
GET /clientes/_mappingConfirme que logradouro_principal e logradouro_secundario aparecem com o tipo keyword no mapping retornado.
Testando dynamic: false — campos novos são armazenados mas não indexados:
PUT /clientes_strict
{
"mappings": {
"dynamic": "false",
"properties": {
"codigo": { "type": "integer" },
"nome": { "type": "text" }
}
}
}Indexe um documento com um campo extra:
POST /clientes_strict/_doc/1
{
"codigo": 1,
"nome": "Teste",
"campo_novo": "valor ignorado"
}Tente buscar pelo campo_novo — nenhum resultado será retornado, pois o campo não foi indexado.
Testando dynamic: strict — documentos com campos não mapeados são rejeitados:
PUT /clientes_rigido
{
"mappings": {
"dynamic": "strict",
"properties": {
"codigo": { "type": "integer" },
"nome": { "type": "text" }
}
}
}POST /clientes_rigido/_doc/1
{
"codigo": 1,
"nome": "Teste",
"campo_nao_mapeado": "isso vai falhar"
}O Elasticsearch retornará um erro de mapping informando que campo_nao_mapeado não está definido no mapping do índice.
O edge_ngram é um tokenizer que gera tokens progressivos a partir do início de cada palavra. Por exemplo, o texto "GOL" com min_gram: 3 e max_gram: 5 gera os tokens GOL, GOLL, GOLLI (se o texto fosse mais longo). Isso é especialmente útil para implementar busca progressiva enquanto o usuário digita — semelhante ao autocomplete.
PUT /fornecedor
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer_ngram_3": {
"tokenizer": "split_3_ngram",
"filter": ["lowercase"]
}
},
"tokenizer": {
"split_3_ngram": {
"type": "edge_ngram",
"min_gram": 3,
"max_gram": 15,
"token_chars": ["letter", "digit", "whitespace"]
}
}
}
},
"mappings": {
"properties": {
"codigo": { "type": "integer" },
"nome_fornecedor": {
"type": "text",
"fields": { "keyword": { "type": "keyword" } }
},
"nome_fornecedor_engram": {
"type": "text",
"analyzer": "my_analyzer_ngram_3",
"search_analyzer": "standard",
"fields": { "keyword": { "type": "keyword" } }
},
"cnpj": { "type": "keyword" },
"endereco": { "type": "keyword" },
"bairro": { "type": "keyword" },
"cidade": { "type": "keyword" },
"uf": { "type": "keyword" }
}
}
}Nota importante sobre
search_analyzer: no camponome_fornecedor_engram, o analyzer de indexação é omy_analyzer_ngram_3(que gera os tokens em ngram), mas o analyzer de busca é ostandard. Isso é intencional — na indexação queremos gerar todos os tokens progressivos, mas na busca queremos tratar o termo digitado pelo usuário como um token inteiro, não tokenizá-lo em ngrams. Usar o mesmo analyzer de indexação na busca produziria resultados incorretos.
Veja como o texto será dividido em tokens durante a indexação:
POST /fornecedor/_analyze
{
"tokenizer": "split_3_ngram",
"text": "GOLLINHASAEREAS"
}Observe que serão gerados tokens progressivos: GOL, GOLL, GOLLI, GOLLL... até o max_gram configurado.
POST /fornecedor/_doc/1
{
"codigo": 123,
"nome_fornecedor": "GOL Linhas Aereas",
"nome_fornecedor_engram": "GOL Linhas Aereas",
"cnpj": "12222334000101",
"endereco": "Rua das Flores, 100",
"bairro": "Centro",
"cidade": "Caxias",
"uf": "RJ"
}POST /fornecedor/_doc/2
{
"codigo": 124,
"nome_fornecedor": "TAM Linhas Aereas",
"nome_fornecedor_engram": "TAM Linhas Aereas",
"cnpj": "12222334000102",
"endereco": "Avenida Brasil, 200",
"bairro": "Fulano",
"cidade": "Santos",
"uf": "SP"
}GET /fornecedor/_search
{
"query": {
"match": {
"nome_fornecedor_engram": "TAM"
}
}
}Graças ao edge_ngram, mesmo digitando apenas TAM a busca encontrará TAM Linhas Aereas. Teste também com GOL e compare os resultados.
Neste laboratório, vamos criar dois índices representando a matriz e a filial de uma empresa, unificá-los com um alias e criar uma visão filtrada por estado.
PUT /fornecedor_matriz
{
"mappings": {
"properties": {
"codigo": { "type": "integer" },
"nome_fornecedor": {
"type": "text",
"fields": { "keyword": { "type": "keyword" } }
},
"cnpj": { "type": "keyword" },
"endereco": { "type": "keyword" },
"bairro": { "type": "keyword" },
"cidade": { "type": "keyword" },
"uf": { "type": "keyword" }
}
}
}PUT /fornecedor_filial
{
"mappings": {
"properties": {
"codigo": { "type": "integer" },
"nome_fornecedor": {
"type": "text",
"fields": { "keyword": { "type": "keyword" } }
},
"cnpj": { "type": "keyword" },
"endereco": { "type": "keyword" },
"bairro": { "type": "keyword" },
"cidade": { "type": "keyword" },
"uf": { "type": "keyword" }
}
}
}POST /fornecedor_matriz/_doc/1
{
"codigo": 124,
"nome_fornecedor": "TAM Linhas Aereas",
"cnpj": "12222334000102",
"endereco": "Rua tal e etc",
"bairro": "Fulano",
"cidade": "Caxias",
"uf": "RJ"
}POST /fornecedor_filial/_doc/1
{
"codigo": 124,
"nome_fornecedor": "GOL Linhas Aereas",
"cnpj": "12222334000102",
"endereco": "Rua tal e etc",
"bairro": "Fulano",
"cidade": "Santos",
"uf": "SP"
}O alias corporacao aponta para os dois índices ao mesmo tempo. Uma busca pelo alias retorna dados de ambos:
POST /_aliases
{
"actions": [
{ "add": { "index": "fornecedor_matriz", "alias": "corporacao" } },
{ "add": { "index": "fornecedor_filial", "alias": "corporacao" } }
]
}GET /corporacao/_searchPOST /_aliases
{
"actions": [
{
"add": {
"index": "fornecedor_*",
"alias": "fornecedores_sp",
"filter": {
"term": { "uf": "SP" }
}
}
}
]
}GET /fornecedores_sp/_searchA busca retornará apenas documentos com uf: SP, independentemente de qual índice eles estão.
Neste laboratório vamos usar component templates e index templates para aplicar mapping, settings e uma política de ILM em múltiplos índices com uma única configuração. Esse é o padrão recomendado em produção para garantir consistência entre índices que seguem a mesma estrutura.
O fluxo é:
ILM Policy → Component Template → Index Template → Índices (criados automaticamente)
PUT /_ilm/policy/policy_pessoas
{
"policy": {
"phases": {
"hot": {
"actions": {}
},
"warm": {
"min_age": "1d",
"actions": {
"forcemerge": {
"max_num_segments": 1
}
}
},
"delete": {
"min_age": "30d",
"actions": {
"delete": {}
}
}
}
}
}Nota sobre a action
freezee as fases cold e frozen: é importante não confundir as fases com as actions:
- Action
freeze: existia como action da fase cold e foi removida no Elasticsearch 9.x. Era usada para reduzir o uso de memória de índices pouco acessados.- Fase cold: continua existindo no 9.x e é totalmente válida. A partir do Elasticsearch 7.10, o ILM injeta automaticamente a action
migratenas fases warm e cold, atualizando o_tier_preferencedo índice para movê-lo ao tier correspondente — sem necessidade de configurar oallocateexplicitamente. Opcionalmente, a actionallocatepode ser usada para controlar o número de réplicas ou definir regras de alocação customizadas além do tier padrão.- Fase frozen: usa a action
searchable_snapshot— os dados são movidos para um repositório de snapshots (S3, GCS, Azure) e ficam pesquisáveis sem ocupar disco local no cluster, mas com latência maior de acesso.Este lab usa apenas hot, warm e delete para simplificar. A fase cold com migração automática de tier e a fase frozen com
searchable_snapshotsão abordadas junto com a arquitetura Hot-Warm-Cold-Frozen da Seção 4.
Um component template é um bloco reutilizável de configurações (settings, mappings, aliases) que pode ser incluído em um ou mais index templates. Isso evita repetição quando vários templates compartilham a mesma estrutura base.
PUT /_component_template/ct_pessoas
{
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1,
"index.lifecycle.name": "policy_pessoas"
},
"mappings": {
"properties": {
"nome": { "type": "text" },
"idade": { "type": "integer" },
"sexo": { "type": "keyword" },
"uf": { "type": "keyword" }
}
},
"aliases": {
"pessoas": {}
}
}
}O index template define o padrão de nome dos índices que receberão as configurações. O campo composed_of inclui o component template criado no passo anterior:
PUT /_index_template/it_pessoas
{
"index_patterns": ["pessoas_*"],
"composed_of": ["ct_pessoas"]
}A partir desse momento, qualquer índice criado com o padrão pessoas_* receberá automaticamente o mapping, os settings e a ILM policy definidos no component template.
Como os índices pessoas_rj e pessoas_sp seguem o padrão pessoas_*, serão criados automaticamente com todas as configurações aplicadas:
POST /_bulk
{ "index": { "_index": "pessoas_rj", "_id": "1" } }
{ "nome": "João da Silva", "sexo": "masculino", "idade": 19, "uf": "RJ" }
{ "index": { "_index": "pessoas_rj", "_id": "2" } }
{ "nome": "Maria Oliveira", "sexo": "feminino", "idade": 28, "uf": "RJ" }
{ "index": { "_index": "pessoas_rj", "_id": "3" } }
{ "nome": "Roberto Carlos", "sexo": "masculino", "idade": 35, "uf": "RJ" }
{ "index": { "_index": "pessoas_rj", "_id": "4" } }
{ "nome": "Ana Maria", "sexo": "feminino", "idade": 14, "uf": "RJ" }
{ "index": { "_index": "pessoas_rj", "_id": "5" } }
{ "nome": "Paulo Souza", "sexo": "masculino", "idade": 15, "uf": "RJ" }POST /_bulk
{ "index": { "_index": "pessoas_sp", "_id": "1" } }
{ "nome": "Bruno Garcia", "sexo": "masculino", "idade": 22, "uf": "SP" }
{ "index": { "_index": "pessoas_sp", "_id": "2" } }
{ "nome": "Renata Santos", "sexo": "feminino", "idade": 30, "uf": "SP" }
{ "index": { "_index": "pessoas_sp", "_id": "3" } }
{ "nome": "Gilberto Ferreira","sexo": "masculino", "idade": 48, "uf": "SP" }
{ "index": { "_index": "pessoas_sp", "_id": "4" } }
{ "nome": "Maria Silva", "sexo": "feminino", "idade": 12, "uf": "SP" }
{ "index": { "_index": "pessoas_sp", "_id": "5" } }
{ "nome": "Pedro Borges", "sexo": "masculino", "idade": 15, "uf": "SP" }GET /pessoas_rjGET /pessoas_spGET /pessoas/_searchVerifique que ambos os índices têm o mapping, os settings e a ILM policy aplicados conforme o component template, e que a busca pelo alias pessoas retorna documentos dos dois índices.

