Experimente o Elasticsearch na prática: Mergulhe em nossos notebooks de amostra, inicie um teste gratuito na nuvem ou experimente o Elastic em sua máquina local agora mesmo.
O Elasticsearch possui recursos poderosos de busca e análise geoespacial há muitos anos, mas a API era bastante diferente daquilo a que os usuários típicos de SIG estavam acostumados. No último ano , adicionamos a linguagem de consulta ES|QL, uma linguagem de consulta encadeada tão fácil, ou até mais fácil, que o SQL. É particularmente adequado para os casos de uso de busca, segurança e observabilidade nos quais o Elastic se destaca. Também estamos adicionando suporte para pesquisa e análise geoespacial no ES|QL, tornando-o muito mais fácil de usar, especialmente para usuários vindos das comunidades SQL ou GIS .
O Elasticsearch 8.12 e 8.13 trouxeram suporte básico para tipos geoespaciais ao ES|QL. Isso foi significativamente aprimorado com a adição de recursos de busca geoespacial na versão 8.14. Mais importante ainda, esse suporte foi projetado para estar em estrita conformidade com o padrão Simple Feature Access do Open Geospatial Consortium (OGC), usado por outros bancos de dados espaciais como o PostGIS, tornando-o muito mais fácil de usar para especialistas em SIG familiarizados com esses padrões.
Neste blog, mostraremos como usar o ES|QL para realizar buscas geoespaciais e como ele se compara aos seus equivalentes em SQL e Query DSL. Também mostraremos como usar o ES|QL para realizar junções espaciais e como visualizar os resultados no Kibana Maps. Note que todos os recursos descritos aqui estão em "prévia técnica" e gostaríamos muito de receber seu feedback sobre como podemos melhorá-los.
Pesquisa de dados geoespaciais
Vamos começar com um exemplo de consulta:
Esta função realiza uma busca por quaisquer polígonos de limites urbanos que se intersectem com um polígono de busca retangular ao redor do Aeroporto Internacional de Sanya Phoenix (SYX).

Em um conjunto de dados de exemplo contendo aeroportos, cidades e limites urbanos, esta busca encontra o polígono de interseção e retorna os campos desejados do documento correspondente:
| abreviar | aeroporto | região | cidade | localização da cidade |
|---|---|---|---|---|
| SYX | Sanya Phoenix Int'l | 天涯区 | Sanya | PONTO(109,5036 18,2533) |
Isso foi fácil! Agora compare isso com a DSL de consulta clássica do Elasticsearch para a mesma consulta:
Ambas as consultas são razoavelmente claras em sua intenção, mas a consulta ES|QL se assemelha bastante ao SQL. A mesma consulta no PostGIS se parece com isto:
Relembre o exemplo em ES|QL. São muito parecidos, não é?
Constatamos que os usuários existentes da API Elasticsearch consideram o ES|QL muito mais fácil de usar. Agora, esperamos que os usuários atuais de SQL, especialmente os usuários de SQL Espacial, achem o ES|QL muito familiar ao que já estão acostumados a ver.
Por que não usar SQL?
E quanto ao Elasticsearch SQL? Já existe há algum tempo e possui algumas funcionalidades geoespaciais. No entanto, o Elasticsearch SQL foi escrito como um wrapper sobre a API de consulta original, o que significa que apenas as consultas que podiam ser transpiladas para a API original eram suportadas. ES|QL não possui essa limitação. Por ser uma pilha de tecnologias completamente nova, permite muitas otimizações que não eram possíveis em SQL. Nossos testes de desempenho mostram que o ES|QL é frequentemente mais rápido que a API de consulta, principalmente em operações de agregação!

