Elasticsearch:使用 ES|QL 进行地理空间距离搜索

作者:来自 Elastic Craig Taverner

在 Elasticsearch 查询语言(ES|QL)中探索地理空间距离搜索,这是 Elasticsearch 地理空间搜索中最受欢迎和最有用的功能之一,也是 ES|QL 中的重要特性。

想获得 Elastic 认证吗?了解下一次 Elasticsearch 工程师培训的时间!

Elasticsearch 提供了大量新功能,帮助你根据自己的使用场景构建最佳搜索解决方案。浏览我们的示例笔记本以了解更多信息,开始免费的云试用,或立即在本地机器上体验 Elastic。


去年,我们介绍了如何使用 ES|QL 执行地理空间搜索,并在后续博客中展示了如何将地理空间数据摄取到 ES|QL 中使用。虽然这些博客介绍了 ES|QL 中强大的地理空间搜索功能,但它们并未涵盖其中最受欢迎的功能之一 —— 在 Elasticsearch 8.15 中引入的距离搜索。

与我们为 ES|QL 添加的所有地理空间功能一样,这个功能也是为了严格遵循 OGC( Open Geospatial Consortium - 开放地理空间联盟)的 Simple Feature Access 标准设计的,该标准也被 PostGIS 等其他空间数据库使用,对于熟悉这些标准的 GIS 专家来说,这项功能更易于使用。

在这篇博客中,我们将向你展示如何使用 ES|QL 执行地理空间距离搜索,并与 SQL 和 Query DSL 的等效方式进行对比。

搜索地理空间数据

让我们回顾一下上一篇博客中使用的主要搜索函数 —— ST_INTERSECTS 函数。假设你有一个丹麦兴趣点(POI)数据集,比如通过 Geofabrik 下载的 OpenStreetMap 丹麦数据,并且已经将其导入到 Elasticsearch 中(例如,使用 Kibana 地图导入 ESRI ShapeFile 的功能),你可以使用 ES|QL 在特定区域内搜索兴趣点,例如哥本哈根市内的兴趣点:

FROM denmark_pois
| WHERE name IS NOT NULL
| WHERE ST_INTERSECTS(geometry,TO_GEOSHAPE("POLYGON ((12.444077 55.606669, 12.681656 55.608996, 12.639084 55.720149, 12.593765 55.762282, 12.459869 55.747985, 12.417984 55.654735, 12.444077 55.606669))"))
| LIMIT 10000

这将搜索所有位于我们用于描绘哥本哈根市的简单多边形内的点状几何图形。

但该查询由于使用了较大的多边形表达式,看起来并不优雅。我们更可能想要查询的是某个中心点一定距离内的所有点,例如我们当前在哥本哈根中央火车站的位置:

FROM denmark_pois
| WHERE name IS NOT NULL
| WHERE ST_DISTANCE(geometry,TO_GEOPOINT("POINT (12.564926 55.672938)")) < 10000
| LIMIT 10000

这个更简单的查询请求获取位于纬度 55.672938 和经度 12.564926(中央车站内)这个点 10,000 米(10 公里)范围内的所有点。

现在,将这个查询与 Elasticsearch Query DSL 中的等效查询进行对比:

POST denmark_pois/_search
{"size": 10000,"query": {"geo_distance": {"distance": "10km","geometry": {"lat": 55.672938,"lon": 12.564926}}}
}

两个查询在意图上都相当清晰。不过请注意,ES|QL 查询与 SQL 非常相似。相同的查询在 PostGIS 中看起来像这样:

SELECT *
FROM denmark_pois
WHERE ST_Distance(geometry::geography,ST_SetSRID(ST_MakePoint(12.564926, 55.672938), 4326)::geography
) < 10000
LIMIT 10000;

回到 ES|QL 的例子,是不是很相似?实际上,ES|QL 查询甚至比 PostGIS 查询更简单,因为它不需要使用 ST_SetSRID 函数为点几何设置坐标参考系(CRS),也不需要使用 ::geography 类型转换来确保在球面坐标系统上进行距离计算。这是因为 ES|QL 的 TO_GEOPOINT 函数使用的是 geo_point 类型,而该类型始终处于 WGS84 坐标参考系中,并确保所有距离计算都基于球面坐标系统。

距离计算方式

