距離的計算及分頁排序

2022-07-15 05:15:11 字數 2875 閱讀 9103

作為乙個基於lbs的o2o電商平台,要給使用者提供 周邊的精準的商品和商家的定位及排序。距離的計算和排序問題就擺在我們面前。

有了使用者和商家的座標位址就可以計算距離。其實就是計算球面上兩個點的曲線距離

計算公式為:

r = 地球半徑

δlat = lat2− lat1;

δlong = long2− long1

a = sin²(δlat/2) + cos(lat1) * cos(lat2) * sin²(δlong/2)

c = 2*atan2(√a, √(1−a));

d = r*c

mysql計算表示式:3956 * 2 * asin ( sqrt (

power(sin((orig.lat - dest.lat)*pi()/180 / 2), 2)   

+  cos(orig.lat * pi()/180) * cos(dest.lat * pi()/180) *  power(sin((orig.lon - dest.lon) * pi()/180 / 2), 2)  ) )

(這裡面的3956 單位是英里,公里為6378)

看到計算公式是不是很複雜 很頭疼,我也是 我忽然想起老祖宗的勾股定理,看看能不能把這一坨公式簡化一下。

我們做的是 身邊o2o 社群電商型,距離都不會太遠,所以可以看作是平面上的兩個點的距離計算。

round(sqrt( power(85.39*(store_lng-".$lng."),2)+power(111.13*(store_lat-".$lat."),2) ),3)

這樣只能減少計算距離的計算量,當商戶資訊較多時,排序壓力還是很大。此時 我們還要再減小搜尋範圍,

減小搜尋範圍到 周圍3km的正方形中。

$max_lng = $lng + $km/85.39;

$min_lng = $lng - $km/85.39;

$max_lat = $lat + $km/111.13;

$min_lat = $lat - $km/111.13;

select

round(sqrt( power(85.39*(store.store_lng-".$lng."),2)+power(111.13*(store.store_lat-".$lat."),2) ),3) as juli

from store

where (store.store_lng between  ".$min_lng." and ".$max_lng." ) and ( store.store_lat between ".$min_lat." and ".$max_lat.")

另外在資料表中的 lng和lat 欄位加聯合索引 。 這樣就解決了查詢 效率問題。

看來 問題解決的差不多了,做個壓測吧。

我勒個去   壓力一大  好慢呀。

排查原因: (1)由於每人的座標不同,導致每次執行的sql語句不同,sql無法做快取。

(2)由於(1)的原因 ,伺服器也不能快取資料,每次都是新的請求,每次都要查庫。

看來非要出殺手鐗了,geohash 登場了。(本來想在二期再加)

原理: 首先將緯度範圍(-90, 90)平分成兩個區間(-90,0)、(0, 90),如果目標緯度位於前乙個區間,則編碼為0,否則編碼為1。由於39.92324屬於(0, 90),所以取編碼為1。然後再將(0, 90)分成 (0, 45), (45, 90)兩個區間,而39.92324位於(0, 45),所以編碼為0。以此類推,直到精度符合要求為止。經度也用同樣的演算法,對(-180, 180)依次細分,得到116.3906的編碼。接下來將經度和緯度的編碼合併,奇數字是緯度,偶數字是經度,得到編碼 11100 11101 00100 01111 00000 01101 01011 00001。最後,用0-9、b-z(去掉a, i, l, o)這32個字母進行base32編碼。

由於geohash 的有邊緣偏差,所以準確度要求高的話,可以加查附件8個區塊的資訊。

$geohash_arr=geohash::around($lng,$lat,$km);

$where="  ((geohash like '%')  or (geohash like '%') "

." or (geohash like '%') or (geohash like '%')"

." or (geohash like '%') or (geohash like '%')"

." or (geohash like '%') or (geohash like '%')"

." or (geohash like '%') )";

public static function around($lng,$lat,$km=3)

else if($km>3)

else if($km>1)

else

$hash=self::encode($lng, $lat, $n);

$ret=self::expand($hash);

array_push($ret,$hash);

return $ret;

}/* * * 獲取擴充套件的hash區塊

* return array

*/public static function expand($hash)

這樣就解決了 併發下 資料庫查詢壓力大的問題。距離的排序也由資料庫 改為了web伺服器。

再優化的話,可以 在資料庫 加冗餘字段,比如geohash4,geohash5,geohash6 分別代表 4位的hash值,5位的hash值,6位的hash值。

店鋪經緯度計算距離然後分頁排序

根據經緯度計算距離,根據距離排序或者是根據店鋪銷量排序 如下 topapi user.shop.list 店鋪分頁距離排序 介面作用說明 public apidescription 店鋪列表 定義api傳入的應用級引數 desc 用於在呼叫界面前,根據定義的引數,過濾必填引數是否已經參入,並且定義引...

通過日期計算距離當前時間的距離

格式1 通過 2014 12 11 22 22 22 獲得 今天22 22 昨天22 22 2天前 1個月前 3年前 nsstring datestr 2015 01 15 22 22 22 nsdateformatter dateformat nsdateformatter alloc init ...

c 及JS計算兩經緯度的距離

經緯度計算距離原理 js 如下 var radlat1 rad lat1 var radlat2 rad lat2 var a radlat1 radlat2 var b rad lng1 rad lng2 var s 2 math.asin math.sqrt math.pow math.sin ...