<?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/cn/search-labs/author/craig-taverner</link>
    </image>
    <link>https://www.elastic.co/cn/search-labs/author/craig-taverner</link>
    <atom:link href="https://www.elastic.co/cn/search-labs/rss/author/craig-taverner.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[cn]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 05:52:22 GMT</lastBuildDate>
  <item>
    <title><![CDATA[使用 Kibana 将地理空间数据输入 Elasticsearch，以便在 ES|QL 中使用]]></title>
    <description><![CDATA[如何使用 Kibana 和 csv 摄取处理器将地理空间数据摄取到 Elasticsearch 中，以便在 Elasticsearch 查询语言 (ES|QL) 中进行搜索。Elasticsearch 具有强大的地理空间搜索功能，ES|QL 将大幅提高易用性和 OGC 熟悉度。但要使用这些功能，我们需要地理空间数据。]]></description>
    <content:encoded><![CDATA[<p>我们最近发布了一篇博客，介绍了如何使用 Elasticsearch 新的强大<a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga"> 管道式查询语言</a><a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one"> ES|QL</a><a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one"> 中 的新</a><a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one"> 地理空间搜索 功能</a> 。要使用这些功能，您需要在 Elasticsearch 中保存地理空间数据。因此，在本博客中，我们将向您展示如何获取地理空间数据，以及如何在 ES|QL 查询中使用这些数据。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfc041ebca11476c6/6a16f70560084b31b93c4344/01fde3b1d714f12bf8673140c9f2f940d443de31-1440x823.jpg" alt="ESQL 地理空间搜索" /><h2>使用 Kibana 导入地理空间数据</h2><p>我们在上一篇博客的示例中使用的数据是基于我们内部用于集成测试的数据。为方便起见，我们在此以 CSV 文件的形式提供了这些信息，您可以使用 Kibana 轻松导入这些信息。数据包括机场、城市和城市边界。您可以从以下网址下载数据</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">机场.csv</a></p><ul><li><p>其中包含三个数据集的合并：</p><ul><li><p>来自<a href="https://www.naturalearthdata.com/downloads/10m-cultural-vectors/airports/">Natural Earth</a>的机场（名称、位置和相关数据</p></li><li><p>来自<a href="https://simplemaps.com/data/world-cities">SimpleMaps</a>的城市位置</p></li><li><p><a href="https://www.partow.net/miscellaneous/airportdatabase/">全球机场数据库</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>其中包含上述机场和城市名称与一个新来源的合并：</p><ul><li><p>来自<a href="https://www.openstreetmap.org/">OpenStreetMap</a>的城市边界</p></li></ul></li></ul></li></ul><p>您可以猜到，我们花了一些时间将这些数据源合并到上述两个文件中，目的是测试 ES|QL 的地理空间特性。这可能与您的具体数据需求不尽相同，但希望这能让您对可能的情况有所了解。我们特别想展示几件有趣的事情：</p><ul><li><p>将包含地理空间字段的数据与其他可索引数据一起导入</p></li><li><p>同时导入<code>geo_point</code> 和<code>geo_shape</code> 数据并在查询中一起使用</p></li><li><p>将数据导入可使用空间关系连接的两个索引中</p></li><li><p>创建摄取管道以促进未来的导入（超越 Kibana）</p></li><li><p>摄取处理器的一些示例，如<code>csv</code> 、<code>convert</code> 和 <code>split</code></p></li></ul><p><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"> 使用</a> CSV 数据，但重要的是要了解 使用<a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html"> Kibana</a><a href="https://www.elastic.co/guide/en/kibana/current/import-geospatial-data.html"> 添加地理数据的 几种方法</a> 。在地图应用程序中，您可以上传 CSV、GeoJSON 和 ESRI ShapeFiles 等分隔数据，还可以直接在地图中绘制图形。在本博客中，我们将重点介绍从 Kibana 主页导入 CSV 文件。</p><h3>导入机场</h3><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>、我们需要处理一些有趣的怪癖。首先，列之间有额外的空白分隔，这不是 CSV 文件的典型特征。其次，<code>type</code> 字段是一个多值字段，我们需要将其分割成不同的字段。最后，有些字段不是字符串，需要转换为正确的类型。所有这些都可以使用 Kibana 的 CSV 导入功能来完成。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt393bc416bf425301/6a16f707839dfa1e86dcfca9/b1afd8c95973bec32f229a9adfaef14680b09a8e-1944x478.png" alt="Kibana 上传 - 预览" /><p>从 Kibana 主页开始。有一个名为"添加集成入门" 的部分，其中有一个名为"上传文件" 的链接：</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte12fc741edab20d3/6a16f709acf088600fbe98bf/996372bb3a52859cc840bd1d8f984a33a0e7ada3-1180x410.png" alt="Kibana 主页 - 上传文件" /><p>点击该链接，您将进入"Upload file" 页面。在此，您可以拖放<code>airports.csv</code> 文件，Kibana 将分析该文件并为您提供数据预览。它应该会自动检测到分隔符是逗号，第一行是标题行。但是，假设所有字段都是<code>text</code> 或<code>keyword</code> ，它可能没有修剪列之间多余的空白，也没有确定字段的类型。我们需要解决这个问题。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf65a09ec0c7a61ad/6a16f70ad7c0227aedde626f/1d9ffa6cdbc0d67a228be1a747ec1ebda6a63099-1800x538.png" alt="Kibana 上传 - 预览" /><p>单击<code>Override settings</code> 并选中<code>Should trim fields</code> 复选框 ，然后<code>Apply</code> 关闭设置。现在，我们需要确定字段的类型。可在下一页查看，请点击<code>Import</code> 。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda9a5f85d8e693dc/6a16f70c60084b72f53c4348/a97aceffb1858eae26a213336913505ae9923b03-1800x526.png" alt="Kibana 上传 - 导入" /><p>首先选择一个索引名称，然后选择<code>Advanced</code> ，进入字段映射和摄取处理器页面。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt56705083cdd9eb18/6a16f70d66c4f93350f8bdbb/058b0fb09da0b8d7f9c9b0a9c83b8b485ce43925-1440x629.png" alt="Kibana 上传 - 字段映射" /><p>在此，我们需要对索引的字段映射和导入数据的摄取管道进行更改。首先，虽然 Kibana 可能会将<code>scalerank</code> 字段自动检测为<code>long</code> ，但却误将<code>location</code> 和<code>city_location</code> 字段视为<code>keyword</code> 。将它们编辑为<code>geo_point</code> ，最后得到类似的映射：</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>您在这里有一定的灵活性，但要注意的是，您选择的类型会影响字段的索引方式和可能的查询类型。例如，如果将<code>location</code> 设置为<code>keyword</code> ，则无法对其执行任何地理空间搜索查询。同样，如果将<code>elevation</code> 设置为<code>text</code> ，则无法对其执行数值范围查询。</p><p>现在是修复摄取管道的时候了。如果 Kibana 自动检测到<code>scalerank</code> 如上所示<code>long</code> ，它还会添加一个处理器，将字段转换为<code>long</code> 。我们需要为<code>elevation</code> 字段添加一个类似的处理器，这次将其转换为<code>double</code> 。编辑管道，确保您已将此转换到位。在保存之前，我们还需要进行一次转换，将<code>type</code> 字段分成多个字段。在管道中添加<code>split</code> 处理器，配置如下</p>{
  "split": {
    "field": "type",
    "separator": ":",
    "ignore_missing": true
  }
}<p>最终的摄取管道应该是这样的</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>请注意，我们没有为<code>location</code> 和<code>city_location</code> 字段添加转换处理器。这是因为字段映射中的<code>geo_point</code> 类型已经了解这些字段中数据的WKT格式。<code>geo_point</code> 类型可以理解一系列格式，包括<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html">WKT、GeoJSON 等</a>。例如，如果我们在 CSV 文件中有<code>latitude</code> 和<code>longitude</code> 两列，我们就需要添加<code>script</code> 或<code>set</code> 处理器，将这两列合并为一个<code>geo_point</code> 字段（例如。<code>"set": {"field": "location", "value": "{{lat}},{{lon}}"}</code>).</p><p>现在我们可以导入文件了。点击<code>Import</code> ，数据就会按照我们刚刚定义的映射和摄取管道导入索引。如果在摄取数据时出现任何错误，Kibana 会在这里报告，这样你就可以编辑源数据或摄取管道，然后再试一次。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte81621425c7289c5/6a16f70f839dfaf608dcfcad/55dde2940c7aba66ce8257d15007ef797b8a5107-1440x415.png" alt="Kibana 上传 - 导入" /><p>请注意，新的摄取管道已经创建。可进入 Kibana 的<code>Stack Management</code> 部分，选择<code>Ingest pipelines</code> 查看。在这里，您可以看到我们刚刚创建的管道，如有必要，还可以对其进行编辑。事实上，<code>Ingest pipelines</code> 部分可用于创建和测试摄取管道，如果你计划进行更复杂的摄取，这是一项非常有用的功能。</p><p>如果您想立即探索这些数据，请跳到后面的章节，但如果您还想导入城市边界，请继续阅读。</p><h3>导入城市边界</h3><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>中的城市边界文件导入更为简单。它包含一个<code>city_boundary</code> 字段和一个<code>city_location</code> 字段，前者是城市边界的 WKT 表示法，如<code>POLYGON</code> ，后者是城市位置的<code>geo_point</code> 表示法。我们可以用与机场数据类似的方式导入这些数据，但有一些不同之处：</p><ul><li><p>我们需要选择覆盖设置<code>Has header row</code> ，因为这不是自动检测到的</p></li><li><p>我们不需要修剪字段，因为数据中已经没有多余的空白了</p></li><li><p>由于所有类型都是字符串或空间类型，因此我们无需编辑采集管道</p></li><li><p>不过，我们必须编辑字段映射，将<code>city_boundary</code> 字段设置为<code>geo_shape</code> ，将<code>city_location</code> 字段设置为 <code>geo_point</code></p></li></ul><p>我们最终的字段映射如下</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>与之前的<code>airports.csv</code> 导入一样，只需单击<code>Import</code> 即可将数据导入索引。数据将通过我们编辑的映射和 Kibana 定义的摄取管道导入。</p><h3>使用开发工具探索地理空间数据</h3><p>在 Kibana 中，通常使用"Discover" 探索索引数据。不过，如果您打算使用 ES|QL 查询编写自己的应用程序，尝试访问原始 Elasticsearch API 可能会更有趣。Kibana 有一个方便的控制台，可用于尝试编写查询。这就是所谓的<code>Dev Tools</code> 控制台，可以在 Kibana 侧边栏中找到。该控制台直接与 Elasticsearch 集群对话，可用于运行查询、创建索引等。</p><p>试试以下方法：</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>结果如下</p><p>距离</p><p>缩写</p><p>名字</p><p>位置</p><p>国家</p><p>城市</p><p>标高</p><p>273418.05776847183</p><p>火腿</p><p>汉堡</p><p>点 (10.005647830925 53.6320011640866)</p><p>德国</p><p>诺德施泰特</p><p>17.0</p><p>337534.653466062</p><p>TXL</p><p>柏林泰格尔国际机场</p><p>点 (13.2903090925074 52.5544287044101)</p><p>德国</p><p>霍恩诺恩多夫</p><p>38.0</p><p>483713.15032266214</p><p>OSL</p><p>奥斯陆加德尔莫尼</p><p>点 (11.0991032762581 60.1935783171386)</p><p>挪威</p><p>奥斯陆</p><p>208.0</p><p>522538.03148094116</p><p>BMA</p><p>Bromma</p><p>点（17.9456175406145 59.3555902065112）</p><p>瑞典</p><p>斯德哥尔摩</p><p>15.0</p><p>522538.03148094116</p><p>ARN</p><p>阿尔兰达</p><p>点 (17.9307299016916 59.6511203397372)</p><p>瑞典</p><p>斯德哥尔摩</p><p>38.0</p><p>624274.8274399083</p><p>DUS</p><p>杜塞尔多夫国际机场</p><p>点 (6.76494446612174 51.2781820420774)</p><p>德国</p><p>杜塞尔多夫</p><p>45.0</p><p>633388.6966435644</p><p>PRG</p><p>鲁兹恩</p><p>点 (14.2674849854076 50.1076511703671)</p><p>捷克</p><p>布拉格</p><p>381.0</p><p>635911.1873311149</p><p>AMS</p><p>史基浦机场</p><p>点 (4.76437693232812 52.3089323889822)</p><p>荷兰</p><p>霍夫多尔普</p><p>-3.0</p><p>670864.137958866</p><p>法国</p><p>法兰克福国际机场</p><p>点 (8.57182286907608 50.0506770895207)</p><p>德国</p><p>法兰克福</p><p>111.0</p><p>683239.2529970079</p><p>WAW</p><p>奥克西国际机场</p><p>点 (20.9727263383587 52.171026749259)</p><p>波兰</p><p>Piaseczno</p><p>111.0</p><h2>使用 Kibana 地图可视化地理空间数据</h2><p>Kibana 地图是可视化地理空间数据的强大工具。它可用于创建具有多个图层的地图，每个图层代表不同的数据集。数据可以通过各种方式进行过滤、汇总和样式化。在本节中，我们将向您展示如何使用上一节导入的数据在 Kibana 地图中创建地图。</p><p>在 Kibana 菜单中，导航至<code>Analytics</code>-&gt;<code>Maps</code> ，打开新的地图视图。单击<code>Add Layer</code> ，选择<code>Documents</code> ，选择数据视图<code>airports</code> ，然后编辑图层样式，使用<code>elevation</code> 字段为标记着色，这样我们就可以很容易地看到每个机场的高度。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdcc4736d88c1abc9/6a16f7102b835f7353f4afca/9e63726d7c059331e6e20e474f8abee53dc2cbb4-840x388.png" alt="Kibana 地图 - 机场图层样式" /><p>单击 "保持更改 "保存地图：</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ec3cc535b5c21d8/6a16f71375879ec091fe15dc/32ad1dadb5d341a2b66662c58638b781122fc22c-2852x1528.png" alt="Kibana 地图 - 机场" /><p>现在添加第二个图层，这次选择<code>airport_city_boundaries</code> 数据视图。这次，我们将使用<code>city_boundary</code> 字段对图层进行样式设置，并将填充颜色设为淡蓝色。这将在地图上显示城市边界。确保对图层重新排序，以确保机场标记位于顶部。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2932d7ff4a7206c9/6a16f7156f7f0409f09145c7/53dd65026f9a98c13f2cc4f9328a79242f0b70de-2854x1510.png" alt="Kibana 地图 - 城市边界图层样式" /><h2>空间连接</h2><p>ES|QL 不支持<code>JOIN</code> 命令，但可以使用<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>实现连接的特殊情况。该命令的操作类似于 SQL 中的 "左连接"，允许您根据两个数据集之间的空间关系，用另一个索引中的数据来丰富一个索引的结果。</p><p>例如，我们可以通过查找包含机场位置的城市边界，用机场服务城市的附加信息来丰富机场表的结果，然后对结果进行一些统计：</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>如果不先准备 enrich 索引就运行该查询，将会收到类似的错误信息：</p>cannot find enrich policy [city_boundaries]<p>如前所述，这是因为 ES|QL 不支持真正的<code>JOIN</code> 命令。其中一个重要原因是 Elasticsearch 是一个分布式系统，而连接是一种昂贵的操作，很难扩展。不过，<code>ENRICH</code> 命令的效率相当高，因为它利用了专门编制的在整个集群中复制的丰富索引，从而可以在每个节点上执行本地连接。</p><p>为了更好地理解这一点，让我们把重点放在上面查询中的<code>ENRICH</code> 命令上：</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary<p>该命令指示 Elasticsearch 丰富从<code>airports</code> 索引中获取的结果，并在原始索引的<code>city_location</code> 字段和<code>airport_city_boundaries</code> 索引的<code>city_boundary</code> 字段之间执行<code>intersects</code> 连接，我们在前面的几个示例中使用了该连接。但其中一些信息在该查询中并不清晰。我们看到的是丰富策略的名称<code>city_boundaries</code> ，缺失的信息被封装在该策略定义中。</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>在这里我们可以看到，它将执行<code>geo_match</code> 查询（<code>intersects</code> 是默认值），要匹配的字段是<code>city_boundary</code> ，而<code>enrich_fields</code> 是我们要添加到原始文档中的字段。其中一个字段<code>region</code> 实际上被用作<code>STATS</code> 命令的分组键，如果没有这种 "左连接 "功能，我们是做不到这一点的。有关 enrich 策略的更多信息，请参阅<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">enrich 文档</a>。</p><p>Elasticsearch 中的丰富索引和策略最初是为在索引时使用另一个准备好的丰富索引中的数据来丰富数据而设计的。不过，在 ES|QL 中，<code>ENRICH</code> 命令在查询时工作，不需要使用摄取管道。这实际上使它与 SQL<code>LEFT JOIN</code> 非常相似，只是不能连接任何两个索引，只能在左侧连接一个普通索引，在右侧连接一个专门编制的丰富索引。</p><p>无论在哪种情况下，无论是用于摄取管道还是在 ES|QL 中使用，都有必要执行一些准备步骤来设置丰富索引和策略。上文我们已经导入了<code>airport_city_boundaries</code> 索引，但在<code>ENRICH</code> 命令中，它不能直接用作丰富索引。我们首先需要执行两个步骤：</p><ul><li><p>创建上述丰富策略，以定义源索引、源索引中要匹配的字段以及匹配后要返回的字段。</p></li><li><p>执行该策略可创建丰富索引。这将建立一个特殊的内部索引，将原始源索引读取到一个更高效的数据结构中，并在整个集群中复制。</p></li></ul><p>可以使用以下命令创建丰富策略：</p>PUT /_enrich/policy/city_boundaries
{
  "match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}<p>可以使用以下命令执行该策略：</p>POST /_enrich/policy/city_boundaries/_execute<p>请注意，如果您更改了<code>airport_city_boundaries</code> 索引的内容，则需要重新执行该策略，才能在丰富索引中看到更改的内容。现在，让我们再次运行原始 ES|QL 查询：</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>这将返回拥有最多机场的前 5 个区域，以及所有匹配区域机场的中心点和这些区域内城市边界的 WKT 表示长度范围：</p><p>中心点</p><p>计数</p><p>地区</p><p>点（-12.13908685930073331.024386116624648)</p><p>126</p><p>无效</p><p>点（-83.1039831787347842.300230911932886)</p><p>3</p><p>底特律</p><p>点 (39.74537850357592 47.21613017376512)</p><p>3</p><p>городской округ Батайск</p><p>点（-156.8098678719252320.476673701778054)</p><p>3</p><p>夏威夷</p><p>点（-73.9451533276587740.70366442203522)</p><p>3</p><p>纽约市</p><p>点（-83.1039831787347842.300230911932886)</p><p>3</p><p>底特律</p><p>点（-76.6687301918864324.306286952923983)</p><p>2</p><p>新普罗维登斯</p><p>点 (-3.0252167768776417 51.39245774131268)</p><p>2</p><p>加的夫</p><p>点（-115.4099348466843432.73126147687435)</p><p>2</p><p>墨西卡利市</p><p>点 (41.790108773857355 50.302146775648)</p><p>2</p><p>Центральный район</p><p>点（-73.8890273217111845.57078813901171)</p><p>2</p><p>蒙特利尔</p><p>您可能还会注意到，最常见的地区是<code>null</code> 。这意味着什么？回想一下，我曾将此命令比作 SQL 中的 "左连接"，也就是说，如果没有为某个机场找到匹配的城市边界，则仍会返回该机场，但<code>airport_city_boundaries</code> 索引中的字段值为<code>null</code> 。结果发现，有 125 个机场没有找到匹配的<code>city_boundary</code> ，有一个机场找到了匹配的<code>region</code> 字段，但该字段是<code>null</code> 。这样就统计出了 126 个机场，结果中没有<code>region</code> 。如果您的用例要求所有机场都能与城市边界相匹配，那就需要获取更多数据来填补空白。有必要确定两件事：</p><ul><li><p><code>airport_city_boundaries</code> 索引中哪些记录没有<code>city_boundary</code> 字段</p></li><li><p><code>airports</code> 索引中哪些记录与<code>ENRICH</code> 命令不匹配（即"......"）。不相交）</p></li></ul><h2>在 Kibana 地图中使用 ES|QL 获取地理空间数据</h2><p>Kibana 在地图应用程序中添加了对空间 ES|QL 的支持。这意味着您现在可以使用 ES|QL 在 Elasticsearch 中搜索地理空间数据，并在地图上将结果可视化。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana 层 ES|QL" /><p>在添加图层菜单中有一个新的图层选项，名为"ES|QL" 。与迄今为止介绍的所有地理空间功能一样，该功能在"技术预览版" 中。选择该选项可根据 ES|QL 查询结果在地图上添加图层。例如，您可以在地图上添加一个图层，显示世界上所有的机场。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - 机场" /><p>或者您也可以添加一个图层，显示<code>airport_city_boundaries</code> 索引中的多边形，或者更好的办法是使用上面那个复杂的<code>ENRICH</code> 查询，生成每个地区有多少个机场的统计数据？</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - 区域统计" /><h2>后续工作计划</h2><p>上一篇<a href="https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one">地理空间搜索</a>博客主要介绍了使用<code>ST_INTERSECTS</code> 等函数进行搜索的方法，Elasticsearch 自 8.14 版起提供了这些功能。本博客将向您展示如何导入我们用于这些搜索的数据。不过，Elasticsearch 8.15 提供了一个特别有趣的功能：<code>ST_DISTANCE</code> ，可用于执行高效的空间距离搜索，这将是下一篇博客的主题！</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[使用 ES|QL 进行 Elasticsearch 地理空间搜索]]></title>
    <description><![CDATA[Elasticsearch 查询语言 (ES|QL) 中的地理空间搜索。Elasticsearch 具有强大的地理空间搜索功能，ES|QL 将大幅提高易用性和 OGC 熟悉度。]]></description>
    <content:encoded><![CDATA[<p>多年来，Elasticsearch 一直拥有强大的<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/geospatial-analysis.html">地理空间搜索和分析功能</a>，但其应用程序接口与典型 GIS 用户习惯的应用程序接口大相径庭。去年，我们<a href="https://www.elastic.co/search-labs/blog/esql-piped-query-language-goes-ga"> 添加了 ES|QL 查询语言</a> ，这是一种管道式 查询语言 ，与 SQL 一样简单，甚至更容易。它特别适合 Elastic 擅长的搜索、安全和可观察性用例。我们还在 ES|QL 中添加了对地理空间搜索和分析的支持，使其更易于使用，特别是对于来自 SQL 或<a href="https://en.wikipedia.org/wiki/Geographic_information_system">GIS</a>社区的用户。</p><p>Elasticsearch 8.12 和 8.13 为 ES|QL 带来了对地理空间类型的基本支持。8.14 版增加了地理空间搜索功能后，这一功能大大增强。更重要的是，这种支持的设计与其他空间数据库（如<a href="https://en.wikipedia.org/wiki/Simple_Features"> </a><a href="https://en.wikipedia.org/wiki/Open_Geospatial_Consortium">PostGIS ）</a> 使用的 开放地理空间联盟（OGC） 的 简单地物访问 标准非常一致，使熟悉这些标准的 GIS 专家更容易使用。</p><p>在本博客中，我们将向您介绍如何使用 ES|QL 执行地理空间搜索，以及它与 SQL 和查询 DSL 的等效功能的比较。我们还将向您展示如何使用 ES|QL 执行空间连接，以及如何在 Kibana 地图中将结果可视化。请注意，此处描述的所有功能都在"技术预览版" 中，我们非常乐意听取您对我们如何改进这些功能的反馈意见。</p><h2>搜索地理空间数据</h2><p>让我们从一个查询示例开始：</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>这将搜索与三亚凤凰国际机场 (SYX) 周围矩形搜索多边形相交的任何城市边界多边形。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3897df6bed5d6061/6a17d7c2abe0f29eccdfe861/e48bac8f246c8842f2ea97ddd54910045262aeb1-1440x808.png" alt="ESQL 地理空间搜索" /><p>在一个包含机场、城市和城市边界的示例数据集中，该搜索可找到相交的多边形，并从匹配文档中返回所需字段：</p><p>缩写</p><p>机场</p><p>地区</p><p>城市</p><p>城市位置</p><p>SYX</p><p>三亚凤凰国际机场</p><p>天涯区</p><p>三亚</p><p>point(109.5036 18.2533)</p><p>这很容易！现在将其与经典的 Elasticsearch 查询 DSL 进行比较：</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>这两个查询的意图都相当明确，但 ES|QL 查询与 SQL 非常相似。同样的查询在 PostGIS 中是这样的：</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>请看 ES|QL 的例子。如此相似，不是吗？</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>我们发现，Elasticsearch API 的现有用户发现 ES|QL 更易于使用。现在，我们希望现有的 SQL 用户，尤其是空间 SQL 用户，会发现 ES|QL 与他们习惯看到的感觉非常相似。</p><h4>为什么不是 SQL？</h4><p>Elasticsearch SQL 如何？它已经存在了一段时间，并具有一些地理空间功能。不过，Elasticsearch SQL 是作为原始查询 API 的封装器编写的，这意味着只支持可转译到原始 API 的查询。ES|QL 没有这种限制。作为一个全新的堆栈，它可以进行许多 SQL 无法实现的优化。我们的基准测试表明，ES|<a href="https://elasticsearch-benchmarks.elastic.co/#tracks/esql/nightly/default/6M">QQL 通常比查询 API 更快</a>，尤其是在聚合方面！</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18bda964c8b24e36/6a17d7c3e3179155d22d568a/b8b6c2b2e45850d832805ed1e71e522f4955f53c-1440x813.png" alt="多边形交叉点基准" /><h2>与 SQL 的区别</h2><p>显然，从前面的例子来看，ES|QL 与 SQL 有些相似，但也有一些重要的区别。例如，ES|QL 是一种管道式查询语言，它以 FROM 等源命令开始，然后用管道 | 字符将所有后续命令串联起来。这样就很容易理解每条命令是如何接收数据表并对该表执行某些操作的，例如使用<code>WHERE</code> 进行过滤，使用<code>EVAL</code> 添加列，或使用<code>STATS</code> 执行聚合。与从<code>SELECT</code> 开始定义最终输出列不同，可以有一个或多个<code>KEEP</code> 命令，最后一个命令指定最终输出结果。这种结构简化了查询的推理过程。</p><p>仔细观察上述示例中的<code>WHERE</code> 命令，我们会发现它与 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>除了字符串引号字符的不同，最大的区别在于我们如何将字符串类型转换为空间类型。在 PostGIS 中，我们使用<code>::geometry</code> 后缀，而在 ES|QL 中，我们使用<code>::geo_shape</code> 后缀。这是因为 ES|QL 在 Elasticsearch 中运行，而类型转换操作符<code>::</code> 可用于将字符串转换为<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-limitations.html#_supported_types">ES|QL 支持的</a>任何类型，在本例中就是<code>geo_shape</code> 。此外，Elasticsearch 中的<code>geo_shape</code> 和<code>geo_point</code> 类型意味着空间坐标系为 WGS84，通常使用 SRID 编号 4326。在 PostGIS 中，这一点需要明确，因此在 WKT 字符串中使用了<code>SRID=4326;</code> 前缀。如果删除该前缀，SRID 将被设置为 0，这更像 Elasticsearch 类型<code>cartesian_point</code> 和<code>cartesian_shape</code> ，它们与任何特定坐标系无关。</p><p>ES|QL 和 PostGIS 也提供了类型转换函数语法：</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>OGC 功能</h2><p>Elasticsearch 8.14 引入了以下四种 OGC 空间搜索功能：</p><p>ES|QL</p><p>PostGIS</p><p>描述</p><p>ST_INTERSECTS</p><p>ST_Intersects</p><p>如果两个几何图形相交，则返回 true，否则返回 false。</p><p>ST_DISJOINT</p><p>ST_Disjoint</p><p>如果两个几何图形不相交，则返回 true，否则返回 false。ST_INTERSECTS 的倒数。</p><p>ST_CONTAINS</p><p>ST_Contains</p><p>如果一个几何体包含另一个几何体，则返回 true，否则返回 false。</p><p>ST_WITHIN</p><p>ST_Within</p><p>如果一个几何体位于另一个几何体内，则返回 true，否则返回 false。ST_CONTAINS 的倒数。</p><p>这些函数的行为与 PostGIS 的对应函数类似，使用方法也相同。例如，如果两个几何图形相交，<code>ST_INTERSECTS</code> 返回 true，否则返回 false。如果您跟踪上表中的文档链接，可能会发现所有 ES|QL 示例都在<code>FROM</code> 子句之后的<code>WHERE</code> 子句中，而所有 PostGIS 示例都使用了字面几何图形。事实上，这两个平台都支持在查询的任何部分使用这些函数。</p><p><code>ST_INTERSECTS</code> 的 PostGIS 文档中的第一个示例是</p>SELECT ST_Intersects(
    'POINT(0 0)'::geometry,
    'LINESTRING ( 2 0, 0 2 )'::geometry
);
<p>ES|QL 相当于此：</p>ROW ST_INTERSECTS(
    "POINT(0 0)"::geo_point,
    "LINESTRING ( 2 0, 0 2 )"::geo_shape
)
<p>请注意我们在 PostGIS 示例中没有指定 SRID。这是因为在 PostGIS 中使用<code>geometry</code> 类型时，所有计算都是在平面坐标系上进行的，因此如果两个几何图形具有相同的 SRID，SRID 是什么并不重要。在 Elasticsearch 中，大多数函数也是如此，但也有例外，<code>geo_shape</code> 和<code>geo_point</code> 使用球形计算，我们将在下一篇关于空间距离搜索的博客中看到这一点。</p><h2>ES|QL 多功能性</h2><p>因此，我们已经看到了在<code>WHERE</code> 子句和<code>ROW</code> 命令中使用空间函数的示例。它们还能在哪里发挥作用？<code>EVAL</code> 命令就是一个非常有用的地方。该命令允许您评估表达式并返回结果。例如，让我们确定按国名分组的所有机场的中心点是否都在勾勒出国家的边界内：</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>结果在意料之中，英国机场的中心点在英国边界内，而不在冰岛边界内，反之亦然：</p><p>中心点</p><p>计数</p><p>英国</p><p>冰岛</p><p>within_uk</p><p>冰岛境内</p><p>点（-21.94663446396589364.13187285885215)</p><p>1</p><p>错误</p><p>true</p><p>错误</p><p>true</p><p>点 (-2.597342072712148 54.33551226578214)</p><p>17</p><p>true</p><p>错误</p><p>true</p><p>错误</p><p>点 (0.04453958108176276 23.74658354606057)</p><p>873</p><p>错误</p><p>错误</p><p>错误</p><p>错误</p><p>事实上，这些函数可用于查询的任何部分，只要其签名是合理的。它们都接收两个参数，参数可以是一个字面空间对象，也可以是一个空间类型的字段，并且都返回一个布尔值。一个重要的考虑因素是，几何图形的坐标参考系（CRS）必须匹配，否则将返回错误信息。这意味着不能在同一个函数调用中混合使用<code>geo_shape</code> 和<code>cartesian_shape</code> 类型。不过，您可以混合使用<code>geo_point</code> 和<code>geo_shape</code> 类型，因为<code>geo_point</code> 类型是<code>geo_shape</code> 类型的特例，两者共享相同的坐标参考系。上文定义的每个函数的文档都列出了支持的类型组合。</p><p>此外，任一参数都可以是空间字面量或字段，顺序不限。您甚至可以指定两个字段、两个字面量、一个字段和一个字面量或一个字面量和一个字段。唯一的要求是类型必须兼容。例如，此查询比较同一索引中的两个字段：</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>该查询基本上是询问城市位置是否在城市边界内，一般来说应该是正确的，但总有例外：</p><p>基数</p><p>计数</p><p>城市</p><p>很少</p><p>29</p><p>错误</p><p>很多</p><p>740</p><p>true</p><p>一个更有趣的问题是，机场所在地是否在机场服务城市的边界之内。不过，机场位置所在的索引与包含城市边界的索引不同。这就需要一种方法来有效查询和关联这两个独立索引中的数据。</p><h2>空间连接</h2><p>ES|QL 不支持<code>JOIN</code> 命令，但可以使用<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>实现连接的特殊情况，其行为类似于 SQL 中的 "左连接"。该命令的操作类似于 SQL 中的 "左连接"，允许您根据两个数据集之间的空间关系，用另一个索引中的数据来丰富一个索引的结果。</p><p>例如，我们可以通过查找包含机场位置的城市边界，用机场服务城市的附加信息来丰富机场表的结果，然后对结果进行一些统计：</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>这将返回拥有最多机场的前 5 个区域，以及所有匹配区域机场的中心点和这些区域内城市边界的 WKT 表示长度范围：</p><p>中心点</p><p>计数</p><p>min_wkt</p><p>max_wkt</p><p>地区</p><p>点（-32.5609347096071932.598117914802714)</p><p>90</p><p>207</p><p>207</p><p>无效</p><p>点（-73.9451533276587740.70366442203522)</p><p>9</p><p>438</p><p>438</p><p>纽约市</p><p>点（-83.1039831787347842.300230911932886)</p><p>9</p><p>473</p><p>473</p><p>底特律</p><p>点（-156.302024586126220.176383580081165)</p><p>5</p><p>307</p><p>803</p><p>夏威夷</p><p>点（-73.8890273217111845.57078813901171)</p><p>4</p><p>837</p><p>837</p><p>蒙特利尔</p><p>那么，这里到底发生了什么？所谓的<code>JOIN</code> 发生在哪里？问题的关键在于<code>ENRICH</code> 命令：</p>FROM airports
| ENRICH city_boundaries ON city_location WITH airport, region, city_boundary
<p>该命令指示 Elasticsearch 丰富从<code>airports</code> 索引中获取的结果，并在原始索引的<code>city_location</code> 字段和<code>airport_city_boundaries</code> 索引的<code>city_boundary</code> 字段之间执行<code>intersects</code> 连接，我们在前面的几个示例中使用了该连接。但其中一些信息在该查询中并不清晰。我们看到的是丰富策略的名称<code>city_boundaries</code> ，缺失的信息被封装在该策略定义中。</p>{
  "geo_match": {
    "indices": "airport_city_boundaries",
    "match_field": "city_boundary",
    "enrich_fields": ["city", "airport", "region", "city_boundary"]
  }
}
<p>在这里我们可以看到，它将执行<code>geo_match</code> 查询（<code>intersects</code> 是默认值），要匹配的字段是<code>city_boundary</code> ，而<code>enrich_fields</code> 是我们要添加到原始文档中的字段。其中一个字段<code>region</code> 实际上被用作<code>STATS</code> 命令的分组键，如果没有这种 "左连接 "功能，我们是做不到这一点的。有关 enrich 策略的更多信息，请参阅<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/enrich-setup.html">enrich 文档</a>。在阅读这些文档时，你会注意到它们描述了如何通过配置摄取管道，在索引时使用丰富索引来丰富数据。ES|QL 不需要这样做，因为<code>ENRICH</code> 命令在查询时起作用。只需用必要的数据和丰富策略准备丰富索引，然后在 ES|QL 查询中使用<code>ENRICH</code> 命令即可。</p><p>您可能还会注意到，最常见的地区是<code>null</code> 。这意味着什么？回想一下，我曾将此命令比作 SQL 中的 "左连接"，也就是说，如果没有为某个机场找到匹配的城市边界，则仍会返回该机场，但<code>airport_city_boundaries</code> 索引中的字段值为<code>null</code> 。结果发现，有 89 个机场没有找到匹配的<code>city_boundary</code> ，有一个机场找到了匹配的<code>region</code> 字段，但该字段是<code>null</code> 。这样就统计出了 90 个机场，结果中没有<code>region</code> 。另一个有趣的细节是<code>MV_EXPAND</code> 命令的必要性。这样做是必要的，因为<code>ENRICH</code> 命令可能会为每个输入行返回多个结果，而<code>MV_EXPAND</code> 则有助于将这些结果分成多行，每个结果一行。这也解释了为什么"Hawaii" 会显示不同的<code>min_wkt</code> 和<code>max_wkt</code> 结果：存在多个名称相同但边界不同的区域。</p><h2>Kibana 地图</h2><p>Kibana 在地图应用程序中添加了对空间 ES|QL 的支持。这意味着您现在可以使用 ES|QL 在 Elasticsearch 中搜索地理空间数据，并在地图上将结果可视化。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91922eb4ef43d290/6a16f7161949f737bfe7a7b5/bd78470bd8a4bc60f0db7006bd804b8fe87e2fea-1440x683.png" alt="Kibana 层 ES|QL" /><p>在添加图层菜单中有一个新的图层选项，名为"ES|QL" 。与迄今为止介绍的所有地理空间功能一样，该功能在"技术预览版" 中。选择该选项可根据 ES|QL 查询结果在地图上添加图层。例如，您可以在地图上添加一个图层，显示世界上所有的机场。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5185ef7461d7e81d/6a16f718839dfa1559dcfcb1/1dd28d3d0509f92d26b0bb5320a2925f7a54c5d9-1440x736.png" alt="Kibana ES|QL - 机场" /><p>或者您也可以添加一个图层，显示<code>airport_city_boundaries</code> 索引中的多边形，或者更好的办法是使用上面那个复杂的<code>ENRICH</code> 查询，生成每个地区有多少个机场的统计数据？</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt51ee3543bb811d98/6a16f71a8b73cbbe63189df1/679a0a401faa613c7cedddd07c64f614ac2b7144-1440x727.png" alt="Kibana ES|QL - 区域统计" /><h2>后续工作计划</h2><p>你可能已经注意到，在上面的两个例子中，我们又加入了一个空间函数<code>ST_CENTROID_AGG</code> 。这是<code>STATS</code> 命令中使用的聚合函数，也是我们计划添加到 ES|QL 中的众多空间分析功能中的第一个。当我们有更多展示时，我们会在博客上介绍！</p><p>在此之前，我们想向您详细介绍我们正在开发的一项特别令人兴奋的功能：执行空间距离搜索的能力，这是 Elasticsearch 最常用的空间搜索功能之一。你能想象距离搜索的语法会是什么样子吗？或许类似于 OGC 功能？敬请关注本系列的下一篇博客，一探究竟！</p><p>剧透警告：Elasticsearch 8.15 刚刚发布，其中包含使用 ES|QL 的空间距离搜索！</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/esql-geospatial-search-part-one</guid>
    <category><![CDATA[Python]]></category>
    <category><![CDATA[ES|QL]]></category>
    <dc:creator><![CDATA[Craig Taverner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd05627be20e89dfb/6a17d7c6414c640256944fdb/de886289dcb56494920875303b622b030b9b810f-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 12 Aug 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>