根據自動定位獲取範圍內最近的資訊
阿新 • • 發佈:2019-01-10
以前的一個專案,需求是根據當前使用者上傳的經緯度座標,在資料庫幾十萬萬條資料中查詢出符合“周圍3公里範圍內”條件的座標點。
所以,我首先想到的是,對每條資料去進行遍歷,跟資料庫中的每個點進行距離計算,當距離小於3公里時候,認為匹配成功。經測試,這樣做確實能得到結果,但是效率極其低下,因為每條資料都得去和資料庫中的幾十萬條資料進行比對,其耗費的時間可想而知。對於這種情況,是使用者所無法忍受的。
後來利用正方形的四個點,去和使用者上傳的經緯度進行比較。由此,問題轉向了,如何計算正方形四個點經緯度的問題!
無意中看到一個的帖子,裡面使用python實現了計算四個點經緯度的方法。
其實現原理也是很相似的,先計算出當前點周圍的正方形的四個點,然後使用經緯度直接去資料庫匹配資料
假設已知點的經緯度分別為lng , lat
先實現經度範圍的查詢,在haversin公式中令φ1 = φ2,可得:
** * 計算某個經緯度的周圍某段距離的正方形的四個點 * * @param * radius 地球半徑 平均6371km * @param * lng float 經度 * @param * lat float 緯度 * @param * distance float 該點所在圓的半徑,該圓與此正方形內切,預設值為1千米 * @return array 正方形的四個點的經緯度座標 */ public function returnSquarePoint($lng, $lat, $distance = 1, $radius = 6371) { $dlng = 2 * asin(sin($distance / (2 * $radius)) / cos(deg2rad($lat))); $dlng = rad2deg($dlng); $dlat = $distance / $radius; $dlat = rad2deg($dlat); return array( 'left-top' => array( 'lat' => $lat + $dlat, 'lng' => $lng - $dlng ), 'right-top' => array( 'lat' => $lat + $dlat, 'lng' => $lng + $dlng ), 'left-bottom' => array( 'lat' => $lat - $dlat, 'lng' => $lng - $dlng ), 'right-bottom' => array( 'lat' => $lat - $dlat, 'lng' => $lng + $dlng ) ); }
在lat和lng上建立一個聯合索引後,使用此項查詢,執行效率飛漲。
上面可以取出範圍內的資料資訊,如果單獨需要最近的資訊的話:獲取兩點之間的距離
/** 其中一個經緯度是自動定位獲取的經緯度 */ function getDistanceBetweenPointsNew( $latitude1 , $longitude1 , $latitude2 , $longitude2 ) { $theta = $longitude1 - $longitude2; $miles = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta))); $miles = acos($miles); $miles = rad2deg($miles); $miles = $miles * 60 * 1.1515; $feet = $miles * 5280; $yards = $feet / 3; $kilometers = $miles * 1.609344; $meters = $kilometers * 1000; return compact('miles','feet','yards','kilometers','meters'); } $point1 = array('lat' => 40.770623, 'long' => -73.964367); $point2 = array('lat' => 40.758224, 'long' => -73.917404); $distance = getDistanceBetweenPointsNew($point1['lat'], $point1['long'], $point2['lat'], $point2['long']); foreach ($distance as $unit => $value) { echo $unit.': '.number_format($value,4).'<br />'; } /** 正常情況只需要根據公里引數對比即可 */