GeoHash核心原理解析

原文地址:http://www.cnblogs.com/LBSer/p/3310455.html

geohash for php:附件下載geohash.tar.gz

?

引子

  機機是個好動又好學的孩子,平日里就喜歡拿著手機地圖點點按按來查詢一些好玩的東西。某一天機機到北海公園游玩,肚肚餓了,于是乎打開手機地圖,搜索北海公園附近的餐館,并選了其中一家用餐。

?

  飯飽之后機機開始反思了,地圖后臺如何根據自己所在位置查詢來查詢附近餐館的呢?苦思冥想了半天,機機想出了個方法:計算所在位置P與北京所有餐館的距離,然后返回距離<=1000米的餐館。小得意了一會兒,機機發現北京的餐館何其多啊,這樣計算不得了,于是想了,既然知道經緯度了,那它應該知道自己在西城區,那應該計算所在位置P與西城區所有餐館的距離啊,機機運用了遞歸的思想,想到了西城區也很多餐館啊,應該計算所在位置P與所在街道所有餐館的距離,這樣計算量又小了,效率也提升了。

  機機的計算思想很樸素,就是通過過濾的方法來減小參與計算的餐館數目,從某種角度上講,機機在使用索引技術。

  一提到索引,大家腦子里馬上浮現出B樹索引,因為大量的數據庫(如MySQL、oracle、PostgreSQL等)都在使用B樹。B樹索引本質上是對索引字段進行排序,然后通過類似二分查找的方法進行快速查找,即它要求索引的字段是可排序的,一般而言,可排序的是一維字段,比如時間、年齡、薪水等等。但是對于空間上的一個點(二維,包括經度和緯度),如何排序呢?又如何索引呢?解決的方法很多,下文介紹一種方法來解決這一問題。

  思想:如果能通過某種方法將二維的點數據轉換成一維的數據,那樣不就可以繼續使用B樹索引了嘛。那這種方法真的存在嘛,答案是肯定的。目前很火的GeoHash算法就是運用了上述思想,下面我們就開始GeoHash之旅吧。

一、感性認識GeoHash

首先來點感性認識,http://openlocation.org/geohash/geohash-js/?提供了在地圖上顯示geohash編碼的功能。

1)GeoHash將二維的經緯度轉換成字符串,比如下圖展示了北京9個區域的GeoHash字符串,分別是WX4ER,WX4G2、WX4G3等等,每一個字符串代表了某一矩形區域。也就是說,這個矩形區域內所有的點(經緯度坐標)都共享相同的GeoHash字符串,這樣既可以保護隱私(只表示大概區域位置而不是具體的點),又比較容易做緩存,比如左上角這個區域內的用戶不斷發送位置信息請求餐館數據,由于這些用戶的GeoHash字符串都是WX4ER,所以可以把WX4ER當作key,把該區域的餐館信息當作value來進行緩存,而如果不使用GeoHash的話,由于區域內的用戶傳來的經緯度是各不相同的,很難做緩存。

?

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

?

3)字符串相似的表示距離相近(特殊情況后文闡述),這樣可以利用字符串的前綴匹配來查詢附近的POI信息。如下兩個圖所示,一個在城區,一個在郊區,城區的GeoHash字符串之間比較相似,郊區的字符串之間也比較相似,而城區和郊區的GeoHash字符串相似程度要低些。

?

?

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

二、GeoHash算法的步驟

下面以北海公園為例介紹GeoHash算法的計算步驟

?

2.1. 根據經緯度計算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,序列的長度跟給定的區間劃分次數有關。

根據緯度算編碼?

bitminmidmax
1-90.0000.00090.000
00.00045.00090.000
10.00022.50045.000
122.50033.75045.000
133.750039.37545.000
039.37542.18845.000
039.37540.781542.188
039.37540.0782540.7815
139.37539.72662540.07825
139.72662539.902437540.07825

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

根據經度算編碼

bitminmidmax
1-1800.000180
10.00090180
090135180
190112.5135
0112.5123.75135
0112.5118.125123.75
1112.5115.3125118.125
0115.3125116.71875118.125
1115.3125116.015625116.71875
1116.015625116.3671875116.71875

?

2.2. 組碼

  通過上述計算,緯度產生的編碼為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。同理,將編碼轉換成經緯度的解碼算法與之相反,具體不再贅述。

