附近的人位置距离计算方法

简介:

附近的人的位置用经纬度表示,然后通过两点的经纬度计算距离。根据网上的推荐,最终采用geohash。

geohash的实现java版:

  View Code

原理看起来很容易懂的样子,就是分区编码。但仔细一想却不是那么简单。算法设计,编码设计,为什么相似等等,现在只会痛恨当时为啥不好好学数学。

那么,只要在上传位置信息的时候计算geohash,然后根据geohash的精度前缀进行匹配查询就可以搜索附近的人。但有两个问题。

问题1:

  计算的附近的概念不精准,仅仅只是一个区域,在边界问题上需要考虑。距离相近的在边界位置geohash显示却在两块区域。因此引入周围8个区域来精算中间一个区域的位置。这样做会把中间区域周围的包含,但最大范围无法估量。因为周围8块所代表的的精度算法,仅仅是该区域内的,而不是包含所有。就是说,假如中间区域精度1km以内,我需要将周围的区域加上才能把全部1km以内的位置包含。如下图所示:

我按照0110的编码匹配,只能得到红色区域内的位置。倘若客户站在区域中心,那么正好该区域的精度就是距离客户的最大距离。但是,在其他区域的客户,比如红点。记红点为A点,A点距离最近的除了0110还包括另外三个区域的点。这样,若仅仅只按中心区域0110搜索附近的人反而不是正确的。于是引入周围8个区域的点。这样,可以把0110区域的人的附近的点全部包含。

距离:

   记一个geohash的精度(区域的边长)为len,记最大距离为可以搜索到的最远的附近的位置,记最小距离为该距离内的所有位置必然包含在内。比如最小距离为d,则方圆为d的距离内的所有点都包含。

     位于中心区域0110的人最大附近距离为:两个对角线b=2√2len。最小距离为:a=len

再次重申:可以肯定搜索到一个精度内的所有人,但还可以包含附近大于一个精度达部分人。

问题2:

  距离需要进行2次计算。若有排序概念还需要排序。

我的抉择:

  我选择了匹配前6位,测试距离大概1km以内。然后面临另一个问题:分页。

分页:

客户端滚动加载,我一次查完9个区域内所有点,然后根据时间排序。选取该时间之前的n条记录。第一页就是前n条。第一页最后一条的时间为t1,第二页就是t1时间往前的的n条,以此类推。那么,问题来了。假如第一页花费时间t,在这段时间内,本来第二页的数据位置信息更新(每次更新后时间改变);然后查询第二页的时候,变动的数据不包含在内了。也就是说,遗漏了变化的点。

在我看来,位置信息可以延时,但不要遗漏。因为喜欢查看附近的人的位置通常是实时改变的,而我们遗漏的恰恰就是互相有需求的双方。所以,要一次查询一个很大范围内的数据。

办法:

我一次将9个区域的点全部取出,然后缓存。由于geohash区域内的人共享一个查询,因此将geohash的前缀作为key来缓存该区域附近的点。那么,其他该区域的人也可以使用本次查询的结果。

用java做分页处理。

第一次请求,所有数据缓存。然后取出前n个,如果排序,则排序后的前n个。缓存信息不可以改变。第二次请求,计算缓存的索引n开始的n个。....

 缺点:

我需要每次都计算距离,排序。

思考:

我想要第一次计算完之后缓存数据,然后第二次直接取出想要的部分。进而省略每次的计算。接着,问题来了。

第一次数据库的查询数据缓存,标记为key_all;客户a通过缓存计算距离,排序,放入缓存,标记为key_a;显然,两个缓存有大量的重复数据。如果仅仅是标记索引,那计算结果的部分无法保存,所以需要复制而后修改,而后存储。虽然省略了部分计算,但加大了内存需求。

对于时间和空间的问题,我们再来看需求。需求是附近的人,而我查看附近的人的翻页频率并不高,也就是说每次计算的次数很少。那我可以不用为了减少部分计算而加大存储。因为加大存储需要空间加倍,而减少计算影响不大。所以放弃每人都缓存数据。采用每次翻页时计算需要的数据。

然后,面临两个问题。

第一个:ehcache读取后的数据,被计算修改后缓存相应改变,因为对象引用相同。

然后我花了两天看反射和序列化,最后采用序列化来复制缓存对象。成功后又觉得不对,缓存显然是有序列化的,我干嘛重复加工,找到配置,copyOnRead="true" copyOnWrite="true"。解决。

第二个:排序和分页的计算方法。

客户分页的时候也会传新的位置过来,位置必然发生改变。那么按照上次分页计算的距离就不能使用了。

也就是说,我需要用户只传递一次位置,只在第一页请求的时候传递位置,往后的页码忽略其位置。因此,还需要保存第一次请求的位置。首先我要区分第一次和其他。根据现有标记无法区分,因为是按照时间排序的。所以不能区分,也就不能忽略。也就是,用户每次请求传递位置和时间。查询该位置附近该时间之前的n条记录。

finally:缓存边界

