geohash介绍与java实现

📅 2026/7/28 14:37:07
geohash介绍与java实现
geohash介绍与java实现前言介绍java实现前言以前在实现查找特定经纬度附近最近目标用户时遇到了一个问题就是要查找出目标用户需要遍历数据库进行经纬度的计算然后进行排序这种自然不是一种比较好的实现方式。例如现在我们有一个平台数据库记录着线下商家的全部经纬度一个用户通过平台发送了当前位置的经纬度需要分别查询出100m 200m 500m1km 10km等的商家或者需要查询出附近最近的10个商家如果采取这种做法当商家的数量到达一定程度就会出现查询特别慢的情况这种情况下推荐使用geohash。介绍geohash时一种将二维的地理位置转换为一维进行查询的一种方式。例如geohash32我们取出一张世界地图将之等分为32块每一块给予一个编码那么在数据库记录的时候我们只需要记住这一编码。当我们进行查询的时候如果编码是相同的我们就知道他们是通一块区域的地理位置。如下 当然我们还可以在每个小格子中再划分32个格子无限递归。递归的越多划分的格子越小那么就目标位置的geohash就越长那么精度就约高。例如 wx5jv4u6 就是北京某一处的geohash。8位经度在后面介绍。详细请看这篇文章https://www.jianshu.com/p/1ecf03293b9ajava实现package com.koubei.collect_script.demo; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * author kelin.ll * date on 2018/6/13 */ public class GeoHashDemo { private LocationBean location; /** * 1 2500km;2 630km;3 78km;4 30km * 5 2.4km; 6 610m; 7 76m; 8 19m */ private int hashLength 8; //经纬度转化为geohash长度 private int latLength 20; //纬度转化为二进制长度 private int lngLength 20; //经度转化为二进制长度 private double minLat;//每格纬度的单位大小 private double minLng;//每个经度的倒下 private static final char[] CHARS {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, b, c, d, e, f, g, h, j, k, m, n, p, q, r, s, t, u, v, w, x, y, z}; public GeoHashDemo(double lat, double lng) { location new LocationBean(lat, lng); setMinLatLng(); } public int gethashLength() { return hashLength; } /** * Author:lulei * Description: 设置经纬度的最小单位 */ private void setMinLatLng() { minLat LocationBean.MAXLAT - LocationBean.MINLAT; for (int i 0; i latLength; i) { minLat / 2.0; } minLng LocationBean.MAXLNG - LocationBean.MINLNG; for (int i 0; i lngLength; i) { minLng / 2.0; } } /** * return * Author:lulei * Description: 求所在坐标点及周围点组成的九个 */ public ListString getGeoHashBase32For9() { double leftLat location.getLat() - minLat; double rightLat location.getLat() minLat; double upLng location.getLng() - minLng; double downLng location.getLng() minLng; ListString base32For9 new ArrayListString(); //左侧从上到下 3个 String leftUp getGeoHashBase32(leftLat, upLng); if (!(leftUp null || .equals(leftUp))) { base32For9.add(leftUp); } String leftMid getGeoHashBase32(leftLat, location.getLng()); if (!(leftMid null || .equals(leftMid))) { base32For9.add(leftMid); } String leftDown getGeoHashBase32(leftLat, downLng); if (!(leftDown null || .equals(leftDown))) { base32For9.add(leftDown); } //中间从上到下 3个 String midUp getGeoHashBase32(location.getLat(), upLng); if (!(midUp null || .equals(midUp))) { base32For9.add(midUp); } String midMid getGeoHashBase32(location.getLat(), location.getLng()); if (!(midMid null || .equals(midMid))) { base32For9.add(midMid); } String midDown getGeoHashBase32(location.getLat(), downLng); if (!(midDown null || .equals(midDown))) { base32For9.add(midDown); } //右侧从上到下 3个 String rightUp getGeoHashBase32(rightLat, upLng); if (!(rightUp null || .equals(rightUp))) { base32For9.add(rightUp); } String rightMid getGeoHashBase32(rightLat, location.getLng()); if (!(rightMid null || .equals(rightMid))) { base32For9.add(rightMid); } String rightDown getGeoHashBase32(rightLat, downLng); if (!(rightDown null || .equals(rightDown))) { base32For9.add(rightDown); } return base32For9; } /** * param length * return * Author:lulei * Description: 设置经纬度转化为geohash长度 */ public boolean sethashLength(int length) { if (length 1) { return false; } hashLength length; latLength (length * 5) / 2; if (length % 2 0) { lngLength latLength; } else { lngLength latLength 1; } setMinLatLng(); return true; } /** * return * Author:lulei * Description: 获取经纬度的base32字符串 */ public String getGeoHashBase32() { return getGeoHashBase32(location.getLat(), location.getLng()); } /** * param lat * param lng * return * Author:lulei * Description: 获取经纬度的base32字符串 */ private String getGeoHashBase32(double lat, double lng) { boolean[] bools getGeoBinary(lat, lng); if (bools null) { return null; } StringBuffer sb new StringBuffer(); for (int i 0; i bools.length; i i 5) { boolean[] base32 new boolean[5]; for (int j 0; j 5; j) { base32[j] bools[i j]; } char cha getBase32Char(base32); if ( cha) { return null; } sb.append(cha); } return sb.toString(); } /** * param base32 * return * Author:lulei * Description: 将五位二进制转化为base32 */ private char getBase32Char(boolean[] base32) { if (base32 null || base32.length ! 5) { return ; } int num 0; for (boolean bool : base32) { num 1; if (bool) { num 1; } } return CHARS[num % CHARS.length]; } /** * param lat * param lng * return * Author:lulei * Description: 获取坐标的geo二进制字符串 */ private boolean[] getGeoBinary(double lat, double lng) { boolean[] latArray getHashArray(lat, LocationBean.MINLAT, LocationBean.MAXLAT, latLength); boolean[] lngArray getHashArray(lng, LocationBean.MINLNG, LocationBean.MAXLNG, lngLength); return merge(latArray, lngArray); } /** * param latArray * param lngArray * return * Author:lulei * Description: 合并经纬度二进制 */ private boolean[] merge(boolean[] latArray, boolean[] lngArray) { if (latArray null || lngArray null) { return null; } boolean[] result new boolean[lngArray.length latArray.length]; Arrays.fill(result, false); for (int i 0; i lngArray.length; i) { result[2 * i] lngArray[i]; } for (int i 0; i latArray.length; i) { result[2 * i 1] latArray[i]; } return result; } /** * param value * param min * param max * return * Author:lulei * Description: 将数字转化为geohash二进制字符串 */ private boolean[] getHashArray(double value, double min, double max, int length) { if (value min || value max) { return null; } if (length 1) { return null; } boolean[] result new boolean[length]; for (int i 0; i length; i) { double mid (min max) / 2.0; if (value mid) { result[i] true; min mid; } else { result[i] false; max mid; } } return result; } class LocationBean { public static final double MINLAT -90; public static final double MAXLAT 90; public static final double MINLNG -180; public static final double MAXLNG 180; private double lat;//纬度[-90,90] private double lng;//经度[-180,180] public LocationBean(double lat, double lng) { this.lat lat; this.lng lng; } public double getLat() { return lat; } public void setLat(double lat) { this.lat lat; } public double getLng() { return lng; } public void setLng(double lng) { this.lng lng; } } public static void main(String[] args) { // TODO Auto-generated method stub GeoHashDemo g new GeoHashDemo(40.222012, 116.248283); g.sethashLength(12); System.out.println(当前坐标g.getGeoHashBase32()); //for (String str: // g.getGeoHashBase32For9()) { // System.out.println(str); //} } }代码出处 https://www.cnblogs.com/gisblogs/p/9177564.html