PHP+MySQL实现附近地点查询功能

最近接触一个项目,需要根据经纬度计算附近的点。数据量为20w。

如果通过foreach循环MySQL数据库中经纬度,然后再结算距离,速度和性能都会很慢。学习了网上一个方法,特记录下来:

实现原理

算出当前经纬度周围的矩形的四个点,然后使用经纬度去直接匹配数据库中的记录。

map

红色部分为要求的搜索范围,绿色部分我们能间接得到的结果范围。

参考球面的计算公式

假设已知点的经纬度分别为$lng, $lat
先实现经度范围的查询,
在haversin公式中令φ1 = φ2,可得:

jisuan

PHP计算方法如下:

//$lat 已知点的纬度
$dlng = 2 * asin(sin($distance / (2 * EARTH_RADIUS)) / cos(deg2rad($lat)));
$dlng = rad2deg($dlng);//转换弧度

纬度范围的查询,
在haversin公式中令 Δλ = 0,可得

weidu


$dlat = $distance/EARTH_RADIUS;//EARTH_RADIUS地球半径

$dlat = rad2deg($dlat); //转换弧度

最后,就可以得出四个点的坐标:
left-top : (lat + dlat, lng – dlng)
right-top : (lat + dlat, lng + dlng)
left-bottom : (lat – dlat, lng – dlng)
right-bottom: (lat – dlat, lng + dlng)

综合以上步骤,得出具体的方法:


function square_point($lng, $lat,$distance = 0.5){
$earthRadius = 6371; //地球半径,平均半径为6371km
$dlng = 2 * asin(sin($distance / (2 * $earthRadius)) / cos(deg2rad($lat)));
$dlng = rad2deg($dlng);

$dlat = $distance/$earthRadius;
$dlat = rad2deg($dlat);

return array(
'left-top'=>array('lat'=>$lat + $dlat,'lng'=>$lng-$dlng),
'right-top'=>array('lat'=>$lat + $dlat, 'lng'=>$lng + $dlng),
'left-bottom'=>array('lat'=>$lat - $dlat, 'lng'=>$lng - $dlng),
'right-bottom'=>array('lat'=>$lat - $dlat, 'lng'=>$lng + $dlng)
);
}

$squares = square_point($lng, $lat);
$info_sql = "select id,lat,lng from `location` where lat<>0 and lat>{$squares['right-bottom']['lat']} and lat<{$squares['left-top']['lat']} and lng>{$squares['left-top']['lng']} and lng<{$squares['right-bottom']['lng']} ";

以上方法就可以实现查询附近地点的功能了。别忘记添加 经纬度的混合索引。经过计算20w数据几毫秒就可以查询到了。

存在的问题和方法:

1、没办法排序。按照距离排序。

1)、查询出来的结果在计算距离,然后返回。

2)、直接在SQL语句中添加排序。


$info_sql = "select id,lat,lng from `location` where lat<>0 and lat>{$squares['right-bottom']['lat']} and lat<{$squares['left-top']['lat']} and lng>{$squares['left-top']['lng']} and lng<{$squares['right-bottom']['lng']}  order by ABS(lat-当前纬度), ABS(leg-当前经度)" ;

使用百度地图测试,部分Javascript代码如下:

百度地图测试

展示效果如下:

zuobiao

 

PHP+MySQL实现附近地点查询功能》上有1条评论

发表评论

电子邮件地址不会被公开。