MongoDB系列五(地理空间索引与查询).
一、经纬度表示方式
MongoDB 中对经纬度的存储有着自己的一套规范(主要是为了可以在该字段上建立地理空间索引)。包括两种方式,分别是 Legacy Coordinate Pairs (这个词实在不知道怎么翻译...) 和 GeoJSON 。
- Legacy Coordinate Pairs
Legacy Coordinate Pairs 又有两种方式可以存储经纬度,可以使用数组(首选)或嵌入式文档。
数组:
<field>: [<longitude>, <latitude> ]
嵌入式文档:
<field>: { <field1>: <longitude>, <field2>: <latitude> }
tips:有效经度值介于-180和180之间。有效纬度值介于-90和90之间。
- GeoJSON
GeoJson 比 Legacy Coordinate Pairs 要强大的多,Legacy Coordinate Pairs 仅仅用来保存一个经纬度,而 GeoJson 可以用来指定点、线和多边形。
点可以用形如[longitude, latitude]([经度,纬度])的两个元素的数组表示:
{
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
}
}
线可以用一个由点组成的数组来表示:
{
"geometry": {
"type": "LineString",
"coordinates": [[125.6, 10.1],[125.6,10.2],[125.6,10.3]]
}
}
多边形的表示方式与线一样(都是一个由点组成的数组),但是"type"不同:
{
"geometry": {
"type": "Polygon",
"coordinates": [[125.6, 10.1],[125.5,10.2],[125.7,10.3]]
}
}
type 除了 Point(点)、LineString(线)、Polygon(多边形),还有 MultiPoint(多点)、MultiLineString(多个线) 和 MultiPolygon(多个多边形)。
"geometry"字段的名字可以是任意的,但是其中的子对象是由GeoJSON指定的,不能改变。
二、地理空间索引
- 2dsphere索引
2dsphere索引用于地球表面类型的地图,允许使用在 Legacy Coordinate Pairs 保存的经纬度字段上和使用GeoJSON格式保存的点、线和多边形字段上。
db.world.ensureIndex({"geometry" : "2dsphere"})
- 2d索引
对于非球面地图(游戏地图、时间连续的数据等),可以使用"2d"索引代替"2dsphere"。
2d 索引 仅允许使用在 Legacy Coordinate Pairs 保存的经纬度字段上。
db.world.ensureIndex({"geometry" : "2d"})
- 区别:
2dsphere索引只支持球形查询(即球面上几何图形的查询)。
2d索引支持平面查询(即在平面上几何图形的查询)和一些球形查询。虽然2d索引支持一些球形查询,但是对这些球形查询使用2d索引可能会导致错误,例如极点附近会出现大量的扭曲变形。
2d索引只能对点进行索引。可以保存一个由点组成的数组,但是它只会被保存为由点组成的数组,不会被当成线。特别是对于"$geoWithin"查询来说,这是一项重要的区别。如果将街道保存为由点组成的数组,那么如果其中的某个点位于给定的形状之内,这个文档就会与$geoWithin相匹配。但是,由这些点组成的线并不一定完全包含在这个形状之内。
三、地理空间查询
可以使用多种不同类型的地理空间查询:交集(intersection)、包含(within)以及接近(nearness)。
- $geoIntersects
定义:指出与查询位置相交的文档。
支持的索引:2dsphere
几何操作符:
- $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的几何图形)
- $geoWithin
定义:指出完全包含在某个区域的文档。
支持的索引:2dsphere、2d
几何操作符:
- $box(仅支持 2d 索引,查询出矩形范围内的所有文档)
- $center(仅支持 2d 索引,查询出圆形范围内的所有文档)
- $polygon (仅支持 2d 索引,查询出多边形范围内的所有文档)
- $centerSphere(支持 2d 索引和 2dsphere 索引,查询出球面圆形范围内的所有文档)
- $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的几何图形)
- $near
定义:指出与查询位置从最近到最远的文档。
支持的索引:2dsphere、2d
几何操作符:
- $maxDistance (支持 2dsphere 索引和 2d 索引,指定查询结果的最大距离)
- $minDistance (仅支持 2dsphere 索引,指定查询结果的最小距离。在4.0后支持 2d 索引)
- $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的点)
备注:$minDistance 官方文档说仅支持 2dsphere 索引,但是我实践证明 $minDistance 也支持 2d 索引,大家可以试试看,这里保留争议。
- $nearSphere
定义:使用球面几何计算近球面的距离,指出与查询位置从最近到最远的文档。
支持的索引:2dsphere、2d
几何操作符:
- $maxDistance (支持 2dsphere 索引和 2d 索引,指定查询结果的最大距离)
- $minDistance (仅支持 2dsphere 索引,指定查询结果的最小距离。在4.0后支持 2d 索引)
- $geometry (仅支持 2dsphere 索引,指定GeoJSON格式的点)
备注:MongoDB 4.0 后对地理空间索引增加的支持?
1、地理空间查询操作符 $near 和 $nearSphere 支持查询的分片集合。
2、MongoDB 4.0 为 $geoNear 聚合运算符和 geoNear 命令添加了一个选项 key,使用户可以在查询时指定要使用的地理空间索引。以前,要使用 $geoNear 聚合运算符或 geoNear 命令,集合只能有一个地理空间索引。
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.98142 , 40.71782 ] },
key: "location",
distanceField: "dist.calculated",
query: { "category": "Parks" }
}
}
])
四、实践
- "$geoIntersects" 操作符找出与查询位置相交的文档 ?
db.driverPoint.find(
{
coordinate: {
$geoIntersects: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 118.193828, 24.492242 ], [ 118.193953, 24.702114 ], [ 118.19387, 24.592242 ],[ 118.193828, 24.492242 ]]
]
}
}
}
}
)
tips:coordinates 表示多边形,第一个点 和 最后一个点 必须相同,因为这样才能拼成一个多边形呀!
- "$geoWithin"操作符找出完全包含在某个区域的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ 118.193828, 24.492242 ], [ 118.193953, 24.702114 ], [ 119.19387, 28.792242 ],[ 118.193828, 24.492242 ]]
]
}
}
}
}
)
- "$geoWithin"操作符找出矩形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$box: [
[ 118.0,24.0 ],
[ 120.0,30.0 ]
]
}
}
}
)
tips:"$box"接受一个两元素的数组:第一个元素指定左下角的坐标,第二个元素指定右上角的坐标。
- "$geoWithin"操作符找出圆形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$center: [ [ 118.067678, 24.444373] , 10 ]
}
}
}
)
tips:"$center"接受一个两元素数组作为参数:第一个元素是一个点,用于指定圆心;第二个参数用于指定半径。
- "$geoWithin"操作符找出多边形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$polygon: [ [ 118.067678 , 24.444373 ], [ 119.067678 , 25.444373 ], [ 120.067678 , 26.444373 ] ]
}
}
}
)
tips:"$polygon" 列表中的最后一个点会被连接到第一个点,以便组成多边形。
- "$geoWithin"操作符找出球面圆形范围内的文档?
db.driverPoint.find(
{
coordinate: {
$geoWithin: {
$centerSphere: [ [ 118.067678, 24.444373 ], 10/3963.2 ]
}
}
}
)
tips:该例子表示 距离 [118.067678, 24.444373] 中心点10 英里范围内的所有文档,查询通过除以地球的大约赤道半径(3963.2英里)将距离转换为弧度。
- $near 找出距离一个点相应距离内的文档?
geoJson 格式(仅支持 2dsphere 索引):
db.driverPoint.find(
{
coordinate: {
$near: {
$geometry: {
type: "Point" ,
coordinates: [ 118.067678 , 24.444373 ]
},
$maxDistance: 3000,
$minDistance: 0
}
}
}
)
Legacy Coordinate Pairs 格式(仅支持 2d 索引):
db.driverPoint.find(
{
coordinate: {
$near: [ 118.193828 , 24.492242 ],
$maxDistance: 0.10
}
}
)
tips:1、$near 当用 geoJson 格式表示时, 距离单位是米(meter)。
2、$near 当用 Legacy Coordinate Pairs 格式表示时,距离单位是弧度(radian)。
3、"$near"是唯一一个会对查询结果进行自动排序的地理空间操作符:"$near"的返回结果是按照距离由近及远排序的。
五、结语
怎么说呢?学习这方面的知识老是给我一种特别乱的感觉。稍微总结下吧!MongoDB 对于地理空间的查询 是基于 它对 地理空间的索引(即2dsphere 和 2d)来实现的。所以,我们只要搞清楚什么时候 该建立 2dsphere 索引,什么时候该建立 2d 索引,然后再找适用于该索引的操作符就很清晰明了了!总之,geoJSON 格式保存的经纬度一定 建立 2dsphere 索引。Legacy Coordinate Pairs 格式保存的经纬度 仅在表示 平面地图的时候才考虑建立 2d 索引,其他情况还是选择 2dsphere 索引。
Spring Data MongoDB 中对地理位置的查询可参考 https://github.com/JMCuixy/SpringDataMongoDB 中单元测试的 Test03.java。
参考资料:
1、《MongoDB 权威指南第二版》
2、https://docs.mongodb.com/manual/reference/operator/query-geospatial/
MongoDB系列五(地理空间索引与查询).的更多相关文章
- MongoDB小结26 - 地理空间索引
现在有一种查询变得越来越流行(尤其是移动设备):找到离当前位置最近的N个场所. MongoDB专为平面坐标查询做了专门的索引,称为地理空间索引. 同样需要用ensureIndex创建,不过,参数是两个 ...
- ElasticSearch实战系列五: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合
Title:ElasticSearch实战系列四: ElasticSearch的聚合查询基础使用教程之度量(Metric)聚合 前言 在上上一篇中介绍了ElasticSearch实战系列三: Elas ...
- 全文索引&&地理空间索引
Ⅰ.全文索引 搜索引擎的实现核心技术,搜索类似where col like '%xxx%';关键字可以出现再某个列任何位置 这种查询条件,B+ tree索引是无法使用的.如果col上创建了索引,因为排 ...
- 6.MongoDB系列之特殊索引和集合类型
1. 地理空间索引及全文搜索 与Elasitcsearch一样,MongoDB同样支持地理空间索引及全文搜索,由于选型常用ES而非MongoDB此处略过 2. TTL索引 首先先了解下固定集合,其类似 ...
- 玩转mongodb(七):索引,速度的引领(全文索引、地理空间索引)
本篇博文主要介绍MongoDB中一些常用的特殊索引类型,主要包括: 用于简单字符串搜索的全文本索引: 用于球体空间(2dsphere)和二维平面(2d)的地理空间索引. 一.全文索引 MongoDB有 ...
- MongoDB 学习笔记之 地理空间索引入门
地理空间索引: 地理空间索引,可用于处理基于地理位置的查询. Point:用于指定所在的具体位置,我们以restaurants为例: db.restaurants.insert({name: &quo ...
- Mongodb地理空间索引
1.索引: 建立索引既耗时也费力,还需要消耗很多资源.使用{"bakckground":true}选项可以使这个过程在后台完成,同时正常处理请求.如果不包括background 这 ...
- mongodb的地理空间索引常见的问题
创建地理空间索引注意事项 创建地理空间索引失败,提示错误信息如下 > db.places.ensureIndex({"loc":"2dsphere"}){ ...
- MongoDB系列一(查询).
一.简述 MongoDB中使用find来进行查询.查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合.默认情况下,"_id"这个键总是被返回,即便是没有指定要返回这 ...
随机推荐
- 1-6 hibernate映射集合属性
1.集合类框架 以Tree开头都是按顺序,默认情况下是升序排列. 以Linked 开头的都是按插入顺序排列的. 2.在hibernate中要持久化集合属性时必须将其声明为接口,如 private Se ...
- 给我一台全新的服务器,使用nginx+gunicorn+supervisor部署django
0.准备工作 在一台全新的服务器中新建用户以及用户的工作目录,之后的操作都以这个用户的身份进行,而不是直接用root. 举个栗子: 在服务器下新建用户rinka并赋予sudo权限 1) root登陆, ...
- 【Flask】 项目结构说明
项目结构 Flask的一大优势就是其极其轻量化.但是也需要注意到,如果我们要用Flask做一个大项目的话,把所有代码写在一个文件里肯定是不合适的.非常难以维护.但是和Django这种框架又不一样,Fl ...
- C++顺序容器知识总结
容器是一种容纳特定类型对象的集合.C++的容器可以分为两类:顺序容器和关联容器.顺序容器的元素排列和元素值大小无关,而是由元素添加到容器中的次序决定的.标准库定义了三种顺序容器的类型:vector.l ...
- 关于ORM,以及Python中SQLAlchemy的scoped_session
orm(object relational mapping):对象关系映射. python面向对象,而数据库是关系型. orm是将数据库关系映射为Python中的对象,不用直接写SQL. 缺点是性能略 ...
- python 信号处理
linux开发中,通常会在进程中设置专门的信号处理方法,比如经常使用的CTRL+C,KILL等信号.如果你熟悉liunx编程,那么python等信号处理方法对你来说就很简单,下面的内容将主要介绍pyt ...
- [转] 关于VS中区分debug与release,32位与64位编译的宏定义
在vs编程中,常常涉及到32位和64位程序的编译,怎么判断当前编译是32位编译还是64位编译?如何判断是debug下编译还是release下编译?因为之前用到,这里记录一下,省的忘了又要疯狂的goog ...
- python替换残缺的多域名图片网址
在获取网站真是图片的时候,经常遇到图片链接残缺问题. 例如下图所示的情况: img标签中的图片链接是残缺的,如果这个网站域名又是多种情况的话,比如 http://sports.online.sh.cn ...
- Hibernate学习错误集锦-GenericJDBCException: could not execute statement
初次使用Hibernate,进行junit测试,报如下错误. 原因:Hibernate帮我们管理主键了,我们不需要对主键赋值,并且主键是自增的.所以在数据库中,逐渐选项应当勾选 org.hiberna ...
- 团队作业7——第二次项目冲刺(Beta版本)
Deadline: 2017-12-10 23:00PM,以博客发表日期为准. 评分基准: 按时交 - 有分,检查的项目包括后文的三个方面 冲刺计划安排(单独1篇博客) 七天的敏捷冲刺(每两天发布 ...