学计算机的人可以定位找人吗,电脑如何实现查找“附近的人”?

当我们打开微信的附近的人可以看到附近的朋友,当我们打开美团附近的商家可以查找附近的饭店、影院等等。所有这一切都离不开一个功能:基于LBS的“附近的”功能,那计算机是如何实现这种功能的?本文讨论一下其原理。

经纬度

我们知道地球是圆的,人们为了方便标识地球,在地球上画上了经度和维度,他们就像平面上(x,y)坐标,知道了一个点就能确定一个位置。同样的,现在手机都有GPS定位功能,知道了经纬度,也就知道你在地球上某一点的具体位置。

6fceb352bf93baa3c70b53bce48ee65d.png

球面上两点距离公式

地球是一个椭圆球体,在高中数学里,曾经给出球面上两点之间的距离公式证明,这里给出结论:

642df59f1521f53608be4bec76a3ec88.png

假设地球半径为R,取值为3963km(因为地球不是正圆,他是椭圆,所有R是有变化的), P的经纬度坐标为(lat1,long1), Q的经纬度坐标为(lat2,long2),那么很容易求得地球上 (P,Q)两点的距离公式为:

d = 3963.0 * arccos[(sin(lat1) * sin(lat2)) + cos(lat1) * cos(lat2) * cos(long2 – long1)]有了这个公式, 就可以把这个公式写成一个SQL函数:

go--计算地球上两个坐标点(经度,纬度)之间距离sql函数--作者:lordbabyCREATE FUNCTION [dbo].[fnGetDistance](@LatBegin REAL, @LngBegin REAL, @LatEnd REAL, @LngEnd REAL) RETURNS FLOAT ASBEGIN --距离(千米) DECLARE @Distance REAL DECLARE @EARTH_RADIUS REAL SET @EARTH_RADIUS = 6378.137 DECLARE @RadLatBegin REAL,@RadLatEnd REAL,@RadLatDiff REAL,@RadLngDiff REAL SET @RadLatBegin = @LatBegin *PI()/180.0 SET @RadLatEnd = @LatEnd *PI()/180.0 SET @RadLatDiff = @RadLatBegin - @RadLatEnd SET @RadLngDiff = @LngBegin *PI()/180.0 - @LngEnd *PI()/180.0 SET @Distance = 2 *ASIN(SQRT(POWER(SIN(@RadLatDiff/2), 2)+COS(@RadLatBegin)*COS(@RadLatEnd)*POWER(SIN(@RadLngDiff/2), 2))) SET @Distance = @Distance * @EARTH_RADIUS --SET @Distance = Round(@Distance * 10000) / 10000 RETURN @DistanceEND然后使用:

SELECT * FROM 商家表名 WHERE fnGetDistance(121.4625,31.220937,longitude,latitude) < 5就可以获取距离我最近在5km之内的商家列表.

致命缺陷

在上面公式里,如果数据量较小,使用起来完全没有问题,但是如果数据量很大却有致命缺陷:计算量太大。

例如你的周围有几万甚至几十万人员时,数据库为了判断附近的人需要进行海量计算,在这情况下可能服务器根本吃不消。

GeoHash编码

那如何在减少计算量的情况下,计算附近的人呢?聪明的计算机专家想到了一个办法:把地图分割为一小块,然后给每个小块编号,存储编号的位置。

首先,把地图展开

22ab523416b958811fe18c44ad68cbf2.png

我们以经度0°为中轴,将地球切成两半[-180°,0°),[0°,180°],并对他们进行二进制编码,左边为0,右边为1。那所有经度坐标在左边的,都得到了0这个编码,而其他的则得到1这个编码。

b8f96c64e0f4eabdd51ed9547a6b6529.png

好了,接下来我们就进行第二次切割,还是按照老规矩,我们把现有的两个部分也分别切割成左右两个部分,于是得到这样的一个图

cf2e7c42be2e2a4d64bd91a5a31e8621.png

如此重复下去,这样,地球上每一个小块,都有一个唯一的“编号”, 如此这样重复N次,我们就可以将地球按经度切割成很多很多的小块,如果切割的次数足够多,那同一个经度值的人,都会在同一个小块儿里,可以粗略认为,他们是同一附近的。

c0f171b0ca413a65b25c58df352db3ba.png

GeoHash查找

通过上面分析GeoHash可以看到其有2个最大的特点:

(1)geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。

(2)编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询

SELECT * FROM place WHERE geohash LIKE 'wx4g0e%')这和传统经纬度计算距离最大差别是:把数字计算转换为了字符串查找。在做索引的情况下,计算机查找要比数字计算快的多的多。

MongoDB数据库

目前,对地球的划分有一些组织进行维护,同时在不少noSQL数据库里,已经内置了对GeoHash的支持。例如在MongoDB数据库,只需一个命令即可得到所需要的结果:

db.runCommand( { geoNear: "places", near: [ 121.4905, 31.2646 ], num:100 })查询结果默认将会由近到远排序,而且查询结果也包含目标点对象、距离目标点的距离等信息。

举报/反馈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值