ES 使用geo point 查询离目标地址最近的数据
需求描述:项目中需要通过经纬度坐标查询目标地所在的行政区。
解决思路大致有种,使用es和mysql分别查询。
1、使用es进行查询
将带有经纬度坐标的省市区数据存入es中,mappings字段使用geo point类型,索引及查询dsl如下。
geo point文档地址:
Geo-distance query | Elasticsearch Guide [8.6] | Elastic
Sort search results | Elasticsearch Guide [8.6] | Elastic
mappings结构:
PUT /sys_district
{"settings": {"index": {"number_of_shards": 1,"number_of_replicas": 1}},"mappings": {"properties": {"id": {"type": "long"},"parent_id": {"type": "long"},"name": {"type": "keyword"},"zipcode": {"type": "integer"},"pinyin": {"type": "keyword"},"location": {"type": "geo_point" // 如果用于地理坐标,可以考虑使用 geo_point 类型},"level": {"type": "byte" },"sort": {"type": "byte"}}}
}
dsl语句:
# 搜索坐标点附近的数据
GET sys_district/_search
{"from": 0,"size": 3,"query": {"bool": {"must": {"match_all": {}},"filter": [{"geo_distance": {# 半径内距离限制"distance": "100km","location": {# 目的地坐标"lat": 34.4328,"lon": 115.88}}},{"term": {"level": "3"}}]}},
# 排序"sort" : [{"_geo_distance" : {"location" : {"lat" : 34.4328,"lon" :115.88},"order" : "asc","unit" : "km"}}]
}
获取举例最近的排序不能漏了
2、使用mysql进行查询
将带有经纬度坐标的省市区数据存入mysql中,使用mysql直接计算,表结构及查询sql如下。
表结构:
CREATE TABLE `sys_district` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',`parent_id` INT(10) UNSIGNED NOT NULL COMMENT '父栏目',`name` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8_general_ci',`zipcode` INT(10) UNSIGNED NOT NULL DEFAULT '0',`pinyin` VARCHAR(100) NOT NULL DEFAULT '' COLLATE 'utf8_general_ci',`lng` VARCHAR(20) NOT NULL DEFAULT '' COLLATE 'utf8_general_ci',`lat` VARCHAR(20) NOT NULL DEFAULT '' COLLATE 'utf8_general_ci',`level` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',`sort` TINYINT(3) UNSIGNED NOT NULL DEFAULT '50' COMMENT '排序',`location` VARCHAR(255) NOT NULL DEFAULT '' COLLATE 'utf8_general_ci',PRIMARY KEY (`id`) USING BTREE
)
COMMENT='(公共)区域数据'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
查询sql:
SELECT * FROM sys_district WHERE ABS(lat - 34.4328) + ABS(lng - 115.88) = (SELECT MIN(ABS(lng - 115.88) + ABS(lat - 34.4328)) FROM sys_district ) LIMIT 1;
使用mysql计算可优化的地方在于,新版本mysql提供了空间几何字段类型POINT,优化后新表结构如下。
CREATE TABLE `sys_district` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',`parent_id` INT(10) UNSIGNED NOT NULL COMMENT '父栏目',`name` VARCHAR(50) NOT NULL DEFAULT '' COLLATE 'utf8mb3_general_ci',`zipcode` INT(10) UNSIGNED NOT NULL DEFAULT '0',`pinyin` VARCHAR(100) NOT NULL DEFAULT '' COLLATE 'utf8mb3_general_ci',`lng` VARCHAR(20) NOT NULL DEFAULT '' COLLATE 'utf8mb3_general_ci',`lat` VARCHAR(20) NOT NULL DEFAULT '' COLLATE 'utf8mb3_general_ci',`geom` POINT NOT NULL COMMENT 'geo',`level` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',`sort` TINYINT(3) UNSIGNED NOT NULL DEFAULT '50' COMMENT '排序',`location` VARCHAR(255) NOT NULL DEFAULT '' COLLATE 'utf8mb3_general_ci',PRIMARY KEY (`id`) USING BTREE,SPATIAL INDEX `geom` (`geom`)
)
COMMENT='(公共)区域数据'
COLLATE='utf8mb3_general_ci'
ENGINE=InnoDB
;
字段设置:
ALTER TABLE `sys_district`ADD COLUMN `geom` POINT NULL AFTER `lat`;UPDATE sys_district SET geom = ST_PointFromText(CONCAT('POINT(', lng, ' ', lat, ')')) ;ALTER TABLE sys_district ADD SPATIAL INDEX(geom);
查询sql如下:
ST_PointFromText(CONCAT('POINT(', lng, ' ', lat, ')')) 将表中的经度和纬度转换为几何点。
ST_Distance_Sphere(geom, ST_PointFromText(CONCAT('POINT(', 120.15, ' ', 30.28, ')'))) 计算每个点与目标点之间的距离(单位为米)。
ORDER BY distance 按距离从小到大排序
SELECT id, name, lng, lat,ST_Distance_Sphere(geom, ST_PointFromText(CONCAT('POINT(', 120.15, ' ', 30.28, ')'))) AS distance
FROM sys_district
ORDER BY distance
LIMIT 3;
3、其他方式
如果带查询的数据项不变化,类似于行政区划的坐标,还可以把这些数据加载到内存中进行计算。
3.1 Java-使用 Haversine 公式来计算(不依赖三方库)
创建表示位置的类
public class Location {private double lon;private double lat;public Location(double lon, double double lat) {this.lon = lon;this.lat = lat;}// Getter 和 Setter 方法}
使用 Haversine 公式计算两点间的距离
public class DistanceCalculator {private static final int EARTH_RADIUS = 6371; // 地球半径,单位为公里/*** 计算两个经纬度点之间的距离*/public static double calculateDistance(Location loc1, Location loc2) {double lat1 = Math.toRadians(loc1.getLat());double lon1 = Math.toRadians(loc1.getLon());double lat2 = Math.toRadians(loc2.getLat());double lon2 = Math.toRadians(loc2.getLon());double dlat = lat2 - lat1;double dlon = lon2 - lon1;double a = Math.sin(dlat / 2) * Math.sin(dlat / 2) +Math.cos(lat1) * Math.cos(lat2) *Math.sin(dlon / 2) * Math.sin(dlon / 2);double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));return EARTH_RADIUS * c; // 返回单位为公里}
}
查找最近的数据点
public class NearestLocationFinder {public static LocationData findNearestLocation(List<LocationData> locations, Location targetLocation) {LocationData nearest = null;double minDistance = Double.MAX_VALUE;for (LocationData location : locations) {Location currentLocation = new Location(location.getLocation().getLon(), location.getLocation().getLat());double distance = DistanceCalculator.calculateDistance(currentLocation, targetLocation);if (distance < minDistance) {minDistance = distance;nearest = location;}}return nearest;}
}
调用方法
public class Main {public static void main(String[] args) {// 已加载所有的位置数据List<LocationData> locations = loadData();// 输入的经纬度Location targetLocation = new Location(115.65, 34.43);// 查找最近的位置LocationData nearest = NearestLocationFinder.findNearestLocation(locations, targetLocation);System.out.println("最近的位置是: " + nearest.getName());}// 加载数据private static List<LocationData> loadData() {return new ArrayList<>();}
}
4、Java-使用JTS STRtree(依赖三方库)
maven依赖
<dependency><groupId>org.locationtech.jts</groupId><artifactId>jts-core</artifactId><version>1.18.2</version>
</dependency>
调用方法
public class NearestPointFinder {public static void main(String[] args) {// 创建一个包含所有位置信息的列表List<LocationData> locations = loadData();// 输入的经纬度double lon = 115.65, lat = 34.43;// 使用JTS的STRtree加速查询STRtree tree = new STRtree();GeometryFactory geometryFactory = new GeometryFactory();for (LocationData location : locations) {Point point = geometryFactory.createPoint(new Coordinate(location.getLocation().getLon(), location.getLocation().getLat()));tree.insert(point.getEnvelopeInternal(), location);}Point targetPoint = geometryFactory.createPoint(new Coordinate(lon, lat));LocationData nearest = (LocationData) tree.nearestNeighbour(targetPoint.getEnvelopeInternal(), null);System.out.println("最近的位置是: " + nearest.getName());}private static List<LocationData> loadData() {// 加载位置数据return new ArrayList<>();}
}
还有其他的一些三方库:H3 by Uber、GeoTools、Spatial4j等。
总结:没有最好的,只有最适合的,按需设计。
相关文章:
ES 使用geo point 查询离目标地址最近的数据
需求描述:项目中需要通过经纬度坐标查询目标地所在的行政区。 解决思路大致有种,使用es和mysql分别查询。 1、使用es进行查询 将带有经纬度坐标的省市区数据存入es中,mappings字段使用geo point类型,索引及查询dsl如下。 geo p…...
本地部署OpenManus及原理介绍
概述: 最近Minaus特别火,随后开源社区就有项目尝试复刻Minaus,项目名称为OpenManus,原理是用推理模型为决策者,将我们输入的问题进行分解后调用本地工具执行。 OpenManus安装: 本人在Ubuntu桌面版本上安装…...
高效手机检测:视觉分析技术的优势
在当今社会,手机已成为人们日常生活和工作中不可或缺的工具。然而,在某些特定场合,如考场、工作场所等,手机的使用却可能带来负面影响。因此,如何有效监测和防止在这些场合偷用手机的行为,成为了一个亟待解…...
Java 多线程编程:提升系统并发处理能力!
多线程是 Java 中实现并发任务执行的关键技术,能够显著提升程序在多核处理器上的性能以及处理多任务的能力。本文面向初级到中级开发者,从多线程的基本定义开始,逐步讲解线程创建、状态管理、同步机制、并发工具以及新兴的虚拟线程技术。每部…...
Linux实时内核稳定性案例
稳定性问题分析 RT_RUNTIME_SHARE案例死锁问题Linux-rt下卡死之hrtimer分析Linux内核宕机案例 -mmap空指针Linux Hung Task分析过程...
解决 VSCode SSH 连接报错:“REMOTE HOST IDENTIFICATION HAS CHANGED” 的问题
问题描述 在使用 VSCode 通过 SSH 连接远程服务器时,我们可能会遇到类似如下的错误日志: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! ... Offending ED25519 key in C:\Users\DELL/…...
Spring Boot配置类原理、Spring Boot核心机制理解,以及实现自动装置的底层原理
目的:从底层源码角度分析 Spring Boot 配置类以及自动装载的底层原理 文章目录 1. Spring Boot 配置类实现自动装载1.1 @Configuration注解1.2 @Configuration 注解完成 bean 注入流程图1.3 @ConfigurationProperties注解赋值2. Spring Boot的核心机制:自动装配2.1 @SpringBo…...
淘宝API vs 爬虫:合规获取实时商品数据的成本与效率对比
以下是淘宝 API 和爬虫在合规获取实时商品数据方面的成本与效率对比: 成本对比 淘宝 API 开发成本:需要申请开发者账号并获取 API 权限,部分敏感或高频访问的接口可能需要额外的审核或付费。开发过程中需要按照平台规定进行编程,相…...
01-Canvas-使用fabric初始
fabric官网: https://fabric5.fabricjs.com/demos/ 创建画布并绘制 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…...
CMake简单入门
简介 CMake 是一个开源的跨平台构建系统生成工具,旨在简化和自动化项目的构建过程。它主要用于管理和控制软件构建的过程,特别是在处理复杂的项目结构和多个平台时。CMake 并不直接进行编译或链接,而是生成本地构建系统所需的文件࿰…...
树莓派 连接 PlutoSDR 教程
在树莓派5上安装PlutoSDR(ADALM-Pluto)的驱动程序,主要需要安装相关的库和工具,以便与PlutoSDR通信,比如libiio和libad9361,并确保系统能够识别设备。由于树莓派5运行的是基于Linux的系统(通常是…...
【时时三省】(C语言基础)用printf函数输出数据3
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 ( 5 ) e格式符。 用格式声明%e指定以指数形式输出实数。如果不指定输出数据所占的宽度和数字部分的小数位数,许多C编译系统(如VisualC)会自动给出数字部分…...
Git使用(二)--如何配置 GitHub 远程仓库及本地 Git 环境
在日常的开发过程中,使用版本控制工具 Git 是一个非常重要的技能,特别是对于管理和协作开发。通过 GitHub,我们可以轻松地进行代码版本管理和共享。这篇博客将带您一步步学习如何配置 Git 环境并将本地仓库与 GitHub 远程仓库连接起来。 一、…...
在Pycharm配置conda虚拟环境的Python解释器
〇、前言 今天在配置python解释器时遇到了这样的问题 经过一下午自行摸索、上网搜寻后,终于找到的解决的方案,遂将该方法简要的记录下来,以备后用,并希望能帮助到有同样问题或需求的朋友:) 我所使用的软件的版本如下,假…...
CURL一文通
文章目录 1.什么是curl2.curl可以发送什么请求3.常见curl发http相关请求怎么写4.curl带上的参数分别有什么,可以怎么用5.进阶用法6.常见错误以及学习指导建议 1.什么是curl 是利用URL语法在命令行下工作的开源文件传输工具。尤其被广泛应用的在linux系统下。 2.cu…...
零基础keil:设置注释快捷键
1.打开快捷键设置: 在Keil中,选择菜单栏中的“Settings”,然后选择“Shortcuts”来打开快捷键设置界面。 2.选择注释命令: 在快捷键设置界面中,找到与注释相关的命令,如“Comment Selection”࿰…...
Java中关于Optional的 orElse 操作,以及 orElse 与 orElseGet 的区别
文章目录 1. 大概说明2. 详细分析2.1 .orElse 操作2.2 .orElse 的作用:避免空指针异常2.3 为什么要用?2.4 orElseGet如何使用2.5 orElse和orElseGet的区别 1. 大概说明 这篇文章的目的是为了说明: orElse 如何使用orElseGet 如何使用两者的…...
TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave)
TCP/IP协议中三次握手(Three-way Handshake)与四次挥手(Four-way Wave) 一、TCP三次握手(Three-way Handshake)二、TCP四次挥手(Four-way Wave)三、常见问题解答总结为什么三次握手不…...
python学智能算法(八)|决策树
【1】引言 前序学习进程中,已经对KNN邻近算法有了探索,相关文章链接为: python学智能算法(七)|KNN邻近算法-CSDN博客 但KNN邻近算法有一个特点是:它在分类的时候,不能知晓每个类别内事物的具…...
【经验】Orin系列Ubuntu远程桌面:VNC、NoMachine、URDC
1、VNC 1.1 Ubuntu端 1)安装VNC服务器 sudo apt install tigervnc-standalone-server2)安装xfce4 桌面 xfce4 用资源较GNOME ,KDE较少。适合老机器,轻量级桌面。与windows界面环境类似。 sudo apt install xfce4 xfce4-goodies也可以使用其它的桌面系统,可以使用如下命…...
【QT:控件】
目录 控件状态:编辑 geometry : window frame windowlcon: qrc机制 qrc的使用方式: window opacity cursor font: ToolTip focusPolicy: styleSheet: 按钮类控件: PushButton: 给按钮添加图标: 给按钮添加快捷键…...
Python(最新版)集成开发环境PyCharm下载安装详细教程
Python 下载和安装 1.进入Python官网 Download Python | Python.org,点击Downloads,这里以Windows为例 2.选择下载Python 3.13.2 Windows 64位的版本。注意:不能在Windows 7 或更早的版本上使用。 3.打开文件,会自动出现安装界…...
PyTorch 实现 Conditional DCGAN(条件深度卷积生成对抗网络)进行图像到图像转换的示例代码
以下是一个使用 PyTorch 实现 Conditional DCGAN(条件深度卷积生成对抗网络)进行图像到图像转换的示例代码。该代码包含训练和可视化部分,假设输入为图片和 4 个工艺参数,根据这些输入生成相应的图片。 1. 导入必要的库 import …...
【BERT和GPT的区别】
BERT采用完形填空(Masked Language Modeling, MLM)与GPT采用自回归生成(Autoregressive Generation)的差异,本质源于两者对语言建模的不同哲学导向与技术目标的根本分歧。这种选择不仅塑造了模型的架构特性,…...
PTA 7-12 排序
题目描述 给定 n 个(长整型范围内的)整数,要求输出从小到大排序后的结果。 本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下: 数据1:只有1个元素;数据2:11个不…...
uniapp 实现的步进指示器组件
采用 uniapp 实现的一款步进指示器组件,展示业务步骤进度等内容,对外提供“前进”、“后退”方法,让用户可高度自定义所需交互,适配 web、H5、微信小程序(其他平台小程序未测试过,可自行尝试) 可…...
大模型-提示词调优
什么是提示词 提示词(Prompt)在大模型应用中扮演着关键角色,它是用户输入给模型的一段文本指令 。简单来说,就是我们向大模型提出问题、请求或描述任务时所使用的文字内容。例如,当我们想让模型写一篇关于春天的散文&a…...
【k8s002】k8s健康检查与故障诊断
k8s健康检查与故障诊断 一、集群状态检查 检查节点健康状态 kubectl get nodes -o wide # 查看节点状态及基本信息 kubectl describe node <node-name> # 分析节点详细事件(如资源不足、网络异常) kubectl top nodes …...
统计数字字符个数(信息学奥赛一本通-1129)
【题目描述】 输入一行字符,统计出其中数字字符的个数。 【输入】 一行字符串,总长度不超过255。 【输出】 输出为1行,输出字符串里面数字字符的个数。 【输入样例】 Peking University is set up at 1898. 【输出样例】 4 【输出样例】 #in…...
CentOS 6 YUM源切换成国内yum源
由于 CentOS 6 已于 2020 年 11 月进入 EOL(End of Life),官方软件源已不再提供更新,因此你可能会遇到 yum makecache 命令失败的问题。以下是解决该问题的详细步骤: ### 解决方案 1. **备份原有 yum 源文件** bash …...
