地理空间索引(2d、2dsphere)
地理空间索引(2d、2dsphere)
MongoDB提供了两种地理空间索引类型:2d和2dsphere。2d索引适用于平面坐标系上的点数据,而2dsphere索引则支持球面坐标系上的点、线和多边形数据。这两种索引都能显著提升地理空间查询的性能。
2d索引
2d索引用于处理平面地图上的点数据,适用于简单的二维坐标系统。这种索引类型最适合处理小范围的地理数据,比如城市地图或游戏地图。
创建2d索引的基本语法:
db.collection.createIndex({ locationField: "2d" })
2d索引支持以下查询操作符:
- $near:查找距离某个点最近的点
- $geoWithin:查找位于某个几何图形内的点
- $box:矩形范围查询
- $center:圆形范围查询
- $polygon:多边形范围查询
示例:创建一个包含位置信息的集合并建立2d索引
db.places.insertMany([
{ name: "Central Park", location: [ -73.97, 40.77 ] },
{ name: "Empire State", location: [ -73.99, 40.75 ] },
{ name: "Times Square", location: [ -73.99, 40.76 ] }
])
db.places.createIndex({ location: "2d" })
查询距离某个点最近的3个地点:
db.places.find({
location: {
$near: [ -73.98, 40.77 ],
$maxDistance: 2
}
}).limit(3)
2dsphere索引
2dsphere索引支持更复杂的地理空间查询,包括点、线和多边形数据。它使用WGS84坐标系,适合处理地球表面的地理数据。
创建2dsphere索引的基本语法:
db.collection.createIndex({ locationField: "2dsphere" })
2dsphere索引支持以下查询操作符:
- $geoWithin:查找完全包含在某个几何图形内的文档
- $geoIntersects:查找与某个几何图形相交的文档
- $near:查找距离某个点最近的文档
- $nearSphere:类似$near,但使用球面距离计算
示例:创建一个包含GeoJSON数据的集合并建立2dsphere索引
db.cities.insertMany([
{
name: "New York",
location: {
type: "Point",
coordinates: [ -73.97, 40.77 ]
}
},
{
name: "San Francisco",
location: {
type: "Point",
coordinates: [ -122.42, 37.78 ]
}
}
])
db.cities.createIndex({ location: "2dsphere" })
查询距离某个点1000米范围内的城市:
db.cities.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [ -73.98, 40.77 ]
},
$maxDistance: 1000
}
}
})
地理空间查询示例
多边形区域查询
查找位于某个多边形区域内的所有点:
db.places.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [[
[ -73.98, 40.76 ],
[ -73.99, 40.76 ],
[ -73.99, 40.77 ],
[ -73.98, 40.77 ],
[ -73.98, 40.76 ]
]]
}
}
}
})
线与多边形相交查询
查找与某条线相交的所有多边形:
db.roads.find({
geometry: {
$geoIntersects: {
$geometry: {
type: "LineString",
coordinates: [
[ -73.98, 40.77 ],
[ -73.99, 40.77 ]
]
}
}
}
})
索引选择与优化
选择2d还是2dsphere索引取决于数据类型和使用场景:
- 如果数据是简单的二维平面坐标且不需要考虑地球曲率,使用2d索引
- 如果数据是GeoJSON格式或需要精确的地球表面距离计算,使用2dsphere索引
复合索引示例:
db.places.createIndex({
location: "2dsphere",
category: 1,
rating: -1
})
这种复合索引可以优化同时包含地理空间条件和其他条件的查询。
性能考虑
地理空间索引的性能受以下因素影响:
- 数据量:索引大小直接影响查询性能
- 查询复杂度:$geoWithin通常比$near更快
- 索引类型:2d索引通常比2dsphere索引更快,但功能有限
对于大型数据集,可以考虑:
- 使用分片集群分散地理空间数据
- 合理设置$maxDistance限制结果集大小
- 避免在查询中使用过于复杂的几何图形
实际应用场景
附近地点搜索
实现一个查找附近餐馆的功能:
function findNearbyRestaurants(longitude, latitude, maxDistance) {
return db.restaurants.find({
location: {
$nearSphere: {
$geometry: {
type: "Point",
coordinates: [ longitude, latitude ]
},
$maxDistance: maxDistance
}
},
category: "restaurant"
}).sort({ rating: -1 }).limit(10)
}
地理围栏应用
检测用户是否进入某个预定区域:
function checkGeoFence(userLocation, fenceId) {
const fence = db.geoFences.findOne({ _id: fenceId })
return db.geoFences.findOne({
_id: fenceId,
geometry: {
$geoIntersects: {
$geometry: {
type: "Point",
coordinates: userLocation
}
}
}
}) !== null
}
地理空间聚合
MongoDB的地理空间聚合功能可以用于更复杂的分析:
计算每个区域内的点数:
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ -73.98, 40.77 ] },
distanceField: "distance",
maxDistance: 5000,
spherical: true
}
},
{
$group: {
_id: "$category",
count: { $sum: 1 },
avgDistance: { $avg: "$distance" }
}
}
])
常见问题与解决方案
-
坐标顺序问题:
- GeoJSON使用[经度, 纬度]顺序
- 传统坐标可能使用[纬度, 经度]顺序
- 确保数据格式一致
-
性能优化:
- 对于大范围查询,先使用$geoWithin缩小范围,再用$near排序
- 避免在查询中使用$or操作符组合多个地理空间条件
-
精度问题:
- 2d索引使用平面距离计算,不适合大范围地理数据
- 2dsphere索引使用球面距离计算,精度更高但计算成本也更高
高级用法
地理空间数据与全文搜索结合
db.places.createIndex({ location: "2dsphere", name: "text" })
db.places.find({
$text: { $search: "coffee" },
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [ -73.98, 40.77 ]
},
$maxDistance: 1000
}
}
})
动态地理空间查询
构建动态查询条件:
function buildGeoQuery(center, radius, categories) {
const query = {
location: {
$geoWithin: {
$centerSphere: [ center, radius / 6378.1 ]
}
}
}
if (categories && categories.length > 0) {
query.category = { $in: categories }
}
return query
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:全文索引与文本搜索
下一篇:哈希索引与TTL索引