<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Craig Taverner - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Craig Taverner - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/pt/search-labs/author/craig-taverner</link>
    </image>
    <link>https://www.elastic.co/pt/search-labs/author/craig-taverner</link>
    <atom:link href="https://www.elastic.co/pt/search-labs/rss/author/craig-taverner.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[pt]]></language>
    <lastBuildDate>Tue, 22 Sep 2026 11:53:56 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Ingerir dados geoespaciais no Elasticsearch com o Kibana para uso no ES|QL]]></title>
    <description><![CDATA[Como usar o Kibana e o processador de ingestão CSV para importar dados geoespaciais para o Elasticsearch para uso com pesquisa na Linguagem de Consulta Elasticsearch (ES|QL). O Elasticsearch possui recursos poderosos de busca geoespacial, que agora estão chegando ao ES|QL para uma facilidade de uso drasticamente aprimorada e familiaridade com o OGC. Mas para utilizar essas funcionalidades, precisamos de dados geoespaciais.]]></description>
    <content:encoded><![CDATA[<p>Recentemente publicamos um artigo no blog descrevendo como usar os novos <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">recursos</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">de pesquisa geoespacial</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">no ES|QL</a>, a nova e poderosa <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">linguagem de consulta encadeada</a> do Elasticsearch. Para usar esses recursos, você precisa ter dados geoespaciais no Elasticsearch. Neste blog, mostraremos como importar dados geoespaciais e como usá-los em consultas ES|QL.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="Pesquisa Geoespacial ESQL" /><h2>Importando dados geoespaciais usando o Kibana</h2><p>Os dados que usamos nos exemplos do blog anterior foram baseados em dados que usamos internamente para testes de integração. Para sua conveniência, incluímos aqui algumas informações em formato CSV que podem ser facilmente importadas usando o Kibana. Os dados são uma mistura de aeroportos, cidades e limites urbanos. Você pode baixar os dados de:</p><ul><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">aeroportos.csv</a></p><ul><li><p>Este arquivo contém uma fusão de três conjuntos de dados:</p><ul><li><p>Aeroportos (nomes, localizações e dados relacionados) do <a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth</a></p></li><li><p>Localização de cidades a partir <a href="https://simplemaps.com/data/world-cities">do SimpleMaps</a></p></li><li><p>Altitudes de aeroportos <a href="https://www.partow.net/miscellaneous/airportdatabase/">do banco de dados global de aeroportos</a></p></li></ul></li></ul></li><li><p><a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">limites_cidade_aeroporto.csv</a></p><ul><li><p>Esta seção contém uma fusão dos nomes de aeroportos e cidades mencionados acima com uma nova fonte:</p><ul><li><p>Limites da cidade do <a href="https://www.openstreetmap.org/">OpenStreetMap</a></p></li></ul></li></ul></li></ul><p>Como você pode imaginar, dedicamos algum tempo a combinar essas fontes de dados nos dois arquivos acima, com o objetivo de poder testar os recursos geoespaciais do ES|QL. Isso pode não ser exatamente o que você precisa em termos de dados, mas espero que lhe dê uma ideia do que é possível. Em particular, queremos demonstrar algumas coisas interessantes:</p><ul><li><p>Importação de dados com campos geoespaciais juntamente com outros dados indexáveis.</p></li><li><p>Importar dados <code>geo_point</code> e <code>geo_shape</code> e usá-los em conjunto em consultas</p></li><li><p>Importar dados para dois índices que podem ser unidos usando uma relação espacial.</p></li><li><p>Criar um pipeline de ingestão para facilitar importações futuras (além do Kibana)</p></li><li><p>Alguns exemplos de processadores de ingestão, como <code>csv</code>, <code>convert</code> e <code>split</code></p></li></ul><p>Embora neste blog abordemos o trabalho com dados CSV, é importante entender que existem <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">várias maneiras</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">de</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">adicionar dados geográficos usando</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">o Kibana</a>. No aplicativo Mapa, você pode carregar dados delimitados, como CSV, GeoJSON e ESRI ShapeFiles, e também pode desenhar formas diretamente no mapa. Neste blog, vamos nos concentrar na importação de arquivos CSV da página inicial do Kibana.</p><h3>Importando os aeroportos</h3><p>O primeiro arquivo, <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">airports.csv</a>, Possui algumas peculiaridades interessantes com as quais precisamos lidar. Em primeiro lugar, as colunas possuem espaços em branco adicionais entre si, o que não é típico de arquivos CSV. Em segundo lugar, o campo <code>type</code> é um campo de múltiplos valores, que precisamos dividir em campos separados. Por fim, alguns campos não são strings e precisam ser convertidos para o tipo correto. Tudo isso pode ser feito usando o recurso de importação de CSV do Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Upload do Kibana - Pré-visualização" /><p>Comece pela página inicial do Kibana. Existe uma seção chamada "Comece adicionando integrações", que possui um link chamado "Carregar um arquivo":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Página inicial do Kibana - Carregar um arquivo" /><p>Clique neste link e você será redirecionado para a página "Enviar arquivo". Aqui você pode arrastar e soltar o arquivo <code>airports.csv</code> , e o Kibana analisará o arquivo e apresentará uma pré-visualização dos dados. Deveria ter detectado automaticamente o delimitador como uma vírgula e a primeira linha como a linha de cabeçalho. No entanto, provavelmente não removeu o espaço em branco extra entre as colunas, nem determinou os tipos dos campos, assumindo que todos os campos são <code>text</code> ou <code>keyword</code>. Precisamos resolver isso.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Upload do Kibana - Pré-visualização" /><p>Clique em <code>Override settings</code> e marque a caixa de seleção para <code>Should trim fields</code> e <code>Apply</code> para fechar as configurações. Agora precisamos corrigir os tipos dos campos. Isso está disponível na próxima página, então clique em <code>Import</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Carregar no Kibana - Importar" /><p>Primeiro escolha um nome de índice e, em seguida, selecione <code>Advanced</code> para acessar os mapeamentos de campo e a página do processador de ingestão.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Carregamento no Kibana - Mapeamento de campos" /><p>Aqui precisamos fazer alterações tanto no mapeamento de campos do índice quanto no pipeline de ingestão para importar os dados. Em primeiro lugar, embora o Kibana provavelmente tenha detectado automaticamente o campo <code>scalerank</code> como <code>long</code>, ele erroneamente percebeu os campos <code>location</code> e <code>city_location</code> como <code>keyword</code>. Edite-os para <code>geo_point</code>, resultando em mapeamentos que se parecem com algo assim:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_location": { "type": "geo_point" },
    "country":       { "type": "keyword" },
    "elevation":     { "type": "double" },
    "location":      { "type": "geo_point" },
    "name":          { "type": "text" },
    "scalerank":     { "type": "long" },
    "type":          { "type": "keyword" }
  }
}<p>Você tem alguma flexibilidade aqui, mas observe que o tipo escolhido afetará a forma como o campo é indexado e os tipos de consultas possíveis. Por exemplo, se você deixar <code>location</code> como <code>keyword</code> não poderá realizar nenhuma consulta de pesquisa geoespacial nele. Da mesma forma, se você deixar <code>elevation</code> como <code>text</code> não poderá executar consultas de intervalo numérico nele.</p><p>Agora é hora de corrigir o pipeline de ingestão. Se o Kibana detectou automaticamente <code>scalerank</code> como <code>long</code> acima, ele também terá adicionado um processador para converter o campo em <code>long</code>. Precisamos adicionar um processador semelhante para o campo <code>elevation</code> , desta vez convertendo-o em <code>double</code>. Edite o pipeline para garantir que essa conversão esteja implementada. Antes de salvar isso, queremos mais uma conversão, para dividir o campo <code>type</code> em vários campos. Adicione um processador <code>split</code> ao pipeline, com a seguinte configuração:</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>O pipeline de ingestão final deve ter a seguinte aparência:</p>{
  "description": "Ingest pipeline created by text structure finder",
  "processors": [
    {
      "csv": {
        "field": "message",
        "target_fields": [
          "abbrev",
          "name",
          "scalerank",
          "type",
          "location",
          "country",
          "city",
          "city_location",
          "elevation"
        ],
        "ignore_missing": false,
        "trim": true
      }
    },
    {
      "convert": {
        "field": "scalerank",
        "type": "long",
        "ignore_missing": true
      }
    },
    {
      "convert": {
        "field": "elevation",
        "type": "double",
        "ignore_missing": true
      }
    },
    {
      "split": {
        "field": "type",
        "separator": ":",
        "ignore_missing": true
      }
    },
    {
      "remove": {
        "field": "message"
      }
    }
  ]
}<p>Observe que não adicionamos um processador de conversão para os campos <code>location</code> e <code>city_location</code> . Isso ocorre porque o tipo <code>geo_point</code> no mapeamento de campo já entende o formato WKT dos dados nesses campos. O tipo <code>geo_point</code> pode entender uma variedade de formatos, incluindo <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT, GeoJSON e outros</a>. Se tivéssemos, por exemplo, duas colunas no arquivo CSV para <code>latitude</code> e <code>longitude</code>, precisaríamos adicionar um processador <code>script</code> ou <code>set</code> para combiná-las em um único campo <code>geo_point</code> (por exemplo, <code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>Agora estamos prontos para importar o arquivo. Clique em <code>Import</code> e os dados serão importados para o índice com os mapeamentos e o pipeline de ingestão que acabamos de definir. Caso ocorram erros na ingestão dos dados, o Kibana os reportará aqui, para que você possa editar os dados de origem ou o pipeline de ingestão e tentar novamente.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Carregar no Kibana - Importando" /><p>Observe que um novo pipeline de ingestão foi criado. Isso pode ser visualizado indo para a seção <code>Stack Management</code> do Kibana e selecionando <code>Ingest pipelines</code>. Aqui você pode ver o pipeline que acabamos de criar e editá-lo, se necessário. Na verdade, a seção <code>Ingest pipelines</code> pode ser usada para criar e testar pipelines de ingestão, um recurso muito útil se você planeja fazer ingestões ainda mais complexas.</p><p>Se você deseja explorar esses dados imediatamente, pule para as seções posteriores, mas se também deseja importar os limites da cidade, continue lendo.</p><h3>Importando os limites da cidade</h3><p>O arquivo de limites da cidade disponível em <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airport_city_boundaries.csv">airport_city_boundaries.csv</a> é um pouco mais simples de importar do que o exemplo anterior. Contém um campo <code>city_boundary</code> que é uma representação WKT do limite da cidade como um <code>POLYGON</code> e um campo <code>city_location</code> que é uma representação <code>geo_point</code> da localização da cidade. Podemos importar esses dados de forma semelhante aos dados dos aeroportos, mas com algumas diferenças:</p><ul><li><p>Precisávamos selecionar a configuração de substituição <code>Has header row</code> pois ela não foi detectada automaticamente.</p></li><li><p>Não foi necessário remover espaços em branco dos campos, pois os dados já estavam livres de espaços desnecessários.</p></li><li><p>Não foi necessário editar o pipeline de ingestão, pois todos os tipos eram de string ou espaciais.</p></li><li><p>No entanto, tivemos que editar os mapeamentos de campo para definir o campo <code>city_boundary</code> como <code>geo_shape</code> e o campo <code>city_location</code> como . <code>geo_point</code></p></li></ul><p>Nossos mapeamentos de campo finais ficaram assim:</p>{
  "properties": {
    "abbrev":        { "type": "keyword" },
    "airport":       { "type": "keyword" },
    "city":          { "type": "keyword" },
    "city_boundary": { "type": "geo_shape" },
    "city_location": { "type": "geo_point" },
    "region":        { "type": "text" }
  }
}<p>Assim como na importação <code>airports.csv</code> anterior, basta clicar em <code>Import</code> para importar os dados para o índice. Os dados serão importados com os mapeamentos que editamos e o pipeline de ingestão definido pelo Kibana.</p><h3>Explorando dados geoespaciais com ferramentas de desenvolvimento</h3><p>No Kibana, é comum explorar os dados indexados com a opção "Descobrir". No entanto, se sua intenção é escrever seu próprio aplicativo usando consultas ES|QL, pode ser mais interessante tentar acessar a API Elasticsearch diretamente. O Kibana possui um console prático para experimentar a escrita de consultas. Isso é chamado de console <code>Dev Tools</code> e pode ser encontrado na barra lateral do Kibana. Este console se comunica diretamente com o cluster Elasticsearch e pode ser usado para executar consultas, criar índices e muito mais.</p><p>Experimente o seguinte:</p>POST /_query?error_trace=true&amp;format=txt
{
  "query": """
FROM airports
| EVAL distance = ST_DISTANCE(city_location, TO_GEOPOINT("POINT(12.565 55.673)"))
| WHERE distance &lt; 1000000 AND scalerank &lt; 6 AND distance &gt; 10000
| SORT distance ASC
| KEEP distance, abbrev, name, location, country, city, elevation
| LIMIT 10
  """
}<p>Isso deverá produzir os seguintes resultados:</p><p>distância</p><p>abreviar</p><p>nome</p><p>Local</p><p>país</p><p>cidade</p><p>elevação</p><p>273418.05776847183</p><p>PRESUNTO</p><p>Hamburgo</p><p>PONTO (10,005647830925 53,6320011640866)</p><p>Alemanha</p><p>Norderstedt</p><p>17.0</p><p>337534,653466062</p><p>TXL</p><p>Aeroporto Internacional de Berlim-Tegel</p><p>PONTO (13.2903090925074 52.5544287044101)</p><p>Alemanha</p><p>Hohen Neuendorf</p><p>38,0</p><p>483713.15032266214</p><p>OSL</p><p>Oslo Gardermoen</p><p>PONTO (11.0991032762581 60.1935783171386)</p><p>Noruega</p><p>Oslo</p><p>208,0</p><p>522538.03148094116</p><p>BMA</p><p>Broma</p><p>PONTO (17,9456175406145 59,3555902065112)</p><p>Suécia</p><p>Estocolmo</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>Arlanda</p><p>PONTO (17,9307299016916 59,6511203397372)</p><p>Suécia</p><p>Estocolmo</p><p>38,0</p><p>624274,8274399083</p><p>DUS</p><p>Aeroporto Internacional de Düsseldorf</p><p>PONTO (6,76494446612174 51,2781820420774)</p><p>Alemanha</p><p>Düsseldorf</p><p>45,0</p><p>633388,6966435644</p><p>PRG</p><p>Ruzyn</p><p>PONTO (14,2674849854076 50,1076511703671)</p><p>República Tcheca</p><p>Praga</p><p>381,0</p><p>635911.1873311149</p><p>AMS</p><p>Schiphol</p><p>PONTO (4,76437693232812 52,3089323889822)</p><p>Países Baixos</p><p>Hoofddorp</p><p>-3,0</p><p>670864.137958866</p><p>FRA</p><p>Frankfurt Internacional</p><p>PONTO (8,57182286907608 50,0506770895207)</p><p>Alemanha</p><p>Frankfurt</p><p>111.0</p><p>683239,2529970079</p><p>UAU</p><p>Okecie Int'l</p><p>PONTO (20,9727263383587 52,171026749259)</p><p>Polônia</p><p>Piaseczno</p><p>111.0</p><h2>Visualizando dados geoespaciais com o Kibana Maps</h2><p>O Kibana Maps é uma ferramenta poderosa para visualizar dados geoespaciais. Pode ser usado para criar mapas com múltiplas camadas, cada camada representando um conjunto de dados diferente. Os dados podem ser filtrados, agregados e formatados de diversas maneiras. Nesta seção, mostraremos como criar um mapa no Kibana Maps usando os dados que importamos na seção anterior.</p><p>No menu do Kibana, navegue até <code>Analytics</code>-&gt;<code>Maps</code> para abrir uma nova visualização do mapa. Clique em <code>Add Layer</code> e selecione <code>Documents</code>, escolhendo a visualização de dados <code>airports</code> e editando o estilo da camada para colorir os marcadores usando o campo <code>elevation</code> , para que possamos ver facilmente a altitude de cada aeroporto.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana Maps - Estilo de Camada de Aeroportos" /><p>Clique em "Manter alterações" para salvar o mapa:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Mapas do Kibana - Aeroportos" /><p>Agora adicione uma segunda camada, desta vez selecionando a visualização de dados <code>airport_city_boundaries</code> . Desta vez, usaremos o campo <code>city_boundary</code> para estilizar a camada e definiremos a cor de preenchimento para um azul claro. Isso mostrará os limites da cidade no mapa. Certifique-se de reordenar as camadas para garantir que os marcadores do aeroporto fiquem por cima.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana Maps - Estilo de Camada de Limites da Cidade" /><h2>Junções espaciais</h2><p>ES|QL não suporta comandos <code>JOIN</code> , mas você pode realizar um caso especial de junção usando o <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich">comando</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a> . 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.</p><p>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:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>Se você executar essa consulta sem primeiro preparar o índice de enriquecimento, receberá uma mensagem de erro como esta:</p>cannot find enrich policy [city_boundaries]<p>Isso ocorre porque, como mencionamos anteriormente, o ES|QL não suporta comandos <code>JOIN</code> verdadeiros. Um motivo importante para isso é que o Elasticsearch é um sistema distribuído, e as junções são operações custosas e difíceis de escalar. No entanto, o comando <code>ENRICH</code> pode ser bastante eficiente, porque utiliza índices enriquecidos especialmente preparados que são duplicados em todo o cluster, permitindo que junções locais sejam realizadas em cada nó.</p><p>Para melhor compreender isso, vamos nos concentrar no comando <code>ENRICH</code> na consulta acima:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>Este comando instrui o Elasticsearch a enriquecer os resultados recuperados do índice <code>airports</code> e a realizar uma junção <code>intersects</code> entre o campo <code>city_location</code> do índice original e o campo <code>city_boundary</code> do índice <code>airport_city_boundaries</code> , 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 <code>city_boundaries</code> e a informação em falta está encapsulada na definição dessa política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>Aqui podemos ver que ele executará uma consulta <code>geo_match</code> (<code>intersects</code> é o padrão), o campo para comparar é <code>city_boundary</code> e os <code>enrich_fields</code> são os campos que queremos adicionar ao documento original. Um desses campos, o <code>region</code> foi na verdade usado como chave de agrupamento para o comando <code>STATS</code> , 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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentação de enriquecimento</a>.</p><p>Os índices e políticas de enriquecimento no Elasticsearch foram originalmente projetados para enriquecer dados no momento da indexação, usando dados de outro índice de enriquecimento já preparado. Em ES|QL, no entanto, o comando <code>ENRICH</code> funciona no momento da consulta e não requer o uso de pipelines de ingestão. Isso efetivamente o torna bastante semelhante a um SQL <code>LEFT JOIN</code>, exceto que você não pode unir quaisquer dois índices, apenas um índice normal à esquerda com um índice enriquecido especialmente preparado à direita.</p><p>Em ambos os casos, seja para pipelines de ingestão ou para uso no ES|QL, é necessário executar algumas etapas preparatórias para configurar o índice e a política de enriquecimento. Já importamos o índice <code>airport_city_boundaries</code> acima, mas este não é diretamente utilizável como um índice de enriquecimento no comando <code>ENRICH</code> . Primeiro, precisamos realizar duas etapas:</p><ul><li><p>Crie a política de enriquecimento descrita acima para definir o índice de origem, o campo no índice de origem a ser comparado e os campos a serem retornados após a correspondência.</p></li><li><p>Execute esta política para criar o índice de enriquecimento. Isso criará um índice interno especial, lendo o índice de origem original para uma estrutura de dados mais eficiente, que será copiada em todo o cluster.</p></li></ul><p>A política de enriquecimento pode ser criada usando o seguinte comando:</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>E a política pode ser executada usando o seguinte comando:</p>POST /_enrich/policy/city_boundaries/_execute<p>Observe que, se você alterar o conteúdo do índice <code>airport_city_boundaries</code> , precisará executar esta política novamente para ver as alterações refletidas no índice enriquecido. Agora, vamos executar a consulta ES|QL original novamente:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| STATS
    centroid = ST_CENTROID_AGG(location),
    count = COUNT(city_location)
    BY region
| SORT count DESC
| LIMIT 10<p>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:</p><p>centroide</p><p>Contagem</p><p>região</p><p>PONTO (-12.139086859300733 31.024386116624648)</p><p>126</p><p>nulo</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>PONTO (39,74537850357592 47,21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>PONTO (-156,80986787192523 20,476673701778054)</p><p>3</p><p>Havaí</p><p>PONTO (-73,94515332765877 40,70366442203522)</p><p>3</p><p>Cidade de Nova York</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>PONTO (-76,66873019188643 24.306286952923983)</p><p>2</p><p>Nova Providência</p><p>PONTO (-3,0252167768776417 51,39245774131268)</p><p>2</p><p>Cardiff</p><p>PONTO (-115,40993484668434 32,73126147687435)</p><p>2</p><p>Município de Mexicali</p><p>PONTO (41,790108773857355 50,302146775648)</p><p>2</p><p>Área Central</p><p>PONTO (-73,88902732171118 45.57078813901171)</p><p>2</p><p>Montreal</p><p>Você também pode notar que a região mais comumente encontrada foi <code>null</code>. 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 <code>null</code> para os campos do índice <code>airport_city_boundaries</code> . Descobriu-se que havia 125 aeroportos que não encontraram nenhum <code>city_boundary</code> correspondente e um aeroporto com uma correspondência onde o campo <code>region</code> era <code>null</code>. Isso levou a uma contagem de 126 aeroportos sem nenhum <code>region</code> nos resultados. Se o seu caso de uso exigir que todos os aeroportos possam ser associados aos limites de uma cidade, isso exigirá a obtenção de dados adicionais para preencher as lacunas. Seria necessário determinar duas coisas:</p><ul><li><p>quais registros no índice <code>airport_city_boundaries</code> não possuem campos <code>city_boundary</code></p></li><li><p>quais registros no índice <code>airports</code> não correspondem usando o comando <code>ENRICH</code> (ou seja, não se cruzam)</p></li></ul><h2>Utilizando ES|QL para dados geoespaciais em mapas do Kibana</h2><p>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.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Camadas do Kibana ES|QL" /><p>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.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeroportos" /><p>Ou você poderia adicionar uma camada que mostre os polígonos do índice <code>airport_city_boundaries</code> , ou ainda melhor, que tal aquela consulta complexa <code>ENRICH</code> acima que gera estatísticas de quantos aeroportos existem em cada região?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estatísticas da região" /><h2>O que vem a seguir?</h2><p>O blog anterior <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">sobre pesquisa geoespacial</a> focou no uso de funções como <code>ST_INTERSECTS</code> para realizar pesquisas, disponíveis no Elasticsearch desde a versão 8.14. E este blog mostra como importar os dados que usamos nessas pesquisas. No entanto, o Elasticsearch 8.15 trouxe uma função particularmente interessante: <code>ST_DISTANCE</code> que pode ser usada para realizar pesquisas eficientes de distância espacial, e este será o tema do próximo blog!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/geospatial-data-ingest-for-esql</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 25 Oct 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Pesquisa geoespacial do Elasticsearch com ES|QL]]></title>
    <description><![CDATA[Pesquisa geoespacial na linguagem de consulta Elasticsearch (ES|QL). O Elasticsearch possui recursos poderosos de busca geoespacial, que agora estão chegando ao ES|QL para uma facilidade de uso drasticamente aprimorada e familiaridade com o OGC.]]></description>
    <content:encoded><![CDATA[<p>O Elasticsearch possui <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">recursos poderosos de busca e análise geoespacial</a> há muitos anos, mas a API era bastante diferente daquilo a que os usuários típicos de SIG estavam acostumados. No último ano <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">, adicionamos a linguagem de consulta ES|QL</a>, 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 <a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a> .</p><p>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 <a href="https://en.wikipedia.org/wiki/Simple_Features">Simple Feature Access</a> do <a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">Open Geospatial Consortium (OGC),</a> 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.</p><p>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.</p><h2>Pesquisa de dados geoespaciais</h2><p>Vamos começar com um exemplo de consulta:</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>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).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="Pesquisa Geoespacial ESQL" /><p>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:</p><p>abreviar</p><p>aeroporto</p><p>região</p><p>cidade</p><p>localização da cidade</p><p>SYX</p><p>Sanya Phoenix Int'l</p><p>天涯区</p><p>Sanya</p><p>PONTO(109,5036 18,2533)</p><p>Isso foi fácil! Agora compare isso com a DSL de consulta clássica do Elasticsearch para a mesma consulta:</p>GET /airport_city_boundaries/_search
{
  "_source": ["abbrev", "airport", "region", "city", "city_location"],
  "query": {
    "geo_shape": {
      "city_boundary": {
        "shape": {
          "type": "polygon",
          "coordinates" : [[
            [109.4, 18.1],
            [109.6, 18.1],
            [109.6, 18.3],
            [109.4, 18.3],
            [109.4, 18.1]
          ]]
        }
      }
    }
  }
}
<p>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:</p>SELECT abbrev, airport, region, city, city_location
FROM airport_city_boundaries
WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
);
<p>Relembre o exemplo em ES|QL. São muito parecidos, não é?</p>FROM airport_city_boundaries
| WHERE ST_INTERSECTS(
      city_boundary,
      "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
  )
| KEEP abbrev, airport, region, city, city_location
<p>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.</p><h4>Por que não usar SQL?</h4><p>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 é <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">frequentemente mais rápido que a API de consulta</a>, principalmente em operações de agregação!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="referência de interseção de polígonos" /><h2>Diferenças em relação ao SQL</h2><p>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 <code>WHERE</code>, adicionar colunas com <code>EVAL</code> ou realizar agregações com <code>STATS</code>. Em vez de começar com <code>SELECT</code> para definir as colunas de saída finais, pode haver um ou mais comandos <code>KEEP</code> , com o último especificando os resultados de saída finais. Essa estrutura simplifica o raciocínio sobre a consulta.</p><p>Analisando o comando <code>WHERE</code> no exemplo acima, podemos ver que ele é bastante semelhante ao exemplo do PostGIS:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    "POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))"::geo_shape
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    'SRID=4326;POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'::geometry
)
<p>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 <code>::geometry</code> , enquanto no ES|QL, usamos o sufixo <code>::geo_shape</code> . Isso ocorre porque o ES|QL é executado dentro do Elasticsearch e o operador de conversão de tipo <code>::</code> pode ser usado para converter uma string em qualquer um dos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">tipos ES|QL suportados</a>, neste caso, um <code>geo_shape</code>. Além disso, os tipos <code>geo_shape</code> e <code>geo_point</code> 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 <code>SRID=4326;</code> na string WKT. Se esse prefixo for removido, o SRID será definido como 0, que é mais parecido com os tipos do Elasticsearch <code>cartesian_point</code> e <code>cartesian_shape</code>, que não estão vinculados a nenhum sistema de coordenadas específico.</p><p>Tanto o ES|QL quanto o PostGIS também fornecem sintaxe para funções de conversão de tipo:</p><p><em>ES|QL</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    TO_GEOSHAPE("POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))")
)
<p><em>PostGIS</em></p>WHERE ST_INTERSECTS(
    city_boundary,
    ST_SetSRID(
      ST_GeomFromText('POLYGON((109.4 18.1, 109.6 18.1, 109.6 18.3, 109.4 18.3, 109.4 18.1))'),
      4326
    )
)
<h2>Funções OGC</h2><p>O Elasticsearch 8.14 introduz as seguintes quatro funções de pesquisa espacial OGC:</p><p>ES|QL</p><p>PostGIS</p><p>Descrição</p><p>ST_INTERSETOS</p><p>ST_Interseções</p><p>Retorna verdadeiro se duas geometrias se intersectam e falso caso contrário.</p><p>ST_DISJOINT</p><p>ST_Disjunto</p><p>Retorna verdadeiro se as duas geometrias não se intersectarem e falso caso contrário. O inverso de ST_INTERSETOS.</p><p>ST_CONTÉM</p><p>ST_Contém</p><p>Retorna verdadeiro se uma geometria contém outra, e falso caso contrário.</p><p>ST_DENTRO</p><p>ST_Dentro</p><p>Retorna verdadeiro se uma geometria estiver dentro de outra, e falso caso contrário. O inverso de ST_CONTAINS.</p><p>Essas funções se comportam de maneira semelhante às suas contrapartes no PostGIS e são usadas da mesma forma. Por exemplo, <code>ST_INTERSECTS</code> 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 <code>WHERE</code> após uma cláusula <code>FROM</code> , 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.</p><p>O primeiro exemplo na documentação do PostGIS para <code>ST_INTERSECTS</code> é:</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>O equivalente em ES|QL seria:</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>Observe que não especificamos o SRID no exemplo do PostGIS. Isso ocorre porque no PostGIS, ao usar o tipo <code>geometry</code> , 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 <code>geo_shape</code> e <code>geo_point</code> usam cálculos esféricos, como veremos no próximo blog sobre pesquisa de distância espacial.</p><h2>Versatilidade ES|QL</h2><p>Então, vimos exemplos acima de uso de funções espaciais em cláusulas <code>WHERE</code> e em comandos <code>ROW</code> . Em que outro lugar fariam sentido? Um local muito útil é no comando <code>EVAL</code> . 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:</p>FROM airports
| EVAL in_uk = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL in_iceland = ST_INTERSECTS(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| EVAL within_uk = ST_WITHIN(location, TO_GEOSHAPE("POLYGON((1.2305 60.8449, -1.582 61.6899, -10.7227 58.4017, -7.1191 55.3291, -7.9102 54.2139, -5.4492 54.0078, -5.2734 52.3756, -7.8223 49.6676, -5.0977 49.2678, 0.9668 50.5134, 2.5488 52.1065, 2.6367 54.0078, -0.9668 56.4625, 1.2305 60.8449))"))
| EVAL within_iceland = ST_WITHIN(location, TO_GEOSHAPE("POLYGON ((-25.4883 65.5312, -23.4668 66.7746, -18.4131 67.4749, -13.0957 66.2669, -12.3926 64.4159, -20.1270 62.7346, -24.7852 63.3718, -25.4883 65.5312))"))
| STATS centroid = ST_CENTROID_AGG(location), count=COUNT() BY in_uk, in_iceland, within_uk, within_iceland
| SORT count ASC
<p>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.</p><p>centroide</p><p>Contagem</p><p>no Reino Unido</p><p>na Islândia</p><p>dentro do Reino Unido</p><p>dentro da Islândia</p><p>PONTO (-21,946634463965893 64.13187285885215)</p><p>1</p><p>falso</p><p>verdadeiro</p><p>falso</p><p>verdadeiro</p><p>PONTO (-2,597342072712148 54,33551226578214)</p><p>17</p><p>verdadeiro</p><p>falso</p><p>verdadeiro</p><p>falso</p><p>PONTO (0,04453958108176276 23,74658354606057)</p><p>873</p><p>falso</p><p>falso</p><p>falso</p><p>falso</p><p>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 <code>geo_shape</code> e <code>cartesian_shape</code> na mesma chamada de função. Você pode, no entanto, misturar os tipos <code>geo_point</code> e <code>geo_shape</code> , já que o tipo <code>geo_point</code> é um caso especial do tipo <code>geo_shape</code> 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.</p><p>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:</p>FROM airport_city_boundaries
| EVAL in_city = ST_INTERSECTS(city_location, city_boundary)
| STATS count=COUNT(*) BY in_city
| SORT count ASC
| EVAL cardinality = CASE(count &lt; 10, "very few", count &lt; 100, "few", "many")
| KEEP cardinality, count, in_city
<p>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:</p><p>cardinalidade</p><p>Contagem</p><p>na cidade</p><p>alguns</p><p>29</p><p>falso</p><p>muitos</p><p>740</p><p>verdadeiro</p><p>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.</p><h2>Junções espaciais</h2><p>ES|QL não suporta comandos <code>JOIN</code> , mas você pode obter um caso especial de junção usando o<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"> comando</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a> , 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.</p><p>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:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
| MV_EXPAND city_boundary
| EVAL boundary_wkt_length = LENGTH(TO_STRING(city_boundary))
| STATS centroid = ST_CENTROID_AGG(location), count = COUNT(city_location), min_wkt = MIN(boundary_wkt_length), max_wkt = MAX(boundary_wkt_length) BY region
| SORT count DESC
| LIMIT 5
<p>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:</p><p>centroide</p><p>Contagem</p><p>min_wkt</p><p>max_wkt</p><p>região</p><p>PONTO (-32,56093470960719 32,598117914802714)</p><p>90</p><p>207</p><p>207</p><p>nulo</p><p>PONTO (-73,94515332765877 40,70366442203522)</p><p>9</p><p>438</p><p>438</p><p>Cidade de Nova York</p><p>PONTO (-83.10398317873478 42.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>Detroit</p><p>PONTO (-156.3020245861262 20,176383580081165)</p><p>5</p><p>307</p><p>803</p><p>Havaí</p><p>PONTO (-73,88902732171118 45.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>Montreal</p><p>Então, o que realmente aconteceu aqui? Onde ocorreu o suposto <code>JOIN</code> ? O ponto crucial da questão reside no comando <code>ENRICH</code> :</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>Este comando instrui o Elasticsearch a enriquecer os resultados recuperados do índice <code>airports</code> e a realizar uma junção <code>intersects</code> entre o campo <code>city_location</code> do índice original e o campo <code>city_boundary</code> do índice <code>airport_city_boundaries</code> , 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 <code>city_boundaries</code> e a informação em falta está encapsulada na definição dessa política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>Aqui podemos ver que ele executará uma consulta <code>geo_match</code> (<code>intersects</code> é o padrão), o campo para comparar é <code>city_boundary</code> e os <code>enrich_fields</code> são os campos que queremos adicionar ao documento original. Um desses campos, o <code>region</code> foi na verdade usado como chave de agrupamento para o comando <code>STATS</code> , 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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentação de enriquecimento</a>. 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 <code>ENRICH</code> 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 <code>ENRICH</code> em suas consultas ES|QL.</p><p>Você também pode notar que a região mais comumente encontrada foi <code>null</code>. 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 <code>null</code> para os campos do índice <code>airport_city_boundaries</code> . Descobriu-se que havia 89 aeroportos que não encontraram nenhum <code>city_boundary</code> correspondente e um aeroporto com uma correspondência onde o campo <code>region</code> era <code>null</code>. Isso levou a uma contagem de 90 aeroportos sem nenhum <code>region</code> nos resultados. Outro detalhe interessante é a necessidade do comando <code>MV_EXPAND</code> . Isso é necessário porque o comando <code>ENRICH</code> pode retornar vários resultados para cada linha de entrada e <code>MV_EXPAND</code> ajuda a separar esses resultados em várias linhas, uma para cada resultado. Isso também esclarece por que "Havaí" mostra resultados diferentes <code>min_wkt</code> e <code>max_wkt</code> : havia várias regiões com o mesmo nome, mas limites diferentes.</p><h2>Mapas do Kibana</h2><p>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.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Camadas do Kibana ES|QL" /><p>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.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeroportos" /><p>Ou você poderia adicionar uma camada que mostre os polígonos do índice <code>airport_city_boundaries</code> , ou ainda melhor, que tal aquela consulta complexa <code>ENRICH</code> acima que gera estatísticas de quantos aeroportos existem em cada região?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estatísticas da região" /><h2>O que vem a seguir?</h2><p>Você deve ter notado que em dois dos exemplos acima incluímos mais uma função espacial <code>ST_CENTROID_AGG</code>. Esta é uma função de agregação usada no comando <code>STATS</code> 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!</p><p>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!</p><p>Alerta de spoiler: o Elasticsearch 8.15 acaba de ser lançado e inclui pesquisa por distância espacial com ES|QL!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</guid>
    <category><![CDATA[Python]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd05627be20e89dfb/6a17d7c6414c640256944fdb/de886289dcb56494920875303b622b030b9b810f-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 Aug 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>