多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

StarRocks ST_Distance_Sphere 函数详解:计算地球表面两点间球面距离

StarRocks ST_Distance_Sphere 函数详解:计算地球表面两点间球面距离 StarRocks ST_Distance_Sphere 函数详解计算地球表面两点间球面距离【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocksST_Distance_Sphere 是 StarRocks 提供的空间地理函数之一用于计算地球表面上两个经纬度坐标点之间的球面距离以米为单位是 LBS基于位置的服务、配送调度、出行导航、地理围栏等场景中做两点间距离筛选与排序的高频工具。读完本文你将掌握该函数的完整语法、参数约定、返回值语义、NULL 与非法坐标处理行为并能结合源码了解其在 StarRocks 前端FE注册与后端BE基于 S2 地理库的实现原理直接在真实表上完成近邻距离查询。函数概述ST_Distance_Sphere属于 StarRocks 空间函数Spatial Functions家族与st_point、st_x、st_y、st_astext、st_circle、st_contains、st_polygon等函数并列完整清单可见 docs/en/sql-reference/sql-functions/spatial-functions 目录。其核心职责是输入两组经纬度坐标输出两点在大地水准球面上的距离单位为米meters。从源码注册表看该函数在前端被显式声明为内置函数在 fe/fe-core/src/main/java/com/starrocks/catalog/FunctionSet.java 中public static final String ST_DISTANCE_SPHERE st_distance_sphere;与其余 Geo 函数一同注册说明它是一个经过正式声明、可被 SQL 解析与优化器处理的系统内置函数而非 UDF。语法与参数说明函数签名如下原始文档定义注意该签名的最后一个形参是y_lat即 Y 点的纬度DOUBLE ST_Distance_Sphere(DOUBLE x_lng, DOUBLE x_lat, DOUBLE y_lng, DOUBLE y_lat)参数类型含义x_lngDOUBLEX 点的经度Longitudex_latDOUBLEX 点的纬度Latitudey_lngDOUBLEY 点的经度Longitudey_latDOUBLEY 点的纬度Latitude返回值DOUBLE类型单位为米。几点使用约定经度范围合法经度在[-180, 180]区间内纬度范围合法纬度在[-90, 90]区间内。超出合法范围的坐标会被判定为无效输入。参数既可以是字面量常量也可以是表中列的值因此可以直接参与SELECT投影、WHERE过滤以及ORDER BY ... LIMIT的近邻排序查询。经纬度使用十进制角度degrees传入函数内部会将其转换为弧度/球面坐标进行计算。参数顺序是常见的踩坑点该函数接收的是经度在前、纬度在后的顺序lng, lat, lng, lat这与许多 GIS 工具中纬度、经度的书写习惯相反也与st_point等函数约定的 X/Y 语义保持一致在 StarRocks 的地理模型中x对应经度、y对应纬度。若将经纬度顺序写反函数不会报错但会计算出完全错误通常偏大的距离这是实际业务中最常见的问题来源。建议在调用前对输入数据做一次坐标顺序校验。使用示例1. 字面量常量调用原始文档给出的示例是在两个北京坐标点之间计算距离MySQL select st_distance_sphere(116.35620117, 39.939093, 116.4274406433, 39.9020987219); ---------------------------------------------------------------------------- | st_distance_sphere(116.35620117, 39.939093, 116.4274406433, 39.9020987219) | ---------------------------------------------------------------------------- | 7336.9135549995917 | ----------------------------------------------------------------------------结果7336.9135549995917表示这两个经纬度点之间的球面距离约为7336.91 米与实际地理常识相符北京城区内两点约 7.3 公里。2. 结合表列计算点对距离在实际业务中更常见的是基于表中存储的坐标列进行计算。例如有一张存储门店坐标的表stores(id, name, lng, lat)可以用如下方式计算每个门店与某个参考点如用户当前位置116.40, 39.90之间的距离SELECT name, ST_Distance_Sphere(116.40, 39.90, lng, lat) AS distance_m FROM stores ORDER BY distance_m ASC LIMIT 10;3. 结合 WHERE 过滤实现半径圈选筛选出距参考点 5 公里以内的所有记录SELECT id, name, ST_Distance_Sphere(116.40, 39.90, lng, lat) AS distance_m FROM stores WHERE ST_Distance_Sphere(116.40, 39.90, lng, lat) 5000;这类距离圈选 距离排序的组合正是该函数在 LBS 场景下的典型用法。返回值与异常处理行为结合后端实现源码 be/src/exprs/geo_functions.cpp可以确认以下运行时行为任一参数为 NULL 时该行结果返回 NULL。实现中先通过ColumnViewer读取四列值并对每一行依次检查x_lng/x_lat/y_lng/y_lat是否为 NULL只要有一个为 NULL 就append_null()见源码第 255-258 行。坐标非法时返回 NULL。底层GeoPoint::st_distance_sphere在校验坐标失败时返回false上层随即追加 NULL见源码第 266-269 行而不是抛错中止查询。同一坐标点两点重合时距离为 0这一点有单元测试佐证在 be/test/exprs/geography_functions_test.cpp 的st_distance_sphereTest中四参数全部传入0.0断言结果等于0。函数是向量化实现通过ColumnBuilder/ColumnViewer对整列数据逐行批量计算并利用ColumnHelper::is_all_const(columns)判断常量列以优化执行见源码第 252-274 行在大量坐标点参与计算时具备良好的列式执行性能。源码级原理基于 S2 地理库的球面距离计算该函数的真正计算逻辑位于 be/src/geo/geo_types.cpp仅 12 行核心代码全部依赖 Google S2 Geometry 库bool GeoPoint::st_distance_sphere(double x_lng, double x_lat, double y_lng, double y_lat, double* result) { S2LatLng x S2LatLng::FromDegrees(x_lat, x_lng); if (!x.is_valid()) { return false; } S2LatLng y S2LatLng::FromDegrees(y_lat, y_lng); if (!y.is_valid()) { return false; } *result S2Earth::ToMeters(x.GetDistance(y)); return true; }其计算链路可以拆解为三步构建球面坐标点S2LatLng::FromDegrees(lat, lng)将十进制的经纬度对转换为 S2 的球面经纬度表示。注意此处传参顺序是(纬度, 经度)与 SQL 层(经度, 纬度)的参数顺序刚好相反说明 SQL 层到地理内核层之间存在一次坐标顺序转换。合法性校验S2LatLng::is_valid()校验纬度是否在[-90, 90]、经度是否在[-180, 180]内任一坐标不合法则函数返回false上层将其折叠为 SQL 层面的 NULL。球面距离换算x.GetDistance(y)返回两点间沿球面的角距离弧度/角度再经S2Earth::ToMeters乘以地球平均半径换算为以米为单位的实际距离。这正是函数名中 Sphere 的含义——它基于球面模型而非更精确但更昂贵的椭球大地水准面模型计算精度满足绝大多数 LBS 业务需求。函数声明位于 be/src/geo/geo_types.h向量化入口GeoFunctions::st_distance_sphere在 be/src/exprs/geo_functions.h 中通过DEFINE_VECTORIZED_FN宏注册与 FE 侧 FunctionSet.java 的字符串名称一一对应构成一条完整的SQL 函数名 → 前端注册 → 后端向量化执行 → S2 地理计算的调用链。注意事项与适用边界球面模型近似函数采用球面模型计算距离未考虑地球椭球形状与海拔在跨洲际长距离场景下与高精度大地测量结果存在米级到百米级的误差城市级、区域级近邻计算完全适用。经纬度顺序牢记先经度、后纬度的入参顺序避免与常见 GIS 工具的先纬度、后经度约定混淆。NULL 语义任何 NULL 或越界坐标都会导致结果为 NULL业务上可用COALESCE/IFNULL处理或提前清洗脏数据。性能提示在WHERE中直接调用该函数做半径过滤时无法直接利用空间索引属于全表逐行计算数据量极大时建议配合分区裁剪或先按经纬度粗粒度矩形过滤再做精确球面距离校验。参考与延伸阅读函数官方定义文档docs/en/sql-reference/sql-functions/spatial-functions/st_distance_sphere.md同目录其他空间函数st_point、st_x、st_y、st_astext、st_circle、st_contains等见 spatial-functions 目录后端向量化实现be/src/exprs/geo_functions.cppS2 球面距离核心算法be/src/geo/geo_types.cpp单元测试be/test/exprs/geography_functions_test.cppFE 端函数注册fe/fe-core/src/main/java/com/starrocks/catalog/FunctionSet.java【免费下载链接】starrocksThe worlds fastest open query engine for sub-second analytics both on and off the data lakehouse. With the flexibility to support nearly any scenario, StarRocks provides best-in-class performance for multi-dimensional analytics, real-time analytics, and ad-hoc queries. A Linux Foundation project.项目地址: https://gitcode.com/GitHub_Trending/st/starrocks创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表