揭秘你所看不见的技术原理 - 附近的人

摘要


相信很多朋友都用到过微信附近的人功能,这个神奇的功能让陌生人能成为朋友、聊友、饭友,甚至能帮助一些朋友解决自身的一些生理需求。点开附近的人,就能显示附近的人甚至是附近的异性,真是一级棒。
但是大家在使用这个功能时有没有想过技术方面的实现原理呢?系统是如何在我们点开附近的人时,帮我们选出附近的人,同时还能计算出距离。接下来我们就来揭秘附近的人这个技术魔法。

定位原理


说到定位其实是离不开定位系统,例如GPS与北斗系统等。这些系统能提供给我们位置信息,也就是我们所处的经纬度。理想状态下,我们拿到经纬度后就能依据每一个用户的经纬度来计算附近的人了。那事实是不是这样呢?
当然不是,如果是这样我这篇文章也就没必要写了,技术点门槛也太低了。那为何不能这么做?其实原因很简单,像微信这种用户动不动就过亿的app,如果每一次定位都依据用户原始的经纬度来计算,运算量实在是太大了。首先要计算与亿级用户的距离,然后依据距离排序。要是没有计算机,我们每分钟能计算3个人,每小时能计算180人,每天计算4320人,每年计算1,576,900,这辈子也算不完了,就算计算机能帮助我们提高10万倍的计算速度,这么多人也要算半个小时。
但是有没有发现,我们打开附件的人可能两秒钟就把附件的用户筛选出来了。这么快的速度肯定不是计算所有的经纬度。其实是有一套计算原理的。

1. 对着地图画格子

对于定位系统来说,我们的地球是被一个一个格子构成的,而每一个格子包含着一定的区域。我们拿北京城区为例,在画格子之前是:
这里写图片描述
将地图放入定位系统后,城区就不再是这个样子了,而是被分割成若干个格子,每一个格子都有格子的“名字”:
这里写图片描述
至于如何定义每一块的名称,后续章节-geohash算法会具体提及,这里不再复述。

2. 找到你所在的格子

定义了格子的名称,当然就有他的用处了,不然这不是白白定义了吗。其实在打开微信附近的人时,系统也会把设备的位置信息给记录,这时候系统依据设备的位置信息,通过geohash算法,计算出所在块名称。比如我们在天安门广场时,系统的计算名称可能是“EFACMDH”,名称有多少个字母主要看系统要求的定位精度最高为多少。我们发现设备位置名称的前5个字母是“EFACM”,正好是在地图中正中间的格子中,也就是包含了天安门的格子。但是设备位置名称后面还包含了“DH”,这说明当前格子包含的位置还不够详细,还不能说明设备所在更为精确的位置。因此我们还需要将格子更为细分,将“EFACM”格子放大,为下图:
这里写图片描述
这个范围内的所有格子前5个字符都是“EFACM”,但是都出现了第六个字符,而且第六个字符不同,其实就是因为这些位置范围都在“EFACM”中,只是对“EFACM”放大细分的结果。
而设备的位置信息为“EFACMDH”,也就是当前的位置范围任然不够精确,还需要继续细分,因此我们找出前六个字符为“EFACMD”的格子,再细分,如下图:
这里写图片描述
依据设备的位置编码,我们找出了设备所处的位置在红色框内,这时候我们把设备的位置信息记录在“EFACMDH”框内:
这里写图片描述
这样就将地图画成了格子,并且将设备的位置也记录在的相应的格子中。

3. 小结

整个定位,其实就是不断地进行着地图区域细化过程,我们依据系统设计的最高经度,计算出设备经纬度所在的区块名称,并将设备与经纬度记录在区块中,如下图:
这里写图片描述
接下来就是通过区块名称,将附件的人揪出来了。

揪出附近的人


上面这些区块与名称,作为用户的我们是看不到也不关心的,我们关心的是附近的人是如何选出来并展现在设备中。

1. 揪出第一批人

