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

简介:

附近的人的位置用经纬度表示,然后通过两点的经纬度计算距离。根据网上的推荐,最终采用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,如需转载请自行联系原作者
相关文章
|
JavaScript
vue实现下拉列表远程搜索示例(根据关键词模糊搜索)
vue实现下拉列表远程搜索示例(根据关键词模糊搜索)
|
前端开发 Java
|
机器学习/深度学习 存储 安全
数据库模型:层次模型、网状模型、关系模型
数据库模型:层次模型、网状模型、关系模型
|
2月前
|
人工智能 BI 语音技术
AR眼镜+AI大模型:颠覆工业设备验收流程的智能革命
本方案结合AR眼镜与AI视觉大模型,打造高效、精准、可追溯的设备验收流程。通过第一视角记录、智能识别、结构化数据生成与智能报表功能,提升验收效率与质量,助力企业实现智能化管理。
|
3月前
|
人工智能 供应链 安全
实现企业级 MCP 服务统一管理和智能检索的实践
本文将深入剖析 MCP Server 的五种主流架构模式,并结合 Nacos 服务治理框架,为企业级 MCP 部署提供实用指南。
962 63
|
11月前
|
安全 数据安全/隐私保护
谨防二维码陷阱:揭秘网络钓鱼攻击与保护措施
当我们深入了解二维码的世界时,了解它们的特性和潜在风险变得至关重要,揭示了伴随其广泛普及的更为阴暗的一面
299 1
|
7月前
|
机器学习/深度学习 人工智能
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
本文介绍了一种名为 Diffusion-DPO 的创新方法,该方法基于直接偏好优化(DPO)原理,简化了扩散模型与人类偏好的对齐过程。相比传统的基于人类反馈的强化学习(RLHF)方法,Diffusion-DPO 避免了显式奖励模型的训练,通过数学近似简化实现流程,并在处理开放词汇表场景时展现出更强的能力。实验结果表明,该方法在 Stable Diffusion 1.5 和 SDXL-1.0 等主流模型上显著提升了生成图像的质量和可控性,为未来扩散模型的发展提供了新的思路。
506 14
Diffusion-DPO:一种基于直接偏好优化的扩散模型对齐新方法
|
关系型数据库 分布式数据库 数据库
【PolarDB 开源】PolarDB 性能调优实录:提升数据库集群吞吐量的技巧
【5月更文挑战第22天】PolarDB 性能调优关键点包括硬件资源配置、数据库参数调整、索引优化、分区策略、事务优化及性能监控。创建高效索引如`CREATE INDEX idx_name ON table_name (column_name);`,根据业务场景选择分区方式,调整事务隔离级别以提升并发性能。监控 CPU、内存等指标,定期维护数据库,结合业务特点综合调优,从而提升数据库集群吞吐量。这些技巧有助于发挥PolarDB潜力,支持业务高效运行。
685 6
|
机器学习/深度学习 人工智能 PyTorch
深度学习领域中pytorch、onnx和ncnn的关系
PyTorch、ONNX 和 NCNN 是深度学习领域中的三个重要工具或框架,它们在模型开发、转换和部署过程中扮演着不同但相互关联的角色。
632 12
|
编解码 移动开发 前端开发
web canvas系列——快速入门上手绘制二维空间点、线、面
web canvas系列——快速入门上手绘制二维空间点、线、面
465 4

热门文章

最新文章