缘由

本周技术群有一个同学说我们该怎么实现 由近到远的基于地理位置的搜索,我创业做电商的系统做过类似这样的服务,我把我们以前的操作给大家分享下

什么是LBS

LBS 全称是 Location  Based Service ,基于位置的服务。我们可以使用到这种服务,真是由于我国移动设备的大量增加,让我们加速进入了 移动互联网的时代。

由近到远的基于地理位置的搜索  其实就是 通过当前使用用户的经纬度,然后从我们自己的数据库中查出指定范围内(例如5km)的数据,按照由近到远的顺序 进行展示。

这句话中有四个条件

  • 用户的经纬度,我们定义 用户维度为:$lat 、经度:$lng

  • 指定范围,定义范围:distince

  • 数据库中商家的经纬度字段,定义 维度为:lat,经度:lng

  • 计算 用户经纬度 与 数据库中商家的经纬度 距离,由远及近进行排序

接下来,我们一起来用两种方案实现

实现方案一:

这种方案会比较挫,

理想模型计算阀值点

计算某个经纬度的周围某段距离的正方形的四个点

为什么这么计算,我给大家举个例子,如果我们把我们的地球仪中国区域直接摁平,是不是地球仪就灭有弧度了 ,我们理想方式就是在一定距离上这么计算的。计算代码如下

/**
 * php代码
 *计算某个经纬度的周围某段距离的正方形的四个点
 *@param float $lng  经度
 *@param float $lat  纬度
 *@param float $distance  该点所在圆的半径,该圆与此正方形内切,默认值为5千米
 *@return array 正方形的四个点的经纬度坐标
 */
 
function squarePoint($lat, $lng,$distance = 5.0){
   $earth_radius = 6371;//地球半径
   $dlng =  2 * asin(sin($distance / (2 * $earth_radius)) / cos(deg2rad($lat)));
   $dlng = rad2deg($dlng);
   $dlat = $distance/$earth_radius;
   $dlat = rad2deg($dlat);
   return [
      'left-top'    =>['lat'=>$lat + $dlat, 'lng'=>$lng - $dlng],
      'right-top'   =>['lat'=>$lat + $dlat, 'lng'=>$lng + $dlng],
      'left-bottom' =>['lat'=>$lat - $dlat, 'lng'=>$lng - $dlng],
      'right-bottom'=>['lat'=>$lat - $dlat, 'lng'=>$lng + $dlng],
   ];
}

取出用户指定距离的数据

根据上面的方法,我们计算出来了4个点,接下来我们直接从数据库取出符合条件的数据

$geo_data = squarePoint($lat,$lng,$distance);
$left_bottom =  $geo_data['left-bottom'];
$right_top = $geo_data['right-top'];
$lat_min = $left_bottom['lat'];
$lat_max = $right_top['lat'];
$lng_min = $left_bottom['lng'];
$lng_max = $right_top['lng']; $sql = "SELECT * FROM table_name 
WHERE lat > {$lat_min} lat < {$lat_max} and lng > {$lng_min} and lng < {$lng_max} ";

按照距离远近排序

这个将 上面的符合条件的结果集取出来,在代码中排序,计算 两个经纬度之间距离的方法如下

/**
 *
 * 根据经纬度计算距离 单位(公里)
 * @param  $lng1 float 经度1
 * @param  $lat1 float 纬度2
 * @param  $lng2 float 经度1
 * @param  $lat2 float 纬度2
 * @return float
 */
function getdistance($lng1,$lat1,$lng2,$lat2)
{
   $dx = $lng1 - $lng2; // 经度差值
   $dy = $lat1 - $lat2; // 纬度差值
   $b = ($lat1 + $lat2) / 2.0; // 平均纬度
   $Lx = deg2rad($dx) * cos(deg2rad($b)); // 东西距离
   $Ly = deg2rad($dy); // 南北距离
   return round(6371*sqrt($Lx * $Lx + $Ly * $Ly),4);  // 用平面的矩形对角距离公式计算总距离
}

按照方法一计算出来,基本问题不大,但是在数据量大(第二步结果集)到一定程度了是有很严重的效率问题的。这里给出一个衍生版本,直接计算距离

SELECT *,SQRT( POWER( $lat - lat, 2) + POWER($lng  - lng, 2) ) AS d 
FROM table_name 
WHERE (lat BETWEEN $lat_min AND $lat_max ) AND (lng BETWEEN $lng_min AND $lng_max ) AND d < $distance 
ORDER BY d ASC LIMIT 10;

实现方案二

这个方法很快,直接可以SQL实现,由于数据库本身也支持很多函数的,我们直接在数据库本身计算就可以了。具体计算代码如下:

/**
 * $lat:用户维度
 * $lng:用户精度
 * $as_name:查询出来的SQL字段名称
 */
get_distance_sql($lat,$lng,$as_name='distance')
{
   return sprintf('round(6371*sqrt( pow((PI()*(abs(`lat`-%f))/180) * cos(PI()*(`lat`+%f)/360),2) 
   + pow((PI()*abs(`lng`-%f)/180),2)),4) as %s',$lat,$lat,$lng,$as_name);
}

具体SQL如下:

/**
* shop_id 商家id
*/
$sql = "SELECT shop_id,lat,lng,".get_distance_sql( $lat,$lng)." FROM table_name 
WHERE distance< = ".$distance." ORDER BY distance ASC" ;

这样就可以直接查出结果并排序了

结论

以上两种方案中,第二个是我我们当时使用的,我们当时数据库几十万,效率还可以。上百万乃至更高的需要大家去实现了

原文地址:【LBS】基于地理位置的搜索之微信 附近的人 简单实现
标签:lbs   附近的人   由远及近   大众点评

