Mysql實現按距離排序、范圍查找


 

現在幾乎所有的O2O應用中都會存在“按范圍搜素、離我最近、顯示距離”等等基於位置的交互,那這樣的功能是怎么實現的呢?本文提供的實現方式,適用於所有數據庫。

實現

實現過程主要分為四步: 
1. 搜索 
在數據庫中搜索出接近指定范圍內的商戶,如:搜索出1公里范圍內的。 
2. 過濾 
搜索出來的結果可能會存在超過1公里的,需要再次過濾。如果對精度沒有嚴格要求,可以跳過。 
3. 排序 
距離由近到遠排序。如果不需要,可以跳過。 
4. 分頁 
如果需要2、3步,才需要對分頁特殊處理。如果不需要,可以在第1步直接SQL分頁。

第1步數據庫完成,后3步應用程序完成。

為了方便下面說明,先給出一個初始表結構,我使用的是MySQL:

step1 搜索

搜索可以用下面兩種方式來實現。

區間查找

customer表中使用兩個字段存儲了經度和緯度,如果提前計算出經緯度的范圍,然后在這兩個字段上加上索引,那搜索性能會很不錯。 
那怎么計算出經緯度的范圍呢?已知條件是移動設備所在的經緯度,還有滿足業務要求的半徑,這很像初中的一道平面幾何題:給定圓心坐標和半徑,求該圓外切正方形四個頂點的坐標。而我們面對的是一個球體,可以使用spatial4j來計算。

geohash的原理不講了,詳細可以看這篇文章,講的很詳細。geohash算法能把二維的經緯度編碼成一維的字符串,它的特點是越相近的經緯度編碼后越相似,所以可以通過前綴like的方式去匹配周圍的商戶。 
customer表要增加一個字段,來存儲每個商戶的geohash編碼,並且建立索引。

 

 

 

 

step3 排序

同樣,排序也需要在應用程序中處理。排序基於上面的過濾結果做就可以了Collections.sort(list, comparator)

step4 分頁

如果需要2、3步,只能在內存中分頁,做法也很簡單,可以參考這篇文章

總結

全文的重點都在於搜索如何實現,更好的利用數據庫的索引,兩種搜索方式以百萬數據量為分割線,第一種適用於百萬以下,第二種適用於百萬以上,未經過嚴格驗證。可能有人會有疑問,過濾和排序都在應用層做,內存占用會不會很嚴重?這是個潛在問題,但大多數情況下不會。看我們大部分的應用場景,都是單一種類POI(Point Of Interest)的搜索,如酒店、美食、KTV、電影院等等,這種數據密度是很小,1公里內的酒店,能有多少家,50家都算多的,所以最終要看具體業務數據密度。本文沒有分析原理,只講了具體實現,有關分析的文章可以看參考鏈接。


參考

http://www.infoq.com/cn/articles/depth-study-of-Symfony2 
http://tech.meituan.com/lucene-distance.html 
http://blog.csdn.net/liminlu0314/article/details/8553926 
http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates 
http://www.cnblogs.com/LBSer/p/3310455.html 
http://cevin.net/geohash/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM