国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 利用Java+MySQL實現附近功能實例

利用Java+MySQL實現附近功能實例

2021-03-01 14:50諸葛流云 Java教程

現在很多手機軟件都用附近搜索功能,但具體是怎么實現的呢?下面這篇文章就來給大家介紹關于利用Java+MySQL實現附近功能的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。

前言

在移動互聯網廣泛發展的今天,APP開發成為許多企業進入移動互聯網的首選,筆者開發了眾多的APP,發現很多app都有這樣一個功能,那就是獲取附近的人,怎么樣來獲取附近的人呢?其實很簡單,就是要時刻記錄用戶的坐標(經緯度)信息到數據庫中,然后根據當前用戶的坐標,搜索數據庫中,和當前坐標位置在 一定范圍內的所有用戶。

其實對于那種地理位置不會變的兩個主體之間的距離,最好是直接將結果靜態化。也就是直接寫死在配置里。

比如,找自己家附近的地鐵站。

這種情況下,一般而言“家”這個主體是不會輕易“跑來跑去”的。每次查詢都計算一次距離沒什么意義。最好是直接將距離持久化后直接查詢。

另一種情況:

獲取APP用戶所在位置附近的地鐵站

這種情況下,用戶的地理位置是變動的。所以每次都得實時計算實際距離。

實現思路

將地球當做一個標準的球體,使用球面距離公式來計算球面兩點間大圓的弧長。

球面距離

?
1
2
3
4
5
6
7
8
9
public static double getDistance2(double long1, double lat1, double long2, double lat2) {
 lat1 = rad(lat1);
 lat2 = rad(lat2);
 double a = lat1 - lat2;
 double b = rad(long1 - long2);
 double sa2 = Math.sin(a / 2.0);
 double sb2 = Math.sin(b / 2.0);
 return 2 * EARTH_MEAN_RADIUS_KM * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
}

知道兩點之間的經緯度就可以。

當然,這種計算不得不放在數據庫里,然后根據距離排序返回。將上面的公式帶入到SQL里就可以。

附近地鐵站示例

建地鐵站示例表

?
1
2
3
4
5
6
7
CREATE TABLE station
(
 id INT AUTO_INCREMENT PRIMARY KEY,
 name VARCHAR(20) NULL COMMENT '地鐵站名',
 lng DOUBLE NULL COMMENT '經度',
 lat DOUBLE NULL COMMENT '維度'
);

SQL示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SET @targetLat = 31.175702;
SET @targetLng = 121.519095;
SELECT
 s.id ,
 s.name ,
 s.lng ,
 s.lat ,
 ROUND(
 6378.138 * 2 * ASIN(
  SQRT(
  POW(
   SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ) , 2 )
  +
  COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 )
  * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 )
  )
 ) * 1000
 ) AS distance
FROM station s
ORDER BY distance ASC , s.id
LIMIT 20;

其中的targetLat 和 targetLng 就是用戶的地理位置。

這樣的確可以達到目的。但是,這是對所有數據先計算了一次和用戶的距離后再排序。

地鐵站的數量太大的時候這種操作可就不太優雅了。不僅不夠優雅,而且效率是很嚇人的。

優化

其實,可以在計算距離之前就將很多數據先過濾掉。

沒必要在 計算上海地鐵站距離的時候將美國的地鐵站距離也計算一遍吧。

這在大多數應用中都可以先將一些不需要的數據過濾掉。

比如在數據是區分城市的情況下就可以將SQL改為下面這樣:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SET @targetLat = 31.175702;
SET @targetLng = 121.519095;
SET @cityId=605;
SELECT
 s.id ,
 s.name ,
 s.lng ,
 s.lat ,
 ROUND(
 6378.138 * 2 * ASIN(
  SQRT(
  POW(
   SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ) , 2 )
  +
  COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 )
  * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 )
  )
 ) * 1000
 ) AS distance
FROM station s
where city_id=@cityId # 先將待計算的數據過濾的一部分
ORDER BY distance ASC , s.id
LIMIT 20;

上面的改進就是先將待計算的數據在計算之前就剔除大部分。找一個長沙地鐵站,沒有必要在上海先找一遍吧。