缓存是有时间限制的,如果用户第一页查询完后,第二页缓存更新,第二页就不能和第一页衔接了。

所以,为了逻辑上还是拓扑上啥的,严谨不漏。我不能接着查询第二页了。也就是读取缓存的时候,策略需要改变。若缓存不在,重新缓存数据,并查询第一页,告诉客户端刷新页面而不是请求第二页。缺点是若用户第二页是缓存结束前访问的就只能刷新,用户体验不好。所以还是不提示了?我不是产品,但严谨的态度来说,我悄悄更新?也就是第二页数据若缓存不在,我就接着查询缓存第一页作为第二页给客户端。又想多了,我不是根据页码分页的,而是根据时间分页的。那么缓存更新的时候需不需要限制时间呢。我需要按时间排序,而且需要全部数据缓存。所以不能限制时间。这样,取出新缓存的数据中,前n条,忽视时间。当缓存存在而不更新的时候才按照时间取下一组数据。客户端虽然会发现和第一页一样的数据,但时间不一样了。为了避免缓存边界的发生,我或许应该延长缓存时间。


 

算法遗漏:

假设默认第一次搜索是geohash匹配前6位,1km以内。设计一共2页,翻到第三页的时候就要加载更大范围内的。所以匹配前5位,这样,问题出现了。

重新匹配前5位的时候包含了之前查过的前6位的数据。

我当然可以对比数组,取消已经显示的,或者在查询匹配的时候就直接去除(比如java 8中的stream)。但这样查询语句就变的复杂。比如我的坐标是&lat=39.9346650000&lon=116.3951690000,对应的geohash是:wx4g0tukk10e。第一次匹配前6位的sql:

1  SELECT id, lat, lon, geohash, updatetime FROM user_location
2 WHERE 1=1 
3 and ( 
4 geohash like 'wx4g0t%' or  geohash like 'wx4g0w%' or  geohash like 'wx4g0s%' 
5 or  geohash like 'wx4g0v%' or  geohash like 'wx4g0m%' or  geohash like 'wx4g0q%' 
6 or  geohash like 'wx4g0y%' or  geohash like 'wx4g0u%' or  geohash like 'wx4g0k%')

匹配前5位并去除前6位的

  View Code

这在数据层次一次性搜索增加了比较次数num*6倍。而事实上,我想做缓存的话,key=6和key=5的缓存存在被包含与包含的关系。理想的状态应该是:key=5的所有数据缓存,key=6的缓存持有key=5的缓存。这是一个对我来说复杂的缓存了。我也发现了,当我自习研究某项技术的时候什么都不会,换句话说自己就是代码搬运工而已。

现在的做法是直接缓存数据。以后升级redis了再考虑别的。



本文转自Ryan.Miao博客园博客,原文链接:http://www.cnblogs.com/woshimrf/p/5000123.html,如需转载请自行联系原作者
相关文章
|
4月前
|
存储 机器学习/深度学习 算法
【算法训练-数组 三】【数组矩阵】螺旋矩阵、旋转图像、搜索二维矩阵
【算法训练-数组 三】【数组矩阵】螺旋矩阵、旋转图像、搜索二维矩阵
35 0
|
3月前
|
算法
算法题—顺时针打印矩阵
算法题—顺时针打印矩阵
22 0
|
3月前
根据经纬度计算两点距离的方法
根据经纬度计算两点距离的方法
|
4月前
|
Python
计算两个位置经纬度距离
计算两个位置经纬度距离
49 0
|
4月前
|
机器学习/深度学习 存储 算法
C# | 凸包算法之Graham,快速找到一组点最外侧的凸多边形
这篇关于凸包算法的文章,本文使用C#和Graham算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组点的凸多边形。凸多边形是指多边形中的每个内角都小于180度的多边形。 凸包算法有什么用呢? 凸包算法的作用是找到这个凸多边形,并且使用最少的点来绘制出它的轮廓。凸包算法在计算机图形学、计算几何和机器学习等领域中有着广泛的应用。
62 0
|
9月前
|
算法
ENVI_IDL:使用反距离权重法选取最近n个点插值(底层实现)并输出为Geotiff格式(效果等价于Arcgis中反距离权重插值)
ENVI_IDL:使用反距离权重法选取最近n个点插值(底层实现)并输出为Geotiff格式(效果等价于Arcgis中反距离权重插值)
251 0
|
10月前
给定三个顶点的坐标使用程序计算三角形
给定三个顶点的坐标使用程序计算三角形
32 0
|
10月前
射线法——判断一个点是否在多边形内部(适用于凸多边形和凹多边形)【关键原理解释+文字伪代码】
射线法——判断一个点是否在多边形内部(适用于凸多边形和凹多边形)【关键原理解释+文字伪代码】
255 0
|
12月前
|
机器学习/深度学习
(模拟)(矩阵坐标表示)1219. 移动距离
(模拟)(矩阵坐标表示)1219. 移动距离
66 0
|
算法 程序员 C语言