<?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/es/search-labs/author/craig-taverner</link>
    </image>
    <link>https://www.elastic.co/es/search-labs/author/craig-taverner</link>
    <atom:link href="https://www.elastic.co/es/search-labs/rss/author/craig-taverner.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[es]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 06:01:00 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Ingirir datos geoespaciales en Elasticsearch con Kibana para su uso en ES|QL]]></title>
    <description><![CDATA[Cómo usar Kibana y el procesador de ingesta csv para ingirse datos geoespaciales en Elasticsearch para usarlos con la búsqueda en el lenguaje de consultas de Elasticsearch (ES|QL). Elasticsearch cuenta con poderosas características de búsqueda geoespacial, que ahora están llegando a ES|QL por una facilidad de uso mucho mejorada y familiaridad con el OGC. Pero para usar estas características, necesitamos datos geoespaciales.]]></description>
    <content:encoded><![CDATA[<p>Recientemente publicamos un blog describiendo cómo emplear las nuevas <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">características</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">de búsqueda geoespacial</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">en ES|QL,</a> el nuevo y poderoso <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">lenguaje de consultas por tubes</a> de Elasticsearch. Para usar estas características, necesitas tener datos geoespaciales en Elasticsearch. Así que en este blog, te mostraremos cómo ingerir datos geoespaciales y cómo usarlos en ES|Consultas QL.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="Búsqueda Geoespacial ESQL" /><h2>Importación de datos geoespaciales usando Kibana</h2><p>Los datos que usamos para los ejemplos del blog anterior se basaban en datos que usamos internamente para pruebas de integración. Para tu comodidad, lo incluimos aquí en forma de algunos archivos CSV que se pueden importar fácilmente usando Kibana. Los datos son una mezcla de aeropuertos, ciudades y límites urbanos. Puedes descargar los datos desde:</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">airports.csv</a></p><ul><li><p>Este contiene una fusión de tres conjuntos de datos:</p><ul><li><p>Aeropuertos (nombres, ubicaciones y datos relacionados) de <a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth</a></p></li><li><p>Ubicaciones de las ciudades según <a href="https://simplemaps.com/data/world-cities">SimpleMaps</a></p></li><li><p>Elevaciones de aeropuertos según <a href="https://www.partow.net/miscellaneous/airportdatabase/">la base de datos global de aeropuertos</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">airport_city_boundaries.csv</a></p><ul><li><p>Esto contiene una fusión de nombres de aeropuertos y ciudades mencionados anteriormente con una fuente nueva:</p><ul><li><p>Límites de la ciudad según <a href="https://www.openstreetmap.org/">OpenStreetMap</a></p></li></ul></li></ul></li></ul><p>Como puedes imaginar, dedicamos un tiempo a combinar estas fuentes de datos en los dos archivos anteriores, con el objetivo de poder probar las características geoespaciales de ES|QL. Puede que esto no sea exactamente lo mismo que tus necesidades específicas de datos, pero espero que esto te dé una idea de lo que es posible. En individuo, queremos demostrar algunas cosas interesantes:</p><ul><li><p>Importación de datos con campos geoespaciales junto con otros datos indexables</p></li><li><p>Importar datos <code>geo_point</code> y <code>geo_shape</code> y usarlos juntos en consultas</p></li><li><p>Importación de datos en dos índices que pueden unir mediante una relación espacial</p></li><li><p>Crear una canalización de ingestión para facilitar futuras importaciones (más allá de Kibana)</p></li><li><p>Algunos ejemplos de procesadores de ingest, como <code>csv</code>, <code>convert</code> y <code>split</code></p></li></ul><p>Aunque en este blog hablaremos sobre cómo trabajar con datos CSV, es importante entender que existen <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">varias formas</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">agregar datos geográficos usando</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">Kibana</a>. Dentro de la aplicación de mapas puedes subir datos delimitados como archivos de forma CSV, GeoJSON y ESRI, y también puedes dibujar formas directamente en el mapa. Para este blog nos centraremos en importar archivos CSV desde la página principal de Kibana.</p><h3>Importación de aeropuertos</h3><p>El primer expediente <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">, airports.csv</a>, tiene algunas rarezas interesantes con las que tenemos que lidiar. En primer lugar, las columnas tienen espacios en blanco adicionales que las separan, algo que no es típico de los archivos CSV. En segundo lugar, el campo <code>type</code> es un campo de varios valores, que necesitamos separar en cuerpos separados. Por último, algunos campos no son cadenas y necesitan convertir al tipo correcto. Todo esto se puede hacer empleando la instalación de importación CSV de Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Kibana Upload - Vista previa" /><p>Empieza en la página principal de Kibana. Hay una sección llamada "Empezar agregando integraciones", que tiene un enlace llamado "Subir un archivo":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Kibana Home - Sube un archivo" /><p>Haz clic en este enlace y serás llevado a la página "Subir archivo". Aquí puedes arrastrar y soltar el archivo <code>airports.csv</code> , y Kibana analizará el archivo y te mostrará una vista previa de los datos. Debería detectar automáticamente el delimitador como una coma, y la primera fila como la fila de cabecera. Sin embargo, probablemente no recortó el espacio en blanco extra entre las columnas, ni determinó los tipos de campos, suponiendo que todos los campos sean <code>text</code> o <code>keyword</code>. Tenemos que arreglar esto.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Kibana Upload - Vista previa" /><p>Haz clic <code>Override settings</code> y marca la casilla para <code>Should trim fields</code>y <code>Apply</code> para cerrar la configuración. Ahora necesitamos fijar los tipos de los campos. Esto está disponible en la página siguiente, así que adelante y haz clic <code>Import</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Kibana Upload - Importación" /><p>Primero elige un nombre de índice y luego selecciona <code>Advanced</code> para acceder a la página de mapeo de campos e ingesta del procesador.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Kibana Upload - Mapeos de campos" /><p>Aquí necesitamos hacer cambios tanto en los mapeos de campos del índice como en la canalización de ingesta para importar los datos. En primer lugar, aunque Kibana probablemente detectó automáticamente el campo <code>scalerank</code> como <code>long</code>, percibió erróneamente los campos <code>location</code> y <code>city_location</code> como <code>keyword</code>. Edítalos para que <code>geo_point</code>, y acabes con mapeos que se ven algo así como:</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>Aquí tienes cierta flexibilidad, pero ten en cuenta que el tipo que elijas afectará a cómo se indexa el campo y qué tipo de consultas son posibles. Por ejemplo, si dejas <code>location</code> tal <code>keyword</code> no puedes realizar ninguna consulta de búsqueda geoespacial sobre él. De manera similar, si dejas <code>elevation</code> tal <code>text</code> no puedes realizar consultas numéricas por rango.</p><p>Ahora es el momento de arreglar la pipeline de ingest. Si Kibana detectó automáticamente <code>scalerank</code> como <code>long</code> anterior, también agregó un procesador para convertir el campo en un <code>long</code>. Necesitamos agregar un procesador similar para el campo <code>elevation</code> , esta vez convirtiéndolo a <code>double</code>. Edita la canalización para cerciorarte de que tienes esta conversión en marcha. Antes de almacenar esto, queremos una conversión más, para dividir el campo de <code>type</code> en varios campos. Agregar un procesador <code>split</code> a la canalización, con la siguiente configuración:</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>La pipeline final de ingesta debería ser la siguiente:</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>Ten en cuenta que no agregamos un procesador de conversión para los campos <code>location</code> y <code>city_location</code> . Esto se debe a que el tipo <code>geo_point</code> en el mapeo de campos ya entiende el formato WKT de los datos en estos campos. El tipo <code>geo_point</code> puede comprender una variedad de formatos, incluyendo <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT, GeoJSON y más</a>. Si tuviéramos, por ejemplo, dos columnas en el archivo CSV para <code>latitude</code> y <code>longitude</code>, tuvimos que agregar un procesador <code>script</code> o un <code>set</code> para combinarlas en un solo campo <code>geo_point</code> (por ejemplo, <code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>Ahora estamos listos para importar el archivo. Haz clic <code>Import</code> y los datos se importarán al índice con los mapeos y la pipeline de ingesta que acabamos de definir. Si hay errores al absorber los datos, Kibana los reportará aquí, así que puedes editar los datos fuente o la pipeline de ingesta y volver a intentarlo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Kibana Upload - Importación" /><p>Fíjate que se creó una nueva canalización de ingestión. Esto puede comprobar yendo a la sección <code>Stack Management</code> de Kibana y seleccionando <code>Ingest pipelines</code>. Aquí puedes ver la canalización que acabamos de crear y editarla si es necesario. De hecho, la sección <code>Ingest pipelines</code> puede usar para crear y probar canalizaciones de ingest, una función muy útil si planeas hacer ingestas aún más complejas.</p><p>Si quieres explorar estos datos inmediatamente, baja a las secciones posteriores, pero si también quieres importar los límites de la ciudad, sigue leyendo.</p><h3>Importación de los límites de la ciudad</h3><p>El archivo de límites de la ciudad disponible en <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> es un poco más sencillo de importar que el ejemplo anterior. Contiene un campo <code>city_boundary</code> que es una representación WKT del límite de la ciudad como <code>POLYGON</code>y un campo <code>city_location</code> que es una representación <code>geo_point</code> de la ubicación de la ciudad. Podemos importar estos datos de forma similar a los datos del aeropuerto, pero con algunas diferencias:</p><ul><li><p>Tuvimos que seleccionar la opción de anulación <code>Has header row</code> ya que no se detectó automáticamente</p></li><li><p>No fue necesario recortar campos, ya que los datos ya estaban limpios de espacio en blanco extra</p></li><li><p>No tuvimos que editar la tubería de ingesta porque todos los tipos eran de cadena o de tipos espaciales</p></li><li><p>Sin embargo, tuvimos que editar los mapeos de campos para establecer el campo <code>city_boundary</code> a <code>geo_shape</code> y el campo <code>city_location</code> a <code>geo_point</code></p></li></ul><p>Nuestros mapeos finales de campo eran los siguientes:</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>Como con la importación <code>airports.csv</code> anterior, simplemente haz clic <code>Import</code> para importar los datos al índice. Los datos se importarán junto con los mapeos que editamos y la pipeline de ingesta que Kibana definió.</p><h3>Explorando datos geoespaciales con herramientas de desarrollo</h3><p>En Kibana es habitual explorar los datos indexados con "Descubrir". Sin embargo, si tu intención es crear tu propia app usando ES|Consultas QL, podría ser más interesante intentar acceder a la API en bruto de Elasticsearch. Kibana tiene una consola práctica para experimentar escribiendo consultas. Esto se llama la consola <code>Dev Tools</code> y se puede encontrar en la barra lateral de Kibana. Esta consola se comunica directamente con el clúster Elasticsearch y puede usar para ejecutar consultas, crear índices y más.</p><p>Prueba lo siguiente:</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>Esto debería proporcionar los siguientes resultados:</p><p>distancia</p><p>Abbrev</p><p>nombre</p><p>Ubicación</p><p>país</p><p>ciudad</p><p>elevación</p><p>273418.05776847183</p><p>JAMÓN</p><p>Hamburgo</p><p>POINT (10.005647830925 53.6320011640866)</p><p>Alemania</p><p>Norderstedt</p><p>17.0</p><p>337534.653466062</p><p>TXL</p><p>Berlin-Tegel Int'l</p><p>POINT (13.2903090925074 52.5544287044101)</p><p>Alemania</p><p>Hohen Neuendorf</p><p>38.0</p><p>483713.15032266214</p><p>OSL</p><p>Oslo Gardermoen</p><p>POINT (11.0991032762581 60.1935783171386)</p><p>Noruega</p><p>Oslo</p><p>208.0</p><p>522538.03148094116</p><p>BMA</p><p>Bromma</p><p>POINT (17.9456175406145 59.3555902065112)</p><p>Suecia</p><p>Estocolmo</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>Arlanda</p><p>POINT (17.9307299016916 59.6511203397372)</p><p>Suecia</p><p>Estocolmo</p><p>38.0</p><p>624274.8274399083</p><p>DUS</p><p>Düsseldorf Int'l</p><p>POINT (6.76494446612174 51.2781820420774)</p><p>Alemania</p><p>Düsseldorf</p><p>45.0</p><p>633388.6966435644</p><p>PRG</p><p>Ruzyn</p><p>POINT (14.2674849854076 50.1076511703671)</p><p>Chequia</p><p>Praga</p><p>381.0</p><p>635911.1873311149</p><p>AMS</p><p>Schiphol</p><p>PUNTO (4.76437693232812 52.3089323889822)</p><p>Países Bajos</p><p>Hoofddorp</p><p>-3.0</p><p>670864.137958866</p><p>FRA</p><p>Nt'l de Frankfurt</p><p>POINT (8.57182286907608 50.0506770895207)</p><p>Alemania</p><p>Fráncfort</p><p>111.0</p><p>683239.2529970079</p><p>WAW</p><p>Okecie Int'l</p><p>POINT (20.9727263383587 52.171026749259)</p><p>Polonia</p><p>Piaseczno</p><p>111.0</p><h2>Visualización de datos geoespaciales con Kibana Maps</h2><p>Kibana Maps es una herramienta poderosa para visualizar datos geoespaciales. Puede emplear para crear mapas con múltiples capas, cada capa representando un conjunto de datos diferente. Los datos pueden filtrar, agregar y estilizar de diversas maneras. En esta sección, te mostraremos cómo crear un mapa en Kibana Maps usando los datos que importamos en la sección anterior.</p><p>En el menú Kibana, navega hasta <code>Analytics</code>-&gt;<code>Maps</code> para abrir una nueva vista del mapa. Haz clic en <code>Add Layer</code> y selecciona <code>Documents</code>, eligiendo el <code>airports</code> de vista de datos y luego editando el estilo de capa para colorear los marcadores usando el campo <code>elevation</code> , para que podamos ver fácilmente la altura de cada aeropuerto.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana Maps - Estilo de Capa de Aeropuertos" /><p>Haz clic en 'Conservar cambios' para almacenar el mapa:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Kibana Maps - Aeropuertos" /><p>Ahora agrega una segunda capa, esta vez seleccionando la vista de datos <code>airport_city_boundaries</code> . Esta vez, usaremos el campo <code>city_boundary</code> para estilizar la capa y pondremos el color de relleno en azul claro. Esto mostrará los límites de la ciudad en el mapa. Cerciórate de reordenar las capas para que los marcadores del aeropuerto estén encima.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana Maps - Estilo de capa de límites de ciudades" /><h2>Unirías espaciales</h2><p>ES|QL no soporta comandos <code>JOIN</code>, pero puedes lograr un caso especial de unión usando el <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 similar a una 'unión por la izquierda' en SQL, permitiéndote enriquecer resultados de un índice con datos de otro índice basar en una relación espacial entre los dos conjuntos de datos.</p><p>Por ejemplo, enriquezcamos los resultados de una tabla de aeropuertos con información adicional sobre la ciudad a la que sirven encontrando el límite de la ciudad que contiene la ubicación del aeropuerto, y luego realicemos algunas estadísticas sobre los 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>Si ejecutas esta consulta sin preparar primero el índice de enriquecimiento, recibirás un mensaje de error como:</p>cannot find enrich policy [city_boundaries]<p>Esto se debe a que, como mencionamos antes, ES|QL no soporta comandos de <code>JOIN</code> verdadero. Una razón importante para ello es que Elasticsearch es un sistema distribuido, y las uniones son operaciones costosas que pueden ser difíciles de escalar. Sin embargo, el comando <code>ENRICH</code> puede ser bastante eficiente, ya que emplea índices de enriquecimiento especialmente preparados que se duplican a lo largo del clúster, permitiendo realizar uniones locales en cada nodo.</p><p>Para entender mejor esto, centrémonos en el comando <code>ENRICH</code> de la consulta anterior:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>Este comando instruye a Elasticsearch para enriquecer los resultados recuperados del índice de <code>airports</code> y realizar una unión <code>intersects</code> entre el campo <code>city_location</code> del índice original y el campo <code>city_boundary</code> del índice de <code>airport_city_boundaries</code> , que usamos en algunos ejemplos anteriores. Pero parte de esta información no es claramente visible en esta consulta. Lo que sí vemos es el nombre de una política de enriquecimiento <code>city_boundaries</code>, y la información que falta está encapsulada dentro de esa definición de política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>Aquí podemos ver que realizará una consulta <code>geo_match</code> (<code>intersects</code> es el valor predeterminado), el campo a emparejar es <code>city_boundary</code>, y los <code>enrich_fields</code> son los campos que queremos agregar al documento original. Uno de esos campos, el <code>region</code> , se usó como clave de agrupación para el comando <code>STATS</code> , algo que no podríamos hacer sin esta capacidad de 'unión izquierda'. Para más información sobre las pólizas de enriquecimiento, consulte la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentación de enriquecimiento</a>.</p><p>Los índices y políticas de enriquecimiento en Elasticsearch fueron diseñados originalmente para enriquecer datos en el momento del índice, empleando datos de otro índice de enriquecimiento preparado. En ES|QL, sin embargo, el comando <code>ENRICH</code> funciona en el momento de la consulta y no requiere el uso de pipelines de ingest. Esto lo hace efectivamente bastante similar a un <code>LEFT JOIN</code>SQL, excepto que no puedes unir dos índices cualquiera, solo un índice normal a la izquierda con un índice enrich especialmente preparado a la derecha.</p><p>En cualquier caso, ya sea para canalizaciones de ingesta o para su uso en ES|QL, es necesario realizar algunos pasos preparatorios para establecer el índice de enriquecimiento y la póliza. Ya importamos el índice de <code>airport_city_boundaries</code> arriba, pero este no se puede usar directamente como índice de enriquecimiento en el comando <code>ENRICH</code> . Primero necesitamos realizar dos pasos:</p><ul><li><p>Crea la política de enriquecimiento descrita anteriormente para definir el índice fuente, el campo en el índice fuente para coincidir y los campos que devolver una vez emparejados.</p></li><li><p>Ejecuta esta política para crear el índice enriquecido. Esto construirá un índice interno especial, leyendo el índice original en una estructura de datos más eficiente que se copia a través del clúster.</p></li></ul><p>La política de enriquecimiento puede crear usando el siguiente comando:</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>Y la política puede ejecutar usando el siguiente comando:</p>POST /_enrich/policy/city_boundaries/_execute<p>Ten en cuenta que si alguna vez cambias el contenido del índice de <code>airport_city_boundaries</code> , tendrás que volver a ejecutar esta política para ver los cambios reflejados en el índice de enriquecimiento. Ahora vamos a ejecutar el ES| originalConsulta QL de nuevo:</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>Esto devuelve las 5 regiones con más aeropuertos, junto con el centroide de todos los aeropuertos que tienen regiones coincidentes, y el rango en longitud de la representación WKT de los límites de la ciudad dentro de esas regiones:</p><p>centroide</p><p>Recuento</p><p>región</p><p>POINT (-12.139086859300733 31.024386116624648)</p><p>126</p><p>nulo</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>POINT (39.74537850357592 47.21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>POINT (-156.80986787192523 20.476673701778054)</p><p>3</p><p>Hawai</p><p>POINT (-73.94515332765877 40.70366442203522)</p><p>3</p><p>Ciudad de Nueva York</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Detroit</p><p>POINT (-76.66873019188643 24.306286952923983)</p><p>2</p><p>Nueva Providencia</p><p>POINT (-3.0252167768776417 51.39245774131268)</p><p>2</p><p>Cardiff</p><p>POINT (-115.40993484668434 32.73126147687435)</p><p>2</p><p>Municipio de Mexicali</p><p>POINT (41.790108773857355 50.302146775648)</p><p>2</p><p>Центральный район</p><p>POINT (-73.88902732171118 45.57078813901171)</p><p>2</p><p>Montréal</p><p>También puede que notes que la región más común era <code>null</code>. ¿Qué podría implicar esto? Recuerda que comparé este comando con un 'left join' en SQL, lo que significa que si no se encuentra ningún límite de ciudad coincidente para un aeropuerto, el aeropuerto sigue devolver pero con valores <code>null</code> para los campos del índice de <code>airport_city_boundaries</code> . Resulta que hubo 125 aeropuertos que no encontraron <code>city_boundary</code>coincidentes, y un aeropuerto con un  coincidente donde el campo de <code>region</code> estaba <code>null</code>. Esto llevó a un recuento de 126 aeropuertos sin <code>region</code> en los resultados. Si tu caso de uso requiere que todos los aeropuertos puedan coincidir con un límite de ciudad, eso requeriría buscar datos adicionales para cubrir los huecos. Sería necesario determinar dos cosas:</p><ul><li><p>qué registros en el índice de <code>airport_city_boundaries</code> no tienen campos <code>city_boundary</code></p></li><li><p>qué registros en el índice de <code>airports</code> no coinciden usando el comando <code>ENRICH</code> (es decir, no intersectar)</p></li></ul><h2>Usando ES|QL para datos geoespaciales en Kibana Maps</h2><p>Kibana agregó soporte para Spatial ES|QL en la aplicación de Mapas. Esto significa que ahora puedes usar ES|QL para buscar datos geoespaciales en Elasticsearch y visualizar los resultados en un mapa.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana Layers ES|QL" /><p>Hay una nueva opción de capa en el menú de agregar capas, llamada "ES|QL". Como todas las características geoespaciales descritas hasta ahora, esto está en "vista previa técnica". Seleccionar esta opción te permite agregar una capa al mapa basada en los resultados de un ES|Consulta QL. Por ejemplo, podrías agregar una capa al mapa que muestre todos los aeropuertos del mundo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeropuertos" /><p>O podrías agregar una capa que muestre los polígonos del índice de <code>airport_city_boundaries</code> , o mejor aún, ¿qué tal esa compleja consulta de <code>ENRICH</code> arriba que genera estadísticas sobre cuántos aeropuertos hay en cada región?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estadísticas de la región" /><h2>¿Qué sigue ahora?</h2><p>El anterior blog de <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">búsqueda geoespacial</a> se centraba en el uso de funciones como <code>ST_INTERSECTS</code> para realizar búsquedas, disponibles en Elasticsearch desde la versión 8.14. Y este blog te muestra cómo importar los datos que usamos para esas búsquedas. Sin embargo, Elasticsearch 8.15 venía con una función especialmente interesante: <code>ST_DISTANCE</code> que puede usar para realizar búsquedas espaciales eficientes, ¡y este será el tema del 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[Búsqueda geoespacial de Elasticsearch con ES|QL]]></title>
    <description><![CDATA[Búsqueda geoespacial en el lenguaje de consultas Elasticsearch (ES|QL). Elasticsearch cuenta con poderosas características de búsqueda geoespacial, que ahora están llegando a ES|QL por una facilidad de uso mucho mejorada y familiaridad con el OGC.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch tuvo poderosos <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">capacidades de búsqueda y análisis geoespacial</a> durante muchos años, pero la API era bastante diferente de lo que los usuarios típicos de SIG estaban acostumbrados. En el último año hemos <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">agregado el ES|Lenguaje de consulta QL</a>, un lenguaje de consulta por tubes tan fácil, o incluso más sencillo, que SQL. Es especialmente adecuado para los casos de búsqueda y observabilidad en los que Elastic destaca. También estamos agregando soporte para búsqueda y análisis geoespacial dentro de ES|QL, lo que lo hace mucho más fácil de usar, especialmente para usuarios que vienen de comunidades SQL o <a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a> .</p><p>Elasticsearch 8.12 y 8.13 llevaron soporte básico para tipos geoespaciales a ES|QL. Esto se mejoró significativamente con la incorporación de capacidades de búsqueda geoespacial en la versión 8.14. Más importante aún, este soporte fue diseñado para ajustar estrechamente al estándar <a href="https://en.wikipedia.org/wiki/Simple_Features">Simple Feature</a> Access del <a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">Open Geospatial Consortium (OGC)</a> empleado por otras bases de datos espaciales como PostGIS, facilitando mucho su uso para expertos en SIG familiarizados con estos estándares.</p><p>En este blog, te mostraremos cómo usar ES|QL para realizar búsquedas geoespaciales y cómo se compara con los equivalentes SQL y Query DSL. También te mostraremos cómo usar ES|QL para realizar uniones espaciales y cómo visualizar los resultados en Kibana Maps. Ten en cuenta que todas las funciones descritas aquí están en "vista previa técnica", y nos encantaría conocer vuestros comentarios sobre cómo podemos mejorarlas.</p><h2>Búsqueda de datos geoespaciales</h2><p>Empecemos con una consulta de ejemplo:</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>Esto realiza una búsqueda de cualquier polígono de límite de ciudad que intersecte con un polígono rectangular alrededor del Aeropuerto Internacional Sanya Phoenix (SYX).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="Búsqueda Geoespacial ESQL" /><p>En un conjunto de datos de ejemplo de aeropuertos, ciudades y límites urbanos, esta búsqueda encuentra el polígono que se cruza y devuelve los campos deseados del documento correspondiente:</p><p>Abbrev</p><p>aeropuerto</p><p>región</p><p>ciudad</p><p>city_location</p><p>SYX</p><p>Sanya Phoenix Internacional</p><p>天涯区</p><p>Sanya</p><p>POINT(109.5036 18.2533)</p><p>¡Eso fue fácil! Ahora compáralo con el tradicional DSL de Elasticsearch Query para la misma 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 consultas son bastante claras en su intención, pero el ES|La consulta QL se parece mucho a SQL. La misma consulta en PostGIS es la siguiente:</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>Mira atrás en el ES|Ejemplo de QL. Muy parecido, ¿verdad?</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>Comprobamos que los usuarios actuales de la API de Elasticsearch encuentran ES|QL mucho más fácil de usar. Ahora esperamos que los usuarios existentes de SQL, especialmente los de SQL Espacial, descubran que ES|QL se siente muy familiar con lo que están acostumbrados a ver.</p><h4>¿Por qué no SQL?</h4><p>¿Y qué pasa con Elasticsearch SQL? Lleva un tiempo existiendo y tiene algunas características geoespaciales. Sin embargo, Elasticsearch SQL se escribía como un envoltorio sobre la API original de Consultas, lo que significaba que solo se soportaban consultas que podían transpilarse a la API original. ES|QL no tiene esta limitación. Ser una pila completamente nueva permite muchas optimizaciones que no eran posibles en SQL. Nuestros benchmarks muestran ES|QL <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">suele ser muy rápido que la API de Consultas</a>, ¡especialmente con agregaciones!</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="polígono-intersección-benchmark" /><h2>Diferencias con SQL</h2><p>Claramente, por el ejemplo anterior, ES|QL es algo similar a SQL, pero hay algunas diferencias importantes. Por ejemplo, ES|QL es un lenguaje de consulta por pipes, que comienza con un comando fuente como FROM y luego encadena todos los comandos posteriores junto con el pipe | carácter. Esto facilita mucho entender cómo cada comando recibe una tabla de datos y realiza alguna acción sobre esa tabla, como filtrar con <code>WHERE</code>, agregar columnas con <code>EVAL</code>, o realizar agregaciones con <code>STATS</code>. En lugar de comenzar con <code>SELECT</code> para definir las columnas de salida finales, puede haber uno o más comandos <code>KEEP</code> , siendo el último el que especifica los resultados finales. Esta estructura simplifica el razonamiento sobre la consulta.</p><p>Centrándonos en el comando <code>WHERE</code> del ejemplo anterior, podemos ver que se parece bastante al ejemplo de 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>Aparte de la diferencia en los caracteres de comillas de cadena, la mayor diferencia está en cómo tipificamos la cadena a un tipo espacial. En PostGIS, usamos el sufijo <code>::geometry</code> , mientras que en ES|QL, usamos el sufijo <code>::geo_shape</code> . Esto se debe a que ES|QL se ejecuta dentro de Elasticsearch, y el operador de typecasting <code>::</code> puede usar para convertir una cadena a cualquiera de los <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">ES| soportadosQL tipia</a>, en este caso, un <code>geo_shape</code>. Además, los tipos <code>geo_shape</code> y <code>geo_point</code> en Elasticsearch implican el sistema de coordenadas espaciales conocido como WGS84, más comúnmente conocido con el número SRID 4326. En PostGIS, esto debe ser explícito, de ahí el uso del prefijo <code>SRID=4326;</code> a la cadena WKT. Si se elimina ese prefijo, el SRID se pondrá en 0, que es más parecido a los tipos de Elasticsearch <code>cartesian_point</code> y <code>cartesian_shape</code>, que no están vinculados a ningún sistema de coordenadas específico.</p><p>Ambos ES|QL y PostGIS también proporcionan sintaxis de funciones de conversión de tipos:</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>Funciones OGC</h2><p>Elasticsearch 8.14 introduce las siguientes cuatro funciones de búsqueda espacial OGC:</p><p>ES|QL</p><p>PostGIS</p><p>Descripción</p><p>ST_INTERSECTS</p><p>ST_Intersects</p><p>Devuelve verdadero si dos geometrías se cruzan, y falso en caso contrario.</p><p>ST_DISJOINT</p><p>ST_Disjoint</p><p>Devuelve verdadero si dos geometrías no se intersectan, y falso en caso contrario. El inverso de ST_INTERSECTS.</p><p>ST_CONTAINS</p><p>ST_Contains</p><p>Devuelve verdadero si una geometría contiene otra, y falso en caso contrario.</p><p>ST_WITHIN</p><p>ST_Within</p><p>Devuelve verdadero si una geometría está dentro de otra, y falso en caso contrario. El inverso de ST_CONTAINS.</p><p>Estas funciones se comportan de forma similar a sus contrapartes PostGIS y se emplean de la misma manera. Por ejemplo, <code>ST_INTERSECTS</code> devuelve verdadero si dos geometrías se intersectan y falso en caso contrario. Si sigues los enlaces de documentación de la tabla anterior, puede que notes que todos los ES|Los ejemplos de QL están dentro de una cláusula de <code>WHERE</code> luego de una cláusula de <code>FROM</code> , mientras que todos los ejemplos de PostGIS usan geometrías literales. De hecho, ambas plataformas soportan el uso de las funciones en cualquier parte de la consulta donde tengan sentido.</p><p>El primer ejemplo en la documentación de PostGIS para <code>ST_INTERSECTS</code> es:</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>El ES|El equivalente en QL de esto sería:</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>Fíjate en que no especificamos el SRID en el ejemplo de PostGIS. Esto se debe a que en PostGIS, al usar el tipo <code>geometry</code> , todos los cálculos se realizan en un sistema de coordenadas planas, por lo que si ambas geometrías tienen el mismo SRID, no importa cuál sea el SRID. En Elasticsearch, esto también es cierto para la mayoría de las funciones, sin embargo, hay excepciones donde <code>geo_shape</code> y <code>geo_point</code> emplean cálculos esféricos, como veremos en el próximo blog sobre búsqueda por distancia espacial.</p><h2>ES|Versatilidad en QL</h2><p>Vimos ejemplos arriba de usar funciones espaciales en cláusulas <code>WHERE</code> y en comandos <code>ROW</code> . ¿Dónde más tendrían sentido? Un lugar muy útil es en el comando <code>EVAL</code> . Este comando te permite evaluar una expresión y devolver el resultado. Por ejemplo, determinemos si los centroides de todos los aeropuertos agrupados por el nombre de sus países están dentro de un límite que delimita el 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>Se esperan los resultados: el centroide de los aeropuertos del Reino Unido está dentro del límite del Reino Unido, y no dentro del límite de Islandia, y viceversa:</p><p>centroide</p><p>Recuento</p><p>in_uk</p><p>in_iceland</p><p>within_uk</p><p>within_iceland</p><p>POINT (-21.946634463965893 64.13187285885215)</p><p>1</p><p>falso</p><p>true</p><p>falso</p><p>true</p><p>POINT (-2.597342072712148 54.33551226578214)</p><p>17</p><p>true</p><p>falso</p><p>true</p><p>falso</p><p>POINT (0.04453958108176276 23.74658354606057)</p><p>873</p><p>falso</p><p>falso</p><p>falso</p><p>falso</p><p>De hecho, estas funciones pueden usar en cualquier parte de la consulta donde su firma tenga sentido. Todos toman dos argumentos, que son o bien un objeto espacial literal o un campo de un tipo espacial, y todos devuelven un valor booleano. Una consideración importante es que el sistema de referencia de coordenadas (CRS) de las geometrías debe coincidir, o se devolverá un error. Esto significa que no puedes mezclar <code>geo_shape</code> y <code>cartesian_shape</code> tipos en la misma llamada de función. Sin embargo, puedes mezclar <code>geo_point</code> y <code>geo_shape</code> tipos, ya que el tipo <code>geo_point</code> es un caso especial del tipo <code>geo_shape</code> , y ambos comparten el mismo sistema de referencia de coordenadas. La documentación de cada una de las funciones definidas anteriormente lista las combinaciones de tipos soportadas.</p><p>Además, cualquiera de los dos argumentos puede ser un literal espacial o un campo, en cualquiera de los dos ordenes. Incluso puedes especificar dos campos, dos literales, un campo y un literal, o un literal y un campo. El único requisito es que los tipos sean compatibles. Por ejemplo, esta consulta compara dos campos en el mismo í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>La consulta básicamente pregunta si la ubicación de la ciudad está dentro del límite de la ciudad, lo cual generalmente debería ser cierto, pero siempre hay excepciones:</p><p>cardinalidad</p><p>Recuento</p><p>in_city</p><p>poco</p><p>29</p><p>falso</p><p>mucho</p><p>740</p><p>true</p><p>Una pregunta mucho más interesante sería si la ubicación del aeropuerto está dentro de los límites de la ciudad a la que sirve el aeropuerto. Sin embargo, la ubicación del aeropuerto se encuentra en un índice diferente al que contiene los límites de la ciudad. Esto requiere un método para consultar y correlacionar eficazmente los datos de estos dos índices separados.</p><h2>Unirías espaciales</h2><p>ES|QL no soporta comandos <code>JOIN</code>, pero puedes lograr un caso especial de unión usando el<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 similar a una 'unión izquierda' en SQL. Este comando funciona de forma similar a una 'unión por la izquierda' en SQL, permitiéndote enriquecer resultados de un índice con datos de otro índice basar en una relación espacial entre los dos conjuntos de datos.</p><p>Por ejemplo, enriquezcamos los resultados de una tabla de aeropuertos con información adicional sobre la ciudad a la que sirven encontrando el límite de la ciudad que contiene la ubicación del aeropuerto, y luego realicemos algunas estadísticas sobre los 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>Esto devuelve las 5 regiones con más aeropuertos, junto con el centroide de todos los aeropuertos que tienen regiones coincidentes, y el rango en longitud de la representación WKT de los límites de la ciudad dentro de esas regiones:</p><p>centroide</p><p>Recuento</p><p>min_wkt</p><p>max_wkt</p><p>región</p><p>PUNTO (-32.56093470960719 32.598117914802714)</p><p>90</p><p>207</p><p>207</p><p>nulo</p><p>POINT (-73.94515332765877 40.70366442203522)</p><p>9</p><p>438</p><p>438</p><p>Ciudad de Nueva York</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>Detroit</p><p>POINT (-156.3020245861262 20.176383580081165)</p><p>5</p><p>307</p><p>803</p><p>Hawai</p><p>POINT (-73.88902732171118 45.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>Montréal</p><p>Entonces, ¿qué pasó realmente aquí? ¿Dónde ocurrió la supuesta <code>JOIN</code> ? El núcleo de la consulta reside en el comando <code>ENRICH</code> :</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>Este comando instruye a Elasticsearch para enriquecer los resultados recuperados del índice de <code>airports</code> y realizar una unión <code>intersects</code> entre el campo <code>city_location</code> del índice original y el campo <code>city_boundary</code> del índice de <code>airport_city_boundaries</code> , que usamos en algunos ejemplos anteriores. Pero parte de esta información no es claramente visible en esta consulta. Lo que sí vemos es el nombre de una política de enriquecimiento <code>city_boundaries</code>, y la información que falta está encapsulada dentro de esa definición de política.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>Aquí podemos ver que realizará una consulta <code>geo_match</code> (<code>intersects</code> es el valor predeterminado), el campo a emparejar es <code>city_boundary</code>, y los <code>enrich_fields</code> son los campos que queremos agregar al documento original. Uno de esos campos, el <code>region</code> , se usó como clave de agrupación para el comando <code>STATS</code> , algo que no podríamos hacer sin esta capacidad de 'unión izquierda'. Para más información sobre las pólizas de enriquecimiento, consulte la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentación de enriquecimiento</a>. Al leer esos documentos, notarás que describen el uso de los índices enrich para enriquecer datos en tiempo de indexación, configurando pipelines de ingest. Esto no es necesario para ES|QL, ya que el comando <code>ENRICH</code> funciona en el momento de la consulta. Basta con preparar el índice de enriquecimiento con los datos y la política de enriquecimiento necesarios, y luego usar el comando <code>ENRICH</code> en tu ES|Consultas QL.</p><p>También puede que notes que la región más común era <code>null</code>. ¿Qué podría implicar esto? Recuerda que comparé este comando con un 'left join' en SQL, lo que significa que si no se encuentra ningún límite de ciudad coincidente para un aeropuerto, el aeropuerto sigue devolver pero con valores <code>null</code> para los campos del índice de <code>airport_city_boundaries</code> . Resulta que había 89 aeropuertos que no encontraron <code>city_boundary</code>coincidentes, y un aeropuerto con un <code>region</code> campo de <code>null</code>. Esto llevó a un recuento de 90 aeropuertos sin <code>region</code> en los resultados. Otro detalle interesante es la necesidad del comando <code>MV_EXPAND</code> . Esto es necesario porque el comando <code>ENRICH</code> puede devolver múltiples resultados por cada fila de entrada, y <code>MV_EXPAND</code> ayuda a separar estos resultados en varias filas, una para cada resultado. Esto también aclara por qué "Hawái" muestra resultados <code>min_wkt</code> y <code>max_wkt</code> diferentes: había varias regiones con el mismo nombre pero diferentes límites.</p><h2>Kibana Maps</h2><p>Kibana agregó soporte para Spatial ES|QL en la aplicación de Mapas. Esto significa que ahora puedes usar ES|QL para buscar datos geoespaciales en Elasticsearch y visualizar los resultados en un mapa.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana Layers ES|QL" /><p>Hay una nueva opción de capa en el menú de agregar capas, llamada "ES|QL". Como todas las características geoespaciales descritas hasta ahora, esto está en "vista previa técnica". Seleccionar esta opción te permite agregar una capa al mapa basada en los resultados de un ES|Consulta QL. Por ejemplo, podrías agregar una capa al mapa que muestre todos los aeropuertos del mundo.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aeropuertos" /><p>O podrías agregar una capa que muestre los polígonos del índice de <code>airport_city_boundaries</code> , o mejor aún, ¿qué tal esa compleja consulta de <code>ENRICH</code> arriba que genera estadísticas sobre cuántos aeropuertos hay en cada región?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Estadísticas de la región" /><h2>¿Qué sigue ahora?</h2><p>Quizá notaste que en dos de los ejemplos anteriores incluimos otra función espacial <code>ST_CENTROID_AGG</code>. Esta es una función agregadora empleada en el comando <code>STATS</code> , y la primera de muchas funciones de análisis espacial que planeamos agregar a ES|QL. ¡Escribiremos sobre ello en el blog cuando tengamos más que mostrar!</p><p>Antes de eso, queremos contarte más sobre una función especialmente emocionante en la que trabajamos: la capacidad de realizar búsquedas espaciales, una de las funciones de búsqueda espacial más empleadas en Elasticsearch. ¿Te imaginas cómo sería la sintaxis de las búsquedas a distancia? ¿Quizá similar a una función OGC? ¡Permanece atento al próximo blog de este serial para descubrirlo!</p><p>Alerta de spoilers: Elasticsearch 8.15 acaba de ser lanzado, y la búsqueda por distancia espacial con ES|¡QL está incluido!</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>