mysql使用Haversine 公式和ST_Distance_Sphere 函數(shù)實現(xiàn)附近的人功能
對于“附近的人”功能,在生活中是比較常用的,像外賣app附近的美食,共享單車app里附近的車輛等等。我們之前使用 ElasticSearch 實現(xiàn)過該功能,本篇文章我們介紹如何通過 MySQL 來實現(xiàn)“附近的人”功能。

ST_Distance_Sphere 函數(shù)
在 MySQL 中,ST_Distance_Sphere 函數(shù)是一個地理空間函數(shù),用于計算兩個地理位置之間的球面距離。它基于球體模型進行計算,并返回兩個點之間的距離結(jié)果。
ST_Distance_Sphere 函數(shù)的語法如下:
ST_Distance_Sphere(point1, point2)
其中,point1 和 point2 是表示地理位置的 POINT 類型的參數(shù)。
示例一:計算北京站到北京西站的距離
以下是一個使用 ST_Distance_Sphere 函數(shù)計算球面距離的示例:
-- 北京站 116.427322,39.902822 北京西站 116.322083,39.8949
SELECT ST_Distance_Sphere(
POINT(116.427322,39.902822),
POINT(116.322083,39.8949)
) AS distance;在上述示例中,我們使用 POINT 類型的參數(shù)表示兩個地理位置點,分別是北京站(經(jīng)度 116.427322,緯度 39.902822)和北京西站(經(jīng)度 116.322083,緯度 39.8949)。然后,我們調(diào)用 ST_Distance_Sphere 函數(shù)來計算這兩個點之間的球面距離,并將結(jié)果命名為 distance。
返回結(jié)果:
distance
-----------------------
9020.641566063772
ST_Distance_Sphere 函數(shù)的返回值是以米為單位的球面距離,可以根據(jù)需要將結(jié)果轉(zhuǎn)換為千米。上面示例中可以看出,北京站到北京西站的距離約為9公里。
需要注意的是,使用
ST_Distance_Sphere函數(shù)進行球面距離計算需要 MySQL 版本 8.0.17 或更高版本,并且需要在數(shù)據(jù)庫中啟用地理空間功能。
示例二:查詢“附近的人”
要實現(xiàn)"附近的人"功能,可以使用MySQL的ST_Distance_Sphere 函數(shù)和索引來處理地理位置數(shù)據(jù)。下面是一個基本的實現(xiàn)步驟:
(1)創(chuàng)建GEO測試表:其中包括id 主鍵、location地理位置信息。地理位置信息可以使用POINT類型來表示。
CREATE TABLE `test_geo` ( `id` bigint NOT NULL AUTO_INCREMENT, `location` point DEFAULT NULL, PRIMARY KEY (`id`) );
(2)添加地理位置數(shù)據(jù):向表中插入地理位置數(shù)據(jù)。
INSERT INTO `test_geo`(`id`, `location`) VALUES (1, POINT(116.39775,39.92029)), (2, POINT(116.395947,39.916208), (3, POINT(116.410624,39.91871)), (4, POINT(116.397235,39.909823)), (5, POINT(116.385304,39.917591)), (6, POINT(116.396548,39.92832)) ;
(3)創(chuàng)建地理索引:為該表的地理位置字段創(chuàng)建索引,以便進行空間查詢。
CREATE SPATIAL INDEX idx_location ON test_geo (location);
(4)查詢附近的人:使用地理空間函數(shù)進行附近的人查詢。
SELECT
*,
ST_Distance_Sphere ( POINT ( 116.410539, 39.912983 ), location ) AS distance -- 返回距離,單位M
FROM
test_geo
WHERE
ST_Distance_Sphere ( POINT ( 116.410539, 39.912983 ), location ) <= 2000 -- 兩公里內(nèi)
ORDER BY
distance -- 由近及遠排序
; 上述查詢使用了ST_Distance_Sphere函數(shù)來計算兩個地理位置之間的球面距離,POINT ( 116.410539, 39.912983 ) 是你的坐標,2000是查詢半徑。這個查詢將返回在給定半徑范圍內(nèi)的數(shù)據(jù)。
查詢結(jié)果:

Haversine 公式
ST_Distance_Sphere 函數(shù)要求MySQL 的版本為 8.0.17 或更高,對于低版本的 MySQL 該怎么辦呢?我們可以使用 Haversine 公式來實現(xiàn)。
Haversine 是一種常用的球面三角函數(shù),用于計算兩個球面位置之間的球面距離。它是根據(jù)地球的球體模型進行計算的,可以用于近似計算兩個經(jīng)緯度坐標之間的球面距離。
Haversine 公式基于球面三角學(xué)和經(jīng)緯度之間的關(guān)系。它的公式如下:
a = sin2(Δlat/2) + cos(lat1) * cos(lat2) * sin2(Δlon/2) c = 2 * atan2(√a, √(1-a)) d = R * c
其中:
lat1和lat2是兩個點的緯度(以弧度表示)。lon1和lon2是兩個點的經(jīng)度(以弧度表示)。Δlat是緯度之差,即lat2 - lat1。Δlon是經(jīng)度之差,即lon2 - lon1。R是地球的半徑,常用的單位是千米或英里。
通過應(yīng)用 Haversine 公式,可以近似計算出兩個經(jīng)緯度坐標之間的球面距離。這個公式考慮了球體的曲率,因此對于較短距離的計算具有較高的精度。然而,對于較長距離,特別是跨越大片陸地或海洋的距離,Haversine 公式可能會引入一定的誤差。
在使用 Haversine 公式進行計算時,需要注意輸入的經(jīng)緯度必須使用弧度表示。如果經(jīng)緯度是以度數(shù)表示,需要將其轉(zhuǎn)換為弧度形式進行計算。
示例一:計算北京站到北京西站的距離
以下是一個使用Haversine公式計算球面距離的示例:
-- 北京站 116.427322,39.902822 北京西站 116.322083,39.8949
select (2 * 6371 * ASIN(SQRT(
POWER(SIN((RADIANS(39.902822) - RADIANS(39.8949)) / 2), 2) +
COS(RADIANS(39.902822)) * COS(RADIANS(39.8949)) * POWER(SIN((RADIANS(116.427322) - RADIANS(116.322083)) / 2), 2)
))) AS distance在上述示例中,我們分別將北京站(經(jīng)度 116.427322,緯度 39.902822)和北京西站(經(jīng)度 116.322083,緯度 39.8949)的經(jīng)緯度數(shù)據(jù)帶入Haversine公式中,然后就可以計算出這兩個點之間的球面距離,并將結(jié)果命名為 distance。
返回結(jié)果:
distance
-----------------------
9.020661388581411
Haversine公式的返回值是以千米為單位的球面距離。
示例二:查詢“附近的人”
我們可以使用Haversine公式來實現(xiàn)"附近的人"功能,下面是一個基本的實現(xiàn)步驟:
(1)創(chuàng)建GEO測試表:其中包括id 主鍵、地理位置信息。地理位置信息可以使用lng表示經(jīng)度,lat表示緯度。
CREATE TABLE `test_geo` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `lng` double DEFAULT NULL, `lat` double DEFAULT NULL, PRIMARY KEY (`id`) );
(2)添加地理位置數(shù)據(jù):向表中插入地理位置數(shù)據(jù)。
INSERT INTO `test_geo`(`id`, `lng`, `lat`) VALUES (1, 116.39775, 39.92029), (2, 116.395947, 39.916208), (3, 116.410624, 39.91871), (4, 116.397235, 39.909823), (5, 116.385304, 39.917591), (6, 116.396548, 39.92832) ;
(3)查詢附近的人:使用Haversine公式進行附近的人查詢。
SELECT
*,
(2 * 6371 * ASIN(
SQRT(
POWER( SIN(( RADIANS( 39.912983 ) - RADIANS( lat )) / 2 ), 2 ) + COS(
RADIANS( 39.912983 )) * COS(
RADIANS( lat )) * POWER( SIN(( RADIANS( 116.410539 ) - RADIANS( lng )) / 2 ), 2 )
))) AS distance -- 返回距離,單位KM
FROM
test_geo
WHERE
(2 * 6371 * ASIN(
SQRT(
POWER( SIN(( RADIANS( 39.912983 ) - RADIANS( lat )) / 2 ), 2 ) + COS(
RADIANS( 39.912983 )) * COS(
RADIANS( lat )) * POWER( SIN(( RADIANS( 116.410539 ) - RADIANS( lng )) / 2 ), 2 )
))) <= 2 -- 兩公里內(nèi)
ORDER BY
distance -- 由近及遠排序
;上述查詢使用了Haversine公式來計算兩個地理位置之間的球面距離,116.410539, 39.912983 是你的坐標,2是查詢半徑。這個查詢將返回在給定半徑范圍內(nèi)的數(shù)據(jù)。
查詢結(jié)果:

總結(jié)
使用 MySQL 來實現(xiàn)“附近的人”功能,可以通過Haversine 公式和ST_Distance_Sphere 函數(shù)兩種方式來實現(xiàn)。對于低版本的 MySQL 只能使用Haversine 公式,但我們還是推薦升級你的 MySQL(8.0.17版本或更新),因為使用ST_Distance_Sphere 函數(shù)不僅使用簡單,而且它還支持空間索引,使得查詢速度更快。
到此這篇關(guān)于mysql實現(xiàn)附近的人功能的文章就介紹到這了,更多相關(guān)mysql附近的人內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Winserver2012下mysql 5.7解壓版(zip)配置安裝教程詳解
這篇文章主要介紹了Winserver2012下mysql 5.7解壓版(zip)配置安裝教程詳解,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-01-01
MySql 8.0及對應(yīng)驅(qū)動包匹配的注意點說明
這篇文章主要介紹了MySql 8.0及對應(yīng)驅(qū)動包匹配的注意點說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06

