PHP實現搜尋附近的人
最近的一個專案要求根據使用者當前位置的經緯度來查詢該使用者方圓十公里以內的人,這個功能並不是什麼很有技術含量的實現(當然,我們僅僅指的是該功能本身和資料量較小的時候,並不包括長期以來其派生出來的其他問題 ),但由於種種考慮,我還是決定將其記錄下來。
以後不管我們從事APP服務端開發,還是做WEB開發,可能經常會有客戶要求實現這樣的功能,所以我們還是要掌握其原理。
【問題的提出】
我們該如何思考這個問題 ? 可能有的小夥伴要說了:“ 既然我們已經知道了當前使用者的經緯度,我們從資料庫裡面查詢使用者的經緯度,然後一一計算,篩選出所有符合條件的使用者。”
我也曾想當然的這樣認為,並沒有考慮到資料庫的感受,當你操作的是一個十萬,百萬級別的資料庫時,這樣的做法帶來的問題將是災難性的,那麼我們到底該如何做呢 ?
【實現思路】
首先,我們應該這樣想: 既然我們知道了使用者當前位置的經緯度,又知道我們將要搜尋的範圍,我們可不可以計算出一個範圍 ?也就是說,根據一箇中心點和半徑,計算出符合條件的經緯度的最大值和最小值 。
【具體實現】
那麼到此,想要獨立思考完成的小夥伴可以不要繼續往下看了。
上面我們提到該功能的一個實現原理,接下來我們就講解一下具體的實現步驟。
我們先宣告一個函式,用作計算經緯度的範圍:
/**
* 根據經緯度和半徑計算出範圍
* @param string $lat 緯度
* @param String $lng 經度
* @param float $radius 半徑
* @return Array 範圍陣列
*/
private function calcScope($lat, $lng, $radius) {
$degree = (24901*1609)/360.0;
$dpmLat = 1/$degree;
$radiusLat = $dpmLat*$radius;
$minLat = $lat - $radiusLat; // 最小緯度
$maxLat = $lat + $radiusLat; // 最大緯度
$mpdLng = $degree*cos($lat * (PI/180));
$dpmLng = 1 / $mpdLng;
$radiusLng = $dpmLng*$radius;
$minLng = $lng - $radiusLng; // 最小經度
$maxLng = $lng + $radiusLng; // 最大經度
/** 返回範圍陣列 */
$scope = array(
`minLat` => $minLat,
`maxLat` => $maxLat,
`minLng` => $minLng,
`maxLng` => $maxLng
);
return $scope;
}
返回的陣列中包含了在 $radius 範圍內,符合條件的最大最小經緯度。
既然我們已經獲取到了範圍,那麼我們就可以開始從資料庫中查詢所有在這個經緯度範圍內符合條件的記錄:
/**
* 根據經緯度和半徑查詢在此範圍內的所有的
* @param String $lat 緯度
* @param String $lng 經度
* @param float $radius 半徑
* @return Array 計算出來的結果
*/
public function searchByLatAndLng($lat, $lng, $radius) {
$scope = $this->calcScope($lat, $lng, $radius); // 呼叫範圍計算函式,獲取最大最小經緯度
/** 查詢經緯度在 $radius 範圍內的電站的詳細地址 */
$sql = `SELECT `欄位` FROM `表名` WHERE `Latitude` < `.$scope[`maxLat`].` and `Latitude` > `.$scope[`minLat`].` and `Longitude` < `.$scope[`maxLng`].` and `Longitude` > `.$scope[`minLng`];
$stmt = self::$db->query($sql);
$res = $stmt->fetchAll(PDO::FETCH_ASSOC); // 獲取查詢結果並返回
return $res;
}
【擴充套件】
直到現在,我們已經知道了如何計算出附近的人,但在實際需求中,我們往往需要計算出每一個人與當前中心點的實際距離。
接著,我們再來看一個方法:
/**
* 獲取兩個經緯度之間的距離
* @param string $lat1 緯一
* @param String $lng1 經一
* @param String $lat2 緯二
* @param String $lng2 經二
* @return float 返回兩點之間的距離
*/
public function calcDistance($lat1, $lng1, $lat2, $lng2) {
/** 轉換資料型別為 double */
$lat1 = doubleval($lat1);
$lng1 = doubleval($lng1);
$lat2 = doubleval($lat2);
$lng2 = doubleval($lng2);
/** 以下演算法是 Google 出來的,與大多數經緯度計算工具結果一致 */
$theta = $lng1 - $lng2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
return ($miles * 1.609344);
}
我們在之前已經計算出了附近符合條件的所有人的經緯度,那麼我們可以將每一個人的經緯度和當前中心點的經緯度作為引數傳入該函式,最終計算出每個人符合條件的人與該中心點的距離。
為了保證程式的嚴謹性,我必須做出以下說明:
經緯度範圍的計算方法是在百度上查詢的,目前尚沒有找到標準的計算工具,因此該演算法無法求證,但大多數帖子基本上採用的這種計算方式。
經緯度距離的計算方式是在 Google 上查詢的,計算結果與大多數計算工具結果相近。之所以在 Google 中查詢,是因為我曾在百度上查詢過多種計算方式,結果都不盡人意。
通過半徑和經緯度計算範圍時,半徑的單位是m;計算距離時,得到的結果是km。因此,要注意單位變化。
我依然在努力求證,尋求有關專業的幫助,獲得更精確的計算結果。
作者:Elvis_Li
連結:http://www.jianshu.com/p/d2080a9b87eb
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
相關文章
- Golang 實現 Redis(9): 使用GeoHash 搜尋附近的人GolangRedis
- 淺談附近地點搜尋
- 通過經緯度計算距離實現附近、附近的人等功能
- 小程式實現附近三公里搜尋和地圖路線導航(改版)地圖
- 用PHP來實現二分搜尋樹(BST)PHP
- Laravel 下 TNTSearch+jieba-PHP 實現中文全文搜尋LaravelJiebaPHP
- PHP - 實現類似於百度的實時搜尋PHP
- Laravel + Elasticsearch 實現中文搜尋LaravelElasticsearch
- Elasticsearch 實現簡單搜尋Elasticsearch
- Jquery + Bootstrap 實現搜尋框jQueryboot
- 實現延遲搜尋功能
- 如何使用 Redis 實現 陪玩原始碼中“附近的人” 這一功能?Redis原始碼
- 如何用Redis實現搜尋介面Redis
- laravel8實現ES搜尋Laravel
- elasticsearch實現基於拼音搜尋Elasticsearch
- ASP智慧搜尋的實現 (轉)
- Redis 實戰 —— 10. 實現內容搜尋、定向廣告和職位搜尋Redis
- [轉載] PHP 基於字典樹演算法實現搜尋聯想功能PHP演算法
- Elasticsearch搜尋功能的實現(五)-- 實戰Elasticsearch
- Sunday搜尋演算法實現演算法
- BM搜尋演算法C實現演算法
- javascript實現二叉搜尋樹JavaScript
- Python如何實現窮舉搜尋?Python
- 基於Elasticsearch實現搜尋建議Elasticsearch
- CSS 實現搜尋相關互動CSS
- 使用 Laravel Scout + ElasticSearch 實現全文搜尋LaravelElasticsearch
- 海量資料搜尋---demo展示百度、谷歌搜尋引擎的實現谷歌
- vue2實現搜尋結果中的搜尋關鍵字高亮Vue
- 【搜尋引擎】 PostgreSQL 10 實時全文檢索和分詞、相似搜尋、模糊匹配實現類似Google搜尋自動提示SQL分詞Go
- 圖的廣度優先搜尋和深度優先搜尋Python實現Python
- DjangoRestFramework 實現分頁功能與搜尋功能DjangoRESTFramework
- 原生javascript實現的選取搜尋元件JavaScript元件
- 微信小程式 簡易搜尋功能實現微信小程式
- Angular6-Filter實現頁面搜尋AngularFilter
- 自己動手實現主題搜尋引擎
- 直播開發app,實時搜尋、搜尋引擎框APP
- 相見恨晚!開源的傻瓜搜尋引擎,幫你快速實現搜尋功能
- PHP 使用 QueryList 輕鬆實現一個百度網盤資源搜尋引擎PHP