通过geohash找出距离某个经纬度点最近的道路(二维空间查询转换为一维比较查询)
场景
通过出租车、货车等发出实时轨迹点,这些轨迹点往往出现偏移,需要找出汽车具体在哪条道路上行驶
传统做法
通过对点进行buffer,然后关联空间数据库(oracle、postgis等)找出与buffer相交的link,逐步比较点与关联link的距离,找出距离最近的link
缺点:
1、空间数据库二维的比较
2、buffer半径可能需要多次设置,有可能buffer没有关联出link,需要放到半径重新进行空间比较
新方案思路
1、对所有道路link进行外包框的geohash计算,获取一个最小的和一个最大的,比如
MULTILINESTRING((116.84977 39.93626,116.84975 39.93648,116.8505 39.93661,116.8509 39.93667,116.85148 39.93681,116.85186 39.93689))
String wkt = "MULTILINESTRING((116.84977 39.93626,116.84975 39.93648,116.8505 39.93661,116.8509 39.93667,116.85148 39.93681,116.85186 39.93689))"; Geometry geom = new WKTReader().read(wkt); Geometry bundary = geom.getEnvelope(); String minGeohash = "zzzzzzzzzzzz"; String maxGeohash = "0"; for(Coordinate c:bundary.getCoordinates()){ String hash = GeoHash.withCharacterPrecision(c.y, c.x, 12).toBase32(); if (minGeohash.compareTo(hash)>0) minGeohash = hash; if (maxGeohash.compareTo(hash)<0) maxGeohash = hash; } System.out.println(minGeohash+","+maxGeohash);
对应minGeohash和maxGeohash为:wx554ypmsd2w,wx555n2cjxyh
2、创建表结构存储到关系型数据库中
create table link_geohash(start String,end String,int link_pid);
创建索引:
create index idx_link_geohash_start on link_geohash(start);
create index idx_link_geohash_end on link_geohash(end);
3、导入数据到表link_geohash
start对应minGeohash,end对应maxGeohash
4、根据点查找对应道路link
比方说点:Point(116.850829 39.936568)、对应的geohash为:wx555n0pmev5
select link_pid from link_geohash where 'wx555n0pmev5' between start,end;
5、通过上一步查出的link编号,获取对应的geometry,再逐个比较,返回距离最小的那根link即可
点到线距离计算公式