TDengine 地理信息使用说明

TDengine 地理信息使用说明

概述

TDengine 从 3.x 版本开始支持地理信息(GIS)功能,提供了一系列 ST_ 开头的地理信息函数,这些函数基于 GEOS 库实现,支持 WKT(Well-Known Text)格式的地理数据处理。

同时 TDengine 也支持地理信息数据类型,这里一起举例说明下如何使用?

重要说明

数据写入和查询的自动转换

  • 写入数据时 :可直接使用 WKT 字符串,无需调用 ST_GeomFromText 函数
  • 查询数据时 :返回结果自动为 WKT 格式,无需调用 ST_AsText 函数

TDengine 会自动处理 WKT 字符串与内部 GEOMETRY 类型之间的转换。

函数使用限制

⚠️ 重要限制:

  1. WHERE 子句限制:TDengine 目前不支持在 WHERE 子句中使用地理函数进行过滤
  2. 参数类型限制 :向地理函数传递 WKT 参数时,必须使用 ST_GeomFromText() 函数将文本转换为 GEOMETRY 类型

基本用法示例

1. 创建表与插入数据

sql 复制代码
-- 创建包含地理信息列的表
CREATE TABLE geo_points (
  ts TIMESTAMP,
  name VARCHAR(64),
  geom GEOMETRY(256)
);

-- 直接使用 WKT 字符串插入数据(无需 ST_GeomFromText)
INSERT INTO geo_points VALUES
  (NOW, 'tiananmen', 'POINT(116.397 39.908)'),
  (NOW, 'airport',   'POINT(116.407 40.080)');

-- 插入线串
INSERT INTO geo_points VALUES
  (NOW, 'road', 'LINESTRING(116.397 39.908, 116.407 40.080)');

-- 插入多边形
INSERT INTO geo_points VALUES
  (NOW, 'area', 'POLYGON((116.3 39.9, 116.4 39.9, 116.4 40.0, 116.3 40.0, 116.3 39.9))');

2. 查询数据

sql 复制代码
-- 查询所有数据(自动以 WKT 格式返回,无需 ST_AsText)
SELECT * FROM geo_points;

输出示例:

复制代码
       ts       |              name              |              geom              |
===================================================================================
 1765100256637 | tiananmen                      | POINT (116.397000 39.908000)   |
 1765100256640 | airport                        | POINT (116.407000 40.080000)   |
 1765100256650 | road                           | LINESTRING (116.397 39.908, 116.407 40.08) |
 1765100256660 | area                           | POLYGON ((116.3 39.9, 116.4 39.9, ...))     |

地理关系判断函数

ST_Intersects - 相交判断

判断两个几何对象是否相交(有任何共享点)。

sql 复制代码
-- 在 SELECT 中使用(注意:必须用 ST_GeomFromText 转换文本参数)
SELECT 
  name, 
  geom,
  ST_Intersects(
    geom, 
    ST_GeomFromText('POLYGON((116.3 39.8, 116.5 39.8, 116.5 40.1, 116.3 40.1, 116.3 39.8))')
  ) AS is_intersect
FROM geo_points;

-- 判断两个几何对象是否相交
SELECT ST_Intersects(
  ST_GeomFromText('LINESTRING(0 0, 1 1)'),
  ST_GeomFromText('LINESTRING(0 1, 1 0)')
) AS is_intersect;
-- 返回: true

⚠️ 注意: 不能在 WHERE 子句中使用,以下语法不支持:

sql 复制代码
-- ❌ 错误用法:WHERE 中不支持函数
SELECT name FROM geo_points 
WHERE ST_Intersects(geom, ST_GeomFromText('POLYGON(...)'));

ST_Contains - 包含判断

判断几何对象 A 是否完全包含几何对象 B。

sql 复制代码
-- 在 SELECT 中判断区域是否包含点
SELECT 
  name,
  geom,
  ST_Contains(
    ST_GeomFromText('POLYGON((116.3 39.8, 116.5 39.8, 116.5 40.1, 116.3 40.1, 116.3 39.8))'),
    geom
  ) AS is_contained
FROM geo_points;

-- 判断多边形是否包含点
SELECT ST_Contains(
  ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
  ST_GeomFromText('POINT(5 5)')
) AS is_contained;
-- 返回: true

ST_ContainsProperly - 严格包含判断

判断 B 的每个点是否都位于 A 的内部(不包括边界)。

sql 复制代码
-- 边界上的点不算严格包含
SELECT ST_ContainsProperly(
  ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
  ST_GeomFromText('POINT(0 0)')
) AS is_contained_properly;
-- 返回: false(因为点在边界上)

SELECT ST_ContainsProperly(
  ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
  ST_GeomFromText('POINT(5 5)')
) AS is_contained_properly;
-- 返回: true(因为点在内部)

ST_Covers - 覆盖判断

