-
Notifications
You must be signed in to change notification settings - Fork 1
6 ‐ Index Settings: Entendendo Mapping, Analyzers e Aliases
Importância e Benefícios:
O mapping no Elasticsearch define como os dados são armazenados e indexados. Uma configuração de mapping adequada permite que você otimize o armazenamento, melhore a performance das consultas e controle a análise de texto.
Exemplo de Uso:
PUT /clientes
{
"mappings": {
"properties": {
"nome": { "type": "text" },
"idade": { "type": "integer" },
"email": { "type": "keyword" }
}
}
}
Este exemplo define um índice clientes
com campos específicos e tipos de dados definidos.
Dynamic Mapping:
O Elasticsearch pode inferir os tipos de dados dos campos durante a indexação. No entanto, para um controle mais refinado, é recomendável definir o mapping explicitamente.
Exemplo de Dynamic Mapping:
Se você não definir um mapping e indexar um documento, o Elasticsearch criará um mapping automaticamente.
POST /clientes/_doc/1
{
"nome": "Maria",
"idade": 28
}
Neste caso, o Elasticsearch inferirá nome
como text
e idade
como integer
.
Dynamic Templates:
Permitem definir regras de mapping para campos com base em padrões de nome, tipo ou outras condições.
Exemplo de Dynamic Template:
PUT /clientes
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
Este template trata todos os novos campos de string como keyword
.
POST clientes/_doc/1
{
"frase": "Boa tarde a todos"
}
GET clientes/_mapping
Analisando o mapeamento do campo criado, observa-se que o dynamic template reconheceu o novo campo como string e o indexou como keyword.
Field Data Types:
Os tipos de dados de campo incluem text
, keyword
, date
, integer
, float
, boolean
e muitos outros.
Exemplo de Multi-Field:
PUT /clientes
{
"mappings": {
"properties": {
"nome": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
Neste exemplo, nome
é indexado como text
e como keyword
no subcampo raw
.
A análise de texto no Elasticsearch é um processo fundamental que transforma texto bruto em termos ou tokens que podem ser indexados. Esse processo é composto por várias etapas, incluindo tokenização, filtragem de tokens, e, em alguns casos, normalização. A análise é essencial para realizar buscas eficientes em campos de texto, permitindo que o Elasticsearch entenda e compare os dados de texto.
Um analyzer no Elasticsearch é uma ferramenta que encapsula o processo de análise de texto, combinando três componentes principais: o tokenizer e, opcionalmente, vários token filters e character filters.
-
Tokenizers: Divide o texto em tokens (geralmente palavras). Por exemplo, o tokenizer
standard
divide o texto em palavras com base em certos critérios de separação, como espaços e pontuação. -
Token Filters: Processam a sequência de tokens gerados pelo tokenizer. Eles podem modificar, adicionar ou remover tokens. Exemplos incluem
lowercase
(converte todos os tokens em letras minúsculas) estop
(remove palavras comuns, também conhecidas como stopwords). -
Character Filters: Processam o texto antes da tokenização, permitindo a substituição ou remoção de caracteres. Por exemplo, um character filter pode remover HTML ou converter caracteres HTML em seus equivalentes de texto.
Exemplo de Analyzer:
GET /_analyze
{
"analyzer": "standard",
"text": "Text for analysis!"
}
Este exemplo demonstra como um texto será analisado usando o analyzer standard
.
Tokenization é o processo de dividir o texto em uma série de tokens ou termos. É o primeiro passo crítico na análise de texto, pois determina a granularidade dos dados que serão indexados e pesquisados.
Exemplo de Tokenization:
POST /_analyze
{
"tokenizer": "standard",
"text": "Quick brown fox."
}
Este exemplo mostra como o texto será dividido em tokens usando o tokenizer standard
.
Os normalizers são usados para campos do tipo keyword
e aplicam uma transformação de normalização de texto. Diferentemente dos analyzers, que podem alterar o número de termos, os normalizers sempre produzem exatamente um termo por termo de entrada, sendo úteis para normalizar tokens para buscas consistentes, como converter textos para minúsculas.
Exemplo de Normalizer:
Suponha que você tenha definido um normalizer no seu mapping que converte texto 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"
}
}
}
}
Este normalizer pode ser usado para garantir que todos os dados no campo meu_campo_keyword
sejam armazenados em letras minúsculas.
POST meu_index/_doc/
{
"meu_campo_keyword": "BOA TARDE"
}
GET meu_index/_search
{
"size": 0,
"aggs": {
"my_aggs": {
"terms": {
"field": "meu_campo_keyword"
}
}
}
}
Aliases e sua Aplicabilidade:
Um alias é um nome alternativo para um índice que pode ser usado para ocultar detalhes de implementação aos usuários ou aplicações.
Exemplo de Criação de Alias:
POST /_aliases
{
"actions": [
{
"add": {
"index": "clientes",
"alias": "clientes_atuais"
}
}
]
}
Agora, clientes_atuais
pode ser usado no lugar do nome do índice clientes
.
Aliases com Filtros:
Exemplo de Alias com Filtro:
POST /_aliases
{
"actions": [
{
"add": {
"index": "clientes",
"alias": "clientes_adultos",
"filter": { "range": { "idade": { "gte": 18 } } }
}
}
]
}
Este alias clientes_adultos
só expõe documentos de clientes com 18 anos ou mais.
Neste laboratório, vamos criar um índice no Elasticsearch chamado clientes
com um mapeamento específico para os campos codigo
, nome
, sexo
, estado_civil
, data_nascimento
e caracteristicas
. Além disso, configuraremos um mapeamento dinâmico para campos com o prefixo logradouro
para serem tratados como keyword
.
- Definir o Índice e o Mapeamento:
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:
-
codigo
: Campo do tipointeger
. -
nome
: Campo do tipotext
com um subcampokeyword
para permitir buscas exatas e baseadas em texto. -
sexo
eestado_civil
: Campos do tipokeyword
para buscas exatas. -
data_nascimento
: Campo do tipodate
para armazenar datas. -
caracteristicas
: Campo do tipotext
para armazenar texto livre. -
dynamic_templates
: Template dinâmico que aplica o tipokeyword
a qualquer campo que comece comlogradouro
.
Agora, vamos indexar um documento de exemplo para ver o mapeamento em ação.
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 Árvores"
}
Neste exemplo, os campos logradouro_principal
e logradouro_secundario
são tratados como keyword
devido ao nosso mapeamento dinâmico.
Você pode verificar o mapeamento efetivo usando a seguinte chamada API:
GET /clientes/_mapping
Essa chamada retornará o mapeamento atual do índice clientes
, permitindo que você confirme se todos os campos estão configurados conforme desejado.
O parâmetro dynamic
no mapeamento do Elasticsearch controla como os campos não especificados no mapeamento são tratados quando novos documentos são indexados. Ele pode ter três valores: true
, false
e strict
.
-
Dynamic: true
Este é o valor padrão. Quando
dynamic
está configurado comotrue
, o Elasticsearch detecta automaticamente os tipos de campo dos campos não mapeados e os adiciona ao mapeamento.Exemplo:
Se indexarmos um novo documento com um campo não definido no mapeamento, como
novo_campo
, o Elasticsearch adicionará automaticamentenovo_campo
ao mapeamento com um tipo inferido. -
Dynamic: false
Quando configurado como
false
, o Elasticsearch não adicionará novos campos ao mapeamento. Os campos não mapeados serão aceitos e indexados, mas não serão pesquisáveis.Exemplo de Mapeamento com Dynamic False:
PUT /clientes { "mappings": { "dynamic": "false", "dynamic_templates": [ { "logradouros_as_keywords": { "match_mapping_type": "string", "match_pattern": "regex", "match": "^logradouro.*", "mapping": { "type": "keyword" } } } ], "properties": { "codigo": { "type": "integer" } // outros campos mapeados } } }
Se indexarmos um documento com um campo que não esteja no mapeamento, esse campo será armazenado, mas não será adicionado ao mapeamento.
-
Dynamic: strict
Se
dynamic
for configurado comostrict
, o Elasticsearch rejeitará documentos que contêm campos não mapeados, retornando um erro.Exemplo de Mapeamento com Dynamic Strict:
PUT /clientes { "mappings": { "dynamic": "strict", "dynamic_templates": [ { "logradouros_as_keywords": { "match_mapping_type": "string", "match_pattern": "regex", "match": "^logradouro.*", "mapping": { "type": "keyword" } } } ], "properties": { "codigo": { "type": "integer" } // outros campos mapeados } } }
Nesse caso, se tentarmos indexar um documento com um campo que não esteja no mapeamento, receberemos um erro.
Ao definir dynamic
como strict
, o Elasticsearch garantirá que somente os campos definidos no mapeamento possam ser indexados, oferecendo um controle estrito sobre a estrutura dos dados no índice.
Neste laboratório, vamos aprender a customizar um analyzer no Elasticsearch usando o tokenizer edge_ngram
. Vamos aplicar isso no contexto de um índice chamado fornecedor
, focando na tokenização do campo nome_fornecedor
para aprimorar as buscas.
-
Defina o índice
fornecedor
com o analyzer customizado:PUT /fornecedor { "settings": { "analysis": { "analyzer": { "my_analyzer_ngram_3": { "tokenizer": "split_3_ngram" } }, "tokenizer": { "split_3_ngram": { "type": "edge_ngram", "min_gram": 3, "max_gram": 15, "token_chars": [ "letter", "digit" ] } } } }, "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": "my_analyzer_ngram_3", "fields": { "keyword": { "type": "keyword" } } }, "cnpj": { "type": "keyword" }, "endereco": { "type": "keyword" }, "bairro": { "type": "keyword" }, "cidade": { "type": "keyword" }, "uf": { "type": "keyword" } } } }
Aqui, criamos um tokenizer
edge_ngram
chamadosplit_3_ngram
, que gera tokens com um comprimento de 3 a 15 caracteres. Este tokenizer é usado no analyzermy_analyzer_ngram_3
, que é aplicado ao camponome_fornecedor_engram
.
Para entender como o texto será tokenizado, você pode usar o seguinte comando:
POST fornecedor/_analyze
{
"tokenizer": "split_3_ngram",
"text": "GOLLINHASAEREAS"
}
Esse comando irá demonstrar como o texto "GOLLINHASAEREAS" será dividido em tokens pelo tokenizer customizado my_analyzer_ngram_3
.
-
Insira o primeiro documento:
POST /fornecedor/_doc/1 { "codigo": 124, "nome_fornecedor": "GOL Linhas Aereas", "nome_fornecedor_engram": "GOL Linhas Aereas", "cnpj": "12222334000102", "endereco": "Rua tal e etc", "bairro": "Fulano", "cidade": "Caxias", "uf": "RJ" }
-
Insira o segundo documento:
POST /fornecedor/_doc/1 { "codigo": 124, "nome_fornecedor": "TAM Linhas Aereas", "nome_fornecedor_engram": "TAM Linhas Aereas", "cnpj": "12222334000102", "endereco": "Rua tal e etc", "bairro": "Fulano", "cidade": "Caxias", "uf": "RJ" }
Agora, vamos realizar uma busca para verificar a eficácia do nosso analyzer:
GET fornecedor/_search
{
"query": {
"match": {
"nome_fornecedor_engram": "TAMLINHASAEREAS"
}
}
}
Nessa busca, estamos procurando por "TAMLINHASAEREAS" no campo nome_fornecedor_engram
. Graças ao nosso analyzer customizado, mesmo que não haja uma correspondência exata, a busca será capaz de encontrar "TAM Linhas Aereas" graças à tokenização feita pelo edge_ngram
.
Neste laboratório, você aprendeu a criar um analyzer customizado usando edge_ngram
no Elasticsearch, aplicá-lo a um campo específico e testar sua funcionalidade. Além disso, você viu como inserir dados e realizar uma busca efetiva utilizando o analyzer customizado para melhorar a relevância dos resultados.
Neste laboratório, aprenderemos a unificar e organizar o acesso a múltiplos índices no Elasticsearch usando aliases. Primeiramente, criaremos dois índices, fornecedor_matriz
e fornecedor_filial
, e depois configuraremos aliases para unificá-los e criar uma visão filtrada.
-
Crie o índice
fornecedor_matriz
: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" } } } }
-
Crie o índice
fornecedor_filial
: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" } } } }
-
Insira um documento no
fornecedor_matriz
: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" }
-
Insira um documento no
fornecedor_filial
: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" }
-
Configure o alias
corporacao
para unificar os dois índices:POST _aliases { "actions": [ { "add": { "index": "fornecedor_matriz", "alias": "corporacao" } }, { "add": { "index": "fornecedor_filial", "alias": "corporacao" } } ] }
-
Teste a busca pelo alias
corporacao
:GET corporacao/_search
Essa busca retornará resultados de ambos os índices,
fornecedor_matriz
efornecedor_filial
.
-
Crie um alias
fornecedores_sp
com um filtro para a UF "SP":POST _aliases { "actions": [ { "add": { "index": "fornecedor_*", "alias": "fornecedores_sp", "filter": { "term": { "uf": "SP" } } } } ] }
-
Realize uma consulta pelo alias
fornecedores_sp
:GET fornecedores_sp/_search
A consulta retornará apenas os documentos do estado de São Paulo.
Você aprendeu a criar e configurar aliases para unificar o acesso a múltiplos índices no Elasticsearch, além de poder restringir o acesso a informações especificas de determinados índices. Com o alias, também é possível aplicar o versionamento de um índice sem que o seu nome original seja alterado.
Neste laboratório, aprenderemos a configurar todos os parâmetros vistos nessa aula de uma só vez. Adicionalmente, vamos atrelar a essas configurações uma política de ILM para entendermos que também podemos definir tudo isso no momento da criação do índice. Primeiro, vamos criar a política que queremos atrelar aos índices em questão; depois, criaremos o que chamamos de componente template, além de atrelar ele a um index template. Por fim, faremos um bulk em dois índices para verificar as configurações feitas.
-
Definir a política
policy_pessoas
:PUT _ilm/policy/policy_pessoas { "policy": { "phases": { "hot": { "actions": { } }, "warm": { "min_age": "1d", "actions": { "forcemerge": { "max_num_segments": 1 } } }, "cold": { "min_age": "7d", "actions": { "freeze": {} } }, "delete": { "min_age": "30d", "actions": { "delete": {} } } } } }
Vamos criar o component template a atrelar às novas configurações a ILM Policy.
-
Definir o component template
ct_pessoas
: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": {} } } }
Nesta etapa vamos criar o template do índice contendo todas as informações que criamos e vamos também atrelar um padrão de nome para os índices se associarem a esse template.
-
Definir o index template
it_pessoas
:PUT _index_template/it_pessoas { "index_patterns": ["pessoas_*"], "composed_of": ["ct_pessoas"] }
-
Indexar documentos no índice
pessoas_rj
: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" }
-
Indexar documentos no índice
pessoas_sp
: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_rj
GET pessoas_sp
GET pessoas/_search
Você aprendeu a aplicar todas as configurações vistas nessa página em poucas operações. Configuramos uma política de ILM, atrelamos essa política a um component template onde adicionamos configurações do índice e mapeamento dos campos esperados; após isso, associamos essas criações a um template de índice, que ficou responsável por encontrar novos índices que atendesse aos critérios passados e aplicasse neles as configurações criadas.