这就引出了一个重要问题:距离是如何计算的?如前所述,ES|QL 的 geo_point 类型始终使用 WGS84 坐标参考系,它是一个球面坐标系统。实际的距离计算使用的是 Haversine 公式,该公式用于根据两个点的纬度和经度计算它们在球面上的距离。这个计算方式适用于 ES|QL 的 ST_DISTANCE 函数以及 Query DSL 的 geo_distance 查询。

这又引出另一个重要点:由于 ES|QL 与 Query DSL 兼容,甚至可以复用底层的 Lucene 空间索引,因此其距离计算也受到 Lucene 空间索引所定义的精度限制。Lucene 使用量化函数将 64 位浮点数转换为 32 位整数,这意味着 Elasticsearch 中的所有空间函数(包括 ES|QL 中的)都受限于这种量级约为 1 厘米 的精度。你可以在这篇博客中了解更多:《Elasticsearch 中基于 BKD 的 geo_shapes:精度 + 效率 + 速度》

ST_DISTANCE 的其他用法

我们可以在许多其他场景中使用 ST_DISTANCE 函数,包括当结果不用于地图显示时:

FROM denmark_pois
| WHERE name IS NOT NULL
| WHERE ST_DISTANCE(geometry, TO_GEOPOINT("POINT (12.564926 55.672938)")) < 10000
| STATS count=COUNT() BY fclass
| SORT count DESC
| LIMIT 16

按类别统计 “兴趣点(points of interest)” 数量的表格结果,按最常见类别排序:

     count     |    fclass
---------------+---------------
1528           |fast_food
930            |cafe
842            |restaurant
492            |clothes
490            |bar
457            |hairdresser
368            |artwork
364            |supermarket
326            |convenience
258            |bakery
255            |bicycle_shop
184            |kiosk
135            |beverages
133            |jeweller
120            |butcher
113            |pub

接下来我们可能想关注咖啡馆,找出离中央车站最近的几个:

FROM denmark_pois
| WHERE name IS NOT NULL AND fclass == "cafe"
| EVAL distance = ST_DISTANCE(geometry, TO_GEOPOINT("POINT (12.564926 55.672938)"))
| WHERE distance < 2000
| SORT distance ASC
| LIMIT 100

这个查询不仅过滤结果,只包含咖啡馆,还计算并返回距离,最近的咖啡馆排在最前面。我们甚至可以用报告的距离在 Kibana 地图上进行颜色标注:

为什么不用 SQL?

Elasticsearch SQL 已经存在一段时间,并且具备一些地理空间功能。但是,Elasticsearch SQL 是作为原始 Query API 之上的一个封装写的,这意味着它只支持可以转换成原始 API 的查询。ES|QL 没有这个限制。作为一个全新的架构,ES|QL 允许许多 SQL 无法实现的优化。它甚至支持 Query API 不支持的功能,比如 EVAL 命令,可以评估表达式并返回结果。我们的基准测试显示,ES|QL 在很多情况下比 Query API 更快,尤其是在聚合操作中!

显然,从之前的例子看,ES|QL 和 SQL 很相似,但有一些重要区别,我们在之前关于 ES|QL 地理空间搜索的博客中做了更详细的讨论。

ST_DISTANCE 性能

一个明显的问题是 ST_DISTANCE 函数的性能如何?乍一看,似乎会很慢,因为它需要对索引中的每个点计算距离。但事实并非如此。ST_DISTANCE 函数经过优化,使用了与 Query DSL 中 geo_distance 查询相同的空间索引。实际上,即使是 SORT distance ASC 命令也经过优化,使用相同的空间索引,因此执行非常快。

去年我们首次实现 ST_DISTANCE 函数时,在基准测试数据集上运行大约需要 30 秒。随后我们进行了名为 “Lucene Pushdown” 的优化,确保在可能的情况下,查询能最大限度地利用底层的 Lucene 索引。经过该优化后,同样的查询只需要 50 毫秒。

这些优化是如何实现的呢?一般来说,对于像 ES|QL 这样的声明式查询语言,查询引擎能够分析查询内容,并确定最优的执行方式。像 ST_DISTANCE 这样的函数是否能被优化,取决于查询结构和底层数据。

举个例子,考虑下面的查询:

FROM airports
| EVAL distance = ST_DISTANCE(location, TO_GEOPOINT("POINT(12.565 55.673)"))
| WHERE distance < 1000000 AND scalerank < 6 AND distance > 10000
| SORT distance ASC
| KEEP distance, abbrev, name, location, country, city