09185841-f7b45cc7e26b45aeac6ff6dc5fa9708c.png

三、GeoHash Base32編碼長度與精度

  下表摘自維基百科:http://en.wikipedia.org/wiki/Geohash

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

三、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點,然后進行實際距離計算。

? ? ? geohash只是空間索引的一種方式,特別適合點數據,而對線、面數據采用R樹索引更有優勢(可參考:深入淺出空間索引:為什么需要空間索引)。

?

參考文獻:

http://en.wikipedia.org/wiki/Geohash

http://openlocation.org/geohash/geohash-js/?

轉載于:https://www.cnblogs.com/daxuan/p/6780394.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/455833.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/455833.shtml
英文地址,請注明出處:http://en.pswp.cn/news/455833.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉載]流行視頻格式講解

*. MPEG/.MPG/.DAT MPEG也是Motion Picture Experts Group 的縮寫。這類格式包括了 MPEG-1, MPEG-2 和 MPEG-4在內的多種視頻格式。MPEG-1相信是大家接觸得最多的了&#xff0c;因為目前其正在被廣泛地應用在 VCD 的制作和一些視頻片段下載的網絡應用上面&#xff0c;大部分的…

Ajax相關介紹

ajax是什么? AJAX 是與服務器交換數據并更新部分網頁的藝術&#xff0c;在不重新加載整個頁面的情況下。 AJAX 指異步 JavaScript 及 XML&#xff08;Asynchronous JavaScript And XML&#xff09;。 AJAX 是一種在 2005 年由 Google 推廣開來的編程模式。 AJAX 不是一種新的…

解決Ubuntu中文件管理器死掉的情況

有時會遇到Ubuntu文件管理器死掉的情況&#xff0c;怎么點擊都沒有反應&#xff0c;這時只需在終端上運行 ps -A | grep nautilus&#xff0c; 查找文件管理器nautilus對應的pid,然后sudokillpid就可以關閉文件管理器進程&#xff0c;隨便點擊一個文件夾就可以重啟文件管理器了…

element table 怎么知道點擊的是第幾行_el-data-table, 讓CRUD更簡單??

基于Vue2.x, element-ui 2.x&#xff0c;以及開源組件el-form-renderer封裝了一個業務組件el-data-table&#xff0c;已在github開源&#xff0c;其目標是&#xff1a;makes restful api crud easily 特點&#xff1a;1. 使用axios自動發送請求2.自帶新增/修改/刪除邏輯(默認新…

Win10無法使用小娜搜索本地應用問題的解決方案

小娜介紹 win10的Cortana小娜是一個功能非常強大的語音和搜索助手&#xff0c;用戶可以通過小娜助手搜索任意的文件和應用軟件&#xff0c;不過有用戶發現win10的小娜搜索不到已安裝的本地軟件&#xff0c;那么win10小娜助手無法搜索本地應用怎么解決呢&#xff1f;下面小編教大…

樣本量

sklearn實戰-乳腺癌細胞數據挖掘(博客主親自錄制視頻教程) https://study.163.com/course/introduction.htm?courseId1005269003&utm_campaigncommission&utm_sourcecp-400000000398149&utm_mediumshare 根據power&#xff0c;effect size,a,決定樣本量 # -*- cod…

【Python】 dict 以key名 去重運算

