geohash的简单分享

geohash算法的简单分享

  昨天和今天都在研究定位的问题,查找附近的地理点,需要用到一个比较好的算法,于是就想起了以前同事分享过的算法,geohash算法。
  昨天本来已经基本实现了,不过写完都已经到第二天了,就没更新了,今天继续调试,完成了优化,更新一下。
  geohash是什么呢?简单讲一下,你现在有个需求,要做定位,获取了一个经纬度,然后要找出附近的符合条件的点,然而数据库里只有这些点的经纬度。一般按照传统的数学逻辑,两点之间的距离(x1,y1),(x2,y2) 根号下((x1-x2)平方+(y1-y2)平方)算起来有点麻烦,你可以交给计算机做啊,他们算起来很快的,哦。 我们分析一下,计算机算加法是很快的,算乘法就会有点慢了,之后再开方,效率会更低,之后呢,你还要遍历,数据库里所有的数据都要算一遍,那效率,数据量大估计会很’可观’。
  这时候就可以引入我们的geohash算法了,我们知道,地球是圆的,但是地图是平面的,我们可以用经纬度表达地图上的每一个点,geohash算法的概念就是将地图分割成若干方块,地球纬度区间是[-90,90],那么我们就可以利用二分法,将一个纬度不断逼近它,举个例子,(我懒得画图了,图片来自维基):

geohash的简单分享_第1张图片

  这是维基的一个例子,纬度是42.6,首先跟0比较大于0,好的bit为1,接着跟45比较,小于45,bit置0,接着跟22.5比较,大于22.5置为1,以此类推,最后编码为101111001001 ,当然了你还可以更长,继续比下去你的精度越高,你的编码就会越长,编码怎么存呢?你不能把这一串01保存到数据库吧,那就编码吧,那就再次编码,使用base32,也就是16进制保存,转换详情见下表:

geohash的简单分享_第2张图片

  一般是将经纬度都编码之后,拼接成一个长字符串,每5位一分隔,转换成一个字符串。
  具体的原理就是这样,当我们比较的时候,不用遍历算数了,sql里有一个叫Like的语句,自动匹配,你可以匹配前若干位数,匹配的位数越长,点与点之间的距离就越接近,这种算法极大的提高了效率,只需要额外加一个字段去存geohash即可。
  算法的缺点就是强行将地球按方格划分,如果两个点位置恰好在圆之内,方格之外,就会被忽略,补救的方法就是额外再扩大8个格子,就看你是想错放,还是错杀了。
  算法的具体实现还是有点复杂的,我也是直接用的前人的工具类,感兴趣的,有需要的同学们可以自己上网搜一下,果然听别人分享和自己实现完全是两回事,这几天终于实现了查找附近的功能,不由得感慨发明算法的人( Gustavo Niemeyer),人家的脑子是怎么长的-_-

你可能感兴趣的:(算法,算法)