java實現搜索附近地點或人的功能


前言

    當前大多數app都有查找附近的功能, 簡單的有查找周圍的運動場館, 復雜的有滴滴, 摩拜查找周圍的車輛. 本文主要闡述查找附近地點的一般實現. 

方案比較

方案1 (性能還不錯)

    數據庫直接存經緯度, 然后計算矩形邊界值, 走索引查詢

方案2 (還沒試過)

    將經緯度轉換成 一個值, 然后進行比較查詢 genhash

    http://blog.csdn.net/newjueqi/article/details/18989867

方案3 (據說高性能, 性能怎樣?待測試)

    mongodb 地理類型, 高性能 http://www.tuicool.com/articles/Jfu6fy

    sqlserver 地理數據 geography https://msdn.microsoft.com/en-us/library/ff929109.aspx

方案1的實現(本文主要闡述此方案)

實現環境: java+MySQL

場景模擬:  張三用戶在成都天府五街查詢周圍10公里內的地點

1. 首先建立經緯度數據, 比如常見地點的經緯度數據庫, 我這里是網上下載的一個shop_area 表數據,里面包含了一些常見地點的經緯度 ,如下圖

2. 然后根據張三用戶所在的經緯度, 以及他要查詢的距離10公里, 得到查詢范圍矩形的四個頂點, 如下圖: 

計算這四個點的 mybatis sql: 

<select id="getCurrentLocationRectangle" parameterType="LocationFilter" resultType="LocationFilter">
    SELECT
        #{myLongitude} - #{distance} / ABS(COS(RADIANS(#{myLatitude})) * 69) AS LongitudeMin, #{myLongitude} + #{distance} / ABS(COS(RADIANS(#{myLatitude})) * 69) AS LongitudeMax, #{myLatitude} - (#{distance} / 69) AS LatitudeMin, #{myLatitude} + (#{distance} / 69) AS LatitudeMax </select>

3. 將剛才得到的矩形四個點的值代入如下sql 來進行經緯度查詢過濾, 記得經緯度字段要建立索引

 mybatis sql: 

<select id="getUserNearbyAreaList" parameterType="com.anuo.app.modules.coach.entity.CoachFilter" resultType="ShopArea"> SELECT * FROM ( SELECT a.*, GetDistance(#{myLatitude}, #{myLongitude}, a.lat, a.lng) AS distance FROM shop_area a WHERE a.lat BETWEEN #{latitudeMin} AND #{latitudeMax} AND a.lng BETWEEN #{longitudeMin} AND #{longitudeMax} ) z <where> <if test="distance > 0 "> AND z.distance &lt; #{distance} </if> </where> ORDER BY z.distance LIMIT #{pageStart},#{pageSize} </select>

因為先是通過四個點走索引過濾的經緯度數據, 所以大大提升了效率. 並且將我們想要的10公里范圍內的經緯度數據過濾了出來, 雖然多查詢了點數據(見下圖四個叉叉處), 見下面第四步, 將多余的剔除掉

4.上面sql中的   AND z.distance &lt; #{distance}  即 AND z.distance 小於指定距離 #{distance}, 是將下圖畫叉叉部分的經緯度數據剔除,這些數據是多余的, 因為為我們要查詢的是圓圈內的數據

這里用到了一個MySQL  GetDistance 函數, 代碼如下

DELIMITER $$

USE `anuoapp`$$ DROP FUNCTION IF EXISTS `GetDistance`$$ CREATE DEFINER=`root`@`localhost` FUNCTION `GetDistance`( myLatitude DECIMAL(11,8),#我當前位置的緯度 myLongitude DECIMAL(11,8),#我當前位置的經度 latitude DECIMAL(11,8), Longitude DECIMAL(11,8) ) RETURNS DOUBLE BEGIN RETURN ( 6371 * ACOS( COS(RADIANS(myLatitude)) * COS(RADIANS(latitude)) * COS(RADIANS(Longitude) - RADIANS(myLongitude)) + SIN(RADIANS(myLatitude)) * SIN(RADIANS(latitude)) ) ); END$$ DELIMITER ;

 最后查詢出張三在成都天府五街周圍10公里內的地點

請求url: http://localhost:8080/v1/apiGetUserNearbyArea

請求體: 

{
  "Token":"6850d1c361e9478ca1e94496ec6b27f9", "Version": "1.8.0", "Entities": [ { "myLatitude":30.54286, "myLongitude":104.075569, "distance":10, "pageSize":10, "pageNumber":1 } ], "IsMobile": true, "PageIndex": 1, "IsInnerTest": true, "IsGetIp": false, "PageSize": 38, "IsEncrypt": true, "Parameters": {} } 

響應:

{
    "success": true, "totalRow": 11, "entities": [ { "id": "510122004", "areaname": "中和街道", "parentid": 510122, "shortname": "中和街道", "lng": "104.082375", "lat": "30.559141", "level": true, "position": "tr_0 tr_510000 tr_510100 tr_510122", "sort": 25, "distance": 1.9241037391984028 }, { "id": "510107063", "areaname": "石羊場街道", "parentid": 510107, "shortname": "石羊場街道", "lng": "104.048271", "lat": "30.590687", "level": true, "position": "tr_0 tr_510000 tr_510100 tr_510107", "sort": 12, "distance": 5.925643914100619 }, { "id": "510122122", "areaname": "萬安鎮", "parentid": 510122, "shortname": "萬安鎮", "lng": "104.112701", "lat": "30.487444", "level": true, "position": "tr_0 tr_510000 tr_510100 tr_510122", "sort": 18, "distance": 7.114938271111233 }, { "id": "510122120", "areaname": "新興鎮", "parentid": 510122, "shortname": "新興鎮", "lng": "104.149757", "lat": "30.52656", "level": true, "position": "tr_0 tr_510000 tr_510100 tr_510122", "sort": 21, "distance": 7.332851650201873 }, { "id": "510107007", "areaname": "火車南站街道", "parentid": 510107, "shortname": "火車南站街道", "lng": "104.082924", "lat": "30.619801", "level": true, "position": "tr_0 tr_510000 tr_510100 tr_510107", "sort": 7, "distance": 8.5843717771867 } ] }

 

完整源碼見:  

https://gitee.com/anuo/anuoapp

在此項目中搜索 apiGetUserNearbyArea 接口即可定位

完整數據庫見: 

https://pan.baidu.com/s/1o9lUJMU


免責聲明!

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



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