H3网格系统将地球表面划分为正六边形网格并分配唯一编号,多用于地理空间分析、路径规划等场景。如果您想要根据区域范围进行聚合查询,可以参考本文提供的方法,通过Lindorm Ganos时空服务基于SQL接口实现的H3网格聚合功能,完成基于H3网格的数据查询业务。
背景信息
随着车联网行业的发展,汽车管理业务受到了更加广泛的关注。同时,也存在根据区域范围进行聚合查询的需求。行业内常使用Uber开发的H3网格索引系统来实现这一需求,该系统采用正六边形网格结构对全球地理空间进行分层划分,确保每个经纬度坐标都能映射到一个独一无二的H3索引值,代表地球表面的一个具体六边形单元格。适用于在不同颗粒度上进行空间聚类、聚合操作的应用场景。
基于H3聚合,可以完成的使用场景包括:
大屏热力图展示:统计不同区域的车辆数,并以热力地图的形式在大屏上进行展示。
车辆调度:根据不同网格区域的车辆热力分布状况,为平衡运力调度提供依据。
动态定价:根据不同网格单元在不同时段内的车辆热力变化,实现早晚高峰高需求区域的动态定价。
H3网格有16个不同层级,不同层级的H3网格覆盖范围如下:
网格层级(精度) | 六边形网格平均面积(m2) | 五边形网格平均面积(m2) |
0 | 4,357,449,416,078.392 | 2,562,182,162,955.496 |
1 | 609,788,441,794.134 | 328,434,586,246.469 |
2 | 86,801,780,398.997 | 44,930,898,497.879 |
3 | 12,393,434,655.088 | 6,315,472,267.516 |
4 | 1,770,347,654.491 | 896,582,383.141 |
5 | 252,903,858.182 | 127,785,583.023 |
6 | 36,129,062.164 | 18,238,749.548 |
7 | 5,161,293.360 | 2,604,669.397 |
8 | 737,327.598 | 372,048.038 |
9 | 105,332.513 | 53,147.195 |
10 | 15,047.502 | 7,592.318 |
11 | 2,149.643 | 1,084.609 |
12 | 307.092 | 154.944 |
13 | 43.870 | 22.135 |
14 | 6.267 | 3.162 |
15 | 0.895 | 0.452 |
技术实现
宽表网格聚合是基于车辆上报的位置点信息,根据指定的精度计算并生成H3网格索引值,并将这些索引值存储在单独的列中。聚合操作将基于H3列和指定精度进行聚合计算,并输出计算结果。同时,可以使用H3_Contains
函数来判断网格之间的包含关系。
由于H3编码的局限性,部分处于边缘的网格可能会被遗漏。
Lindorm Ganos时空服务提供了一系列基于H3网格的时空函数,
H3_Contains
函数及其他函数的使用说明,请参见H3函数。
前提条件
已将客户端IP地址添加至Lindorm白名单。如何添加,请参见设置白名单。
已开通宽表引擎,且宽表引擎的版本为2.6.5及以上版本。如何查看和升级当前版本,请参见宽表引擎版本说明和升级小版本。
重要如果您的宽表引擎为2.6.5以下版本且无法进行升级,请联系Lindorm技术支持(钉钉号:s0s3eg3)为您升级版本。
已开通Lindorm Ganos时空服务。如何开通,请参见开通时空服务(免费)。
操作步骤
步骤一:创建数据表并写入数据
创建数据表
carData
。CREATE TABLE carData(cid INT, x DOUBLE, y DOUBLE, h3 LONG, PRIMARY KEY(cid));
创建二级索引。
CREATE INDEX h3_idx ON carData(h3);
写入数据。网格的层级可以参考背景信息章节中的表格。点坐标的网格一般选择13~14层级,此处以层级14为例。
UPSERT INTO carData(cid, x, y, h3) VALUES (1, 116.44043, 39.9219, h3(116.44043, 39.9219, 14)), (2, 116.43528, 39.9228, h3(116.43528, 39.9228, 14)), (3, 116.42842, 39.92335, h3(116.42842, 39.92335, 14)), (4, 116.41175, 39.92298, h3(116.41175, 39.92298, 14)), (5, 116.40473, 39.92287, h3(116.40473, 39.92287, 14)), (6, 116.40108, 39.91697, h3(116.40108, 39.91697, 14)), (7, 116.40025, 39.91668, h3(116.40025, 39.91668, 14)), (8, 116.39918, 39.91203, h3(116.39918, 39.91203, 14)), (9, 116.3971, 39.91373, h3(116.3971, 39.91373, 14)), (10, 116.38908, 39.80132, h3(116.38908, 39.80132, 14));
如果您对于经纬度坐标有H3网格聚合以外的计算需求(如地理围栏告警),建议将经纬度坐标存储为POINT类型。您可以参考以下示例代码建表并写入数据:
// 创建POINT类型的表
CREATE TABLE carPoint(cid INT, p GEOMETRY(POINT), h3 LONG, PRIMARY KEY(cid));
// 创建二级索引
CREATE INDEX h3_idx ON carPoint(h3);
// 插入网格数据
UPSERT INTO carPoint(cid, p, h3) VALUES
(1, ST_MakePoint(116.44043, 39.9219), h3(116.44043, 39.9219, 14)),
(2, ST_MakePoint(116.43528, 39.9228), h3(116.43528, 39.9228, 14)),
(3, ST_MakePoint(116.42842, 39.92335), h3(116.42842, 39.92335, 14)),
(4, ST_MakePoint(116.41175, 39.92298), h3(116.41175, 39.92298, 14)),
(5, ST_MakePoint(116.40473, 39.92287), h3(116.40473, 39.92287, 14)),
(6, ST_MakePoint(116.40108, 39.91697), h3(116.40108, 39.91697, 14)),
(7, ST_MakePoint(116.40025, 39.91668), h3(116.40025, 39.91668, 14)),
(8, ST_MakePoint(116.39918, 39.91203), h3(116.39918, 39.91203, 14)),
(9, ST_MakePoint(116.3971, 39.91373), h3(116.3971, 39.91373, 14)),
(10, ST_MakePoint(116.38908, 39.80132), h3(116.38908, 39.80132, 14));
步骤二:数据查询
聚合查询
如果以h3列的网格精度(精度14)聚合,查询语句如下:
SELECT h3, count(*) AS carCount FROM carData GROUP BY h3;
返回结果如下:
+--------------------+----------+ | h3 | carCount | +--------------------+----------+ | 640384869502320991 | 1 | | 640384869499623143 | 1 | | 640384869512099119 | 1 | | 640384864449685735 | 1 | | 640384864454095007 | 1 | | 640384864453485615 | 1 | | 640384864373589303 | 1 | | 640384864374069599 | 1 | | 640384864373873255 | 1 | | 640384867555368103 | 1 | +--------------------+----------+
其中,h3为计算后生成的H3网格索引值,carCount表示各网格区域中的车辆数。
如果需要使用其他H3精度,且聚合语句不包含
H3_Contains
条件,需要使用/*+ _l_force_index_('h3_idx') */
强制启用索引,查询语句如下:SELECT /*+ _l_force_index_('h3_idx') */ h3_cellToParent(h3, 8) AS h3CellId, count(*) AS carCount FROM carData GROUP BY h3_cellToParent(h3, 8);
返回结果如下:
+--------------------+----------+ | h3CellId | carCount | +--------------------+----------+ | 613363266611052543 | 3 | | 613363266686550015 | 1 | | 613363266690744319 | 2 | | 613363269792432127 | 1 | | 613363271736492031 | 1 | | 613363271738589183 | 1 | | 613363271749074943 | 1 | +--------------------+----------+
H3网格的前端显示可以参考Uber官方提供的h3-js工具,访问地址:h3-js工具。
网格包含查询
使用H3网格快速筛选出在指定空间范围内的车辆数据。
具体实现如下:
H3_PolygonToCells
函数将指定的多边形对象转换为H3网格单元。H3_Contains
函数判断多边形对象所对应的H3网格是否包含表carData
中的h3列。如果包含,输出包含在多边形对象中的轨迹点。
H3_PolygonToCells
函数的使用方式,请参见H3_PolygonToCells。
SELECT cid, x, y
FROM carData
WHERE H3_Contains(
H3_PolygonToCells(ST_GeomFromText('POLYGON ((116.4265 39.9284, 116.4455 39.9284, 116.4455 39.9145, 116.4265 39.9145, 116.4265 39.9284))'), 10),
h3)
ORDER BY cid;
如果表carData
对h3列创建了二级索引,则H3_Contains
查询会自动使用索引进行查询优化。
返回结果如下:
+-----+-----------+----------+
| cid | x | y |
+-----+-----------+----------+
| 1 | 116.44043 | 39.9219 |
| 2 | 116.43528 | 39.9228 |
| 3 | 116.42842 | 39.92335 |
+-----+-----------+----------+