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

来源:https://www.cnblogs.com/Gkey55/archive/2018/02/11/8443137.html
-Advertisement-
Play Games

前言 當前大多數app都有查找附近的功能, 簡單的有查找周圍的運動場館, 複雜的有滴滴, 摩拜查找周圍的車輛. 本文主要闡述查找附近地點的一般實現. 搜索附近的人也是同樣的思路. 方案比較 方案1 (性能還不錯) 資料庫直接存經緯度, 然後計算矩形邊界值, 走索引查詢 方案2 (還沒試過) 將經緯度 ...


前言

    當前大多數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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #HTMLTestRunner代碼修改參考 微微微笑 的說明,下麵是鏈接,這個已經說的很詳細了 https://www.cnblogs.com/miniren/p/5301081.html (一) 前言 unittest在命令行輸出測試結果。你可能需要生成一個所有測試的執行結果作為報告或者把測試結果 ...
  • (一) Test Suite測試套件 一個測試套件是多個測試或測試用例的集合,是針對被測程式的對應的功能和模塊創建的一組測試,一個測試套件內的測試用例將一起執行。 應用unittest的TestSuites特性,可以將不同的測試組成一個邏輯組,然後設置統一的測試套件,並通過一個命令來執行測試。這都是 ...
  • 由於本篇博文的項目都很簡單,所以本次開個特例,本次解析兩個項目,但是都很簡單的 項目一:用socket實現文件傳輸 本項目很簡單,作為小項目的預熱的,前面剛學完socket,這裡馬上又利用socket進行項目開發,難不倒各位 項目要求: 1.用socket完成文件上傳功能 2.文件位置可以設置 3. ...
  • 本文主要介紹Hibernate如何實現一對多、多對多表,實現相關操作。 ...
  • 這是畢業校招二面時遇到的手寫編程題,當時剛剛開始學習python,整個棧寫下來也是費了不少時間。畢竟語言只是工具,只要想清楚實現,使用任何語言都能快速的寫出來。 何為最小棧?棧最基礎的操作是壓棧(push)和退棧(pop),現在需要增加一個返回棧內最小值的函數(get_min),要求get_min函 ...
  • 記憶體限制:256 MiB時間限制:1000 ms標準輸入輸出 題目類型:傳統評測方式:文本比較 上傳者: 匿名 記憶體限制:256 MiB時間限制:1000 ms標準輸入輸出 題目類型:傳統評測方式:文本比較 上傳者: 匿名 提交提交記錄統計討論測試數據 題目描述 這是一道模板題。 輸入兩個多項式,輸 ...
  • Description 在組合博弈論中,Nim游戲是一個非常經典的問題,Nim游戲可描述如下:有n堆石子,每堆石子數分別為a1, a2, …, an (ai≥0)。現有兩人輪流從這n堆中取石子,每次必須從某一堆中取任意多的石子,至少要取一個,必須從同一堆中取石子,並且不能超過這一堆石子的總數。如果某 ...
  • 聯編的概念 聯編是指一個電腦程式自身彼此關聯的過程,在這個聯編過程中,需要確定程式中的操作調用(函數調用)與執行該操作(函數)的代碼段之間的映射關係。 意思就是這個函數的實現有多種,聯編就是把調用和對應的實現進行映射的操作。按照聯編進行的階段不同,可分為靜態聯編和動態聯編。 靜態聯編 靜態聯編工作 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...