如何利用 Spring Data MongoDB 进行地理位置相关的查询?
以下是如何使用 Spring Data MongoDB 进行地理位置相关查询的步骤和示例:
核心概念:
- GeoJSON 对象: MongoDB 推荐使用 GeoJSON 格式来存储地理位置数据。Spring Data MongoDB 提供了相应的 GeoJSON 类型,如
GeoJsonPoint
,GeoJsonPolygon
,GeoJsonLineString
等。GeoJsonPoint
: 表示一个点,例如[longitude, latitude]
。
- 地理空间索引 (Geospatial Index): 为了高效地执行地理位置查询,必须在存储位置数据的字段上创建地理空间索引。
2dsphere
: 支持球面几何计算,适用于地球表面的经纬度数据(推荐)。2d
: 支持平面几何计算,适用于二维平面上的点。
- 查询操作符: MongoDB 提供了多种地理位置查询操作符:
$near
/$nearSphere
: 查找靠近某个点的文档,并按距离排序。$geoWithin
: 查找几何形状(如多边形、圆形)内的文档。$geoIntersects
: 查找与指定 GeoJSON 对象相交的文档。$centerSphere
(与$geoWithin
结合使用): 定义一个球心和半径的圆形区域进行查询。
步骤详解:
步骤 1: 添加依赖
确保你的 pom.xml
(Maven) 或 build.gradle
(Gradle) 文件中包含 Spring Data MongoDB 的依赖:
<!-- pom.xml (Maven) -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
步骤 2: 定义实体 (Entity)
在你的实体类中,使用 org.springframework.data.mongodb.core.geo.GeoJsonPoint
(或其他 GeoJSON 类型) 来存储位置信息。
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.mapping.Document;@Document(collection = "locations")
public class LocationEntity {@Idprivate String id;private String name;// 存储经纬度信息,并创建 2dsphere 索引@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)private GeoJsonPoint location; // [longitude, latitude]public LocationEntity() {}public LocationEntity(String name, GeoJsonPoint location) {this.name = name;this.location = location;}// Getters and Setterspublic String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public GeoJsonPoint getLocation() {return location;}public void setLocation(GeoJsonPoint location) {this.location = location;}@Overridepublic String toString() {return "LocationEntity{" +"id='" + id + '\'' +", name='" + name + '\'' +", location=" + (location != null ? location.getCoordinates() : null) +'}';}
}
注意:
@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
注解会自动在location
字段上创建2dsphere
索引。这是进行地理位置查询的关键。- GeoJSON 点的坐标顺序是
[longitude, latitude]
(经度在前,纬度在后)。
步骤 3: 创建 Repository 接口
Spring Data MongoDB 可以通过方法名派生查询,或者使用 @Query
注解自定义查询。
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Polygon;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;public interface LocationRepository extends MongoRepository<LocationEntity, String> {// 1. 查找靠近某个点的文档 (使用 $nearSphere)// Spring Data 会自动使用 $nearSphere 因为索引是 2dsphere// Point 来自 org.springframework.data.geo.Point (x=longitude, y=latitude)// Distance 来自 org.springframework.data.geo.DistanceList<LocationEntity> findByLocationNear(Point point, Distance distance);// 也可以只按点查找,不限制距离 (结果按距离排序)List<LocationEntity> findByLocationNear(Point point);// 2. 查找在指定多边形内的文档 (使用 $geoWithin)// Polygon 来自 org.springframework.data.geo.PolygonList<LocationEntity> findByLocationWithin(Polygon polygon);// 3. 查找在指定圆形区域内的文档 (使用 $geoWithin 和 $centerSphere)// Circle 来自 org.springframework.data.geo.Circle// Spring Data 会将其转换为 $geoWithin 与 $centerSphereList<LocationEntity> findByLocationWithin(org.springframework.data.geo.Circle circle);// 4. 查找与指定 GeoJSON 几何图形相交的文档 (使用 $geoIntersects)// 需要使用 MongoTemplate 或 @Query 来实现更复杂的 GeoJSON 相交查询,// 因为派生查询对 $geoIntersects 的支持有限,尤其是对于复杂的 GeoJSON 输入。// 但简单的 Point 相交可以。// 对于更复杂的 GeoJSON (如 Polygon),通常使用 MongoTemplate 或 @Query// List<LocationEntity> findByLocationIntersects(GeoJson geometry); // 示例,可能需要自定义实现}
使用的 Spring Data Geo 类型:
org.springframework.data.geo.Point
: 用于查询参数,表示一个点 (x 对应经度, y 对应纬度)。org.springframework.data.geo.Distance
: 用于指定距离,可以包含单位 (如Metrics.KILOMETERS
)。org.springframework.data.geo.Polygon
: 用于查询参数,表示一个多边形。org.springframework.data.geo.Circle
: 用于查询参数,表示一个圆形。org.springframework.data.geo.Box
: 用于查询参数,表示一个矩形。
步骤 4: 使用 Repository 或 MongoTemplate
进行查询
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;import jakarta.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;@Service
public class LocationService {@Autowiredprivate LocationRepository locationRepository;@Autowiredprivate MongoTemplate mongoTemplate;@PostConstructpublic void init() {locationRepository.deleteAll(); // 清理旧数据// 插入一些示例数据// 故宫 (116.403963, 39.915119)locationRepository.save(new LocationEntity("Forbidden City", new GeoJsonPoint(116.403963, 39.915119)));// 天安门广场 (116.3912757, 39.9037078)locationRepository.save(new LocationEntity("Tiananmen Square", new GeoJsonPoint(116.3912757, 39.9037078)));// 颐和园 (116.275136, 39.999077)locationRepository.save(new LocationEntity("Summer Palace", new GeoJsonPoint(116.275136, 39.999077)));// 东方明珠 (121.499718, 31.239703)locationRepository.save(new LocationEntity("Oriental Pearl Tower", new GeoJsonPoint(121.499718, 31.239703)));}public void performGeoQueries() {System.out.println("--- Performing Geo Queries ---");// 中心点: 北京市中心附近 (例如王府井 116.417427, 39.913904)Point centerPoint = new Point(116.417427, 39.913904); // longitude, latitude// 1. 查找王府井附近 5 公里内的地点Distance fiveKilometers = new Distance(5, Metrics.KILOMETERS);List<LocationEntity> nearWangfujing = locationRepository.findByLocationNear(centerPoint, fiveKilometers);System.out.println("\nLocations near Wangfujing (5km):");nearWangfujing.forEach(System.out::println); // 应该包含故宫和天安门// 2. 查找在指定多边形内的地点 (大致覆盖北京二环内)// 注意:多边形的点必须形成闭合环路,且第一个点和最后一个点相同Polygon beijingRing2 = new Polygon(new Point(116.30, 39.85), //西南new Point(116.50, 39.85), //东南new Point(116.50, 39.95), //东北new Point(116.30, 39.95), //西北new Point(116.30, 39.85) //闭合);List<LocationEntity> withinBeijingRing2 = locationRepository.findByLocationWithin(beijingRing2);System.out.println("\nLocations within Beijing Ring 2 (approx):");withinBeijingRing2.forEach(System.out::println); // 应该包含故宫和天安门// 3. 查找在指定圆形区域内的地点 (以故宫为圆心,2公里为半径)Point forbiddenCityCoords = new Point(116.403963, 39.915119);Distance twoKilometers = new Distance(2, Metrics.KILOMETERS);// 对于2dsphere索引, Circle的距离单位会被正确处理 (例如转换为弧度)Circle aroundForbiddenCity = new Circle(forbiddenCityCoords, twoKilometers);List<LocationEntity> withinCircle = locationRepository.findByLocationWithin(aroundForbiddenCity);System.out.println("\nLocations within 2km of Forbidden City:");withinCircle.forEach(System.out::println); // 应该包含故宫和天安门// 4. 使用 MongoTemplate 进行 $geoIntersects 查询// 定义一个 GeoJsonPolygon (注意点顺序,逆时针为外部,顺时针为内部,但通常简单多边形即可)// 这里用和上面一样的多边形,但用 GeoJsonPolygonGeoJsonPolygon queryPolygon = new GeoJsonPolygon(new Point(116.30, 39.85),new Point(116.50, 39.85),new Point(116.50, 39.95),new Point(116.30, 39.95),new Point(116.30, 39.85));Query intersectsQuery = new Query(Criteria.where("location").intersects(queryPolygon));List<LocationEntity> intersectingLocations = mongoTemplate.find(intersectsQuery, LocationEntity.class);System.out.println("\nLocations intersecting with query polygon (MongoTemplate):");intersectingLocations.forEach(System.out::println);// 5. 使用 MongoTemplate 进行 $nearSphere 查询,并指定最小和最大距离Query nearQueryWithMinMax = new Query(Criteria.where("location").nearSphere(centerPoint) // 使用 Spring Data Point.minDistance(1000 / 6378137.0) // 最小距离1公里 (转换为弧度,MongoDB $nearSphere 需要弧度或米)// 或者直接用米: .minDistance(1000) 如果MongoDB版本支持.maxDistance(5000 / 6378137.0) // 最大距离5公里// 或者直接用米: .maxDistance(5000));// 如果MongoDB 4.0+ 且 Spring Data MongoDB 2.2+, 可以直接用米// Query nearQueryWithMinMaxMeters = new Query(// Criteria.where("location")// .nearSphere(centerPoint)// .minDistance(1000.0) // 1000 meters// .maxDistance(5000.0) // 5000 meters// );// List<LocationEntity> nearWithMinMax = mongoTemplate.find(nearQueryWithMinMaxMeters, LocationEntity.class);// System.out.println("\nLocations near Wangfujing (1km-5km, MongoTemplate):");// nearWithMinMax.forEach(System.out::println);// 对于 $nearSphere,Spring Data 的 Repository 方法中的 Distance 对象会自动处理单位转换。// 使用 MongoTemplate 时,对于 $minDistance / $maxDistance:// - 如果是 `2dsphere` 索引,MongoDB 期望距离单位是米。// - 如果是 `2d` 索引,MongoDB 期望距离单位是索引坐标系的单位。// Spring Data MongoDB 3.0+ 配合 MongoDB 4.0+,`nearSphere` 可以直接接受米为单位的 `minDistance`/`maxDistance`。// 如果使用较旧版本,可能需要将距离转换为弧度(如示例中除以地球半径)。// 简单的 findByLocationNear(Point, Distance) 通常是更方便的选择。}
}
运行示例 (在一个 Spring Boot 应用中):
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class MongoGeoApplication {public static void main(String[] args) {SpringApplication.run(MongoGeoApplication.class, args);}@BeanCommandLineRunner runner(LocationService locationService) {return args -> {locationService.performGeoQueries();};}
}
总结与要点:
- 实体定义: 使用
GeoJsonPoint
(或其他GeoJson*
类型) 存储位置,并用@GeoSpatialIndexed
创建2dsphere
索引。 - 坐标顺序: 始终记住 GeoJSON 使用
[longitude, latitude]
。Spring Data 的Point
对象构造函数new Point(x, y)
中x
是经度,y
是纬度。 - Repository 查询: Spring Data Repositories 为常见的地理位置查询(如
Near
,Within
)提供了便捷的方法名派生。 MongoTemplate
: 对于更复杂或自定义的地理位置查询(如$geoIntersects
配合复杂 GeoJSON 对象,或需要更精细控制$nearSphere
的$minDistance
/$maxDistance
),可以使用MongoTemplate
。- 单位:
org.springframework.data.geo.Distance
: 允许你指定单位 (如Metrics.KILOMETERS
,Metrics.MILES
)。Spring Data 会在与 MongoDB 交互时处理转换。- MongoDB 的
$nearSphere
和$centerSphere
(用于2dsphere
索引) 默认使用米作为距离单位。 - 当使用
MongoTemplate
时,需要注意minDistance
/maxDistance
的单位,较新版本的 MongoDB (4.0+) 和 Spring Data MongoDB (2.2+/3.0+) 可以直接使用米。
- 性能: 地理空间索引对于查询性能至关重要。确保索引已正确创建。
相关文章:
如何利用 Spring Data MongoDB 进行地理位置相关的查询?
以下是如何使用 Spring Data MongoDB 进行地理位置相关查询的步骤和示例: 核心概念: GeoJSON 对象: MongoDB 推荐使用 GeoJSON 格式来存储地理位置数据。Spring Data MongoDB 提供了相应的 GeoJSON 类型,如 GeoJsonPoint, GeoJsonPolygon, …...

服务器并发实现的五种方法
文章目录 前言一、单线程 / 进程二、多进程并发三、多线程并发四、IO多路转接(复用)select五、IO多路转接(复用)poll六、IO多路转接(复用)epoll 前言 关于网络编程相关知识可看我之前写过的文章࿱…...
PYTORCH_CUDA_ALLOC_CONF基本原理和具体示例
PYTORCH_CUDA_ALLOC_CONFmax_split_size_mb 是 PyTorch 提供的一项环境变量配置,用于控制 CUDA 显存分配的行为。通过指定此参数,可以有效管理 GPU 显存的碎片化,缓解因显存碎片化而导致的 “CUDA out of memory”(显存溢出&#…...
2025年系统架构师---综合知识卷
1.进程是一个具有独立功能的程序关于某数据集合的一次运行活动,是系统进行资源分配和调度的基本单位(线程包含于进程之中,可并发,是系统进行运算调度的最小单位)。一个进程是通过其物理实体被感知的,进程的物理实体又称为进程的静态描述,通常由三部分组成,分别是程序、…...
AI 抠图软件批量处理 + 发丝级精度,婚纱 / 玻璃一键抠透明 免安装
各位抠图小能手们,今天我要给大家介绍一款超厉害的工具——AiartyImageMattingPortable!它是基于人工智能的便携式图像抠图工具,专门为快速、精准抠图而生,处理复杂边缘和透明物体那简直就是它的拿手好戏! 咱先说说它…...
JVM 深度解析
一、JVM 概述 1.1 什么是 JVM? JVM(Java Virtual Machine,Java 虚拟机)是 Java 程序运行的核心引擎。它像一个“翻译官”,将 Java 字节码转换为机器能理解的指令,并管理程序运行时的内存、线程等资源。 …...

新能源汽车移动充电服务:如何通过智能调度提升充电桩可用率?
随着新能源汽车的普及,充电需求激增,但固定充电桩的布局难以满足用户灵活补能的需求,尤其在高峰时段或偏远地区,"充电难"问题日益凸显。移动充电服务作为新兴解决方案,通过动态调度充电资源,有望…...

SpringCloud Alibaba微服务-- Sentinel的使用(笔记)
雪崩问题: 小问题引发大问题,小服务出现故障,处理不当,可能导致整个微服务宕机。 假如商品服务出故障,购物车调用该服务,则可能出现处理时间过长,如果一秒几十个请求,那么处理时间过…...

PARSCALE:大语言模型的第三种扩展范式
----->更多内容,请移步“鲁班秘笈”!!<----- 随着人工智能技术的飞速发展,大语言模型(LLM)已成为推动机器智能向通用人工智能(AGI)迈进的核心驱动力。然而,传统的…...

在Windows上,将 Ubuntu WSL 安装并迁移到 D 盘完整教程(含 Appx 安装与迁移导入)
💻 将 Ubuntu WSL 安装并迁移到 D 盘完整教程(含 Appx 安装与迁移导入) 本文记录如何在 Windows 系统中手动启用 WSL、下载 Ubuntu 安装包、安装并迁移 Ubuntu 到 D 盘,避免默认写入 C 盘,提高系统性能与可维护性。 ✅…...

企微获取会话内容,RSA 解密函数
企微获取会话内容,RSA 解密函数 企微获取会话内容下载SDKSDK配置解密过程解密代码参考SDK文件上传到服务器最后 企微获取会话内容 官方文档: https://developer.work.weixin.qq.com/document/path/91774 下载SDK 根据自己的环境下载对应的SDK。 SDK配置…...

MyBatis入门:快速搭建数据库操作框架 + 增删改查(CRUD)
一、创建Mybatis的项目 Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动 1.添加依赖 或者 手动添加依赖 <!--Mybatis 依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactI…...

离线安装Microsoft 照片【笔记】
实验环境为:Windows 10 企业版 LTSC。 1.下载好相关离线依赖包和安装包。 2.管理员身份运行powershell,输入以下命令行: Add-AppPackage .\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe.Appx Add-AppPackage .\Microsoft.NET…...
地理卷积神经网络加权回归模型的详细实现方案
以下为地理卷积神经网络加权回归模型的详细实现方案。由于篇幅限制,代码和说明将分模块呈现。 地理卷积神经网络加权回归模型实现 目录 理论基础数据预处理模型架构设计空间权重矩阵生成混合模型实现实验与结果分析优化与扩展结论一、理论基础 1.1 地理加权回归(GWR) 地理…...

【后端高阶面经:Elasticsearch篇】39、Elasticsearch 查询性能优化:分页、冷热分离与 JVM 调优
一、索引设计优化:构建高效查询的基石 (一)分片与副本的黄金配置 1. 分片数量计算模型 # 分片数计算公式(单分片建议30-50GB) def calculate_shards(total_data_gb, single_shard_gb=30):return max...
光伏电站及时巡检:守护清洁能源的“生命线”
在“双碳”目标驱动下,光伏电站作为清洁能源的主力军,正以年均20%以上的装机增速重塑全球能源格局。然而,这些遍布荒漠、屋顶的“光伏矩阵”并非一劳永逸的能源提款机,其稳定运行高度依赖精细化的巡检维护。山东枣庄触电事故、衢州…...

基于 ZU49DR FPGA 的无线电射频数据采样转换开发平台核心板
无线电射频数据采样转换开发板及配套开发平台的核心板,该SOM核心板是一个最小系统,包括AMD公司的 Zynq UltraScale RFSOC 第3代系列XCZU49DR-2FFVF1760I FPGA、时钟、电源、内存以及 Flash。与其配套的底板是标准的全高全长Gen4.0 x8的PCIE卡,…...

软考 系统架构设计师系列知识点之杂项集萃(69)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(68) 第114题 若对关系R(A,B,C,D)和S(C,D,E)进行关系代数运算,则表达式 与()等价。 A.…...
从源码编译支持ffmpeg(H264编码)的opencv(创建mp4视频报错:H264 is not supported with codec id 28)
目录 步骤 1:安装 FFmpeg 在 Ubuntu 上安装 FFmpeg 在 Windows 上安装 FFmpeg 验证FFmpeg是否支持H264编码 步骤 3:克隆 OpenCV 源码 步骤 4:编译 步骤 5:验证安装 本人的配置如下: 系统:Ubuntu 18…...

leetcode 83和84 Remove Duplicates from Sorted List 和leetcode 1836
目录 83. Remove Duplicates from Sorted List 82. Remove Duplicates from Sorted List II 1836. Remove Duplicates From an Unsorted Linked List 删除链表中的结点合集 83. Remove Duplicates from Sorted List 代码: /*** Definition for singly-linked l…...
每日leetcode(昨天赶飞机没做,今天补)
896. 单调数列 - 力扣(LeetCode) 题目 如果数组是单调递增或单调递减的,那么它是 单调 的。 如果对于所有 i < j,nums[i] < nums[j],那么数组 nums 是单调递增的。 如果对于所有 i < j,nums[i]…...
SDL2常用函数:SDL_BlitSurfaceSDL_UpdateWindowSurface 数据结构及使用介绍
SDL_BlitSurface SDL_BlitSurface 是 SDL 1.2/2.0 中都存在的函数,用于将一个表面(Surface)的内容复制到另一个表面,支持部分复制、格式转换和简单的混合操作。 核心功能 表面复制:将源表面的像素数据复制到目标表面区域选择:可…...

【LeetCode 热题 100】买卖股票的最佳时机 / 跳跃游戏 / 划分字母区间
⭐️个人主页:小羊 ⭐️所属专栏:LeetCode 热题 100 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 买卖股票的最佳时机跳跃游戏跳跃游戏 II划分字母区间 买卖股票的最佳时机 买卖股票的最佳时机 class Solution { pu…...

万亿参数背后的算力密码:大模型训练的分布式架构与自动化运维全解析
目录 一、技术融合的时代背景 二、深度学习在 AI 大模型中的核心作用 2.1 预训练与微调机制 2.2 多模态深度学习的突破 三、分布式计算:大模型训练的基础设施 3.1 分布式训练核心原理 3.2 数据并行实战(PyTorch DDP) 3.3 模型并行与混…...
LangChain03-图数据库与LangGraph
图数据库与LangGraph集成实践 1. 引言 在构建智能问答系统、推荐引擎或复杂决策流程时,传统的关系型数据库和向量数据库往往难以满足对实体关系建模和多跳推理的需求。图数据库(如 Neo4j、TigerGraph)通过节点-边-属性的结构化表示ÿ…...
rabbitmq单机多实例部署
RabbitMQ 单实例部署 单实例部署是指在一台服务器上运行一个 RabbitMQ 实例。这种部署方式适用于小型应用或开发环境,配置简单,资源占用较少。单实例部署的核心是安装 RabbitMQ 并启动服务,通常需要配置 Erlang 环境,因为 RabbitMQ 是基于 Erlang 编写的。单实例部署的优势…...

Linux10正式版发布,拥抱AI了!
📢📢📢📣📣📣 作者:IT邦德 中国DBA联盟(ACDU)成员,10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主,全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…...

在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南
当然可以!以下是一篇结构清晰、语言通俗易懂的技术博客草稿,供你参考和使用: 在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南 背景介绍 最近在对一台内网的 OpenEuler-22.03 服务器进行安全扫描时,发现其 SSH 版本存在…...

全能邮箱全能邮箱:实现邮件管理的自动化!
全能邮箱全能邮箱:实现邮件管理的自动化! 全能邮箱全能邮箱的配置教程?如何注册烽火域名邮箱? 全能邮箱全能邮箱作为一种创新的邮件管理解决方案,正逐渐改变我们处理邮件的方式。蜂邮EDM将围绕全能邮箱全能邮箱&…...
[特殊字符] Linux 日志查看与分析常用命令全攻略
在日常运维与开发排查中,我们经常需要查看服务日志来定位问题。本文系统整理了几种常用的日志查看命令,包括 tail、cat、grep、split、sed 等,并结合实际应用场景,提供了完整的使用方式和示例。 📌 一、tail 命令 ——…...