當然,這種情況比較特殊一點,因為你事先能知道用戶所處的城市。

另一種改進就是:

以用戶所在位置為圓心,畫一個半徑為R的圓,然后反推出這個圓圈的外接四邊形的經緯度范圍。在計算距離之前先將外接四邊形經經緯度之外的數據過濾掉。

指定一個理想的半徑R,先過濾掉不可能符合條件的數據。

反推外接四邊形范圍

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 獲取距離指定經緯度的點{@code radius} KM 的外接四邊形(嚴格來說應該是外接立方體)四個頂點的經緯度
 *
 * @param lng 經度
 * @param lat 緯度
 * @param radius 半徑,單位:KM
 * @return <lng1,lng2,lat1,lat2>
 */
public static Tuple4<Double> calcBoxByDistFromPt(double lng, double lat, double radius) {
 SpatialContext context = SpatialContext.GEO;
 Rectangle rectangle = context.getDistCalc()//
  .calcBoxByDistFromPt(//
   context.makePoint(lng, lat), //
   radius * com.spatial4j.core.distance.DistanceUtils.KM_TO_DEG, context, null//
  );
 return new Tuple4<>(rectangle.getMinX(), rectangle.getMaxX(), rectangle.getMinY(), rectangle.getMaxY());
}

這里用到的工具類maven坐標如下:

?
1
2
3
4
5
<dependency>
 <groupId>com.spatial4j</groupId>
 <artifactId>spatial4j</artifactId>
 <version>0.5</version>
</dependency>

此時的SQL可以改成這樣:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SET @targetLat = 31.175702;
SET @targetLng = 121.519095;
SELECT
 s.id ,
 s.name ,
 s.lng ,
 s.lat ,
 ROUND(
 6378.138 * 2 * ASIN(
  SQRT(
  POW(
   SIN( ( @targetLat * PI() / 180 - s.lat * PI() / 180 ) / 2 ) , 2 )
  +
  COS( @targetLat * PI( ) / 180 ) * COS( s.lat * PI( ) / 180 )
  * POW( SIN( ( @targetLng * PI() / 180 - s.lng * PI() / 180 ) / 2 ) , 2 )
  )
 ) * 1000
 ) AS distance
FROM station s
WHERE
 ( s.lng BETWEEN ${lng1} AND ${lng2} )
 AND ( s.lat BETWEEN ${lat1} AND ${lat2} )
ORDER BY distance ASC , s.id
LIMIT 20;

上面的 lng1,lng2,lat1,lat2 就是外接四邊形的范圍。

引用資料:http://blog.csdn.net/a364572/article/details/50483568

示例源碼

service:https://github.com/hylexus/bl...

初始化數據:https://github.com/hylexus/bl...

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://segmentfault.com/a/1190000012314546

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 久久精品99国产精品日本 | 久久久久久久国产精品 | 欧洲成人在线 | 成人a在线| 日本不卡免费一区二区三区综合久久 | 国产综合亚洲精品一区二 | 国产精品久久久久久久久免费桃花 | 午夜视频在线免费看 | 日本一区二区三区免费观看 | 久久久亚洲 | 国产一区二区三区四 | 国产欧美一区二区精品性色 | 国产精品2 | 久久夜色精品国产 | 一区二区免费在线观看 | 欧美一级特黄aaaaaaa在线观看 | 亚洲乱码国产乱码精品精软件 | 免费观看污污视频 | av在线网址观看 | 日韩欧美综合 | 激情视频网站 | av私库在线观看 | 国产精品中文字幕在线观看 | 国产精品三级视频 | 精品视频网 | 亚洲精美视频 | 天堂一区二区三区在线 | 欧美国产精品一区二区三区 | 在线激情视频 | 性欧美精品高清 | 日韩中文字幕视频 | 欧美日韩一区二区三区免费视频 | 亚洲成人自拍 | 国产精品久久久久久久久久东京 | 国产精品久久久久久久久久东京 | 91久久精品一区二区二区 | 久久思久久 | 欧美日韩精品一区二区三区四区 | 国产一区日韩精品 | 91黄视频| 国产精品视频免费观看 |