如题所描述的场景有很多,比如以自己所在的位置为圆点,搜索附近的商铺或者银行等;再或者通过打车软件叫车时,以自己所在位置为圆点,搜索附近可供服务的车辆或司机等。
1 所需要的信息
圆点的位置信息(1个),附近物体上报的位置信息(N个)。
2 常用的技术方案
利用数据库(mysql、oracle)提供的空间解析函数,扫表逐个计算两点之间的距离,然后进行比较判断。此方案当位置表数据量很大时,速度很慢。
3 优化后的方案:Geohash算法+数据库空间解析函数
实现流程简要如下:
(1)司机或车辆的位置信息上报时,使用Geohash算法进行编码后,保存入库。
(2)查询时根据圈选半径选取合适的精读分段级别,依据指定级别查询数据库。
(3)查询的同时,使用空间解析函数进行距离计算并进行过滤。
补充说明:
(1)未防止查询到的数据量过大,可根据距离默认进行排序,限制返回数据的条数。
(2)为减少前期计算的数据量,可通过对数据提前标记业务标签的方式进行提前初筛过滤。
4 实例:
以所处时间(2023-05-16 15:51:36),圈选司机入参: lng:113.814829, lat:22.633092, 圈选半径:50000米, 时间窗口:5min,物理车型:1018,1019,1020,圈选司机:
select tt.driver_id from
(
select
t1.driver_id,
st_distance_sphere(ST_POINTFROMTEXT('POINT(113.814829 22.633092)'),t1.gis) as distance
from driver_location_info t1
inner join driver_tag_info t2
on t1.driver_id = t2.driver_id
where
t1.geo_hash_three in ( 'ws0' , 'ws2' , 'ws3' , 'ws1' , 'wec' , 'web' , 'w7z' , 'wkp' , 'wkr' )
and t2.physics_vehicle_id in (1018,1019,1020)
and t1.location_time BETWEEN '2023-05-16 15:46:36' and '2023-05-16 15:51:36'
) as tt
where tt.distance <= 50000 order by tt.distance asc limit 1000;
MySQL官方提供的空间解析函数
1、Point(x, y)
作用:构造坐标,后面的空间函数会用到。以地球为例,在这个函数里x代表经度,y代表纬度。2、ST_Distance(g1, g2)
作用:计算 g1 和 g2 之间的直线距离。3、ST_Distance_Sphere(g1, g2 [, radius])
作用:MySQL5.7版本新增,用于计算球体上两点之间的最短球面距离(以米为单位),默认半径值为:6,370,986米(地球的半径),不输入radius参数默认计算地球两点之间的最短球面距离。
实例1-使用Mysql空间解析函数,计算两个经纬度点之间的最短球面距离
实例2-使用Mysql空间解析函数,搜索指定范围之内的数据
更多空间解析函数见官方文档:
MySQL5.7版本:
https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html
MySQL8.0版本:
https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html