Diferenças em relação ao SQL
Claramente, pelo exemplo anterior, o ES|QL é de certa forma semelhante ao SQL, mas existem algumas diferenças importantes. Por exemplo, ES|QL é uma linguagem de consulta encadeada, começando com um comando de origem como FROM e, em seguida, encadeando todos os comandos subsequentes com o caractere pipe |. Isso torna muito fácil entender como cada comando recebe uma tabela de dados e realiza alguma ação nessa tabela, como filtrar com WHERE, adicionar colunas com EVAL ou realizar agregações com STATS. Em vez de começar com SELECT para definir as colunas de saída finais, pode haver um ou mais comandos KEEP , com o último especificando os resultados de saída finais. Essa estrutura simplifica o raciocínio sobre a consulta.
Analisando o comando WHERE no exemplo acima, podemos ver que ele é bastante semelhante ao exemplo do PostGIS:
ES|QL
PostGIS
Além da diferença nos caracteres de aspas da string, a maior diferença está em como convertemos a string para um tipo espacial. No PostGIS, usamos o sufixo ::geometry , enquanto no ES|QL, usamos o sufixo ::geo_shape . Isso ocorre porque o ES|QL é executado dentro do Elasticsearch e o operador de conversão de tipo :: pode ser usado para converter uma string em qualquer um dos tipos ES|QL suportados, neste caso, um geo_shape. Além disso, os tipos geo_shape e geo_point no Elasticsearch implicam o sistema de coordenadas espaciais conhecido como WGS84, mais comumente referido usando o número SRID 4326. No PostGIS, isso precisa ser explícito, daí o uso do prefixo SRID=4326; na string WKT. Se esse prefixo for removido, o SRID será definido como 0, que é mais parecido com os tipos do Elasticsearch cartesian_point e cartesian_shape, que não estão vinculados a nenhum sistema de coordenadas específico.
Tanto o ES|QL quanto o PostGIS também fornecem sintaxe para funções de conversão de tipo:
ES|QL
PostGIS
Funções OGC
O Elasticsearch 8.14 introduz as seguintes quatro funções de pesquisa espacial OGC:
| ES|QL | PostGIS | Descrição |
|---|---|---|
| ST_INTERSETOS | ST_Interseções | Retorna verdadeiro se duas geometrias se intersectam e falso caso contrário. |
| ST_DISJOINT | ST_Disjunto | Retorna verdadeiro se as duas geometrias não se intersectarem e falso caso contrário. O inverso de ST_INTERSETOS. |
| ST_CONTÉM | ST_Contém | Retorna verdadeiro se uma geometria contém outra, e falso caso contrário. |
| ST_DENTRO | ST_Dentro | Retorna verdadeiro se uma geometria estiver dentro de outra, e falso caso contrário. O inverso de ST_CONTAINS. |
Essas funções se comportam de maneira semelhante às suas contrapartes no PostGIS e são usadas da mesma forma. Por exemplo, ST_INTERSECTS retorna verdadeiro se duas geometrias se intersectam e falso caso contrário. Se você seguir os links de documentação na tabela acima, poderá notar que todos os exemplos ES|QL estão dentro de uma cláusula WHERE após uma cláusula FROM , enquanto todos os exemplos PostGIS estão usando geometrias literais. Na verdade, ambas as plataformas suportam o uso das funções em qualquer parte da consulta onde façam sentido.
O primeiro exemplo na documentação do PostGIS para ST_INTERSECTS é:
O equivalente em ES|QL seria:
Observe que não especificamos o SRID no exemplo do PostGIS. Isso ocorre porque no PostGIS, ao usar o tipo geometry , todos os cálculos são feitos em um sistema de coordenadas planas e, portanto, se ambas as geometrias tiverem o mesmo SRID, não importa qual seja o SRID. No Elasticsearch, isso também é verdade para a maioria das funções, no entanto, existem exceções onde geo_shape e geo_point usam cálculos esféricos, como veremos no próximo blog sobre pesquisa de distância espacial.
Versatilidade ES|QL
Então, vimos exemplos acima de uso de funções espaciais em cláusulas WHERE e em comandos ROW . Em que outro lugar fariam sentido? Um local muito útil é no comando EVAL . Este comando permite avaliar uma expressão e retornar o resultado. Por exemplo, vamos determinar se os centroides de todos os aeroportos agrupados por seus nomes de país estão dentro de um limite que delimita o país:
Os resultados são os esperados: o centroide dos aeroportos do Reino Unido está dentro das fronteiras do Reino Unido, e não dentro das fronteiras da Islândia, e vice-versa.
| centroide | Contagem | no Reino Unido | na Islândia | dentro do Reino Unido | dentro da Islândia |
|---|---|---|---|---|---|
| PONTO (-21,946634463965893 64.13187285885215) | 1 | falso | verdadeiro | falso | verdadeiro |
| PONTO (-2,597342072712148 54,33551226578214) | 17 | verdadeiro | falso | verdadeiro | falso |
| PONTO (0,04453958108176276 23,74658354606057) | 873 | falso | falso | falso | falso |
Na verdade, essas funções podem ser usadas em qualquer parte da consulta onde sua assinatura faça sentido. Todas elas recebem dois argumentos, que podem ser um objeto espacial literal ou um campo de um tipo espacial, e todas retornam um valor booleano. Uma consideração importante é que o sistema de referência de coordenadas (SRC) das geometrias deve coincidir, caso contrário, será retornado um erro. Isso significa que você não pode misturar os tipos geo_shape e cartesian_shape na mesma chamada de função. Você pode, no entanto, misturar os tipos geo_point e geo_shape , já que o tipo geo_point é um caso especial do tipo geo_shape e ambos compartilham o mesmo sistema de referência de coordenadas. A documentação de cada uma das funções definidas acima lista as combinações de tipos suportadas.
Além disso, qualquer um dos argumentos pode ser um literal espacial ou um campo, em qualquer ordem. Você pode até especificar dois campos, dois literais, um campo e um literal, ou um literal e um campo. O único requisito é que os tipos sejam compatíveis. Por exemplo, esta consulta compara dois campos no mesmo índice:
A consulta basicamente pergunta se a localização da cidade está dentro dos limites da cidade, o que geralmente deve ser verdade, mas sempre há exceções:
| cardinalidade | Contagem | na cidade |
|---|---|---|
| alguns | 29 | falso |
| muitos | 740 | verdadeiro |
Uma questão muito mais interessante seria saber se a localização do aeroporto está dentro dos limites da cidade que ele serve. No entanto, a localização do aeroporto reside em um índice diferente daquele que contém os limites da cidade. Isso requer um método para consultar e correlacionar dados de forma eficaz a partir desses dois índices separados.
Junções espaciais
ES|QL não suporta comandos JOIN , mas você pode obter um caso especial de junção usando o comando ENRICH , que se comporta de forma semelhante a uma 'junção esquerda' em SQL. Este comando funciona de forma semelhante a uma 'junção à esquerda' em SQL, permitindo enriquecer os resultados de um índice com dados de outro índice com base em uma relação espacial entre os dois conjuntos de dados.
Por exemplo, vamos enriquecer os resultados de uma tabela de aeroportos com informações adicionais sobre a cidade que eles atendem, encontrando o limite da cidade que contém a localização do aeroporto e, em seguida, realizar algumas análises estatísticas dos resultados:
Isso retorna as 5 principais regiões com o maior número de aeroportos, juntamente com o centroide de todos os aeroportos que possuem regiões correspondentes e o intervalo de comprimento da representação WKT dos limites das cidades dentro dessas regiões:
| centroide | Contagem | min_wkt | max_wkt | região |
|---|---|---|---|---|
| PONTO (-32,56093470960719 32,598117914802714) | 90 | 207 | 207 | nulo |
| PONTO (-73,94515332765877 40,70366442203522) | 9 | 438 | 438 | Cidade de Nova York |
| PONTO (-83.10398317873478 42.300230911932886) | 9 | 473 | 473 | Detroit |
| PONTO (-156.3020245861262 20,176383580081165) | 5 | 307 | 803 | Havaí |
| PONTO (-73,88902732171118 45.57078813901171) | 4 | 837 | 837 | Montreal |
Então, o que realmente aconteceu aqui? Onde ocorreu o suposto JOIN ? O ponto crucial da questão reside no comando ENRICH :
Este comando instrui o Elasticsearch a enriquecer os resultados recuperados do índice airports e a realizar uma junção intersects entre o campo city_location do índice original e o campo city_boundary do índice airport_city_boundaries , que usamos em alguns exemplos anteriores. Mas algumas dessas informações não estão claramente visíveis nesta consulta. O que vemos é o nome de uma política de enriquecimento city_boundaries e a informação em falta está encapsulada na definição dessa política.
Aqui podemos ver que ele executará uma consulta geo_match (intersects é o padrão), o campo para comparar é city_boundary e os enrich_fields são os campos que queremos adicionar ao documento original. Um desses campos, o region foi na verdade usado como chave de agrupamento para o comando STATS , algo que não poderíamos ter feito sem essa capacidade de 'junção à esquerda'. Para obter mais informações sobre políticas de enriquecimento, consulte a documentação de enriquecimento. Ao ler esses documentos, você notará que eles descrevem o uso de índices de enriquecimento para enriquecer dados no momento da indexação, configurando pipelines de ingestão. Isso não é necessário para ES|QL, pois o comando ENRICH funciona no momento da consulta. Basta preparar o índice de enriquecimento com os dados necessários e a política de enriquecimento e, em seguida, usar o comando ENRICH em suas consultas ES|QL.
Você também pode notar que a região mais comumente encontrada foi null. O que isso poderia implicar? Lembre-se de que comparei este comando a um 'left join' em SQL, o que significa que se nenhum limite de cidade correspondente for encontrado para um aeroporto, o aeroporto ainda será retornado, mas com valores null para os campos do índice airport_city_boundaries . Descobriu-se que havia 89 aeroportos que não encontraram nenhum city_boundary correspondente e um aeroporto com uma correspondência onde o campo region era null. Isso levou a uma contagem de 90 aeroportos sem nenhum region nos resultados. Outro detalhe interessante é a necessidade do comando MV_EXPAND . Isso é necessário porque o comando ENRICH pode retornar vários resultados para cada linha de entrada e MV_EXPAND ajuda a separar esses resultados em várias linhas, uma para cada resultado. Isso também esclarece por que "Havaí" mostra resultados diferentes min_wkt e max_wkt : havia várias regiões com o mesmo nome, mas limites diferentes.
Mapas do Kibana
O Kibana adicionou suporte para Spatial ES|QL no aplicativo Maps. Isso significa que agora você pode usar o ES|QL para pesquisar dados geoespaciais no Elasticsearch e visualizar os resultados em um mapa.

