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

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