Apache Doris 地理查询实操:从建表到跑出第一条空间 SQL
【免费下载链接】dorisApache Doris is an easy-to-use, high performance and unified analytics database.项目地址: https://gitcode.com/gh_mirrors/dori/doris
本文覆盖 Apache Doris 地理查询相关功能:空间数据类型、常用空间函数、端到端查询写法与性能注意点。一个具体场景:连锁品牌要在全国门店和百万级 POI 里,圈出"3 公里内有竞对"的候选点。这个需求不用引入独立 GIS 引擎,一条带空间函数的 SQL 就能解决。
30 秒跑通第一条空间查询
CREATE TABLE demo_geo ( id BIGINT, name STRING, loc STRING ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1; INSERT INTO demo_geo VALUES (1, 'point_a', ST_Point(116.397, 39.916)); SELECT id, name, ST_Contains(ST_Polygon('POLYGON((116.3 39.9, 116.5 39.9, 116.5 40.0, 116.3 40.0, 116.3 39.9))'), loc) FROM demo_geo;你刚才完成了一轮完整的"写入几何 → 判定空间关系":ST_Point造出坐标点,ST_Polygon从 WKT 文本造出多边形,ST_Contains返回该点是否落在多边形里。
核心数据类型,各管什么用
Doris 的空间对象本质是存成 WKT 文本的字符串列(WKB 二进制可用ST_AsBinary/ST_GeometryFromWKB互转),几何解析与计算在 BE 的be/src/geo/目录实现,底层走 S2 球面几何:
| 类型 | 存什么 | 典型场景 | 例子 |
|---|---|---|---|
| Point | 单个经纬度坐标 | 门店、POI、用户定位 | 门店点位 |
| LineString | 有序坐标折线 | 路线、河流边界 | 配送路线 |
| Polygon | 闭合环形区域 | 行政区、配送围栏 | 配送围栏 |
| Circle | 圆心加半径的圆 | 周边辐射圈 | 3 公里圈 |
围栏这类文本型几何用ST_Polygon或ST_GeometryFromText从 WKT 构造;单个坐标点直接写ST_Point(经度, 纬度)即可。
高频函数拆解
算距离——"谁离我最近"类问题
距离类问题只认一个函数:ST_Distance_Sphere,返回球面距离,单位米。
SELECT ST_Distance_Sphere(116.397, 39.916, 121.473, 31.230) AS dist_m; -- 北京到上海,结果约 10700000 米最容易踩的坑:四个参数是 经度、纬度、经度、纬度,把经纬度写反会得到一个莫名其妙的"距离"。
判关系——"点落在哪个区域里"类问题
关系判断用ST_Contains(外, 内)返回 BOOLEAN,"点是否在多边形内"就写成多边形包含点。
SELECT ST_Contains( ST_Polygon('POLYGON((116.3 39.9, 116.5 39.9, 116.5 40.0, 116.3 40.0, 116.3 39.9))'), ST_Point(116.417, 39.917)) AS in_area;注意 Doris 目前只提供了ST_Contains这一个包含类谓词,没有独立的ST_Within;另外多边形外环必须首尾闭合。
量属性——"面积多大"类问题
面积类函数按单位分成两个:ST_Area_Square_Meters与ST_Area_Square_Km,按量级选单位。
SELECT ST_Area_Square_Km(ST_Polygon('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))')) AS area_km2;别拿"度"当面积单位直觉理解:输入是经纬度坐标,计算基于地球球面,不是平面方格。
一个完整的端到端案例:门店选址
场景:给一个新点位 (116.40, 39.92),找最近的存量门店,并筛出落在东三环某多边形内的门店。
CREATE TABLE stores ( id BIGINT, name STRING, lng DOUBLE, lat DOUBLE, city STRING ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 8; INSERT INTO stores VALUES (1, '王府井店', 116.417, 39.917, '北京'), (2, '西单店', 116.374, 39.913, '北京'), (3, '国贸店', 116.461, 39.909, '北京'), (4, '中关村店', 116.310, 39.984, '北京');第一条查询:按球面距离取最近门店,把经纬度列现场拼成几何再算。
SELECT name, ST_Distance_Sphere(lng, lat, 116.40, 39.92) AS dist_m FROM stores ORDER BY dist_m LIMIT 1;第二条查询:空间谓词直接进 WHERE,只保留围栏内的门店,ST_AsText输出 WKT 方便丢给下游 GIS 工具。
SELECT name, ST_AsText(ST_Point(lng, lat)) AS wkt FROM stores WHERE ST_Contains( ST_Polygon('POLYGON((116.39 39.90, 116.48 39.90, 116.48 39.93, 116.39 39.93, 116.39 39.90))'), ST_Point(lng, lat));优化对比:全国千万级门店表上,先收窄数据范围再算空间函数。
-- 先按城市等值过滤,再逐行算距离 SELECT name, ST_Distance_Sphere(lng, lat, 116.40, 39.92) AS dist_m FROM stores WHERE city = '北京' ORDER BY dist_m LIMIT 1;空间函数本身对 VARCHAR 逐行计算,省掉无谓的城市就是省掉一批逐行计算。
性能与常见坑
- Doris 目前没有专用的空间索引属性,建表时不存在
spatial_index这类配置,空间加速完全靠"先过滤后计算"。 - 遵循"先过滤后计算":把分区、桶键等值条件放前,空间函数谓词放后,缩小逐行计算的行数。
- 坐标系默认按 WGS84 理解,混入 GCJ-02 的坐标系数据会有几十到几百米偏差。
- 新手最常犯的错:参数顺序写反成"纬度、经度"。反例:
ST_Distance_Sphere(39.916, 116.397, 31.230, 121.473),北京、上海的位置直接互换,距离算出来就是错的。
下一步可以做什么
- 翻一翻
be/src/geo/geo_types.h里的 S2 球面几何实现,看距离和面积是怎么算的。 - 用
ST_AsBinary/ST_GeometryFromWKB走一轮 WKB 二进制互转,适合对接已有 GIS 数据管道。 - 把空间谓词放进 JOIN 之前,用分区裁剪和等值谓词先缩小数据集,再验证查询耗时差异。
【免费下载链接】dorisApache Doris is an easy-to-use, high performance and unified analytics database.项目地址: https://gitcode.com/gh_mirrors/dori/doris
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考