最近遇到一个问题,需要根据基站的经纬度给基站进行分组,两个基站距离相差10米内分到一组,最开始是通过两层循环处理的(笛卡尔积),这样的速度非常慢。最开始因为这个是偶尔还会运行一次,对效率也没要求,项目开始阶段需求紧,站也少,能凑合用,就没去优化,现在站达到40-50万个,这个就用不了了,就到处找资料,最后找到geohash算法,正好解决我这个问题,消除掉笛卡尔积问题,速度几十倍的提升,在此做下记录,以防后面忘记!

算法工具类:

package com.nokia.uip.common;import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;public class GeoHash {
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 static int numbits = 20; //经纬度单独编码长度private static double minLat;
private static double minLng;private final static char[] digits = { '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' };//定义编码映射关系
final static HashMap<Character, Integer> lookup = new HashMap<Character, Integer>();
//初始化编码映射内容
static {int i = 0;for (char c : digits) {lookup.put(c, i++);}
}public GeoHash(){setMinLatLng();
}public String encode(double lat, double lon) {BitSet latbits = getBits(lat, -90, 90);BitSet lonbits = getBits(lon, -180, 180);StringBuilder buffer = new StringBuilder();for (int i = 0; i < numbits; i++) {buffer.append( (lonbits.get(i))?'1':'0');buffer.append( (latbits.get(i))?'1':'0');}String code = base32(Long.parseLong(buffer.toString(), 2));//Log.i("okunu", "encode  lat = " + lat + "  lng = " + lon + "  code = " + code);return code;
}public ArrayList<String> getArroundGeoHash(double lat, double lon){//Log.i("okunu", "getArroundGeoHash  lat = " + lat + "  lng = " + lon);ArrayList<String> list = new ArrayList<>();double uplat = lat + minLat;double downLat = lat - minLat;double leftlng = lon - minLng;double rightLng = lon + minLng;String leftUp = encode(uplat, leftlng);list.add(leftUp);String leftMid = encode(lat, leftlng);list.add(leftMid);String leftDown = encode(downLat, leftlng);list.add(leftDown);String midUp = encode(uplat, lon);list.add(midUp);String midMid = encode(lat, lon);list.add(midMid);String midDown = encode(downLat, lon);list.add(midDown);String rightUp = encode(uplat, rightLng);list.add(rightUp);String rightMid = encode(lat, rightLng);list.add(rightMid);String rightDown = encode(downLat, rightLng);list.add(rightDown);//Log.i("okunu", "getArroundGeoHash list = " + list.toString());return list;
}//根据经纬度和范围,获取对应的二进制
private BitSet getBits(double lat, double floor, double ceiling) {BitSet buffer = new BitSet(numbits);for (int i = 0; i < numbits; i++) {double mid = (floor + ceiling) / 2;if (lat >= mid) {buffer.set(i);floor = mid;} else {ceiling = mid;}}return buffer;
}//将经纬度合并后的二进制进行指定的32位编码
private String base32(long i) {char[] buf = new char[65];int charPos = 64;boolean negative = (i < 0);if (!negative){i = -i;}while (i <= -32) {buf[charPos--] = digits[(int) (-(i % 32))];i /= 32;}buf[charPos] = digits[(int) (-i)];if (negative){buf[--charPos] = '-';}return new String(buf, charPos, (65 - charPos));
}private void setMinLatLng() {minLat = MAXLAT - MINLAT;for (int i = 0; i < numbits; i++) {minLat /= 2.0;}minLng = MAXLNG - MINLNG;for (int i = 0; i < numbits; i++) {minLng /= 2.0;}
}//根据二进制和范围解码
private double decode(BitSet bs, double floor, double ceiling) {double mid = 0;for (int i=0; i<bs.length(); i++) {mid = (floor + ceiling) / 2;if (bs.get(i)){floor = mid;}else {ceiling = mid;}}return mid;
}//对编码后的字符串解码
public double[] decode(String geohash) {StringBuilder buffer = new StringBuilder();for (char c : geohash.toCharArray()) {int i = lookup.get(c) + 32;buffer.append( Integer.toString(i, 2).substring(1) );}BitSet lonset = new BitSet();BitSet latset = new BitSet();//偶数位,经度int j =0;for (int i=0; i< numbits*2;i+=2) {boolean isSet = false;if ( i < buffer.length() ) {isSet = buffer.charAt(i) == '1';}lonset.set(j++, isSet);}//奇数位,纬度j=0;for (int i=1; i< numbits*2;i+=2) {boolean isSet = false;if ( i < buffer.length() ) {isSet = buffer.charAt(i) == '1';}latset.set(j++, isSet);}double lon = decode(lonset, -180, 180);double lat = decode(latset, -90, 90);return new double[] {lat, lon};
}public static void main(String[] args)  throws Exception{GeoHash geohash = new GeoHash();String s = geohash.encode(40.222012, 116.248283);System.out.println(s);System.out.println(geohash.encode(25.34722200,98.4827770));System.out.println(geohash.encode(22.44841800,99.9760520));//geohash.getArroundGeoHash(40.222012, 116.248283);double[] geo = geohash.decode(s);System.out.println(geo[0]+" "+geo[1]);
}
}