什么叫做第一批人,其实就像是微信中第一批大约展示20个人,这20人是离我们最近的20人,为了选出这20位好汉,系统进行了如下步骤:
这里写图片描述

  • 找出所有在设备(浅蓝色点)所在的区块“EFACMDH”中的全部设备(蓝黑色的点);
  • 依据浅蓝色点与所有蓝黑色点的经纬度,计算出亮点之间的距离(这个网上有教程,很容易算),并对两点距离进行排序;
  • 读取蓝黑色所有点的用户信息(头像、名称、微信号等等);
  • 按距离有小到大发送给设备并显示在附近的人中。

通过这些步骤,系统既获得了附近人的位置,又获得了用户信息、与当前设备距离等信息。所以说不只是显示距离,甚至附近的人在哪里都可以查询到,只是可能涉及到了用户隐私,不提供这项功能而已。

2. 还想看其他人

当“EFACMDH”区块记录的用户小于20名,或者用户还想查看更多的附近的人时,就需要扩大查询范围了。其实扩大查询范围无非就是减少一位名称,从查询“EFACMDH”变成查询“EFACMD”。流程如下:
这里写图片描述

  • 将名称英文字母减少一位,由“EFACMDH”变成“EFACMD”;
  • 查询区块名称类似于“EFACMD”的所有区块,例如“EFACMDHA”至“EFACMDY”区块,共同组成“EFACMDH”区块;
  • 找出“EFACMD”的所有位置信息,并依据“1. 揪出第一批人”的方法获得排序后的用户信息
  • 将用户信息回传给设备,并显示。

扩大查询范围其实要比查询当前区块的消耗是要大一些的。因为需要将若干个小区块组合成一个大区块;同时还要进行区块名类似性匹配,比精确匹配的消耗是要高上不少的。这就是为何查询附近的人时,都是先显示少数最近的一些人。

3. 小结

知道了附近的人查询原理,是不是觉得原来实现这么简单。其实中间还设计一些hash匹配、数据存储等,只是这些过于技术,与业务联系不紧密,这里也就没必要过深入地研究了。有兴趣的同学可以查阅redis数据库的geohash模块。

geohash算法


本章节与附近人业务关系不大了,而且内容偏技术性,若不是技术方面的同学可以跳过了。

1. geohash简单原理

上面已经把如何查找附近的人技术原理梳理了一遍,但是留下了一个问题是每一个区块都有一个名字,这个名字是如何来的?接下来将揭晓这个谜团。
为了方便提取位置信息,人为地把地球划分了经度与纬度,依据经纬度,又可以画一些经纬度参考线。犹如地球仪中,人为地划分了若干条经度线与纬度线,依据这些参考线我们可以知道某一些位置在参考线以东或者以西、以南或者以北,从而估算出大概的经度纬度。
geohash算法就是依据这个原理,算法思路就是对参考线进行不断细分,判断当前位置是在参考线以东(右)或者参考线以西(左),以东用1来标记,以西用0来标记,最后组成一个01串,再依据01串按照一定的编码格式转换成容易辨认的英文字符+数字的组合。

2. geohash计算过程

依据上述原理,接下来详细介绍一下geohash的计算过程,这里拿经纬度(116.389550, 39.928167)进行算法说明。

a. 纬度计算

中学学过的地理知识知道,地球分为南纬与北纬,分别都是0~90°,但是在计算机中,用文字定义南纬与北纬较为麻烦,所以计算机中用区间定义[-90,0)与[0,90]分为南北纬,同时叫做左右区间。区分了左右区间,接下来就是整个计算过程:

  • 判断当前纬度39.928167是在左区间还是右区间,发现是在右区间[0,90]中,在右区间标识为1;
  • 接着将区间[0,90]进行左右区间二分,二分后为 [0,45),[45,90],可以确定39.928167属于左区间 [0,45),标记为0;
  • 不断重复上述过程39.928167总是属于某个区间[a,b]。随着每次迭代区间[a,b]总在缩小,并越来越逼近39.928167;
  • 依据最大精度,定义一个最大重复次数,这里我们定义为15,这样就能得出一个01字串;