这条查询从哥本哈根中央车站计算到所有机场的距离,筛选出重要机场(scalerank 小于 6),并且距离在 10 公里到 1000 公里之间(排除了哥本哈根机场本身),最后按距离排序。这是相当繁重的工作,如何加速呢?

查询引擎内置一系列优化规则,通过反复应用这些规则,将查询转换成语义等价但执行更快的形式。

在这个例子中,主要做了以下优化:

  • 自动添加了 LIMIT 1000(如果你没有自己加,ES|QL 会自动加)。

  • SORTLIMIT 合并成一个 Lucene 特别支持的 TOPN 操作。

  • WHERE 条件拆成两部分:

    1. 先按 scalerank 过滤,这是一个已建立索引的字段,方便用 “Lucene Pushdown” 做优化。

    2. 对剩余文档计算距离,然后根据距离上下限过滤,这一步也可能进一步优化。

  • 推送尽可能多的过滤条件到 Lucene 底层:

    • scalerank 过滤直接推到 Lucene。

    • 把距离过滤转换成两个空间过滤:

      • ST_INTERSECTS(location, TO_GEOSHAPE("CIRCLE(12.565 55.673, 1000000)"))(距离上限)

      • ST_DISJOINT(location, TO_GEOSHAPE("CIRCLE(12.565 55.673, 10000)"))(距离下限)

    • 这些空间过滤利用 Lucene 的空间索引快速筛掉不匹配的文档。

    • TOPN 操作推给 Lucene,Lucene 原生支持 GeoDistanceSort

这大幅减少了需要计算距离的文档数量,极大减轻了 ES|QL 计算引擎负担。剩下的处理步骤是:

  • 从过滤后文档提取位置字段。

  • 计算每个文档的距离(因为查询仍需返回距离值)。

  • 提取 KEEP 命令要求的其他字段。

  • 各数据节点将数据返回给协调节点。

  • 协调节点对合并结果做最终的距离排序。

正如前面提到的,这种优化使查询性能大幅提升。在 6000 万条数据的基准测试中,经过优化的查询只需约 50 毫秒,而未优化时需要 30 秒。

OGC 函数

正如上一篇博客中所述,Elasticsearch 8.14 引入了四个 OGC 空间搜索函数。随着 8.15 版本中 ST_DISTANCE 的加入,我们现在拥有了一套完整的 OGC 函数,这些函数被视为 ES|QL 中核心的“空间搜索”函数:

  • ST_INTERSECTS:如果两个几何体相交,返回 true,否则返回 false。与 PostGIS 中的 ST_Intersects 相对应。

  • ST_DISJOINT:如果两个几何体不相交,返回 true,否则返回 false。是 ST_INTERSECTS 的反义。与 PostGIS 中的 ST_Disjoint 相对应。

  • ST_CONTAINS:如果一个几何体包含另一个几何体,返回 true,否则返回 false。与 PostGIS 中的 ST_Contains 相对应。

  • ST_WITHIN:如果一个几何体位于另一个几何体内部,返回 true,否则返回 false。是 ST_CONTAINS 的反义。与 PostGIS 中的 ST_Within 相对应。

  • ST_DISTANCE:返回两个几何体之间的距离。如果字段类型是 geo_point,距离计算使用球面计算方法,与现有的 Elasticsearch geo_distance 查询相同。与 PostGIS 中的 ST_Distance 相对应。

所有这些函数的行为与其 PostGIS 对应函数相似,使用方式也相同。如果你查看上文中的文档链接,会发现所有 ES|QL 的示例都写在 FROM 之后的 WHERE 子句中,而 PostGIS 示例则使用具体的几何字面量。实际上,这两个平台都支持在查询中任何语义合理的部分使用这些函数。

限制

PostGIS 文档中 ST_DISTANCE 的第一个示例是:

SELECT ST_Distance('SRID=4326;POINT(-72.1235 42.3521)'::geometry,'SRID=4326;LINESTRING(-72.1260 42.45, -72.123 42.1546)'::geometry );

这个在 ES|QL 中的等价写法是:

ROW ST_DISTANCE("POINT(-72.1235 42.3521)"::geo_point,"LINESTRING(-72.1260 42.45, -72.123 42.1546)"::geo_shape
)

不过,目前 ES|QL 还不支持 geo_shape。现在只能计算两个 geo_point 几何体之间,或者两个 cartesian_point 几何体之间的距离。