GeoHash位数与距离对应关系

这里通过算法encode的值是8位的时候, 距离是19米 ,刚好符合我的要求,工具代码类里这个参数是控制计算的长度的,当为20的时候符合我的要求

private static int numbits = 20; //经纬度单独编码长度

代码留档

@Testpublic void test1(){List<Map<String,Object>> list = quarterCloseAreaResService.queryAreaCompute();GeoHash geoHash = new GeoHash();Map<String,List<Map<String,Object>>> concurrentHashMap = new ConcurrentHashMap<String,List<Map<String,Object>>>();list.parallelStream().forEach(e->{List<Map<String,Object>> concurrentList = null;String value = geoHash.encode(Double.parseDouble(e.get("compute_latitude").toString()),Double.parseDouble(e.get("compute_longitude").toString()));if(concurrentHashMap.containsKey(value)){concurrentList = concurrentHashMap.get(value);concurrentList.add(e);concurrentHashMap.put(value,concurrentList);}else{concurrentList = new ArrayList<>();concurrentList.add(e);concurrentHashMap.put(value,concurrentList);}e.put(e.get("id").toString(),value);}); AtomicInteger smallGroup = new AtomicInteger(0);List<String> keyList = new ArrayList<>(concurrentHashMap.keySet()); keyList.parallelStream().forEach(key->{int id = smallGroup.incrementAndGet();Map<String,Object> paramMap = new HashMap<>();List<Map<String, Object>> value = concurrentHashMap.get(key); List<Integer> ids = new ArrayList<>();value.stream().forEach(e->{ids.add(Integer.valueOf(e.get("id").toString()));}); paramMap.put("smallGroup",id);paramMap.put("list",ids); quarterCloseAreaResService.updateAreaComputeGroup(paramMap); });}

