通过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即可

 

点到线距离计算公式

 

posted on 2017-12-15 14:42  李雷  阅读(850)  评论(0编辑  收藏  举报

导航