判断 B 中的每个点是否都位于 A 内部或边界上。

sql 复制代码
-- 与 Contains 类似,但包括边界情况
SELECT ST_Covers(
  ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
  ST_GeomFromText('POINT(0 0)')
) AS is_covered;
-- 返回: true(边界点也算覆盖)

ST_Equals - 空间相等判断

判断两个几何对象是否在空间上相等。

sql 复制代码
-- 点的顺序不同,但表示相同的多边形
SELECT ST_Equals(
  ST_GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'),
  ST_GeomFromText('POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
) AS is_equal;
-- 返回: true

-- 相同的点
SELECT ST_Equals(
  ST_GeomFromText('POINT(1 1)'),
  ST_GeomFromText('POINT(1 1)')
) AS is_equal;
-- 返回: true

ST_Touches - 接触判断

判断两个几何对象是否相接触(相交但内部不相交)。

sql 复制代码
-- 两个多边形共享边界
SELECT ST_Touches(
  ST_GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))'),
  ST_GeomFromText('POLYGON((1 0, 2 0, 2 1, 1 1, 1 0))')
) AS is_touching;
-- 返回: true

-- 点/点不会触碰(点没有边界)
SELECT ST_Touches(
  ST_GeomFromText('POINT(0 0)'),
  ST_GeomFromText('POINT(0 0)')
) AS is_touching;
-- 返回: false

实际应用场景

场景 1:查找附近的地点

sql 复制代码
-- 创建兴趣点表
CREATE TABLE poi (
  ts TIMESTAMP,
  name VARCHAR(100),
  category VARCHAR(50),
  location GEOMETRY(256)
);

-- 插入数据
INSERT INTO poi VALUES
  (NOW, '北京天安门', '景点', 'POINT(116.397 39.908)'),
  (NOW, '故宫博物院', '景点', 'POINT(116.397 39.918)'),
  (NOW, '王府井', '商圈', 'POINT(116.410 39.915)'),
  (NOW, '首都机场', '交通', 'POINT(116.407 40.080)');

-- 查找矩形区域内的所有景点(在 SELECT 中返回判断结果)
SELECT 
  name, 
  location,
  ST_Intersects(
    location,
    ST_GeomFromText('POLYGON((116.38 39.90, 116.42 39.90, 116.42 39.93, 116.38 39.93, 116.38 39.90))')
  ) AS in_area
FROM poi 
WHERE category = '景点';

-- 应用层需要根据 in_area 字段过滤结果

场景 2:区域覆盖分析

sql 复制代码
-- 创建服务区域表
CREATE TABLE service_area (
  ts TIMESTAMP,
  store_name VARCHAR(100),
  coverage GEOMETRY(512)
);

-- 插入服务范围(圆形区域可用多边形近似)
INSERT INTO service_area VALUES
  (NOW, '门店A', 'POLYGON((116.3 39.9, 116.35 39.88, 116.4 39.9, 116.35 39.92, 116.3 39.9))');

-- 查找能覆盖指定地点的门店(在 SELECT 中计算)
SELECT 
  store_name,
  coverage,
  ST_Contains(
    coverage, 
    ST_GeomFromText('POINT(116.33 39.90)')
  ) AS can_serve
FROM service_area;

场景 3:批量地理计算

sql 复制代码
-- 创建设备位置表
CREATE TABLE device_location (
  ts TIMESTAMP,
  device_id VARCHAR(50),
  position GEOMETRY(128)
);

-- 创建围栏区域表
CREATE TABLE geofence (
  ts TIMESTAMP,
  fence_id INT,
  fence_name VARCHAR(100),
  boundary GEOMETRY(512)
);

-- 计算设备与围栏的关系(应用层过滤)
SELECT 
  d.device_id, 
  d.position, 
  g.fence_name,
  ST_Contains(g.boundary, d.position) AS inside_fence
FROM device_location d, geofence g
WHERE d.ts >= NOW - 1h;

转换函数说明

ST_GeomFromText - WKT 转 GEOMETRY(必需)

功能:将 WKT 文本转换为 GEOMETRY 类型

用途

  • 向地理函数传递常量 WKT 参数时必须使用
  • INSERT 语句中不需要使用(自动转换)
sql 复制代码
-- ✅ 正确:函数参数必须使用 ST_GeomFromText
SELECT ST_Contains(
  ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))'),
  geom
) FROM geo_points;

-- ❌ 错误:直接传递文本字符串
SELECT ST_Contains(
  'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))',
  geom
) FROM geo_points;

-- ✅ 正确:INSERT 时可以直接使用文本
INSERT INTO geo_points VALUES (NOW, 'test', 'POINT(1 1)');

ST_AsText - GEOMETRY 转 WKT(可选)

功能:将 GEOMETRY 类型转换为 WKT 文本

