根据经纬度坐标查询最近的门店

1. 直接通过 mysql 查询

DB::table('shop')->selectRaw("id,lon,lat,
  ROUND(ST_DISTANCE(point(lon,lat),point({$lon},{$lat})) /0.0111,2) distance")
  ->orderBy('distance')
  ->first();

2. 查询所有坐标,循环计算距离

/** 获取用户最近的店铺
 * @param $shopList
 * @param $lon
 * @param $lat
 * @return array
 */
function nearestShop($shopList, $lon, $lat){
    $arr = [];
    foreach ($shopList as $key => $shop){
        $arr[$key] = getDistance($lon, $lat, $shop->lon, $shop->lat);
    }
    asort($arr);    //按距离排序
    return $shopList[array_keys($arr)[0]];
}

/** 根据坐标计算距离
 * @param float $lon1
 * @param float $lat1
 * @param float $lon2
 * @param float $lat2
 * @param int $unit 单位 2是公里
 * @param int $decimal 四舍五入小数点后位数
 * @return float
 */
function getDistance($lon1, $lat1, $lon2, $lat2, $unit = 2, $decimal = 2){
    $EARTH_RADIUS = 6371; // 地球半径系数

    //将角度转为狐度
    $radLng1 = deg2rad($lon1);
    $radLat2 = deg2rad($lat2);
    $radLat1 = deg2rad($lat1);
    $radLng2 = deg2rad($lon2);

    $distance = 2 * asin(sqrt(pow(sin(($radLat1-$radLat2) / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin(($radLng1-$radLng2) / 2), 2))) * $EARTH_RADIUS * 1000;

    if ($unit === 2) {
        $distance /= 1000;
    }
    return round($distance, $decimal);
}
php
本作品采用《CC 协议》,转载必须注明作者和本文链接
所幸无碍
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 7
playmaker

redis GEO不香吗?

2年前 评论
liaosp 2年前
Steven1998 2年前
expectedSelf (楼主) 2年前

2种方法的效率有测过吗

2年前 评论
❤seven 2年前
playmaker

redis GEO不香吗?

2年前 评论
liaosp 2年前
Steven1998 2年前
expectedSelf (楼主) 2年前

你这每次查询都是全表扫描计算`性能有问题 我用过的2种方法来处理LBS问题

  1. 用mysql自带的geohash来处理,这个可以参考mysql文档,给每个坐标生成一个hash值,然后用索引like去查找,长度越长精度越高,但是不能做到自由的精确查找,有一定误差,可以先筛选再计算
  2. 将坐标和id导入到其他支持空间计算的第三方,比如mongo/redis啥,计算查找出来id,再去mysql查询具体数据
2年前 评论

这种需求适合用geo hash 实现

2年前 评论

0.0111 为啥用这个

2年前 评论
expectedSelf (楼主) 2年前

曾经做过,使用 geohash 方案

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!