前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Geohash之范围搜索

Geohash之范围搜索

作者头像
lzugis
发布2018-10-23 11:19:44
1.4K0
发布2018-10-23 11:19:44
举报

概述

很多时候,我们都会遇到这样的需求:查找某个点周边多少距离的点。从本质来说,是一个缓冲区分析+空间查找,本文结合Geohash来实现类似的功能。

效果

范围搜索结果
范围搜索结果
说明:
  1. 红色的点和红色的圈是查找的中心点和距离(5km);
  2. 蓝色的点+粉色的点是通过geohash查找出来的点;
  3. 粉色的点是通过过滤后的点;

实现

本文实现是结合sqlite数据库实现的,实现的思路如下:

1. 数据的初始化

本示例所用的数据源于网络下载下来的shp数据,并做了解析入库,表结构如下:

代码语言:javascript
复制
CREATE TABLE "geocode_point"
(
  id NVARCHAR(50) PRIMARY KEY NOT NULL,
  poiname NVARCHAR(200),
  x NUMERIC,
  y NUMERIC,
  minzoom INTEGER(2),
  maxzoom INTEGER(2)
, geohash NVARCHAR(20) NULL)
数据展示
数据展示

2. 根据geohash查找点

根据查找的距离范围,先获取geohash的位数,实现方法如下:

代码语言:javascript
复制
    /**
     * 获取距离有效位数
     * @param radius
     * @return
     */
    public int effectnum(double radius){
        int result = 0;
        if (radius <= 0) result = 0;
        else if (radius < 1) result = 10;
        else if (radius < 5) result = 9;
        else if (radius < 20) result = 8;
        else if (radius < 77) result = 7;
        else if (radius < 610) result = 6;
        else if (radius < 2400) result = 5;
        else if (radius < 20000) result = 4;
        else if (radius < 78000) result = 3;
        else if (radius < 630000) result = 2;
        else result = 0;
        return result;
    }

再查找前面的值相同的记录,实现代码如下:

代码语言:javascript
复制
int precision = geoHash.effectnum(dist);
String strGeohash = geoHash.encode(lat, lon, 0);
String filters = "where geohash like '"+strGeohash.substring(0, precision)+"%'";
List _list = geoDao.getDataByFilter(points.getTableName(), points.getTableFields(), filters, new Object[]{});

3. 计算满足条件的点

由于是经纬度的数据,所以在计算两点距离的时候进行了坐标转换,将经纬度转换为了Web墨卡托,此举是结合geotools实现的。

1)坐标转换
代码语言:javascript
复制
    public double[] lonlat2WebMactor(double lon, double lat){
        Point geom =new GeometryFactory().createPoint(new Coordinate(lon, lat));
        try{
            CoordinateReferenceSystem crsTarget = CRS.decode("EPSG:3857");
            // 投影转换
            MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, crsTarget);
            Point webPoint = (Point)JTS.transform(geom, transform);
            return new double[]{webPoint.getX(), webPoint.getY()};
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }
2)计算距离
代码语言:javascript
复制
    public double distance(String geohash1, String geohash2){
        Map lonlat1 = decode(geohash1),
            lonlat2 = decode(geohash2);
        double lat1 = (Double) lonlat1.get("lat"),
                lon1 = (Double) lonlat1.get("lon");
        double lat2 = (Double) lonlat2.get("lat"),
                lon2 = (Double) lonlat2.get("lon");
        double[] webPoint1 = lonlat2WebMactor(lon1, lat1),
                webPoint2 = lonlat2WebMactor(lon2, lat2);
        return Math.sqrt(Math.pow(webPoint1[0]-webPoint2[0], 2d)+Math.pow(webPoint1[1]-webPoint2[1], 2d));
    };
3)筛选满足条件的点

将查询出来的结果做比较,筛选满足条件的点。

代码语言:javascript
复制
        for(int i=0;i<_list.size();i++){
            Map map = (Map)_list.get(i);
            String _geohash = map.get("geohash").toString();
            double _dist = geoHash.distance(strGeohash, _geohash);
            if(_dist<dist)list.add(map);
        }
        return list;

将2和3串起来,实现代码如下:

代码语言:javascript
复制
    public List searchByDist(double lon, double lat, double dist){
        List list = new ArrayList();
        int precision = geoHash.effectnum(dist);
        String strGeohash = geoHash.encode(lat, lon, 0);
        String filters = "where geohash like '"+strGeohash.substring(0, precision)+"%'";
        List _list = geoDao.getDataByFilter(points.getTableName(), points.getTableFields(), filters, new Object[]{});
        System.out.println(JSONArray.toJSONString(_list));
        for(int i=0;i<_list.size();i++){
            Map map = (Map)_list.get(i);
            String _geohash = map.get("geohash").toString();
            double _dist = geoHash.distance(strGeohash, _geohash);
            if(_dist<dist)list.add(map);
        }
        return list;
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年12月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 效果
  • 实现
    • 1. 数据的初始化
      • 2. 根据geohash查找点
        • 3. 计算满足条件的点
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档