3 ‐ Explorando os Dados: Query DSL - BktechBrazil/elasticstacktotal GitHub Wiki
3.1 - Query DSL: Searches, Filters e Aggregations
A Query DSL (Domain-Specific Language) do Elasticsearch é uma poderosa linguagem de consulta baseada em JSON que permite aos usuários realizar pesquisas complexas, filtrar dados e executar agregações para extrair insights significativos de seus dados armazenados no Elasticsearch.
Searches
A Query DSL permite realizar buscas completas, combinando diversos tipos de consultas para atender às necessidades específicas de pesquisa. As buscas podem ser simples, como procurar por uma palavra específica em um campo de texto, ou complexas, combinando várias consultas e filtros.
-
Match Query: Uma das consultas mais comuns, usada para buscar um texto específico em um campo. Ajusta a relevância da correspondência com base em quão bem o termo de busca corresponde.
{ "match": { "campo": "texto de busca" } } -
Bool Query: Permite combinar várias consultas usando operadores booleanos (
must,should,must_not,filter), proporcionando uma maneira flexível de construir consultas complexas.{ "bool": { "must": [{ "match": { "campo1": "valor1" } }], "filter": [{ "term": { "campo2": "valor2" } }], "must_not": [{ "range": { "campo3": { "lte": 10 } } }] } }
Filters
Os filtros são usados para refinar os resultados de uma busca, geralmente sem considerar a relevância. Eles são mais rápidos que as consultas, pois são cacheáveis, e são ideais para limitar os resultados a um conjunto específico de documentos.
-
Term Filter: Utilizado para filtrar documentos que contêm um valor exato em um campo específico.
{ "term": { "campo": "valor" } } -
Range Filter: Permite filtrar documentos com base em um intervalo de valores, como datas ou números.
{ "range": { "campo": { "gte": "inicio", "lte": "fim" } } }
Aggregations
As agregações são uma poderosa funcionalidade do Elasticsearch que permite processar e sumarizar dados em tempo real. Elas oferecem a capacidade de extrair tendências, padrões e estatísticas dos seus dados.
-
Terms Aggregation: Agrupa os dados por valores únicos de um campo e calcula o total de documentos em cada grupo.
{ "aggs": { "nomes_agregacao": { "terms": { "field": "campo" } } } } -
Histogram Aggregation: Agrupa os dados em intervalos definidos, útil para distribuições de valores numéricos.
{ "aggs": { "nomes_agregacao": { "histogram": { "field": "campo_numerico", "interval": 10 } } } }
A Query DSL do Elasticsearch é um recurso extremamente versátil e poderoso, permitindo aos usuários realizar consultas detalhadas e análises profundas dos seus dados, ajustando-se às mais diversas necessidades de busca e análise de informações.
3.2 - Laboratório: Inserindo Documentos de Cadastro de Clientes no Elasticsearch
Neste laboratório, você aprenderá a inserir documentos em um índice do Elasticsearch representando um cadastro de clientes. Cada documento conterá informações como nome_completo, sexo, codigo e endereço.
Pré-requisitos:
- Ter o Elasticsearch instalado e em execução na sua máquina.
- Acesso ao terminal ou a um cliente REST como Postman ou Kibana Dev Tools para enviar requisições ao Elasticsearch.
Passo 1: Definindo o Índice
Primeiramente, defina um índice onde os documentos serão armazenados. Você pode fazer isso via Kibana Dev Tools ou um cliente REST. O nome do índice será cadastro_clientes.
PUT /cadastro_clientes
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"nome_completo": { "type": "text" },
"sexo": { "type": "keyword" },
"codigo": { "type": "integer" },
"endereço": { "type": "text" }
}
}
}
Passo 2: Inserindo Documentos
Após definir o índice, insira os documentos representando cada cliente. Abaixo está o exemplo de como inserir um documento. Repita o processo para inserir um total de 10 documentos.
POST /_bulk
{ "index" : { "_index" : "cadastro_clientes", "_id" : "1" } }
{ "nome_completo" : "João da Silva", "sexo" : "masculino", "codigo" : 1, "endereço" : "Rua Exemplo, 123, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "2" } }
{ "nome_completo" : "Maria Oliveira", "sexo" : "feminino", "codigo" : 2, "endereço" : "Avenida Exemplo, 456, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "3" } }
{ "nome_completo" : "Roberto Carlos", "sexo" : "masculino", "codigo" : 3, "endereço" : "Travessa Exemplo, 789, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "4" } }
{ "nome_completo" : "Ana Maria", "sexo" : "feminino", "codigo" : 4, "endereço" : "Rua Segunda, 101, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "5" } }
{ "nome_completo" : "Paulo Souza", "sexo" : "masculino", "codigo" : 5, "endereço" : "Avenida Principal, 202, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "6" } }
{ "nome_completo" : "Clara Costa", "sexo" : "feminino", "codigo" : 6, "endereço" : "Rua Terceira, 303, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "7" } }
{ "nome_completo" : "Pedro Marques", "sexo" : "masculino", "codigo" : 7, "endereço" : "Sexta Avenida, 606, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "8" } }
{ "nome_completo" : "Sandra Gomes", "sexo" : "feminino", "codigo" : 8, "endereço" : "Rua Quinta, 505, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "9" } }
{ "nome_completo" : "Ricardo Almeida", "sexo" : "masculino", "codigo" : 9, "endereço" : "Avenida Sexta Feira, 606, Cidade, Estado" }
{ "index" : { "_index" : "cadastro_clientes", "_id" : "10" } }
{ "nome_completo" : "Tereza Costa", "sexo" : "feminino", "codigo" : 10, "endereço" : "Rua Sétima, 707, Cidade, Estado" }
Altere os valores de nome_completo, sexo, codigo, e endereço para refletir as informações de cada cliente. O número após _doc/ representa o ID do documento, que deve ser único para cada cliente (neste caso, de 1 a 10).
Passo 3: Verificando a Inserção
Para verificar se os documentos foram inseridos corretamente, você pode executar uma consulta de pesquisa simples.
GET /cadastro_clientes/_search
{
"query": {
"match_all": {}
}
}
Esta consulta retorna todos os documentos no índice cadastro_clientes. Certifique-se de que todos os 10 documentos estão presentes e corretos.
3.3 Operações CRUD no Elasticsearch Usando APIs
As operações CRUD (Create, Read, Update, Delete) são fundamentais para a interação com os dados armazenados no Elasticsearch. Vou demonstrar como realizar cada uma dessas operações usando o índice cadastro_clientes como exemplo.
1. Create (Criação)
Para criar (ou indexar) um documento, você pode usar a API PUT ou POST. Se você especificar um ID, deve usar PUT; caso contrário, use POST e o Elasticsearch gerará um ID automaticamente.
-
Inserindo um documento com um ID específico:
PUT /cadastro_clientes/_doc/11 { "nome_completo": "Carlos Teixeira", "sexo": "masculino", "codigo": 11, "endereço": "Rua Oito, 808, Cidade, Estado" } -
Inserindo um documento sem especificar um ID (o Elasticsearch gera um ID automaticamente):
POST /cadastro_clientes/_doc { "nome_completo": "Lucia Andrade", "sexo": "feminino", "codigo": 12, "endereço": "Avenida Nove, 909, Cidade, Estado" }
2. Read (Leitura)
Para ler ou buscar documentos, você pode usar a API GET. Para buscar um documento pelo ID, basta especificar o índice e o ID do documento.
-
Buscando um documento por ID:
GET /cadastro_clientes/_doc/1
Para realizar buscas mais complexas, você pode usar a API search com a Query DSL.
-
Buscando documentos com uma query:
GET /cadastro_clientes/_search { "query": { "match": { "sexo": "feminino" } } }
3. Update (Atualização)
Para atualizar um documento, use a API POST com o endpoint _update e o ID do documento. Você pode usar a seção doc para especificar as alterações.
-
Atualizando um documento:
POST /cadastro_clientes/_update/1 { "doc": { "endereço": "Nova Rua, 123, Nova Cidade, Estado" } }
4. Delete (Deleção)
Para deletar um documento, use a API DELETE com o índice e o ID do documento.
-
Deletando um documento:
DELETE /cadastro_clientes/_doc/1
Operações Avançadas de Atualização e Deleção no Elasticsearch
Além das operações básicas de CRUD, o Elasticsearch oferece métodos poderosos para atualizar e deletar documentos em massa, baseados em critérios específicos, utilizando update_by_query e delete_by_query.
Update by Query (Atualização por Consulta)
A operação update_by_query permite atualizar múltiplos documentos com base em uma consulta. Essa abordagem é útil quando você precisa atualizar todos os documentos que correspondem a determinados critérios.
-
Exemplo de atualização por consulta:
Digamos que você queira atualizar o campo
endereçopara "Endereço Atualizado" para todos os clientes do sexo feminino.POST /cadastro_clientes/_update_by_query { "script": { "source": "ctx._source['endereço'] = 'Endereço Atualizado'", "lang": "painless" }, "query": { "match": { "sexo": "feminino" } } }
Neste exemplo, todos os documentos que têm o campo sexo com o valor "feminino" terão seu campo endereço atualizado para "Endereço Atualizado".
Delete by Query (Deleção por Consulta)
A operação delete_by_query permite deletar documentos com base em uma consulta. É uma forma eficaz de remover múltiplos registros que atendem a certos critérios sem a necessidade de deletá-los individualmente.
-
Exemplo de deleção por consulta:
Suponha que você queira deletar todos os clientes com o código menor que 5.
POST /cadastro_clientes/_delete_by_query { "query": { "range": { "codigo": { "lt": 5 } } } }
Esse comando deletará todos os documentos no índice cadastro_clientes cujo campo codigo seja menor que 5.
Essas operações avançadas oferecem uma maneira poderosa e flexível de atualizar ou remover grandes conjuntos de documentos no Elasticsearch, tornando o gerenciamento de dados mais eficiente em cenários complexos.
3.4 - Possibilidades de Busca Usando a Query DSL no Elasticsearch
A Query DSL do Elasticsearch permite realizar buscas complexas e precisas através de uma variedade de consultas. Vamos explorar algumas dessas possibilidades:
1. Boolean Query
Combina várias consultas usando operadores booleanos (must, should, must_not, filter).
GET /cadastro_clientes/_search
{
"query": {
"bool": {
"must": [
{ "match": { "nome_completo": "Costa" } },
{ "match": { "endereço": "Atualizado" } }
],
"should": [
{ "term": { "sexo": "feminino" } }
],
"must_not": [
{ "range": { "codigo": { "lt": 5 } } }
]
}
}
}
2. Boosting Query
Diminui a relevância dos resultados que correspondem a uma condição indesejada.
GET /cadastro_clientes/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"sexo": "masculino"
}
},
"negative": {
"range": {
"codigo": {
"lte": 7
}
}
},
"negative_boost": 0.2
}
}
}
3. Intervals Query
Permite refinar consultas de texto com regras específicas sobre os intervalos em que os termos ocorrem.
GET /cadastro_clientes/_search
{
"query": {
"intervals": {
"endereço": {
"all_of": {
"intervals": [
{
"match": {
"query": "Avenida Cidade",
"max_gaps": 2,
"ordered": true
}
}
]
}
}
}
}
}
4. Match Query
Busca por documentos que correspondam ao texto fornecido, com análise de texto.
GET /cadastro_clientes/_search
{
"query": {
"match": {
"nome_completo": "Sandra Gomes"
}
}
}
5. Match Phrase Query
Busca por documentos que contenham uma sequência específica de palavras.
GET /cadastro_clientes/_search
{
"query": {
"match_phrase": {
"endereço": "Avenida Sexta"
}
}
}
6. Query String
Permite consultas complexas, incluindo operadores lógicos e curingas, em uma sintaxe de string.
GET /cadastro_clientes/_search
{
"query": {
"query_string": {
"query": "(Avenida AND Sexta) OR (Carlos AND Rua)"
}
}
}
7. Simple Query String
Versão mais simples e robusta da query_string, evitando alguns erros comuns de sintaxe.
GET /cadastro_clientes/_search
{
"query": {
"simple_query_string": {
"query": "Carlos Costa -Avenida"
}
}
}
8. Term e Terms Query
Busca por documentos que contêm um valor exato em um campo (não analisado).
GET /cadastro_clientes/_search
{
"query": {
"term": {
"sexo": "masculino"
}
}
}
Para múltiplos termos:
GET /cadastro_clientes/_search
{
"query": {
"terms": {
"codigo": [4, 7, 8]
}
}
}
9. Exists Query
Encontra documentos onde um campo especificado existe.
GET /cadastro_clientes/_search
{
"query": {
"exists": {
"field": "endereço"
}
}
}
10. Fuzzy Query
Usada para encontrar termos que são parecidos com o termo de pesquisa, baseando-se na distância de Levenshtein.
GET /cadastro_clientes/_search
{
"query": {
"fuzzy": {
"nome_completo": {
"value": "Tiexeira"
}
}
}
}
11. Range Query
Permite encontrar documentos cujos valores estão dentro de um intervalo especificado.
GET /cadastro_clientes/_search
{
"query": {
"range": {
"codigo": {
"gte": 5,
"lte": 10
}
}
}
}
Cada um desses tipos de consultas oferece uma maneira única e poderosa de interagir com seus dados no Elasticsearch, permitindo desde buscas simples até análises complexas e detalhadas.
3.5 - Utilizando Filters na Query DSL no Elasticsearch
Os filtros (filters) no Elasticsearch são utilizados para refinar os resultados da busca com base em critérios específicos, sem levar em conta a relevância ou pontuação do documento (scoring). Eles são uma ferramenta poderosa para melhorar a performance das buscas, pois os resultados dos filtros são cacheáveis, o que acelera consultas subsequentes com os mesmos critérios.
Vantagem em Relação à Performance
A principal vantagem dos filtros em relação às queries tradicionais é o desempenho. Quando um filtro é aplicado, o Elasticsearch pode utilizar caches de bitsets, que são maneiras eficientes de armazenar resultados de consultas em memória. Isso significa que, se o mesmo filtro for usado novamente, o Elasticsearch pode recuperar rapidamente o resultado do cache, em vez de recalculá-lo. Além disso, os filtros não calculam pontuações, reduzindo a carga computacional.
Exemplos de Uso de Filters
1. Term Filter
Utilizado para encontrar documentos que contêm exatamente o termo especificado em um campo.
GET /cadastro_clientes/_search
{
"query": {
"bool": {
"filter": {
"term": {
"sexo": "masculino"
}
}
}
}
}
2. Range Filter
Permite encontrar documentos cujos valores estão dentro de um determinado intervalo.
GET /cadastro_clientes/_search
{
"query": {
"bool": {
"filter": {
"range": {
"codigo": {
"gte": 5,
"lte": 10
}
}
}
}
}
}
3. Exists Filter
Busca por documentos em que um determinado campo está presente.
GET /cadastro_clientes/_search
{
"query": {
"bool": {
"filter": {
"exists": {
"field": "endereço"
}
}
}
}
}
4. Bool Filter
Combina vários filtros usando lógica booleana.
GET /cadastro_clientes/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"sexo": "feminino"
}
},
{
"range": {
"codigo": {
"gte": 5
}
}
}
]
}
}
}
Usar filtros é essencial quando você está interessado apenas em determinar se um documento corresponde ou não aos critérios, sem se importar com a relevância ou ordenação por relevância. Ao aproveitar o cacheamento e evitar cálculos desnecessários de relevância, os filtros oferecem uma maneira rápida e eficiente de realizar buscas no Elasticsearch, especialmente em grandes volumes de dados.
3.6 - Uso de Agregações no Elasticsearch
As agregações no Elasticsearch permitem que você sumarize, calcule e analise seus dados de maneiras complexas, possibilitando a extração de insights e padrões valiosos. As agregações podem ser categorizadas em diversos tipos, como métricas, bucket, e pipeline, cada uma com sua própria funcionalidade e caso de uso.
Capacidades e Possibilidades
- Metric Aggregations: Calculam valores de métricas como média, soma, min, max, entre outros, a partir dos dados.
- Bucket Aggregations: Agrupam documentos em "buckets" com base em um campo ou critério, semelhante a uma cláusula "GROUP BY" em SQL.
- Pipeline Aggregations: Permitem combinar outras agregações para realizar cálculos e análises mais complexas e a consolidação dos cálculos do Bucket Aggregations.
As agregações podem ser usadas para:
- Calcular médias, somas ou estatísticas em campos específicos.
- Contar o número de ocorrências de termos ou categorias.
- Encontrar o valor máximo ou mínimo em um conjunto de dados.
- Criar histogramas ou distribuições de dados.
- E muito mais, dependendo da criatividade e necessidade do uso.
Exemplo de Agregação: Terms Aggregation
Suponha que queremos contar o número de clientes para cada valor único de sexo no índice cadastro_clientes. Usaremos uma terms aggregation para isso.
GET /cadastro_clientes/_search
{
"size": 0,
"aggs": {
"count_by_sexo": {
"terms": {
"field": "sexo"
}
}
}
}
Explicação:
"size": 0: Não retorna os documentos em si, apenas o resultado da agregação."aggs": Define as agregações a serem realizadas."count_by_sexo": Nome da agregação."terms": Tipo da agregação, que nesse caso é uma agregação de termos."field": "sexo": Define o campo pelo qual os documentos serão agrupados.
O resultado dessa agregação mostrará quantos clientes existem para cada valor único do campo sexo. É uma maneira poderosa de resumir e entender melhor a distribuição dos seus dados.
3.7 - Laboratório
Vamos agora montar um exemplo que abrange todas as funcionalidades de uma agregação
1. Criando o Índice "saldo"
Primeiro, vamos definir o índice "saldo" com a estrutura de mapping especificada:
PUT /saldo
{
"mappings": {
"properties": {
"num_conta": { "type": "keyword" },
"nome": { "type": "text" },
"sexo": { "type": "keyword" },
"cidade": { "type": "keyword" },
"estado": { "type": "keyword" },
"saldo": { "type": "double" }
}
}
}
2. Inserindo Documentos com a API Bulk
Agora, vamos inserir 10 documentos aleatórios no índice "saldo". Os dados são fictícios e servem apenas para ilustrar o exemplo.
POST /_bulk
{ "index" : { "_index" : "saldo", "_id" : "1" } }
{ "num_conta": "1001", "nome": "Ana Beatriz", "sexo": "feminino", "cidade": "Recife", "estado": "PE", "saldo": 1000.00 }
{ "index" : { "_index" : "saldo", "_id" : "2" } }
{ "num_conta": "1002", "nome": "Carlos Eduardo", "sexo": "masculino", "cidade": "Rio de Janeiro", "estado": "RJ", "saldo": 3000.00 }
{ "index" : { "_index" : "saldo", "_id" : "3" } }
{ "num_conta": "1003", "nome": "Juliana Martins", "sexo": "feminino", "cidade": "Belo Horizonte", "estado": "MG", "saldo": 1500.00 }
{ "index" : { "_index" : "saldo", "_id" : "4" } }
{ "num_conta": "1004", "nome": "Roberto Silva", "sexo": "masculino", "cidade": "Porto Alegre", "estado": "RS", "saldo": 1800.00 }
{ "index" : { "_index" : "saldo", "_id" : "5" } }
{ "num_conta": "1005", "nome": "Fernanda Oliveira", "sexo": "feminino", "cidade": "Goiânia", "estado": "GO", "saldo": 2200.00 }
{ "index" : { "_index" : "saldo", "_id" : "6" } }
{ "num_conta": "1006", "nome": "Lucas Peixoto", "sexo": "masculino", "cidade": "Manaus", "estado": "AM", "saldo": 1900.00 }
{ "index" : { "_index" : "saldo", "_id" : "7" } }
{ "num_conta": "1007", "nome": "Patrícia Rocha", "sexo": "feminino", "cidade": "Recife", "estado": "PE", "saldo": 2100.00 }
{ "index" : { "_index" : "saldo", "_id" : "8" } }
{ "num_conta": "1008", "nome": "Eduardo Lima", "sexo": "masculino", "cidade": "Manaus", "estado": "AM", "saldo": 2300.00 }
{ "index" : { "_index" : "saldo", "_id" : "9" } }
{ "num_conta": "1009", "nome": "Sandra Gomes", "sexo": "feminino", "cidade": "Goiânia", "estado": "GO", "saldo": 2000.00 }
{ "index" : { "_index" : "saldo", "_id" : "10" } }
{ "num_conta": "1010", "nome": "André Fonseca", "sexo": "masculino", "cidade": "Goiânia", "estado": "GO", "saldo": 9000.00 }
3. Exemplos de Agregações
Métricas Aggregations (Média do Saldo):
Primeiro, vamos calcular a média do saldo para todos os documentos.
GET /saldo/_search
{
"size": 0,
"aggs": {
"media_saldo": {
"avg": {
"field": "saldo"
}
}
}
}
Bucket Aggregations (Agrupando por Estado):
Agora, vamos agrupar os dados por estado e calcular a média do saldo para cada estado.
GET /saldo/_search
{
"size": 0,
"aggs": {
"saldo_por_estado": {
"terms": {
"field": "estado"
},
"aggs": {
"media_saldo": {
"avg": {
"field": "saldo"
}
}
}
}
}
}
Pipeline Aggregations (Diferença de Saldo entre os Sexos):
Vamos criar uma agregação que primeiro agrupa por sexo, calcula a média do saldo e depois utiliza uma pipeline aggregation para calcular a média total das médias do bucket sexo.
GET /saldo/_search
{
"size": 0,
"aggs": {
"saldo_por_sexo": {
"terms": {
"field": "sexo"
},
"aggs": {
"media_saldo": {
"avg": {
"field": "saldo"
}
}
}
},
"media_saldo_buckets": {
"avg_bucket": {
"buckets_path": "saldo_por_sexo>media_saldo"
}
}
}
}
Esses exemplos ilustram como você pode realizar agregações encadeadas e dependentes para extrair insights complexos de seus dados no Elasticsearch.