经纬度距离排序算法

已知数据库中有很多位置经纬度坐标 lng 、 lat,将这些位置按照距已知位置A(坐标 $lng 、$lat)的距离升序排序

SQL 语句

数据量小直接用SQL查询即可

升序排序示例:distance 是计算出来的距离单位是公里

 $sql = "select *, ACOS(SIN(( $lat * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS(( $lat * 3.1415) / 180 ) * COS((lat * 3.1415) / 180 ) *COS(( $lng * 3.1415) / 180 - (lng * 3.1415) / 180 ) ) * 6380 as distance from `store` where (`status` = '1') and `type_id` = '1'  order by `distance` asc limit 30 offset 30";

Laravel 中

升序排序示例:distance 是计算出来的距离单位是公里


 $distance = "ACOS(SIN(( $lat * 3.1415) / 180 ) *SIN((lat * 3.1415) / 180 ) +COS(( $lat* 3.1415) / 180 ) * COS((lat * 3.1415) / 180 ) *COS(( $lng* 3.1415) / 180 - (lng * 3.1415) / 180 ) ) * 6380";

$list     = $this->model->select('*')->addSelect(\DB::raw($distance . ' as distance'))->orderBy('distance', 'ASC')->get()->toArray();

dd($list);

Redis Geo 方式

数据量大的情况下要考虑elasticssearch、Redis、MongoDB 等第三方存储,性能更佳。

1、创建Redis数据源:通过 geoAdd 方法将数据库中的位置坐标存储到redis中

geoadd 方法:用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。

Redis::geoAdd($key, $lng, $lat, $member);

2、获取排序好的位置列表

georadius 方法:以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

public static function geoRadius($key, $lng, $lat, int $distance = 500, string $unit = 'km', array $options = ['WITHDIST', 'ASC'])
{
    return Redis::geoRadius($key, $lng, $lat, $distance, $unit, $options);
}