將日期相同的數據統計在一起 a_count [ {create_time: 2020-03-05, total_len: 1, count_invite: 1}, {create_time: 2020-03-11, total_len: 2, count_invite: 2}, {create_time: 2020-03-18, total_len: 2, count_invite: 2}, {create_time: 2020-03-06, total_len: 1, …

Vue相關知識總結

Vue簡介 Vue是js的一個庫,類似于JQuery Vue當前版本已經發展到2.X版本,并且現在市面上基本使用的都是2.X版本. 現在一些知名的互聯網公司,例如滴滴,美團等,都在大量的使用vue 本段內容主要講解Vue的基本知識和指令,了解vue的基本概念 注意: Vue 不支持 IE8 及以下版本 vue中…

宏塊幀內預測的具體過程

對一個宏塊進行幀內預測的具體過程如下&#xff1a; &#xff08;1&#xff09;對于8x8色度塊就選擇一種幀內色度預測模式建立相應的幀內預測塊&#xff1b; &#xff08;2&#xff09;按遍歷的方法分別計算4種Intra_16x16幀內預測模式的代價&#xff08;Rdcost16x16&#xf…

qt獲得 cpu 主頻信息_高主頻有什么用?我們玩了幾款3A大作找到答案

[PConline 雜談]對于熱愛游戲的人來說&#xff0c;能在極致特效下流暢運行喜歡的游戲是一件幸事&#xff0c;因此作為影響游戲運算的CPU重要性不容小視。CPU如何判定&#xff1f;眾所周知&#xff0c;核心數和主頻算是判定一個CPU好壞的主要依據&#xff0c;但大多數CPU產品在高…

解決:關于Git無法提交 index.lock File exists的問題

問題 今天提交代碼時&#xff0c;在一次提交&#xff0c;莫名其妙沒成功后&#xff0c;再次用git commit -a命令時&#xff0c;出現以下錯誤&#xff0c;無論是用git還是TortoiseGit等其他客戶端都會出現以下這個問題。。 錯誤日志 $ git commit -a fatal: Unable to create …

span居中

在父元素中加style"text-align:center"; 比如下面這樣 <head></head><body><div style"width:300px;border:1px red solid;text-align:center;"><span style"width:100px;">測試</span></div></bo…

打造自己的 APP「冰與火百科」(一):分析定位

回想自己最開始學習 Android 的動力&#xff0c;其實很簡單&#xff0c;就是想在手機上看到自己設計的 APP。但是在工作后&#xff0c;一直做的都是「別人」的 APP&#xff0c;偶爾還要做一些自己不太認可的設計和交互&#xff0c;從中獲取到的成就感還不及第一次在手機上看到「…

python爬取有道翻譯

python爬蟲爬取有道翻譯教程 編寫環境 為了寶寶們能夠正確讀懂本教程,在正式開始前,寶寶們需要搭建的環境如下: 連接互聯網的win10電腦,(win7也可以)Google瀏覽器(版本無要求)Python(版本3就可以了),如果沒有安裝的小伙伴可以參考python安裝以及版本檢測requests庫(版本沒啥…

PartitionMotionSearch()

Outline: 1、 CFG文件中有關多參考幀的相關選項 2、 多參考幀涉及到的數據結構和全局變量 3、 保存重建圖像為參考幀 4、 編碼一幀前&#xff0c;設置參考幀列表 5、 多參考幀的使用&#xff08;即參考幀的選擇策略問題&#xff09; 6、 遺留問題 1、CFG文件中有關多參考…

bat 發送post請求_get post 請求

HTTP是一個基于TCP/IP來傳遞數據的通信協議。1.GET和POST請求的區別&#xff1f;a: GET/POST本質上都是TCP鏈接&#xff0c;GET傳body和POST拼參數&#xff0c;理論上都是可行的。b: 實際上HTTP協議對URL長度是沒有限制的&#xff1b;限制URL長度大多數是瀏覽器或者服務器的配置…

Safengine Android so加密

公司讓我找一個可以對android&#xff0c;嵌入式和Linux x86平臺的so庫進行加密的工具&#xff0c;我看搞了兩天這個工具&#xff0c;反正也沒用上&#xff0c;就把教程發出來了 下載地址&#xff1a;http://www.safengine.com/mobile/download.html 使用方法&#xff1a; 我使…

boltdb 學習和實踐

golang boltdb的學習和實踐 1. 安裝 go get github.com/boltdb/bolt 2.創建和啟動數據庫 db, err : bolt.Open("my.db", 0600, nil) 其中open的第一個參數為路徑,如果數據庫不存在則會創建名為my.db的數據庫&#xff0c; 第二個為文件操作&#xff0c;第三個參數是可…

【django】使用django-crontab執行django自定義指令

django-crontab 部署 需求&#xff1a;再指定的時間內輸入django的自定義指令&#xff0c;來進行一些需求的操作。 使用流程: 1.安裝&#xff1a; pip install django-crontab 2.配置 settings.py文件: 再settings.py 文件中添加 django-crontab: INSTALLED_APPS (...django…

濾波問題匯總

1。A:JM86里面,GetStrength這個函數中下面這個數組有什么作用呢??byte BLK_NUM[2][4][4] {{{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}},{{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}} ;blk_y (mb_y<<2) (blkQ >> 2) ;blk_x (mb_x<<2)…