http://www.wubiao.info/372
随着移動終端的普及,很多應用都基于LBS功能,附近的某某(餐館、銀行、妹紙等等)。
基礎資料中,一般儲存了目标位置的經緯度;利用使用者提供的經緯度,進行對比,進而獲得是否在附近。
目标:
查找附近的XXX,由近到遠傳回結果,且結果中有與目标點的距離。
針對查找附近的XXX,提出兩個方案,如下:
一、方案A:
=================================================================================================
抽象為球面兩點距離的計算,即已知道球面上兩點的經緯度;
點(緯度,經度),A($radLat1,$radLng1)、B($radLat2,$radLng2);
優點:通俗易懂,部署簡單便捷
缺點:每次都會查詢資料庫,性能堪憂
1、推導
通過餘弦定理以及弧度計算方法,最終推導出來的算式A為:
1 | |
目前網上大多使用Google公開的距離計算公司,推導算式B為:
1 | |
其中 :
$radLat1、$radLng1,$radLat2,$radLng2 為弧度
$R 為地球半徑
2、通過測試兩種算法,結果相同且都正确,但通過PHP代碼測試,兩點間距離,10W次性能對比,自行推導版本計算時長算式B較優,如下:
//算式A
0.56368780136108float(431)
0.57460689544678float(431)
0.59051203727722float(431)
//算式B
0.47404885292053float(431)
0.47808718681335float(431)
0.47946381568909float(431)
3、是以采用數學方法推導出的公式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
4、在實際應用中,需要從資料庫中周遊取出符合條件,以及排序等操作,
将所有資料取出,然後通過PHP循環對比,篩選符合條件結果,顯然性能低下;是以我們利用下Mysql存儲函數來解決這個問題吧。
4.1、建立Mysql存儲函數,并對經緯度字段建立索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | |
4.2、查詢SQL
通過SQL,可設定距離以及排序;可搜尋出符合條件的資訊,以及有一個較好的排序
1 | |
二、方案B
=================================================================================================
Geohash算法;geohash是一種位址編碼,它能把二維的經緯度編碼成一維的字元串。
比如,成都永豐立交的編碼是wm3yr31d2524
優點:
1、利用一個字段,即可存儲經緯度;搜尋時,隻需一條索引,效率較高
2、編碼的字首可以表示更大的區域,查找附近的,非常友善。 SQL中,LIKE ‘wm3yr3%’,即可查詢附近的所有地點。
3、通過編碼精度可模糊坐标、隐私保護等。
缺點: 距離和排序需二次運算(篩選結果中運作,其實挺快)
1、geohash的編碼算法
成都永豐立交經緯度(30.63578,104.031601)
1.1、緯度範圍(-90, 90)平分成兩個區間(-90, 0)、(0, 90), 如果目标緯度位于前一個區間,則編碼為0,否則編碼為1。
由于30.625265屬于(0, 90),是以取編碼為1。
然後再将(0, 90)分成 (0, 45), (45, 90)兩個區間,而39.92324位于(0, 45),是以編碼為0,
然後再将(0, 45)分成 (0, 22.5), (22.5, 45)兩個區間,而39.92324位于(22.5, 45),是以編碼為1,
依次類推可得永豐立交緯度編碼為101010111001001000100101101010。
1.2、經度也用同樣的算法,對(-180, 180)依次細分,(-180,0)、(0,180) 得出編碼110010011111101001100000000000
1.3、合并經緯度編碼,從高到低,先取一位經度,再取一位緯度;得出結果 111001001100011111101011100011000010110000010001010001000100
1.4、用0-9、b-z(去掉a, i, l, o)這32個字母進行base32編碼,得到(30.63578,104.031601)的編碼為wm3yr31d2524。
1 2 3 4 5 6 | |
2、政策
1、在緯度和經度入庫時,資料庫新加一字段geohash,記錄此點的geohash值
2、查找附近,利用 在SQL中 LIKE ‘wm3yr3%’;且此結果可緩存;在小區域内,不會因為改變經緯度,而重新資料庫查詢
3、查找出的有限結果,如需要求距離或者排序,可利用距離公式和二維資料排序;此時也是少量資料,會很快的。
3、PHP基類
geohash.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |
三、測試
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
四、總結
方案B的亮點在于:
1、搜尋結果可緩存,重複使用,不會因為使用者有小範圍的移動,直接穿透資料庫查詢。
2、先縮小結果範圍,再運算、排序,可提升性能。
254條記錄,性能對比,
在實際應用場景中,方案B資料庫搜尋可記憶體緩存;且如資料量更大,方案B結果會更優。
方案A:
0.016560077667236
0.032402992248535
0.040318012237549
方案B
0.0079810619354248
0.0079669952392578
0.0064868927001953
五、其他
兩種方案,根據應用場景以及負載情況合理選擇,當然推薦方案B;
不管哪種方案,都記得,給列加上索引,利于資料庫檢索。