MongoDB二维座标索引,GeoHash的运用原理

GeoHash:GeoHash是一种将二维的经纬度转换成字符串的方法。

原出处:http://www.cnblogs.com/LBSer/p/3310455.html
运用:mongoDB使用geoHash对二维经纬度座标索引转换为可排序的一维索引,从而可以使用B树类似的二分查找的方式对其进行相关的搜索查询。
如:用户在地图上搜索附近几百米内的饭馆位置。
每一个字符串代表了某一矩形区域。也就是说,这个矩形区域内所有的点(经纬度座标)都共享相同的GeoHash字符串,同时在大部分情况下,字符串前缀匹配越多的距离越近。

划分的矩形区域 这里写图片描述
因此,geoHash做了下列几个动作:
1)GeoHash将二维的经纬度转换成字符串。
2)字符串越长,表示的范围越精确。
3)字符串相似的表示距离相近(大部分情况下是的),可以利用字符串的前缀匹配来查询附近的POI信息点。

因此可以使用geoHash执行2维座标转1维字符串,且转化后的字符串可排序,通过匹配前缀来进行附近搜索。

geoHash的编码方法:逼近编码。
如:北海公园座标 纬度:39.928167 经度:116.389550

1.对纬度执行类似二分法编码。

  1. 将【-90,90】分为左右两部分,【-90,0】左区间和【0,90】右区间,39.928167在右区间范围,赋值1。
  2. 然后将【0,90】分为左右两个区间,【0,45】左区间和【45,90】右区间,39.928167属于左区间,赋值0。
  3. 以此类推,随着算法的进行会产生一个序列10111 00011,序列的长度跟给定的区间划分次数有关。

2.对经度执行类似的二分法编码,序列:11010 01011。
3.组码。

  1. 将经度算出的序列与纬度算出的序列进行组合,偶数位放经度,奇数位放纬度,把2串编码组合生成新串:11100 11101 00100 01111。
  2. 使用0-9、b-z(去掉a, i, l, o)这32个字母进行base32编码,首先将11100 11101 00100 01111转成十进制,对应着28、29、4、15,十进制对应的编码就是wx4g。
  3. 同理,将编码转换成经纬度的解码算法与之相反,具体不再赘述。

GeoHash Base32编码长度与精度
详情见下表: 摘自维基百科:http://en.wikipedia.org/wiki/Geohash
这里写图片描述

GeoHash算法为什么可以实现有序编码

为什么分别给经度和维度编码?为什么需要将经纬度两串编码交叉组合成一串编码?

如图所示,我们将二进制编码的结果填写到空间中,当将空间划分为四块时候,编码的顺序分别是左下角00,左上角01,右下脚10,右上角11,也就是类似于Z的曲线,当我们递归的将各个块分解成更小的子块时,编码的顺序是自相似的(分形),每一个子快也形成Z曲线,这种类型的曲线被称为Peano空间填充曲线。
这种类型的空间填充曲线的优点是将二维空间转换成一维曲线(事实上是分形维),对大部分而言,编码相似的距离也相近, 但Peano空间填充曲线最大的缺点就是突变性,有些编码相邻但距离却相差很远,比如0111与1000,编码是相邻的,但距离相差很大。
这里写图片描述

除Peano空间填充曲线外,还有很多空间填充曲线,如图所示,其中效果公认较好是Hilbert空间填充曲线,相较于Peano曲线而言,Hilbert曲线没有较大的突变。为什么GeoHash不选择Hilbert空间填充曲线呢?可能是Peano曲线思路以及计算上比较简单吧,事实上,Peano曲线就是一种四叉树线性编码方式。

这里写图片描述

使用注意点

1)由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。

这里写图片描述

解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。
2)我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。
3)geohash只是空间索引的一种方式,特别适合点数据,而对线、面数据采用R树索引更有优势(可参考:深入浅出空间索引:为什么需要空间索引)。

转载出处:http://www.cnblogs.com/LBSer

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章