接下来

自从加入 ST_DISTANCE 之后,我们新增了两个聚合函数:

  • ST_CENTROID_AGG(8.15 版本新增)

  • ST_EXTENT_AGG(8.18 版本新增)

这两个函数用于 STATS 命令的聚合,是我们计划在 ES|QL 中添加的众多空间分析功能中的前两个。我们有更多内容时会发布博客进行介绍!

原文:Geospatial distance search with ES|QL - Elasticsearch Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86995.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

列举开源的模型和推理框架

当然可以&#xff01;下面是一个系统性的列表&#xff0c;按 开源大模型&#xff08;LLM&#xff09; 和 推理框架 两大类列出&#xff0c;并配上简要说明。 &#x1f9e0; 一、开源大语言模型&#xff08;LLMs&#xff09; 名称发布者语言能力模型大小特点LLaMA 2 / 3Meta英文…

深入讲解一下 Nomic AI 的 GPT4All 这个项目

我们来深入讲解一下 Nomic AI 的 GPT4All 这个项目。 这是一个非常优秀和流行的开源项目&#xff0c;我会从**“它是什么”、“为什么它很重要”、“项目架构和源码结构”以及“如何使用”**这几个方面为你全面剖析。 一、项目概述 (Project Overview) 简单来说&#xff0c;…

力扣HOT100之技巧:287. 寻找重复数

这道题真的是中等题吗&#xff1f;我请问呢&#xff1f;&#xff1f;我怎么觉得是困难题呢&#xff1f; 这道题的思路太难想了&#xff0c;想不出来&#xff0c;直接去看的这位大佬的题解&#xff0c;写得很清楚。 这道题可以将其转化为环形链表问题&#xff0c;可是为什么只要…

QT log4qt 无法生成日志到中文的路径中的解决方案

一.使用log4qt时,应用程序安装在带有中文路径下,导致无法生成日志到安装目录中? 问题描述:如下的配置文件,log4j.appender.File.File 后面跟随的路径是当前路径,你可能觉得自己的日志能够生成在当前路径中,如果你试着用自己的程序双击启动一个文件时,你会发现日志生成在…

让 Deepseek 写电器电费计算器小程序

微信小程序版电费计算器 以下是一个去掉"电器名称"后的微信小程序电费计算器代码&#xff0c;包含所有必要文件&#xff1a; 1. app.json (全局配置) {"pages": ["pages/index/index"],"window": {"backgroundColor": &q…

第二部分-静态路由实验

目录 一、什么是路由&#xff1f; 1.1.定义 1.2.路由作用 1.3.路由类型 1.3.1.直连路由 1.3.2.静态路由 1.3.3.动态路由 1.3.4.路由表 1.5.路由器的匹配原则 1.6.路由配置 1.6.1.静态路由配置 1.6.2.动态路由配置 二、实验 2.1.静态路由 2.1.1.实验拓扑 2.1.2.实验过程 2.2.缺省…

Could not initialize Logback logging from classpath:logback-spring.xml

jdk21、springboot 3.2.12启动报错找不到logback.xml Logging system failed to initialize using configuration from classpath:logback-spring.xml java.lang.IllegalStateException: Could not initialize Logback logging from classpath:logback-spring.xmlat org.sprin…

NORA:一个用于具身任务的小型开源通才视觉-语言-动作模型

25年4月来自新加坡技术和设计大学的论文“NORA: a Small Open-Sourced Generalist Vision Language Action Model for Embodied Tasks”。 现有的视觉-语言-动作 (VLA) 模型在零样本场景中展现出优异的性能&#xff0c;展现出令人印象深刻的任务执行和推理能力。然而&#xff…

在Ubuntu中使用Apache2部署项目

1. 安装Apache2 sudo apt update sudo apt install apache2 -y安装完成后&#xff0c;Apache会自动启动&#xff0c;通过浏览器访问 http://服务器IP 应看到默认的Apache欢迎页。 2. 配置防火墙&#xff08;UFW&#xff09; sudo ufw allow Apache # 允许Apache通过防火墙 …

【QT系统相关】QT文件

目录 1. Qt 文件概述 2. 输入输出设备类 3 文件读写类 读取文件内容 写文件 实现一个简单的记事本 4. 文件和目录信息类 QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 1. Qt 文件概述 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨…

