在已知的二维坐标里找到最接近的点

一、业务场景

最近在研发的项目,在做可视化层,在全球地图上,对我们的国家的陆地地图经纬度按照步长为1的间隔做了二维处理。在得到一组整数的点位信息后,需要将我们已有的数据库数据(业务项目)按照地址的经纬度,映射到这些点位上,找到对应的id建立联系。简化后的处理逻辑如下:
在这里插入图片描述
参考上图:
纬度为y轴,跨度为35,间距为1
经度为x轴,跨度为61,间距为1
橙色的点为业务项目对应的经纬度信息(x’,y’)
需要计算出二维坐标中整数点上最靠近的点(利用三角形三边公式)
MIN(aa + bb)
第一层:粉色层
第二层:灰色层

由于我们国家的地图存在边界,并不是一个规规矩矩的4方形,且我国的内陆海渤海的包围圈,海洋地区并不计入在二维坐标中,跨度为1的情况下,会出现项目对应的坐标点,需要一层一层对外查找的情况。
在这里插入图片描述

二、点位数据

CREATE TABLE `china_grid_map` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主见',`lng` decimal(20,6) NOT NULL COMMENT '经度',`lat` decimal(20,6) NOT NULL COMMENT '纬度',PRIMARY KEY (`id`),KEY `idx_lat` (`lng`),KEY `idx_lng` (`lat`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自定义中国陆地地图网格经纬度信息';

部分示例数据

INSERT INTO china_grid_map (id, lng, lat) VALUES (1, 74.000000, 39.000000),(3, 74.000000, 40.000000),(4, 75.000000, 37.000000),(5, 75.000000, 38.000000),(7, 75.000000, 39.000000),(9, 75.000000, 40.000000),(11, 76.000000, 37.000000),(13, 76.000000, 38.000000),(15, 76.000000, 39.000000),(17, 76.000000, 40.000000),(18, 77.000000, 36.000000),(20, 77.000000, 37.000000),(22, 77.000000, 38.000000),(24, 77.000000, 39.000000),(26, 77.000000, 40.000000),(28, 77.000000, 41.000000),(30, 78.000000, 36.000000),(32, 78.000000, 37.000000),(34, 78.000000, 38.000000),(36, 78.000000, 39.000000),(38, 78.000000, 40.000000),(40, 78.000000, 41.000000),(42, 79.000000, 32.000000),(44, 79.000000, 34.000000),(46, 79.000000, 35.000000),...
(1911, 131.000000, 44.000000),(1913, 131.000000, 45.000000),(1915, 131.000000, 46.000000),(1917, 131.000000, 47.000000),(1920, 132.000000, 46.000000),(1922, 132.000000, 47.000000),(1925, 133.000000, 46.000000),(1927, 133.000000, 47.000000),(1929, 133.000000, 48.000000),(1930, 134.000000, 47.000000),(1932, 134.000000, 48.000000);

三、实现方式

v1.0 版本 MySQL-直取数据

假设要求的项目坐标点为:
{“lat”: “31.231706”, “lng”: “121.472644”}
第一版本:
直接利用sql,查找出最靠近的四个点,然后再计算距离。

select id, lng, lat
from china_grid_map
where lat <= (select lat as latright from china_grid_map where lat >= 31.231706 order by lat limit 1)and lat >= (select lat as latleft from china_grid_map where lat <= 31.231706 order by lat desc limit 1)and lng <= (select lng as lngright from china_grid_map where lng >= 121.472644 order by lng limit 1)and lng >= (select lng as lngLeft from china_grid_map where lng <= 121.472644 order by lng desc limit 1);

如果查到了点 就求出最小的距离对应的点
如果没查到,重复上面点查询,扩大点数

存在的问题:
1.SQL复杂,如果点位正好在边界上,无论扩充多少层都查不到数据
2.耗时久

v2.0 版本 redis-Zset

{“lat”: “31.231706”, “lng”: “121.472644”}
已经知道步长为1,所以最靠近的点,如图1中所示,直接对x’,y’向下向上取整,组合。

利用redis缓存,使用Zset模型
key存储序列化后的信息,score用经度值
利用Zset的对经度范围取值,score (x,x+1)
对返回的数据再挨个查找,找出映射的id

存在的问题:
1.耗时久,因为按照经度 (x,x+1)取值 还是会得到很多数据,需要循环对比数据 才能得到对应的id
2.批量导入数据时,需要反反复复的从redis中取数据

v3.0 版本 内存-HashMap

Map<String,Long> CACHE = new HashMap<>();
key = lat + “-” + lng
value = id