用途

  • SELECT 查询结果已自动转换为 WKT 格式,通常不需要显式调用
  • 某些特殊场景需要确保文本格式输出时使用
sql 复制代码
-- 通常不需要(自动转换)
SELECT geom FROM geo_points;

-- 显式转换(结果相同)
SELECT ST_AsText(geom) FROM geo_points;

支持的几何类型

TDengine 支持以下 WKT 几何类型:

  1. POINT - 点:'POINT(x y)'
  2. LINESTRING - 线串:'LINESTRING(x1 y1, x2 y2, ...)'
  3. POLYGON - 多边形:'POLYGON((x1 y1, x2 y2, ..., x1 y1))'
  4. MULTIPOINT - 多点:'MULTIPOINT((x1 y1), (x2 y2))'
  5. MULTILINESTRING - 多线串
  6. MULTIPOLYGON - 多多边形
  7. GEOMETRYCOLLECTION - 几何集合

使用建议与限制

当前限制

  1. WHERE 子句限制

    • ❌ 不支持在 WHERE 中使用地理函数
    • ✅ 只能在 SELECT 中计算,然后在应用层过滤结果
  2. 函数参数传递限制

    • ❌ 不能直接传递文本字符串给函数
    • ✅ 必须使用 ST_GeomFromText() 转换文本参数

变通方案

由于不支持 WHERE 过滤,建议的使用子查询模式:

sql 复制代码
SELECT * FROM 
      (
				SELECT 
				  *,
				  ST_Contains(boundary, position) AS match_result
				FROM your_table
			)
			WHERE match_result = 'true'

性能优化建议

  1. 使用常量优化:当查询中一个参数为常量时,TDengine 会自动创建 PreparedGeometry 以提升性能

    sql 复制代码
    -- 好的实践:常量作为第一个参数
    SELECT ST_Contains(
      ST_GeomFromText('POLYGON(...)'),  -- 常量
      location                           -- 变量
    ) FROM poi;
  2. 减少计算量:由于无法在 WHERE 中过滤,建议先用其他条件缩小数据集

    sql 复制代码
    -- 先用时间范围过滤,再计算地理关系
    SELECT 
      *,
      ST_Intersects(geom, ST_GeomFromText('POLYGON(...)')) AS in_area
    FROM geo_points
    WHERE ts >= NOW - 1d;  -- 先过滤时间
  3. 合理设置 GEOMETRY 列长度

    sql 复制代码
    -- 简单点位:GEOMETRY(128)
    -- 复杂多边形:GEOMETRY(512) 或更大

注意事项

  1. ✅ 地理信息函数需要 TDengine 编译时启用 GEOS 支持
  2. ✅ GEOMETRY 类型存储的是二进制格式,但输入输出自动转换为 WKT
  3. ✅ 空间关系判断返回 BOOL 类型(true/false),NULL 输入返回 NULL
  4. ✅ 坐标系统需要应用层统一管理(如统一使用 WGS84 经纬度)
  5. ⚠️ 不支持在 WHERE 子句中使用地理函数
  6. ⚠️ 向函数传递 WKT 参数时必须使用 ST_GeomFromText 转换

以上示例展示了 TDengine 地理信息函数的正确用法。关键要点:

  • INSERT 时:直接使用 WKT 字符串
  • 函数参数 :必须用 ST_GeomFromText() 转换
  • WHERE 过滤:不支持,需在应用层处理
  • SELECT 输出:自动转换为 WKT 格式
相关推荐
leijmdas1 小时前
git操作命令
大数据·git·elasticsearch
Light602 小时前
Spark OA 系统深度分析与改造报告(整合版 + 领码 SPARK 改造计划 + 功能缺口)
大数据·分布式·spark
RioLopez2 小时前
大数据HADOOP之部署HADOOP平台
大数据·hadoop·eclipse
青云交2 小时前
Java 大视界 -- Java 大数据机器学习模型在自然语言处理中的对话系统多轮交互优化与用户体验提升
java·大数据·机器学习·自然语言处理·对话系统·多轮交互
搜移IT科技2 小时前
加密货币市场的二元性 XBIT Wallet 硬件钱包风险缓解多元化策略
大数据·人工智能
Adellle2 小时前
windows安装ES(8.14.x版本)
大数据·windows·elasticsearch
摇滚侠2 小时前
ElasticSearch 是什么,ES 是什么?
大数据·elasticsearch·搜索引擎
摇滚侠2 小时前
ElasticSearch 教程入门到精通,条件分页排序查询,多条件范围查询,完全匹配高亮查询,聚合查询,映射关系,笔记13、14、15、16、17
大数据·笔记·elasticsearch
IT·小灰灰2 小时前
DeepSeek-V3.2:开源大模型的里程碑式突破与硅基流动平台实战指南
大数据·人工智能·python·深度学习·算法·数据挖掘·开源