Existe uma nova opção de camada no menu "Adicionar camadas", chamada "ES|QL". Assim como todos os recursos geoespaciais descritos até agora, este está em "prévia técnica". Selecionar esta opção permite adicionar uma camada ao mapa com base nos resultados de uma consulta ES|QL. Por exemplo, você poderia adicionar uma camada ao mapa que mostrasse todos os aeroportos do mundo.

Ou você poderia adicionar uma camada que mostre os polígonos do índice airport_city_boundaries , ou ainda melhor, que tal aquela consulta complexa ENRICH acima que gera estatísticas de quantos aeroportos existem em cada região?

O que vem a seguir?
Você deve ter notado que em dois dos exemplos acima incluímos mais uma função espacial ST_CENTROID_AGG. Esta é uma função de agregação usada no comando STATS e a primeira de muitas funcionalidades de análise espacial que planejamos adicionar ao ES|QL. Vamos publicar um artigo sobre isso quando tivermos mais informações para mostrar!
Antes disso, gostaríamos de falar mais sobre um recurso particularmente interessante no qual trabalhamos: a capacidade de realizar buscas por distância espacial, um dos recursos de busca espacial mais utilizados do Elasticsearch. Você consegue imaginar como seria a sintaxe para buscas por distância? Talvez semelhante a uma função OGC? Fique ligado(a) no próximo post desta série para descobrir!
Alerta de spoiler: o Elasticsearch 8.15 acaba de ser lançado e inclui pesquisa por distância espacial com ES|QL!