重复数纬度范围左区间右区间39.928167
1[-90.0, 90.0][-90.0, 0.0)[0.0, 90.0]1
2[0, 90.0][0.0, 45.0)[45.0, 90]0
3[0.0, 45.0)[0.0, 22.5)[22.5, 45.0)1
4[22.5, 45.0][22.5, 33.75)[33.75, 45.0]1
5[33.75, 45.0][33.75, 39.375)[39.375, 45.0]1
6[39.375, 45.0][39.375, 42.1875)[42.1875, 45.0]0
7[39.375, 42.1875)[39.375, 40.7812)[40.7812, 42.1875)0
8[39.375, 40.7812)[39.375, 40.0781)[40.0781, 40.7812)0
9[39.375, 40.0781)[39.375, 39.7265)[39.7265, 40.0781)1
10[39.7265, 40.0781)[39.7265, 39.9023)[39.9023, 40.0781)1
11[39.9023, 40.0781)[39.9023, 39.9902)[39.9902, 40.0781)0
12[39.9023, 39.9902)[39.9023, 39.9462)[39.9462, 39.9902)0
13[39.9023, 39.9462)[39.9023, 39.9243)[39.9243, 39.9462)1
14[39.9243, 39.9462)[39.9243, 39.9353)[39.9353, 39.9462)0
15[39.9243, 39.9353)[39.9243, 39.9298)[39.9298, 39.9353)0
  • 纬度最终得到的01字串为:1 0 1 1 1 0 0 0 1 1 0 0 1 0 0

b. 全局计算

经度计算与纬度计算类似,也是依据区间划分,左右判断来进行,这里就不在复述了,给出最终计算结果为:1 1 0 1 0 0 1 0 1 1 0 0 0 1 0,接下来就是如何通过经度与纬度的01字串,编码成相应的字母+数字的组合。

  • 将经度与纬度的01字串进行合并,合并方法为:基数为放纬度,偶数位放经度,如下表:
123456789101112131415161718192021222324252627282930
101110001100100
110100101100010
110110111000010011110000100100
  • 最终字串为:11011, 01110, 00010, 01111, 00001, 00100
  • 将字串转换成十进制,得到:27, 14, 2, 15, 1, 4
  • 对应base32编码表,如下:
数字字符
00
11
22
33
44
55
66
77
88
99
10b
11c
12d
13e
14f
15g
16h
17j
18k
19m
20n
21p
22q
23r
24s
25t
26u
27v
28w
29x
30y
31z
  • 最终得出(116.389550, 39.928167)所在区块为:VF2G14(可能有计算错误,不要在意这些细节)

这就是我们如何通过位置点,计算出位置所在区块的原理了。

3. 计算精度问题

通过上面的计算可以看到,循环计算15次才获得6位geohash字串,那6位geohash的精度是多少呢?如下表:

geohash长度纬度位数经度位数纬度误差经度误差距离误差(km)
123± 23± 23± 2500
255± 2.8± 56± 630
378± 0.7± 0.7± 78
41010± 0.087± 0.18± 20
51213± 0.022± 0.022± 2.4
61515± 0.0027± 0.0055± 0.61
71718± 0.00068± 0.00068± 0.076
82020± 0.000086± 0.000172± 0.01911
92223± 0.000021± 0.000021± 0.00478
102525± 0.00000268± 0.00000536± 0.0005971
112728± 0.00000067± 0.00000067± 0.0001492
123030± 0,00000008± 0.00000017± 0.0000186

可以看出geohash的长度达到6个字符的误差是610m,长度达到8以上时精度已经达到了10m级。
但是当前民用领域定位系统的定位误差都在10m以上,如果在城区由于高楼、大树等影响定位系统型号,所以误差可以达到50m(不要看到导航软件那么准就认为没有误差,其实那是经过了强大的数据修正)。所以通过geohash定位附近的人时,8位已经是极限了,定位系统的精度导致再高的精度已经没有了意义。

总结


以上已经把附近的人找寻原理、定位算法原理都梳理了一遍,是不是觉得自己可以出门去寻找那个附近的人了。
当前移动设备非常发达,每一个智能手机中几乎都会安装GPS或者北斗芯片,而且GPS与北斗系统一直在不断升级,定位的精度也越来越高。这样附近的人算法精度也就越来越高。同时设备提供的API也非常容易使用,也为基于位置的服务变得(LBS)非常发达。相信通过原理的讲解能让大家更为了解隐藏在底层的东西。

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值