<?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/fr/search-labs/author/craig-taverner</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/author/craig-taverner</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/author/craig-taverner.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 10:31:34 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Ingérer des données géospatiales dans Elasticsearch avec Kibana pour les utiliser dans ES|QL]]></title>
    <description><![CDATA[Comment utiliser Kibana et le processeur d'ingestion csv pour ingérer des données géospatiales dans Elasticsearch afin de les utiliser pour la recherche dans Elasticsearch Query Language (ES|QL). Elasticsearch possède de puissantes fonctionnalités de recherche géospatiale, qui sont désormais intégrées à ES|QL pour une facilité d'utilisation et une familiarité avec l'OGC considérablement améliorées. Mais pour utiliser ces fonctionnalités, nous avons besoin de données géospatiales.]]></description>
    <content:encoded><![CDATA[<p>Nous avons récemment publié un blog décrivant comment utiliser les nouvelles <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">fonctionnalités</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">de recherche géospatiale</a> <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">dans ES|QL,</a> le nouveau et puissant <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">langage de requête par pipeline</a> d' Elasticsearch. Pour utiliser ces fonctionnalités, vous devez disposer de données géospatiales dans Elasticsearch. Dans ce blog, nous allons donc vous montrer comment ingérer des données géospatiales et comment les utiliser dans des requêtes ES|QL.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="Recherche géospatiale ESQL" /><h2>Importation de données géospatiales à l'aide de Kibana</h2><p>Les données que nous avons utilisées pour les exemples du blog précédent étaient basées sur les données que nous utilisons en interne pour les tests d'intégration. Pour vous faciliter la tâche, nous l'avons inclus ici sous la forme de quelques fichiers CSV qui peuvent être facilement importés à l'aide de Kibana. Les données sont un mélange d'aéroports, de villes et de limites de villes. Vous pouvez télécharger les données à partir 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">aéroports.csv</a></p><ul><li><p>Il s'agit d'une fusion de trois ensembles de données :</p><ul><li><p>Aéroports (noms, emplacements et données connexes) de <a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth</a></p></li><li><p>Localisation des villes à partir de <a href="https://simplemaps.com/data/world-cities">SimpleMaps</a></p></li><li><p>Élévations des aéroports à partir de la <a href="https://www.partow.net/miscellaneous/airportdatabase/">base de données mondiale des aéroports</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_de_la_ville_de_l'aeroport.csv</a></p><ul><li><p>Il s'agit d'une fusion des noms d'aéroports et de villes ci-dessus avec une nouvelle source :</p><ul><li><p>Limites de la ville d'après <a href="https://www.openstreetmap.org/">OpenStreetMap</a></p></li></ul></li></ul></li></ul><p>Comme vous pouvez le deviner, nous avons passé un certain temps à combiner ces sources de données dans les deux fichiers ci-dessus, dans le but de pouvoir tester les fonctionnalités géospatiales d'ES|QL. Il se peut que cela ne corresponde pas tout à fait à vos besoins spécifiques en matière de données, mais j'espère que cela vous donnera une idée de ce qui est possible. En particulier, nous voulons démontrer quelques points intéressants :</p><ul><li><p>Importation de données contenant des champs géospatiaux avec d'autres données indexables</p></li><li><p>Importer les données <code>geo_point</code> et <code>geo_shape</code> et les utiliser ensemble dans les requêtes</p></li><li><p>Importation de données dans deux index qui peuvent être reliés à l'aide d'une relation spatiale</p></li><li><p>Création d'un pipeline d'ingestion pour faciliter les importations futures (au-delà de Kibana)</p></li><li><p>Quelques exemples de processeurs d'acquisition, tels que <code>csv</code>, <code>convert</code> et <code>split</code></p></li></ul><p>Bien que nous parlions de travailler avec des données CSV dans ce blog, il est important de comprendre qu'il y a <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">plusieurs façons d</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">'</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">ajouter des données géographiques en utilisant</a> <a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html">Kibana</a>. Dans l'application Carte, vous pouvez télécharger des données délimitées telles que CSV, GeoJSON et ESRI ShapeFiles et vous pouvez également dessiner des formes directement dans la carte. Pour ce blog, nous nous concentrerons sur l'importation de fichiers CSV à partir de la page d'accueil de Kibana.</p><h3>Importation des aéroports</h3><p>Le premier fichier, <a href="https://raw.githubusercontent.com/elastic/elasticsearch-labs/refs/heads/main/supporting-blog-content/geospatial-data-ingest/airports/airports.csv">airports.csv,</a> a quelques particularités intéressantes avec lesquelles nous devons composer. Tout d'abord, les colonnes sont séparées par des espaces blancs supplémentaires, ce qui n'est pas typique des fichiers CSV. Deuxièmement, le champ <code>type</code> est un champ à valeurs multiples, que nous devons diviser en champs distincts. Enfin, certains champs ne sont pas des chaînes de caractères et doivent être convertis dans le bon type. Tout cela peut être fait en utilisant la fonction d'importation CSV de Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Kibana Upload - Aperçu" /><p>Commencez par la page d'accueil de Kibana. Une section intitulée "Get started by adding integrations" contient un lien intitulé "Upload a file":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Kibana Home - Télécharger un fichier" /><p>En cliquant sur ce lien, vous accéderez à la page "Upload file". Ici, vous pouvez faire glisser et déposer le fichier <code>airports.csv</code>, et Kibana analysera le fichier et vous présentera un aperçu des données. Il aurait dû détecter automatiquement que le délimiteur était une virgule et que la première ligne était la ligne d'en-tête. Cependant, il n'a probablement pas supprimé les espaces blancs supplémentaires entre les colonnes, ni déterminé les types de champs, en supposant que tous les champs sont soit <code>text</code>, soit <code>keyword</code>. Nous devons y remédier.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Kibana Upload - Aperçu" /><p>Cliquez sur <code>Override settings</code> et cochez les cases <code>Should trim fields</code> et <code>Apply</code> pour fermer les paramètres. Nous devons maintenant fixer les types de champs. Elle est disponible à la page suivante, alors cliquez sur <code>Import</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Kibana Upload - Importation" /><p>Choisissez d'abord un nom d'index, puis sélectionnez <code>Advanced</code> pour accéder à la page des mappages de champs et du processeur d'ingestion.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Kibana Upload - Correspondance des champs" /><p>Ici, nous devons apporter des modifications aux mappages de champs pour l'index, ainsi qu'au pipeline d'ingestion pour l'importation des données. Tout d'abord, alors que Kibana a probablement auto-détecté le champ <code>scalerank</code> comme étant <code>long</code>, il a perçu par erreur les champs <code>location</code> et <code>city_location</code> comme étant <code>keyword</code>. Modifiez-les à l'adresse <code>geo_point</code>, et vous obtiendrez des correspondances qui ressembleront à quelque chose de semblable :</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>Vous disposez d'une certaine marge de manœuvre, mais sachez que le type de champ choisi aura une incidence sur la manière dont il sera indexé et sur le type de requêtes possibles. Par exemple, si vous laissez <code>location</code> comme <code>keyword</code>, vous ne pouvez pas effectuer de recherches géospatiales sur ce site. De même, si vous laissez <code>elevation</code> en tant que <code>text</code>, vous ne pouvez pas effectuer de requêtes sur les plages numériques.</p><p>Il est maintenant temps de réparer le pipeline d'ingestion. Si Kibana a détecté automatiquement <code>scalerank</code> comme <code>long</code> ci-dessus, il aura également ajouté un processeur pour convertir le champ en <code>long</code>. Nous devons ajouter un processeur similaire pour le champ <code>elevation</code>, en le convertissant cette fois en <code>double</code>. Modifiez le pipeline pour vous assurer que cette conversion est en place. Avant de l'enregistrer, nous souhaitons effectuer une autre conversion, afin de diviser le champ <code>type</code> en plusieurs champs. Ajouter un processeur <code>split</code> au pipeline, avec la configuration suivante :</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>Le pipeline d'ingestion final devrait ressembler à ceci :</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>Notez que nous n'avons pas ajouté de processeur de conversion pour les champs <code>location</code> et <code>city_location</code>. Cela s'explique par le fait que le type <code>geo_point</code> dans la correspondance des champs comprend déjà le format WKT des données de ces champs. Le type <code>geo_point</code> peut comprendre une série de formats, notamment <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT, GeoJSON, etc</a>. Si nous avions, par exemple, deux colonnes dans le fichier CSV pour <code>latitude</code> et <code>longitude</code>, nous aurions dû ajouter un processeur <code>script</code> ou <code>set</code> pour les combiner en un seul champ <code>geo_point</code> (par exemple. <code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>Nous sommes maintenant prêts à importer le fichier. Cliquez sur <code>Import</code> et les données seront importées dans l'index avec les mappings et le pipeline d'ingestion que nous venons de définir. Si des erreurs surviennent lors de l'ingestion des données, Kibana les signale ici, afin que vous puissiez modifier les données sources ou le pipeline d'ingestion et réessayer.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Kibana Upload - Importation" /><p>Remarquez qu'une nouvelle ligne d'ingestion a été créée. Il peut être consulté en allant dans la section <code>Stack Management</code> de Kibana, et en sélectionnant <code>Ingest pipelines</code>. Ici, vous pouvez voir le pipeline que nous venons de créer et le modifier si nécessaire. En fait, la section <code>Ingest pipelines</code> peut être utilisée pour créer et tester des pipelines d'ingestion, une fonctionnalité très utile si vous prévoyez d'effectuer des ingérences encore plus complexes.</p><p>Si vous souhaitez explorer ces données immédiatement, passez aux sections suivantes, mais si vous souhaitez également importer les limites des villes, continuez à lire.</p><h3>Importation des limites de la ville</h3><p>Le fichier des limites des villes disponible à l'adresse <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> est un peu plus simple à importer que l'exemple précédent. Il contient un champ <code>city_boundary</code> qui est une représentation WKT des limites de la ville sous forme de <code>POLYGON</code>, et un champ <code>city_location</code> qui est une représentation <code>geo_point</code> de l'emplacement de la ville. Nous pouvons importer ces données de la même manière que les données aéroportuaires, à quelques différences près :</p><ul><li><p>Nous avons dû sélectionner le paramètre d'annulation <code>Has header row</code> car il n'était pas détecté automatiquement.</p></li><li><p>Nous n'avons pas eu besoin de découper les champs, car les données étaient déjà exemptes d'espaces blancs supplémentaires.</p></li><li><p>Nous n'avons pas eu besoin de modifier le pipeline d'ingestion car tous les types étaient soit des chaînes de caractères, soit des types spatiaux.</p></li><li><p>Nous avons toutefois dû modifier les correspondances entre les champs afin de définir le champ <code>city_boundary</code> comme étant <code>geo_shape</code> et le champ <code>city_location</code> comme étant <code>geo_point</code></p></li></ul><p>Nos mappages de champs finaux se présentaient comme suit :</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>Comme pour l'importation <code>airports.csv</code>, il suffit de cliquer sur <code>Import</code> pour importer les données dans l'index. Les données seront importées avec les mappings que nous avons édités et le pipeline d'ingestion défini par Kibana.</p><h3>Explorer les données géospatiales avec les outils de développement</h3><p>Dans Kibana, il est habituel d'explorer les données indexées avec "Discover". Cependant, si votre intention est d'écrire votre propre application en utilisant des requêtes ES|QL, il peut être plus intéressant d'essayer d'accéder à l'API Elasticsearch brute. Kibana dispose d'une console pratique pour expérimenter l'écriture de requêtes. Il s'agit de la console <code>Dev Tools</code>, qui se trouve dans la barre latérale de Kibana. Cette console communique directement avec le cluster Elasticsearch et peut être utilisée pour exécuter des requêtes, créer des index, etc.</p><p>Essayez ce qui suit :</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>Cela devrait donner les résultats suivants :</p><p>distance</p><p>abbrev</p><p>nom</p><p>Lieu</p><p>pays</p><p>ville</p><p>élévation</p><p>273418.05776847183</p><p>HAM</p><p>Hambourg</p><p>POINT (10.005647830925 53.6320011640866)</p><p>Allemagne</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>Allemagne</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>Norvège</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>Suède</p><p>Stockholm</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>Arlanda</p><p>POINT (17.9307299016916 59.6511203397372)</p><p>Suède</p><p>Stockholm</p><p>38.0</p><p>624274.8274399083</p><p>DHS</p><p>Düsseldorf Int'l</p><p>POINT (6.76494446612174 51.2781820420774)</p><p>Allemagne</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>Tchécoslovaquie</p><p>Prague</p><p>381.0</p><p>635911.1873311149</p><p>AMS</p><p>Schiphol</p><p>POINT (4.76437693232812 52.3089323889822)</p><p>Pays-Bas</p><p>Hoofddorp</p><p>-3.0</p><p>670864.137958866</p><p>FRA</p><p>Francfort Int'l</p><p>POINT (8.57182286907608 50.0506770895207)</p><p>Allemagne</p><p>Francfort</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>Pologne</p><p>Piaseczno</p><p>111.0</p><h2>Visualiser des données géospatiales avec Kibana Maps</h2><p>Kibana Maps est un outil puissant de visualisation des données géospatiales. Il peut être utilisé pour créer des cartes avec plusieurs couches, chaque couche représentant un ensemble de données différent. Les données peuvent être filtrées, agrégées et stylisées de différentes manières. Dans cette section, nous allons vous montrer comment créer une carte dans Kibana Maps en utilisant les données que nous avons importées dans la section précédente.</p><p>Dans le menu Kibana, naviguez vers <code>Analytics</code>-&gt;<code>Maps</code> pour ouvrir une nouvelle vue de la carte. Cliquez sur <code>Add Layer</code> et sélectionnez <code>Documents</code>, choisissez la vue de données <code>airports</code> et modifiez le style de la couche pour colorer les marqueurs à l'aide du champ <code>elevation</code>, de sorte que nous puissions facilement voir à quelle hauteur se trouve chaque aéroport.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana Maps - Style de calque pour les aéroports" /><p>Cliquez sur "Conserver les modifications" pour enregistrer la carte :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Kibana Maps - Aéroports" /><p>Ajoutez maintenant une deuxième couche, en sélectionnant cette fois la vue de données <code>airport_city_boundaries</code>. Cette fois-ci, nous utiliserons le champ <code>city_boundary</code> pour styliser le calque et définir la couleur de remplissage sur un bleu clair. Les limites de la ville apparaissent alors sur la carte. Veillez à réorganiser les couches de manière à ce que les marqueurs d'aéroport soient placés en haut.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana Maps - Style de calque pour les limites des villes" /><h2>Jointures spatiales</h2><p>ES|QL ne prend pas en charge les commandes <code>JOIN</code>, mais vous pouvez réaliser un cas spécial de jointure à l'aide de la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich">commande</a> <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a>. Cette commande s'apparente à une "jointure gauche" en SQL, vous permettant d'enrichir les résultats d'un index avec des données d'un autre index sur la base d'une relation spatiale entre les deux ensembles de données.</p><p>Par exemple, enrichissons les résultats d'un tableau d'aéroports avec des informations supplémentaires sur la ville qu'ils desservent en trouvant la limite de la ville qui contient l'emplacement de l'aéroport, puis effectuons quelques statistiques sur les résultats :</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 vous exécutez cette requête sans avoir au préalable préparé l'index enrichi, vous obtiendrez un message d'erreur du type</p>cannot find enrich policy [city_boundaries]<p>En effet, comme nous l'avons déjà mentionné, ES|QL ne prend pas en charge les véritables commandes <code>JOIN</code>. L'une des raisons principales est qu'Elasticsearch est un système distribué et que les jointures sont des opérations coûteuses qu'il peut être difficile de faire évoluer. Cependant, la commande <code>ENRICH</code> peut être très efficace, car elle utilise des index enrichis spécialement préparés qui sont dupliqués sur l'ensemble du cluster, ce qui permet d'effectuer des jointures locales sur chaque nœud.</p><p>Pour mieux comprendre, concentrons-nous sur la commande <code>ENRICH</code> dans la requête ci-dessus :</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>Cette commande demande à Elasticsearch d'enrichir les résultats extraits de l'index <code>airports</code> et d'effectuer une jointure <code>intersects</code> entre le champ <code>city_location</code> de l'index original et le champ <code>city_boundary</code> de l'index <code>airport_city_boundaries</code>, que nous avons utilisé dans quelques exemples plus tôt. Mais certaines de ces informations ne sont pas clairement visibles dans cette requête. Ce que nous voyons, c'est le nom d'une politique d'enrichissement <code>city_boundaries</code>, et l'information manquante est encapsulée dans cette définition de politique.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>Ici, nous pouvons voir qu'il effectuera une requête <code>geo_match</code> (<code>intersects</code> est la valeur par défaut), que le champ à comparer est <code>city_boundary</code> et que les champs <code>enrich_fields</code> sont les champs que nous voulons ajouter au document d'origine. L'un de ces champs, le <code>region</code>, a été utilisé comme clé de regroupement pour la commande <code>STATS</code>, ce que nous n'aurions pas pu faire sans cette capacité de "jointure à gauche". Pour plus d'informations sur les politiques d'enrichissement, voir la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentation d'enrichissement</a>.</p><p>Les index et politiques d'enrichissement d'Elasticsearch ont été conçus à l'origine pour enrichir les données au moment de l'indexation, en utilisant les données d'un autre index d'enrichissement préparé. Dans ES|QL, cependant, la commande <code>ENRICH</code> fonctionne au moment de la requête et ne nécessite pas l'utilisation de pipelines d'ingestion. Cela le rend assez similaire à un SQL <code>LEFT JOIN</code>, sauf que vous ne pouvez pas joindre deux index, mais seulement un index normal à gauche avec un index enrichi spécialement préparé à droite.</p><p>Dans les deux cas, que ce soit pour les pipelines d'ingestion ou pour l'utilisation dans ES|QL, il est nécessaire d'effectuer quelques étapes préparatoires pour mettre en place l'index et la politique d'enrichissement. Nous avons déjà importé l'index <code>airport_city_boundaries</code> ci-dessus, mais il n'est pas directement utilisable comme index d'enrichissement dans la commande <code>ENRICH</code>. Nous devons d'abord effectuer deux démarches :</p><ul><li><p>Créez la politique d'enrichissement décrite ci-dessus pour définir l'index source, le champ de l'index source à comparer et les champs à renvoyer une fois la correspondance établie.</p></li><li><p>Exécutez cette politique pour créer l'index d'enrichissement. Cela permet de construire un index interne spécial, en lisant l'index source d'origine dans une structure de données plus efficace qui est copiée à travers le cluster.</p></li></ul><p>La politique d'enrichissement peut être créée à l'aide de la commande suivante :</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>La politique peut être exécutée à l'aide de la commande suivante :</p>POST /_enrich/policy/city_boundaries/_execute<p>Notez que si vous modifiez le contenu de l'index <code>airport_city_boundaries</code>, vous devrez réexécuter cette politique pour que les changements soient reflétés dans l'index enrichi. Exécutons à nouveau la requête ES|QL d'origine :</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>Cette méthode permet d'obtenir les 5 régions qui comptent le plus d'aéroports, ainsi que le centroïde de tous les aéroports qui ont des régions correspondantes et la longueur de la représentation WKT des limites des villes à l'intérieur de ces régions :</p><p>centroïde</p><p>Compte</p><p>région</p><p>POINT (-12.139086859300733 31.024386116624648)</p><p>126</p><p>nul</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Détroit</p><p>POINT (39.74537850357592 47.21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>POINT (-156.80986787192523 20.476673701778054)</p><p>3</p><p>Hawaï</p><p>POINT (-73.94515332765877 40.70366442203522)</p><p>3</p><p>Ville de New York</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>3</p><p>Détroit</p><p>POINT (-76.66873019188643 24.306286952923983)</p><p>2</p><p>New Providence</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>Municipalité 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>Vous pouvez également remarquer que la région la plus fréquemment trouvée est <code>null</code>. Qu'est-ce que cela peut signifier ? Rappelez-vous que j'ai comparé cette commande à une "jointure gauche" en SQL, ce qui signifie que si aucune limite de ville correspondante n'est trouvée pour un aéroport, l'aéroport est toujours renvoyé, mais avec les valeurs <code>null</code> pour les champs de l'index <code>airport_city_boundaries</code>. Il s'avère que 125 aéroports n'ont pas trouvé de correspondance avec <code>city_boundary</code>, et un aéroport avec une correspondance où le champ <code>region</code> était <code>null</code>. Cela a conduit à un décompte de 126 aéroports sans <code>region</code> dans les résultats. Si votre cas d'utilisation exige que tous les aéroports puissent être mis en correspondance avec les limites d'une ville, il faudra trouver des données supplémentaires pour combler les lacunes. Il serait nécessaire de déterminer deux choses :</p><ul><li><p>les enregistrements de l'index <code>airport_city_boundaries</code> qui n'ont pas de champs <code>city_boundary</code></p></li><li><p>les enregistrements de l'index <code>airports</code> qui ne correspondent pas à l'aide de la commande <code>ENRICH</code> (c'est-à-dire. ne se croisent pas)</p></li></ul><h2>Utilisation de ES|QL pour les données géospatiales dans Kibana Maps</h2><p>Kibana a ajouté la prise en charge de Spatial ES|QL dans l'application Maps. Cela signifie que vous pouvez désormais utiliser ES|QL pour rechercher des données géospatiales dans Elasticsearch et visualiser les résultats sur une carte.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Couches Kibana ES|QL" /><p>Il existe une nouvelle option de couche dans le menu d'ajout de couches, appelée "ES|QL". Comme toutes les fonctions géospatiales décrites jusqu'à présent, il s'agit d'un aperçu technique "" . Cette option permet d'ajouter une couche à la carte en fonction des résultats d'une requête ES|QL. Par exemple, vous pouvez ajouter une couche à la carte qui montre tous les aéroports du monde.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aéroports" /><p>Vous pouvez également ajouter une couche qui montre les polygones de l'index <code>airport_city_boundaries</code> ou, mieux encore, la requête complexe <code>ENRICH</code> ci-dessus qui génère des statistiques sur le nombre d'aéroports dans chaque région.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Statistiques par région" /><h2>Et ensuite ?</h2><p>Le précédent blog sur <a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">la recherche géospatiale</a> s'est concentré sur l'utilisation de fonctions telles que <code>ST_INTERSECTS</code> pour effectuer des recherches, disponibles dans Elasticsearch depuis la version 8.14. Ce blog vous montre comment importer les données que nous avons utilisées pour ces recherches. Cependant, Elasticsearch 8.15 a été doté d'une fonction particulièrement intéressante : <code>ST_DISTANCE</code> qui peut être utilisée pour effectuer des recherches de distance spatiale efficaces, et ce sera le sujet du prochain 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[Recherche géospatiale Elasticsearch avec ES|QL]]></title>
    <description><![CDATA[Recherche géospatiale dans le langage de requête Elasticsearch (ES|QL). Elasticsearch possède de puissantes fonctionnalités de recherche géospatiale, qui sont désormais intégrées à ES|QL pour une facilité d'utilisation et une familiarité avec l'OGC considérablement améliorées.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch dispose depuis de nombreuses années de puissantes <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">fonctionnalités de recherche et d'analyse géospatiales</a>, mais l'API était très différente de celle à laquelle les utilisateurs de SIG étaient habitués. L'année dernière, nous avons <a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga">ajouté le langage d'interrogation ES|QL</a>, un langage d'interrogation par pipeline aussi facile, voire plus facile, que SQL. Il est particulièrement adapté aux cas d'utilisation de la recherche, de la sécurité et de l'observabilité dans lesquels Elastic excelle. Nous avons également ajouté la prise en charge de la recherche et de l'analyse géospatiales dans ES|QL, ce qui facilite grandement son utilisation, en particulier pour les utilisateurs issus des communautés SQL ou <a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a>.</p><p>Elasticsearch 8.12 et 8.13 ont apporté une prise en charge de base des types géospatiaux à ES|QL. Cette fonction a été considérablement améliorée par l'ajout de capacités de recherche géospatiale dans la version 8.14. Plus important encore, ce support a été conçu pour se conformer étroitement à la norme <a href="https://en.wikipedia.org/wiki/Simple_Features">Simple Feature Access de</a> l'<a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">Open Geospatial Consortium (OGC)</a> utilisée par d'autres bases de données spatiales comme PostGIS, ce qui le rend beaucoup plus facile à utiliser pour les experts SIG familiarisés avec ces normes.</p><p>Dans ce blog, nous vous montrerons comment utiliser ES|QL pour effectuer des recherches géospatiales, et comment il se compare aux équivalents SQL et Query DSL. Nous vous montrerons également comment utiliser ES|QL pour effectuer des jointures spatiales et comment visualiser les résultats dans Kibana Maps. Notez que toutes les fonctionnalités décrites ici figurent dans l'aperçu technique de "" , et nous serions ravis de recevoir vos commentaires sur la manière dont nous pouvons les améliorer.</p><h2>Recherche de données géospatiales</h2><p>Commençons par un exemple de requête :</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>Cette opération permet de rechercher tous les polygones de limite de ville qui recoupent un polygone de recherche rectangulaire autour de l'aéroport international de Sanya Phoenix (SYX).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="Recherche géospatiale ESQL" /><p>Dans un échantillon de données d'aéroports, de villes et de limites de villes, cette recherche trouve le polygone d'intersection et renvoie les champs souhaités à partir du document correspondant :</p><p>abbrev</p><p>aéroport</p><p>région</p><p>ville</p><p>ville_location</p><p>SYX</p><p>Sanya Phoenix Int'l</p><p>天涯区</p><p>Sanya</p><p>POINT(109.5036 18.2533)</p><p>C'était facile ! Comparez maintenant cela au DSL Elasticsearch Query classique pour la même requête :</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>Les deux requêtes sont raisonnablement claires dans leur intention, mais la requête ES|QL ressemble beaucoup à SQL. La même requête dans PostGIS se présente comme suit :</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>Reprenez l'exemple de ES|QL. C'est un peu la même chose, non ?</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>Nous avons constaté que les utilisateurs existants de l'API Elasticsearch trouvent ES|QL beaucoup plus facile à utiliser. Nous pensons que les utilisateurs de SQL, en particulier ceux de Spatial SQL, trouveront que ES|QL est très proche de ce qu'ils ont l'habitude de voir.</p><h4>Pourquoi pas SQL ?</h4><p>Qu'en est-il d'Elasticsearch SQL ? Il existe depuis un certain temps et possède des fonctions géospatiales. Cependant, Elasticsearch SQL a été écrit comme une enveloppe au-dessus de l'API de requête originale, ce qui signifie que seules les requêtes qui pouvaient être transposées vers l'API originale étaient prises en charge. ES|QL n'a pas cette limitation. Le fait qu'il s'agisse d'une pile entièrement nouvelle permet de nombreuses optimisations qui n'étaient pas possibles avec SQL. Nos benchmarks montrent qu'ES|QL est <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">très souvent plus rapide que l'API Query</a>, en particulier avec les agrégations !</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="polygone-intersection-benchmark" /><h2>Différences avec SQL</h2><p>Il ressort clairement de l'exemple précédent que ES|QL est quelque peu similaire à SQL, mais qu'il existe des différences importantes. Par exemple, ES|QL est un langage d'interrogation par pipeline, qui commence par une commande source telle que FROM et enchaîne toutes les commandes suivantes à l'aide du caractère de pipeline |. Il est ainsi très facile de comprendre comment chaque commande reçoit un tableau de données et effectue une action sur ce tableau, comme le filtrage avec <code>WHERE</code>, l'ajout de colonnes avec <code>EVAL</code>, ou l'exécution d'agrégations avec <code>STATS</code>. Plutôt que de commencer par <code>SELECT</code> pour définir les colonnes de sortie finales, il peut y avoir une ou plusieurs commandes <code>KEEP</code>, la dernière spécifiant les résultats de sortie finaux. Cette structure simplifie le raisonnement sur la requête.</p><p>Si l'on se concentre sur la commande <code>WHERE</code> dans l'exemple ci-dessus, on constate qu'elle ressemble beaucoup à l'exemple 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>Outre la différence entre les caractères de citation des chaînes, la plus grande différence réside dans la façon dont nous transformons la chaîne de caractères en un type spatial. Dans PostGIS, nous utilisons le suffixe <code>::geometry</code>, tandis que dans ES|QL, nous utilisons le suffixe <code>::geo_shape</code>. En effet, ES|QL fonctionne au sein d'Elasticsearch, et l'opérateur de conversion de type <code>::</code> peut être utilisé pour convertir une chaîne en l'un des <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">types ES|QL pris en charge</a>, dans ce cas, un <code>geo_shape</code>. En outre, les types <code>geo_shape</code> et <code>geo_point</code> dans Elasticsearch impliquent le système de coordonnées spatiales connu sous le nom de WGS84, plus communément désigné par le numéro SRID 4326. Dans PostGIS, cela doit être explicite, d'où l'utilisation du préfixe <code>SRID=4326;</code> pour la chaîne WKT. Si ce préfixe est supprimé, le SRID sera fixé à 0, ce qui est plus proche des types Elasticsearch <code>cartesian_point</code> et <code>cartesian_shape</code>, qui ne sont pas liés à un système de coordonnées spécifique.</p><p>ES|QL et PostGIS fournissent également une syntaxe de fonction de conversion de type :</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>Fonctions de l'OGC</h2><p>Elasticsearch 8.14 introduit les quatre fonctions de recherche spatiale de l'OGC suivantes :</p><p>ES|QL</p><p>PostGIS</p><p>Description</p><p>ST_INTERSECTS</p><p>ST_Intersects</p><p>Retourne true si deux géométries se croisent, et false dans le cas contraire.</p><p>ST_DISJOINT</p><p>ST_Disjoint</p><p>Retourne true si deux géométries ne se croisent pas, et false dans le cas contraire. L'inverse de ST_INTERSECTS.</p><p>ST_CONTAINS</p><p>ST_Contains</p><p>Retourne true si une géométrie en contient une autre, et false sinon.</p><p>ST_WITHIN</p><p>ST_Within</p><p>Retourne true si une géométrie est à l'intérieur d'une autre, et false dans le cas contraire. L'inverse de ST_CONTAINS.</p><p>Ces fonctions se comportent de manière similaire à leurs homologues PostGIS et sont utilisées de la même manière. Par exemple, <code>ST_INTERSECTS</code> renvoie un message vrai si deux géométries se croisent et un message faux dans le cas contraire. Si vous suivez les liens de documentation dans le tableau ci-dessus, vous remarquerez que tous les exemples ES|QL se trouvent dans une clause <code>WHERE</code> après une clause <code>FROM</code>, alors que tous les exemples PostGIS utilisent des géométries littérales. En fait, les deux plates-formes permettent d'utiliser les fonctions dans n'importe quelle partie de la requête où elles sont utiles.</p><p>Le premier exemple dans la documentation PostGIS pour <code>ST_INTERSECTS</code> est le suivant :</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>L'équivalent en ES|QL serait le suivant :</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>Notez que nous n'avons pas spécifié le SRID dans l'exemple de PostGIS. En effet, dans PostGIS, lorsque l'on utilise le type <code>geometry</code>, tous les calculs sont effectués sur un système de coordonnées planaires et, par conséquent, si les deux géométries ont le même SRID, le SRID n'a pas d'importance. Dans Elasticsearch, c'est également le cas pour la plupart des fonctions, mais il existe des exceptions où <code>geo_shape</code> et <code>geo_point</code> utilisent des calculs sphériques, comme nous le verrons dans le prochain blog sur la recherche de distance spatiale.</p><h2>ES|QL polyvalence</h2><p>Nous avons donc vu ci-dessus des exemples d'utilisation de fonctions spatiales dans les clauses <code>WHERE</code> et dans les commandes <code>ROW</code>. Où cela aurait-il un sens ? Un endroit très utile est la commande <code>EVAL</code>. Cette commande permet d'évaluer une expression et de renvoyer le résultat. Par exemple, déterminons si les centroïdes de tous les aéroports regroupés par nom de pays se trouvent à l'intérieur d'une frontière délimitant le pays :</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>Les résultats sont attendus, les centroïdes des aéroports britanniques sont situés à l'intérieur de la frontière britannique, mais pas à l'intérieur de la frontière islandaise, et vice versa :</p><p>centroïde</p><p>Compte</p><p>in_uk</p><p>en_pays</p><p>within_uk</p><p>à l'intérieur de la patrie</p><p>POINT (-21.946634463965893 64.13187285885215)</p><p>1</p><p>faux</p><p>vrai</p><p>faux</p><p>vrai</p><p>POINT (-2.597342072712148 54.33551226578214)</p><p>17</p><p>vrai</p><p>faux</p><p>vrai</p><p>faux</p><p>POINT (0.04453958108176276 23.74658354606057)</p><p>873</p><p>faux</p><p>faux</p><p>faux</p><p>faux</p><p>En fait, ces fonctions peuvent être utilisées dans n'importe quelle partie de la requête où leur signature a un sens. Ils prennent tous deux arguments, qui sont soit un objet spatial littéral, soit un champ d'un type spatial, et renvoient tous une valeur booléenne. Il est important de noter que le système de référence des coordonnées (CRS) des géométries doit correspondre, sinon une erreur sera renvoyée. Cela signifie que vous ne pouvez pas mélanger les types <code>geo_shape</code> et <code>cartesian_shape</code> dans le même appel de fonction. Vous pouvez toutefois mélanger les types <code>geo_point</code> et <code>geo_shape</code>, car le type <code>geo_point</code> est un cas particulier du type <code>geo_shape</code>, et tous deux partagent le même système de référence de coordonnées. La documentation relative à chacune des fonctions définies ci-dessus énumère les combinaisons de types prises en charge.</p><p>En outre, chaque argument peut être un littéral spatial ou un champ, dans l'un ou l'autre ordre. Vous pouvez même spécifier deux champs, deux littéraux, un champ et un littéral, ou un littéral et un champ. La seule condition est que les types soient compatibles. Par exemple, cette requête compare deux champs dans le même index :</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 requête demande essentiellement si la ville est située à l'intérieur des limites de la ville, ce qui devrait généralement être le cas, mais il y a toujours des exceptions :</p><p>cardinalité</p><p>Compte</p><p>dans_la_ville</p><p>peu</p><p>29</p><p>faux</p><p>nombreux</p><p>740</p><p>vrai</p><p>Une question bien plus intéressante serait de savoir si l'emplacement de l'aéroport se trouve à l'intérieur des limites de la ville desservie par l'aéroport. Cependant, l'emplacement de l'aéroport se trouve dans un index différent de celui qui contient les limites de la ville. Il faut donc trouver une méthode pour interroger efficacement les données de ces deux index distincts et les mettre en corrélation.</p><h2>Jointures spatiales</h2><p>ES|QL ne prend pas <code>JOIN</code> en charge les commandes, mais vous pouvez réaliser un cas spécial de jointure à l'aide de la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"><code>ENRICH</code></a><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-enrich"> </a>commande, qui se comporte de la même manière qu'une "jointure gauche" en SQL. Cette commande s'apparente à une "jointure gauche" en SQL, vous permettant d'enrichir les résultats d'un index avec des données d'un autre index sur la base d'une relation spatiale entre les deux ensembles de données.</p><p>Par exemple, enrichissons les résultats d'un tableau d'aéroports avec des informations supplémentaires sur la ville qu'ils desservent en trouvant la limite de la ville qui contient l'emplacement de l'aéroport, puis effectuons quelques statistiques sur les résultats :</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>Cette méthode permet d'obtenir les 5 régions qui comptent le plus d'aéroports, ainsi que le centroïde de tous les aéroports qui ont des régions correspondantes et la longueur de la représentation WKT des limites des villes à l'intérieur de ces régions :</p><p>centroïde</p><p>Compte</p><p>min_wkt</p><p>max_wkt</p><p>région</p><p>POINT (-32.56093470960719 32.598117914802714)</p><p>90</p><p>207</p><p>207</p><p>nul</p><p>POINT (-73.94515332765877 40.70366442203522)</p><p>9</p><p>438</p><p>438</p><p>Ville de New York</p><p>POINT (-83.10398317873478 42.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>Détroit</p><p>POINT (-156.3020245861262 20.176383580081165)</p><p>5</p><p>307</p><p>803</p><p>Hawaï</p><p>POINT (-73.88902732171118 45.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>Montréal</p><p>Alors, que s'est-il vraiment passé ? Où s'est produite la supposée <code>JOIN</code>? L'essentiel de la question réside dans la commande <code>ENRICH</code>:</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>Cette commande demande à Elasticsearch d'enrichir les résultats extraits de l'index <code>airports</code> et d'effectuer une jointure <code>intersects</code> entre le champ <code>city_location</code> de l'index original et le champ <code>city_boundary</code> de l'index <code>airport_city_boundaries</code>, que nous avons utilisé dans quelques exemples plus tôt. Mais certaines de ces informations ne sont pas clairement visibles dans cette requête. Ce que nous voyons, c'est le nom d'une politique d'enrichissement <code>city_boundaries</code>, et l'information manquante est encapsulée dans cette définition de politique.</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>Ici, nous pouvons voir qu'il effectuera une requête <code>geo_match</code> (<code>intersects</code> est la valeur par défaut), que le champ à comparer est <code>city_boundary</code> et que les champs <code>enrich_fields</code> sont les champs que nous voulons ajouter au document d'origine. L'un de ces champs, le <code>region</code>, a été utilisé comme clé de regroupement pour la commande <code>STATS</code>, ce que nous n'aurions pas pu faire sans cette capacité de "jointure à gauche". Pour plus d'informations sur les politiques d'enrichissement, voir la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">documentation d'enrichissement</a>. En lisant ces documents, vous remarquerez qu'ils décrivent l'utilisation des index d'enrichissement pour enrichir les données au moment de l'indexation, en configurant les pipelines d'ingestion. Cela n'est pas nécessaire pour ES|QL, car la commande <code>ENRICH</code> fonctionne au moment de la requête. Il suffit de préparer l'index d'enrichissement avec les données et la politique d'enrichissement nécessaires, puis d'utiliser la commande <code>ENRICH</code> dans vos requêtes ES|QL.</p><p>Vous pouvez également remarquer que la région la plus fréquemment trouvée est <code>null</code>. Qu'est-ce que cela peut signifier ? Rappelez-vous que j'ai comparé cette commande à une "jointure gauche" en SQL, ce qui signifie que si aucune limite de ville correspondante n'est trouvée pour un aéroport, l'aéroport est toujours renvoyé, mais avec les valeurs <code>null</code> pour les champs de l'index <code>airport_city_boundaries</code>. Il s'avère que 89 aéroports n'ont pas trouvé de correspondance avec <code>city_boundary</code>, et un aéroport avec une correspondance où le champ <code>region</code> était <code>null</code>. Cela a conduit à un décompte de 90 aéroports sans <code>region</code> dans les résultats. Un autre détail intéressant est la nécessité de la commande <code>MV_EXPAND</code>. Cela est nécessaire car la commande <code>ENRICH</code> peut renvoyer plusieurs résultats pour chaque ligne d'entrée, et <code>MV_EXPAND</code> permet de séparer ces résultats en plusieurs lignes, une pour chaque résultat. Cela explique également pourquoi "Hawaii" affiche des résultats différents de <code>min_wkt</code> et <code>max_wkt</code>: il y avait plusieurs régions portant le même nom mais ayant des limites différentes.</p><h2>Cartes Kibana</h2><p>Kibana a ajouté la prise en charge de Spatial ES|QL dans l'application Maps. Cela signifie que vous pouvez désormais utiliser ES|QL pour rechercher des données géospatiales dans Elasticsearch et visualiser les résultats sur une carte.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Couches Kibana ES|QL" /><p>Il existe une nouvelle option de couche dans le menu d'ajout de couches, appelée "ES|QL". Comme toutes les fonctions géospatiales décrites jusqu'à présent, il s'agit d'un aperçu technique "" . Cette option permet d'ajouter une couche à la carte en fonction des résultats d'une requête ES|QL. Par exemple, vous pouvez ajouter une couche à la carte qui montre tous les aéroports du monde.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - Aéroports" /><p>Vous pouvez également ajouter une couche qui montre les polygones de l'index <code>airport_city_boundaries</code> ou, mieux encore, la requête complexe <code>ENRICH</code> ci-dessus qui génère des statistiques sur le nombre d'aéroports dans chaque région.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - Statistiques par région" /><h2>Et ensuite ?</h2><p>Vous avez peut-être remarqué que dans deux des exemples ci-dessus, nous avons inséré une autre fonction spatiale <code>ST_CENTROID_AGG</code>. Il s'agit d'une fonction d'agrégation utilisée dans la commande <code>STATS</code> et de la première des nombreuses fonctions d'analyse spatiale que nous prévoyons d'ajouter à ES|QL. Nous en parlerons sur notre blog lorsque nous en aurons plus à montrer !</p><p>Avant cela, nous souhaitons vous parler d'une fonctionnalité particulièrement intéressante sur laquelle nous avons travaillé : la possibilité d'effectuer des recherches spatiales par distance, l'une des fonctionnalités de recherche spatiale les plus utilisées d'Elasticsearch. Pouvez-vous imaginer à quoi pourrait ressembler la syntaxe des recherches à distance ? Peut-être similaire à une fonction de l'OGC ? Restez à l'écoute du prochain blog de cette série pour le découvrir !</p><p>Alerte au spoiler : Elasticsearch 8.15 vient d'être publié, et la recherche de distance spatiale avec ES|QL est incluse !</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>