基於地理位置演算法GeoHash核心原理解析

2021-09-26 18:13:26 字數 3105 閱讀 9879

geohash base32編碼長度與精度

具體應用

geohash將二維的經緯度轉換成字串,如北京9個區域的geohash字串,分別是wx4er,wx4g2、wx4g3等等,每乙個字串代表了某一矩形區域

因此這個矩形區域內所有的點(經緯度座標)都共享相同的geohash字串,

左上角這個區域內的使用者不斷傳送位置資訊請求餐館資料,由於這些使用者的geohash字串都是wx4er,所以可以把wx4er當作key,把該區域的餐館資訊當作value來進行快取,而如果不使用geohash的話,由於區域內的使用者傳來的經緯度是各不相同的,很難做快取。

字串越長,表示的範圍越精確。如圖所示,5位的編碼能表示10平方千公尺範圍矩形區域,而6位編碼能表示更精細的區域(約0.34平方千公尺)

字串相似的表示距離相近(特殊情況後文闡述),這樣可以利用字串的字首匹配來查詢附近的poi資訊。如下兩個圖所示,乙個在城區,乙個在郊區,城區的geohash字串之間比較相似,郊區的字串之間也比較相似,而城區和郊區的geohash字串相似程度要低些。

通過上面的介紹我們知道了geohash就是一種將經緯度轉換成字串的方法,並且使得在大部分情況下,字串字首匹配越多的距離越近,回到我們的案例,根據所在位置查詢來查詢附近餐館時,只需要將所在位置經緯度轉換成geohash字串,並與各個餐館的geohash字串進行字首匹配,匹配越多的距離越近。

以北海公園為例介紹geohash演算法的計算步驟

根據經緯度計算geohash二進位制編碼

地球緯度區間是[-90,90], 北海公園的緯度是39.928167,可以通過下面演算法對緯度39.928167進行逼近編碼:

1)將區間[-90,90]轉換為[-90,0],[0,90],可以確定39.928167屬於右區間[0,90],給標記為1;

2)接著將區間[0,90]進行二分為 [0,45),[45,90],可以確定39.928167屬於左區間 [0,45),給標記為0;

3)遞迴上述過程39.928167總是屬於某個區間[a,b]。隨著每次迭代區間[a,b]總在縮小,並越來越逼近39.928167;

4)如果給定的緯度x(39.928167)屬於左區間,則記錄0,如果屬於右區間則記錄1,這樣隨著演算法的進行會產生乙個序列1011100,序列的長度跟給定的區間劃分次數有關。

根據緯度算編碼

同理,地球經度區間是[-180,180],可以對經度116.389550進行編碼。根據經度算編碼

組碼通過上述計算,緯度產生的編碼為10111 00011,經度產生的編碼為11010 01011。偶數字放經度,奇數字放緯度,把2串編碼組合生成新串:11100 11101 00100 01111。

最後使用用0-9、b-z(去掉a, i, l, o)這32個字母進行base32編碼,首先將11100 11101 00100 01111轉成十進位制,對應著28、29、4、15,十進位制對應的編碼就是wx4g。同理,將編碼轉換成經緯度的解碼演算法與之相反,具體不再贅述。

可以看出,當geohash base32編碼長度為8時,精度在19公尺左右,而當編碼長度為9時,精度在2公尺左右,編碼長度需要根據資料情況進行選擇。

如圖所示,我們將二進位制編碼的結果填寫到空間中,當將空間劃分為四塊時候,編碼的順序分別是左下角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 點,然後進行實際距離計算。

elasticsearch基於地理位置的搜尋

參考 elasticsearch基於地理位置的搜尋,有乙個專門的物件geo point儲存地理位置資訊 經度,緯度 並且提供了一些基本的查詢方法,如geo bounding box。put my geo name 建立了乙個my geo索引,新增了乙個欄位location,它的型別是geo poin...

洋山港 地理位置

洋山港區位於浙江省嵊泗縣境內。由大洋山港口區和小洋山港口區組成。可供開發的深水岸線4900公尺,是上海國際航運中心的深水港區。位於嵊泗海域西部大洋山島的北岸。東北距縣城21.41海浬,西北距上海市蘆潮港18.9海浬。大洋山島海岸線總長16697公尺 其中基岩10214公尺 可利用岸線3200公尺,聖...

geospatial地理位置

redis的geo在redis3.2版本就退出來了推算地理位置資訊,兩地之間的距離 可以查詢一些測試資料 引數 key 緯度,經度 名稱 127.0.0.1 6379 geoadd china city 116.397128 39.916527 beijin integer 1127.0.0.1 6...