传统的GIS数据库,如ArcGIS这种传统桌面型的软件,主要还是强调测绘模型数据的规范化输入。GIS的本质上在于多维索引,对一个最简单的平面地图来说,主要就是靠最原始的GPS芯片返回的经纬度坐标。问题是,即使静止在同一个位置,由于地球在自转(?),卫星反射返回的信号时间可能不一样,这样得到的经纬度坐标不能保持一模一样。更不用说移动中的目标(汽车)了。中国的GPS坐标还会涉及到一个非线性的加密扰乱,人为地降低精度。
PostgreSQL(pg)数据库有一个插件,可以用于存储POI(Place of Interest,或Point of Interest),即附带了经纬度坐标属性的数据记录。经纬度坐标可以认为是2维的数值型数据,但是坐标系本身却又有额外的问题:经纬度坐标是球面的,并且它有多不同的国际标准。假如我们不考虑这个,即不要求绝对精确的网格系统,只要求保证每个维度上的严格偏序关系成立即可,则GIS数据库引擎本身的目标就是:
给定一个POI查询位置,快速返回一个包含此POI的最小区域范围?
考虑SQL数据库里的key,它是一个1维的value range index。而GIS的key是2维的,如何实现索引呢?一般就是R树(包围盒)、k-d树(相当于扩展的B+树,每个维度轮流索引)或者是某些混合方案,当然还有一个基于GeoHash的快速定位。原则上,不同的最小区域在边界处可能是有重叠的,因此,为保证查询结果不会遗漏,需要查询一个POI所在区域的9宫格邻域,当然也有使用6边形的,不规则多边形、三角形当然也可以(数学的离散几何里的平面镶嵌)。
对R树而言,最简单的是基于实时计算机图形学里的BSP概念的划分,当然,也可以使用4叉树、八叉树,n叉树,其本质就是对于一个2维的(x,y)坐标,划分函数,要求能够高效决定查询落在哪个子范围内,如此就可以快速地以log复杂度定位最终的最小包围区域了。考虑到实际这些最小区域中的POI对象的密度不均匀,这些划分方案最好应该是自适应的,即:原生的就解决掉数据倾斜(分布不均匀)的问题。
当需要将一个平面地图绘制出来时,无非就是一个分层问题,以及每个图元的2D图形学绘制。三角形、矩形这类简单的对应建筑物的,以及河流、道路对应的Bezier曲线。GIS中可能需要额外考虑高度维度,即等高线的绘制(很容易联想到机器学习里的梯度下降),而城市交通地图里建筑物虽然有简单的根据高度绘制的3D效果,但是实际上却没有室外与室内的无缝对接,以及室内每一层的平面结构示意图。
好吧,现在考虑地图引擎里的导航模块,From anywhere to anywhere。通常每个道路的对接点可以看作图的一个顶点,道路就是边,而道路的长度,或者依据交通工具的不同(步行、自驾、公交)所花费的时间作为权重,这样就可以运行一个Dijkstra算法。但是这个算法对于对于所有的道路连接情况而言,显然规模太大了,需要做一个“预聚类/聚合”处理,即小路优先合并到大路,最后汇并到主干道/高速公路什么的。
当实现实时导航功能时,需要及时作出转弯/直行的提醒,为了实现这个目标,数据库除了需要adjacency查询性能高效以外,还需要能够根据当前的速度作为合理的预测,就像雷达预测空中飞机的下一个时刻的位置一样。