Java查找附近的目标 |【原创】使用Geohash查找周边附近的目标 Java Spring
前言须知
本章讲解如何使用Geohash查找附近的位置,以及如何解决Geohash区域边缘问题。
一个Geohash代表的是一个区域,一个Geohash字符串代表一个区域(如一个正方形),同一区域内的Geohash相同,不同区域的Geohash不同。
因相邻区域的Geohash不同,所以会有边缘问题:如范围2.4km的Geohash直接匹配则查不到相邻区域相距100米的目标。
本篇使用九宫格方法来解决边缘问题。
特别提醒:Geohash是根据经纬度计算直线距离,而大多地图导航软件会根据目标之间的路线计算路径距离,所以会有差距。
干货
1.加载依赖–使用开源项目Geohash的发行jar包
项目Github地址:https://github.com/kungfoo/geohash-java
发行jar包的Maven仓库地址:https://mvnrepository.com/artifact/ch.hsr/geohash
pom依赖
1 | <dependency> |
2.计算geoHash字符串
本篇从地图上选了四个地点,以一个示例来讲计算方法及说明相关问题:
以下代码使用示例地图上的四个点的经纬度生成对应的geoHash字符串1 | import ch.hsr.geohash.GeoHash; |
1 | 和平饭店(用户所在地址)geoHash:wtw3s |
- 说明:
相信有些读者可能注意到:
丛示例的输出可以看出“和平饭店”与“东方明珠塔”相距1km,geoHash却不同;
而“和平饭店”与“东新大厦”、“房地大厦”相距更远,其geoHash却相同;
↑ 这就是下一段落要说的边缘问题。
GeoHash可利用字符串前几位匹配的规则查找相距不超过一定距离的目标;
- 字符位数与距离对应表:
geoHash位数 距离(km) 1 ±2500 2 ±630 3 ±78 4 ±20 5 ±2.4 6 ±0.61 7 ±0.076 8 ±0.019
上例中使用5位数的geoHash及锁定了±2.4km附近的位置。
即用2.4km范围内的所有地点的经纬度计算所得的5位geoHash都是一致的
因此可以根据这个特点做附近地点的高效检索:
从数据库高效检索附近地点
1.将所有地点的geoHash计算出;
2.将各地点的geoHash在数据库的表中保存为一列geoHash并建立索引
Tips:数据库里geoHash应建立索引,且应为BTree索引。因为Hash索引不支持模糊匹配;
可直接使用如下语句获取同一个geoHash区域中的附近地点
1 | where geoHash like 'wtw3s%' |
3.geoHash区域边缘问题
可能已经发现,既然geoHash代表的是一个区域,那必然会产生边缘性问题:
如上例中的用户所在地“和平饭店”,距离“东方明珠塔”只有1km,二者geoHash却不同。
这是因为两者处于两个geoHash区域的边缘。所以直接匹配一个字符串会出现问题。
- 笔者使用九宫格的想法:获取目标位置周围八个宫格,从数据库检索获取九个宫格中所有的目标,再在Java应用中逐个进行目标距离计算比较,根据距离约束排除在距离外的目标即可。
上述距离计算使用经纬度可直接计算两个目标的直线距离:
详细计算方法可参照我的另一篇分享:根据经纬度计算两者距离 (笔者尽快更新)
4.结语
如有疑问欢迎联系博主,谢谢!
本分享所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Vayne的技术分享!