按照步骤二的模式获取到点列表后,从map中get(key);
如果第一层4个点未命中,扩大到第二层

存在的问题:
1.存在内存中,分布式系统部署,每台服务器上的内存各自独立[好在该点位信息一旦生成后不会修改,在项目初始化后,不存在插入、删除相关的操作,只要考虑查询的时间效率]
2.791个点,消耗的存储比较大:113944

v4.0 版本 内存-二维数组 long[][]

由于点位是提前知道不会变动,且是步长为1的有规则的数据
经度数据区间 : 74 - 134 总个数 61
纬度数据区间 : 19 - 53 总个数 35

private static long[][] GRID_ARRAY = new long[61][35]; 

在项目启动时初始化缓存数据

public void initCacheByArray() {//先获取到所有的点位数据List<GridMapDO> mapDOS = baseMapper.listAllDO();if (CollectionUtil.isEmpty(mapDOS)) {return;}//循环将数据放入到缓存中for (GridMapDO grid : mapDOS) {int arrayLng = getArrayLng(grid.getLng());int arrayLat = getArrayLat(grid.getLat());if (arrayLng == -1 || arrayLat == -1) {//存在越界的点位log.info(">>>>>>>>>存在越界点位[经度:{},纬度:{}],跳过缓存<<<<<<<", grid.getLng(), grid.getLat());continue;}//找到对应的位置 将id存储为数组的值GRID_ARRAY[arrayLng][arrayLat] = grid.getId();}log.info(">>>> 缓存结束,缓存内容:[{}] <<<<<<", JSONObject.toJSONString(GRID_ARRAY));}private int getArrayLng(BigDecimal lng) {//防止数组下标越界int intLng = lng.intValue();if (intLng < 74 || intLng > 134) {return -1;}return lng.intValue() - 74;}private int getArrayLat(BigDecimal lat) {int intLat = lat.intValue();if (intLat < 19 || intLat > 53) {return -1;}return lat.intValue() - 19;}

用的时候 只需要计算出点位,直接从数组中取对应的下标即可。
如果 GRID_ARRAY[x][y] == 0L 说明点位不是中国的大陆地图
如果 GRID_ARRAY[x][y] != 0L 计算出该点的距离平方

存在的问题:
1.存在内存中,分布式系统部署,每台服务器上的内存各自独立[好在该点位信息一旦生成后不会修改,在项目初始化后,不存在插入、删除相关的操作,只要考虑查询的时间效率]
2.791个点,消耗的存储比V3.0版本减少了1个数量级,但是数组用的是连续的存储空间

四、总结

可以多尝试,找出最合适项目的,结合数据的规律,空间换时间 等等
只有实践了 才能找到最佳的吧…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/138449.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GUN、MIT、Apache、BSD、MPL各种开源协议介绍和区别

文章目录 目前主流的开源协议GNU通用公共许可证&#xff08;GNU General Public License&#xff0c;GPL&#xff09;MIT许可证Apache许可证BSD许可证MPL Mozilla公共许可证&#xff08;Mozilla Public License&#xff0c;MPL&#xff09; 各种主流开源协议的区别GNU通用公共许…

玩转Nginx

Nginx是什么 Nginx&#xff08;engine x&#xff09;是一款的Web服务器、反向代理服务器&#xff0c;能够实现前端Web应用的部署、请求反向代理及负载均衡处理等功能。 特点 轻量&#xff0c;占用内存少高可靠高并发、高性能可扩展性好支持热部署BSD许可证(开源、可修改再发…

使用FFmpeg+ubuntu系统转化flac无损音频为mp3

功能需求如上题,我们来具体的操作一下: 1.先在ubuntu上面安装FFmpeg:sudo apt install ffmpeg 2.进入有flac音频文件的目录使用下述命令: ffmpeg -i test.FLAC -c:a libmp3lame -q:a 2 output.mp3 3.如果没有什么意外的话,你就能看到你的文件夹里面已经有转化好的mp3文件了 批…

Python —— excel文件操作(超详细)

背景 很多公司还是用excel去管理测试用例的&#xff0c;所以为了减少重复繁琐的导出导出工作&#xff0c;学会如何用代码操作excel表格很实用~ 1、读取excel文件基本步骤 1、操作excel的一些库 1、xlrd&#xff1a;读取库&#xff0c;xlwt&#xff1a;写入&#xff0c;现在…

Golang Linux 安装与环境变量配置

下载 Go 二进制包 wget https://dl.google.com/go/go1.21.1.linux-amd64.tar.gz 解压文件并将其移至 /usr/local 目录 sudo tar -C /usr/local -xzf go1.20.1.linux-amd64.tar.gz -C 选项解压文件到 /usr/local 目录&#xff0c;查看 /usr/local/go 目录的内容 将 Go 二进…

token登录的实现

token登录的实现 我这种token只是简单的实现token&#xff0c;就是后端利用UUID 生成简单随机码&#xff0c;利用随机码作为在Redis中的键&#xff0c;然后存储的用户信息作为值&#xff0c;在每次合理请求的时候对token的有效时间进行刷新&#xff08;利用拦截器&#xff09;&…

IP风险查询:抵御DDoS攻击和CC攻击的关键一步

随着互联网的普及&#xff0c;网络攻击变得越来越普遍和复杂&#xff0c;对企业和个人的网络安全构成了重大威胁。其中&#xff0c;DDoS&#xff08;分布式拒绝服务&#xff09;攻击和CC&#xff08;网络连接&#xff09;攻击是两种常见且具有破坏性的攻击类型&#xff0c;它们…

python实现命令tree的效果

把所有的文档都传到了git上,但是内容过多找起来不方便,突发奇想如果能在readme中,递归列出所有文件同时添加上对应的地址,这样只需要搜索到对应的文件点击就能跳转过去了… 列出文件总得有个显示格式,所以就按照tree的来了… 用python实现命令tree的效果 首先,这是tree的效果…

【力扣每日一题】2023.9.21 收集树中金币

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一棵树&#xff0c;不过这棵树不是普通的树&#xff0c;而是无向无根树。给我们一个二维数组表示节点之间的连接关系&#xff…

Open3D 进阶(11)使用GMM-Tree算法对点云配准

GMM-Tree算法 一、算法原理1、主要函数2、参考文献二、代码实现三、结果展示1、点云初始位置2、配准后的位置四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 1、

快速用Python进行数据分析技巧详解

概要 一些小提示和小技巧可能是非常有用的&#xff0c;特别是在编程领域。有时候使用一点点黑客技术&#xff0c;既可以节省时间&#xff0c;还可能挽救“生命”。 一个小小的快捷方式或附加组件有时真是天赐之物&#xff0c;并且可以成为真正的生产力助推器。所以&#xff0…

解密list的底层奥秘

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

Android之MediaMetricsService实现本质(四十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

王江涛十天搞定考研词汇

学习目标&#xff1a; 考研词汇 学习内容&#xff1a; 2023-9-17 第一天考研词汇 学习时间&#xff1a; 开始:2023-9-17 结束:进行中 学习产出&#xff1a; 2023-9-17intellect智力&#xff1b;知识分子intellectual智力的&#xff1b;聪明的intellectualize使...理智化&a…

JsonUtils

1、工具类 package com.atguigu.utils;import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.Deserialization…

flink集群与资源@k8s源码分析-回顾

本章是分析系列最后一章,作为回顾,以运行架构图串联起所有分析场景 1 启动集群,部署集群(提交k8s),新建作业管理器组件 2 构建和启动flink master组件 3 提交作业,N/A

RocketMQ 消费者分类与分组

文章目录 消费者分类PushConsumerPushConsumer 内部原理使用注意事项 SimpleConsumerinvisibleDuration 消息不可见时间 消费者分组&#xff08;消费者负载均衡&#xff09;广播消费和共享消费负载均衡策略多个消费者消费顺序消息多消费者消费顺序消息示例 消费者分组管理关闭自…

IDEA最新激 20活23码

人狠话不多 大家好&#xff0c;最近Intelli Idea官方的校验规则进行了更新&#xff0c;之前已经成功激20活23的Idea可能突然无法使用了。 特地从网上整理了最新、最稳定的激20活23码分享给大家&#xff0c;希望可以帮助那些苦苦为寻找Idea激20活23码而劳累的朋友们。 本激23…

外国固定资产管理系统功能有哪些

很多公司都在寻找提高自己资产管理效益的方法。为了满足这一要求&#xff0c;国外的固定资产管理系统已经发展成多种形式。以下是国外一些常见的固定资产管理系统的特点:自动化和智能化:许多现代固定资产管理系统采用自动化和数字化技术&#xff0c;以简化流程&#xff0c;减少…

Windows本地mysql 的安装教程(一步一步进行安装)

目录 1 下载安装包2 安装 1 下载安装包 下载网址&#xff1a; https://dev.mysql.com/downloads/ 选择这个 2 安装 编写MySQL配置文件 在解压目录下新建my.ini文件 将下面文本拷贝进my,ini文件中 [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录 ----------…