LBS——實現附近功能的幾種方案淺談
一、背景
附近的人、景點,也即POI,這種需求多見於LBS中,這塊不是很專業,也沒有特別去實現過,只是根據網路查詢的相關網友的說法,將幾種實現手段羅列一下。
前提條件說明,做這種需要興趣點的經緯度資訊,以及需要查詢的地點的經緯度資訊,前者屬於歷史資料(更新不頻繁),後者則是在每次查詢的時候都需要變更的。
二、具體實現方法
1、直接利用關係型資料庫進行計算得出距離的方案
1 SELECT 2 id, ( 3 3959 * acos ( 4 cos ( radians(78.3232) ) 5 * cos( radians( lat ) ) 6View Code* cos( radians( lng ) - radians(65.3234) ) 7 + sin ( radians(78.3232) ) 8 * sin( radians( lat ) ) 9 ) 10 ) AS distance 11 FROM markers 12 HAVING distance < 30 13 ORDER BY distance 14 LIMIT 0 , 20;
裡面的三角函式是基於球體進行距離的近似計算,然後根據這個會有一些查詢上的優化,比如先篩選一個矩形區域,然後再進行上面的查詢,類似下面這樣
1 select name, 2 ( 3959 * acos( cos( radians(42.290763) ) 3 * cos( radians( locations.lat ) ) 4 * cos( radians( locations.lng ) - radians(-71.35368) ) 5 + sin( radians(42.290763) ) 6 * sin( radians( locations.lat ) ) ) ) AS distance 7View Codefrom locations 8 where active = 1 9 and locations.lat between X1 and X2 10 and locations.Long between y1 and y2 11 having distance < 10 ORDER BY distance;
具體可以參考Stack Overflow網址,
Find features within given coordinates and distance using MySQL
Fastest Way to Find Distance Between Two Lat/Long Points
2、利用相關資料庫自帶的geo地理處理功能
這個主要就包括了Redis,Mysql(需要5.7版本以上),MongoDB這三種實現方式,三者都是通過資料庫自帶的地理座標處理函式實現給定經緯度查一定範圍內的包含的興趣點,
其中,
Redis利用內部提供的geo指令實現距離的計算以及篩選最近點
Mysql利用spatial資料型別和spatial索引,以及特有的一些函式,例如MBRContains,
MongoDB則是採用geoJSON這種資料格式(這個用的好像還挺多,echarts裡面的地圖功能就有用到這種資料格式,是種規範的地理表示方式),以及相關的地理查詢操作完成一些像是最近距離等的需求
redis的具體實現可以參考這篇文章
Mysql和MongoDB的實現可以參考這篇文章結合官網,
Mysql: LBS實現查詢附近的人 (兩經緯度之間的距離)
3、利用GeoHash演算法結合Mysql或者其他關係型資料庫,自己實現附近點的搜尋
關於geoHash是什麼,可以參考下面這篇文章
裡面說的為了解決臨界點需要附近8個點的hash值,這個計算其實只要掌握經度的二進位制值是從左往右逐漸加1,緯度的值則是從下往上逐漸加1,掌握這個規律剩下的都比較簡單了。
具體原理只要知道字首匹配的位數越多,距離越近即可(距離越近,字首不一定匹配,具體在分界線處有問題,所以通過附近8個點一起計算),具體字首匹配位數和精度的關係可以粗略見下表
至於具體實現不管是php,js還是java都可以在github上找到相關的執行緒程式碼。
使用範例可以參考
開發LBS應用之 根據一點的經緯度實現附近點的查詢 – geohash
最後再提供一個講解geoHash看起來比較高大上的網址
高效的多維空間點索引演算法 — Geohash 和 Google S2
個人理解,就是將多維空間利用一維線段進行填充,最後將二維問題轉換成一維問題,然後在一維的資料上進行索引,最後有個小問題就是對於精度選取是否得當對於問題影響較大,所以根據實際問題需要可能還需要進行對最後結果進行距離的篩選
三、小結
這些都是自己找的相關實現思路,並沒有去特意實現,記錄一下,防止遺忘。
從開發和效率角度來說,
方法3效率最高,但是具體細節調整需要可能會比較多,
方法2效率居中,如果沒接觸過這塊功能,相關api掌握起來可能比較費時,但是會比較省時,
方法1效率最低,實現起來也簡單。
具體開發過程可能需要根據業務需求以及原有業務資料的儲存方式進行合理選擇