智能推荐

【LBS】基于地理位置的搜索之微信 附近的人 简单实现的更多相关文章

  1. HMS Core基于地理位置请求广告,流量变现快人一步

    对于想买车的用户来说,如果走在路上刷社交软件时突然在App里收到一条广告:"前方500米商圈里的某品牌汽车正在做优惠,力度大福利多."不管买不买,八成都会去看看,原因有三:距离近. ...

  2. 基于LBS的地理位置附近的搜索以及由近及远的排序

    Nosql学习之Redis资料(一) http://redis.io/download 目前基于LBS地理位置的搜索已经应用非常广了,的确是个很方便的东西. 我们做程序的就是要考虑如何通过这些功能,来 ...

  3. #研发解决方案介绍#基于ES的搜索+筛选+排序解决方案

    郑昀 基于胡耀华和王超的设计文档 最后更新于2014/12/3 关键词:ElasticSearch.Lucene.solr.搜索.facet.高可用.可伸缩.mongodb.SearchHub.商品中 ...

  4. html5:地理信息 LBS基于地理的服务和百度地图API的使用

    地理位置请求 单次定位请求getCurrentPosition(请求成功函数,请求失败函数,数据收集方式) 多次定位请求watchPosition(请求成功函数,请求失败函数,数据收集方式) 关闭更新 ...

  5. 微信公众号开发系列-13、基于RDIFramework.NET框架整合微信开发应用效果展示

    1.前言 通过前面一系列文章的学习,我们对微信公众号开发已经有了一个比较深入和全面的了解. 微信公众号开发为企业解决那些问题呢? 我们经常看到微信公众号定制开发.微信公众平台定制开发,都不知道这些能给 ...

  6. 在微信框架模块中,基于Vue&Element前端的微信公众号和企业微信的用户绑定

    在一个和微信相关的业务管理系统,我们有时候需要和用户的微信账号信息进行绑定,如对公众号.企业微信等账号绑定特定的系统用户,可以进行扫码登录.微信信息发送等操作,用户的绑定主要就是记录公众号用户的ope ...

  7. 用postgreSQL做基于地理位置的app(zz)

    前言:项目中用到了postgreSQL中的earthdistance()函数功能计算地球上两点之间的距离,中文的资料太少了,我找到了一篇英文的.讲的很好的文章,特此翻译,希望能够帮助到以后用到eart ...

  8. 强化学习(十八) 基于模拟的搜索与蒙特卡罗树搜索(MCTS)

    在强化学习(十七) 基于模型的强化学习与Dyna算法框架中,我们讨论基于模型的强化学习方法的基本思路,以及集合基于模型与不基于模型的强化学习框架Dyna.本文我们讨论另一种非常流行的集合基于模型与不基 ...

  9. Elasticsearch 基于 URL 的搜索请求

    背景 Elasticsearch 不像关系型数据库,没有简易的 SQL 用来查询数据,只能通过调用 RESTful API 实现查询.大体上查询分为两种,基于 URL 的和基于请求主体的.基于 URL ...

随机推荐

  1. 《软件测试自动化之道》读书笔记 之 基于反射的UI测试

    <软件测试自动化之道>读书笔记 之 基于反射的UI测试 2014-09-24 测试自动化程序的任务待测程序测试程序  启动待测程序  设置窗体的属性  获取窗体的属性  设置控件的属性  ...

  2. Oracle数据导入指定表空间

    1. 打开工具Oracle SQL Plus 以dba身份登录sys用户 sqlplus /nologconn sys@url as sysdba 2. 创建用户并指定表空间 使用客户端工具或者Web ...

  3. 施工测量中Cad一些非常有用的插件

    经常会遇到坐标在cad中批量展点.从cad中批量保存坐标点.导入cad中的坐标怎么才能有点号,怎么快速标注cad里的坐标点··· ··· 这一切都是可以程序化的,cad是可以二次开发的,我经常用易语言 ...

  4. 【iCore1S 双核心板_ARM】例程一:ARM驱动三色LED

    实验原理: 通过STM32的三个GPIO驱动一个三色LED,引脚PF3接蓝色LED(ARM_LEDB), 引脚PF4接绿色LED(ARM_LEDG),引脚PF5接红色LED(ARM_LEDR),  G ...

  5. Java多线程系列——过期的suspend()挂起、resume()继续执行线程

    简述 这两个操作就好比播放器的暂停和恢复. 但这两个 API 是过期的,也就是不建议使用的. 不推荐使用 suspend() 去挂起线程的原因,是因为 suspend() 在导致线程暂停的同时,并不会 ...

  6. Ansible and FileBeta

    使用Ansible通过ssh批量读取和修改Client设备 1. 安装ansible工具 apt-get install ansible 2. 添加需要访问的client信息 ansible配置文件如 ...

  7. Oracle调整内存超出限制出现ORA-27100: shared memory realm already exists问题解决办法

    今天测试服务器遇到问题 ORA-04030:out of process memory when trying to allocate string bytes 一看就猜到是内存不足了,把Oracle ...

  8. [Tensorflow] Cookbook - Object Classification based on CIFAR-10

    Convolutional Neural Networks (CNNs) are responsible for the major breakthroughs in image recognitio ...

  9. [Algorithm] Warm-up puzzles

    闲下来后,需要讲最近涉及到的算法全部整理一下,有个indice,方便记忆宫殿的查找 MIT的算法课,地球上最好:https://ocw.mit.edu/courses/electrical-engin ...

  10. 大杂烩 -- ArrayList的动态增长 源码分析

    基础大杂烩 -- 目录 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 问题:当ArrayList中放入的元素一直增加会如 ...