爱普生RX8111CE实时时钟模块在汽车防盗系统中的应用

在汽车智能化与电子化的发展浪潮中&#xff0c;汽车防盗系统是现代汽车安全的重要组成部分&#xff0c;其核心功能是通过监测车辆状态并及时发出警报来防止车辆被盗或被非法操作。爱普生RX8111CE实时时钟模块凭借其高精度、低功耗和丰富的功能&#xff0c;能够为汽车防盗系统提…

SQL注入攻击原理与防御全解析

目录 一、引言 二、SQL 注入原理 2.1 SQL 注入的概念 2.2 SQL 注入产生的原因 2.3 SQL 注入的本质 2.4 SQL 注入的关键点 三、SQL 注入的实现方法 3.1 常见的 SQL 注入场景 3.2 不同类型的 SQL 注入方式 3.3 SQL 注入的一般流程 四、SQL 注入的危害 4.1 数据泄露 …

写实交互数字人:赋能消防知识科普,点亮智能交互讲解新未来

在数字化浪潮席卷全球的今日&#xff0c;科技创新以前所未有的速度重塑着我们的生活方式与产业格局。消防知识科普&#xff0c;作为守护生命财产安全的关键防线&#xff0c;也亟待借力新兴技术实现变革与突破。深声科技以其行业领先的 2D 写实交互数字人技术&#xff0c;为消防…

用 HTML、CSS 和 JavaScript 实现五子棋人机对战游戏

引言 在 Web 开发的世界里&#xff0c;通过 HTML、CSS 和 JavaScript 可以创造出各种各样有趣的互动游戏。今天&#xff0c;我们将深入探讨如何实现一个简单而又富有挑战性的五子棋人机对战游戏。这个游戏不仅能让你重温经典的五子棋玩法&#xff0c;还能通过 AI 对战功能给你…

【QT】自动更新库QSimpleUpdater使用实例封装

【QT】自动更新库QSimpleUpdater使用实例封装 QSimpleUpdater 库信号介绍appcastDownloaded 信号downloadFinished信号概括 参数介绍 实例编写 QSimpleUpdater 库 QSimpleUpdater是一个用于QT的开源自动更新库&#xff0c;它可以帮助开发者实现应用程序的版本检查和自动更新功…

Nginx、CDN、 DNS的关系解析

文章目录 Nginx 与 CDN 的关系1. 角色定位2. 协作方式3. 自建 CDN vs. 第三方 CDN Nginx 与 DNS 的关系1. 角色定位2. 协作方式3. 性能优化 CDN 与 DNS 的关系1. 角色定位2. 协作方式3. 高级 DNS 技术 三者结合的典型架构总结 Nginx、CDN 和 DNS 是现代网络架构中的三个关键组件…

PH热榜 | 2025-06-13

1. Flowstep 标语&#xff1a;借助人工智能&#xff0c;瞬间设计出美观的用户界面。 介绍&#xff1a;Flowstep 是您的 AI 设计助手&#xff0c;将简单的文字提示转化为用户界面设计、线框图和流程图。它能加速您的工作流程&#xff0c;让您轻松迭代&#xff0c;内置建议帮助…

Spectacular AI Gemini2 跑通实时建图

参考链接&#xff1a;Spectacular AI 硬件设备 gemini2 测试了gemini335没成功 修改record.cpp 仓库链接&#xff1a;sdk 读取Timu_cam ros2 run tf2_ros tf2_echo imu坐标系&#xff08;加速度计和陀螺仪都可以&#xff0c;两者变换为单位阵&#xff09;camera_rgb_optic…

简析MDM在餐饮设备中的部署与应用

引言&#xff1a;科技驱动餐饮运营升级 在竞争激烈的餐饮行业&#xff0c;科技已成为提升服务质量和运营效率的关键。从自助点餐机、数字菜单牌&#xff0c;到移动收银系统&#xff0c;智能设备已经深入餐厅的日常运营。然而&#xff0c;随着设备数量和种类的增加&#xff0c;…

RocketMQ总结

深入理解RocketMQ三高架构设计 高性能 顺序写磁盘 mmap 零拷贝异步刷盘 刷盘策略可配置轻量网络协议 长连接复用 高可用 主从复制机制、controller、dledger集群NameServer 多副本无状态客户端自动切换 Broker消息刷盘机制保障可靠性 高可扩展性 Broker 水平扩展Consu…