java实现 GeoHash 算法(GeoHash位数与距离对应关系)相关推荐

  1. c语言geohash算法,geohash实现(c语言)

    GeoHash算法 首先,你要Baidu下,找到该算法核心原理,这里摘自网络文档,简单介绍下. GeoHash算法是通过二分法,经过一定次数的无限逼近,将经纬度的二维坐标浮点值变成一个可排序.可比较的 ...

  2. java 汉明距离_算法:hamming 海明距离(汉明距离):Java实现

    在信息论中,两个等长二进制字符串之间的汉明距离是两个字符串对应位置的不同字符的个数.例如,1011101 与 1001001 之间的汉明距离是 2. 汉明距离是以理查德·卫斯里·汉明的名字命名的,汉明 ...

  3. [990]Geohash算法原理及实现

    文章目录 经纬度常识 基本原理 Geohash算法 GeoHash的精度 具体的计算方法 1.纬度相同,经度不同 2.经度相同,纬度不同 问题 代码实现 geohash在mysql中的使用 最近需要实 ...

  4. Geohash算法的概括

    Geohash算法就是将经纬度编码,将二维变一维,给地址位置分区的一种算法. 基本原理 GeoHash是一种地址编码方法.他能够把二维的空间经纬度数据编码成一个字符串 我们知道,经度范围是东经180到 ...

  5. 高效的多维空间点索引算法 — Geohash 和 Google S2(转)

    转自:https://mp.weixin.qq.com/s?__biz=MjM5OTM0MzIwMQ==&mid=2652551603&idx=1&sn=f45f06d6a56 ...

  6. 高效的多维空间点索引算法 — Geohash 和 Google S2—绝对好文

    引子 每天我们晚上加班回家,可能都会用到滴滴或者共享单车.打开 app 会看到如下的界面: app 界面上会显示出自己附近一个范围内可用的出租车或者共享单车.假设地图上会显示以自己为圆心,5公里为半径 ...

  7. Geohash算法原理及实现

    最近需要实现一个功能,查找车辆附近的加油站,如果车和加油站距离在200米以内,则查找成功. 加油站数量肯定不小,能否缩小查找范围,否则以遍历形式,效率肯定高不了. Geohash算法就是将经纬度编码, ...

  8. Java 根据经纬度计算两点间的距离

    Java实现 public final class DistanceUtils {/*** 地球半径,单位 km*/private static final double EARTH_RADIUS = ...

  9. Java根据经纬度计算两点之间的距离

    1. 前言   在我们平时使用美团,饿了么等app进行订餐,或者使用猫眼进行订电影票的时候,都有一个距离的排序,表明该家店距离我们当前的位置,这种基于地理位置的服务,统一被称为LBS(Location ...

最新文章

  1. mysql int和bigdecimal,mysql的 int 类型,刨析返回类型为BigDicemal 类型的奇怪现象
  2. SAP MM ME21N 创建PO时报错 - Net price in CNY becomes too large – 之对策
  3. mysql 权重搜索
  4. Platform Builder 6.0与Windows 7兼容性的问题
  5. java cookie p3p_P3P解决cookie存取的跨域问题
  6. c++ vector拷贝构造_vector------stl学习笔记一
  7. 通过adb巧用monkey获取android设备中所有应用的主activity
  8. c语言编程被当作病毒,为什么这个微不足道的C程序被检测为病毒?
  9. python课后题答案第一章_python核心编程课后习题解答第一章
  10. Git分支 and PullFetchMerge
  11. Tech-Ed2004的收获
  12. 实验一 顺序表基本操作的实现
  13. 论文中MathType公式居中,编号右对齐
  14. Flash CS3:FLV视频短片我来做!
  15. 计算机应用基础windows10 +office2016题库及答案
  16. zotero文献管理|chartero 插件 绝对是有一款让你离不开的插件,可视化你的文献阅读记录,提取PDF图片方便阅读
  17. linux下回收站无法清空 解决
  18. 抖音壁纸表情包小程序搭建部署说明、广告分佣规则说明以及迭代新计划
  19. Devops 开发运维基础篇之Jenkins部署与使用
  20. zkeys阿帕云对接易支付插件,支持zkeys阿帕云最新版(亲测可用)

热门文章

  1. 神奇玻璃制品:鲁珀特之泪
  2. 用5v1a的充电器给1.2v的镍氢电池充电(充满后可自动断电)或者可以定时
  3. 丹佛斯变频器al13故障_丹佛斯变频器常见故障维修
  4. OneNote 与 OneNote 2016 有什么区别?
  5. 软件测试-------Web(性能测试 / 界面测试 / 兼容性测试 / 安全性测试)
  6. UI 设计代码化:低代码式设计语言 —— Unflow
  7. linux 排程命令,linux 任务管理与调度
  8. python pandas excel 排序_python – Pandas – 使用datetimeindex对数据帧进行排序
  9. 前端提效 - js 批量导出 excel 为zip压缩包
  10. 计算机故障小知识,计算机故障的一小知识.doc