1. 程式人生 > >MongoDB——地理空間索引和查詢

MongoDB——地理空間索引和查詢

MongoDB提供了一系列的索引和查詢機制來處理地理空間資訊。這一節會介紹MongoDB的地理索引特性。您可以閱讀 地理索引教程 來了解關於MongoDB中地理查詢的完整示例。

表面

在您儲存地理資料和編寫查詢條件前,首先,您必須選擇表面型別,這將被用在計算中。您所選擇的型別將會影響您的資料如何被儲存,建立的索引的型別,以及您的查詢的語法形式。

MongoDB提供了兩種表面型別:

球面

如果需要計算地理資料就像在一個類似於地球的球形表面上,您可以選擇球形表面來儲存資料,這樣就可以使用 2dsphere 索引。

您可以按照座標軸:經度,緯度 的方式把位置資料儲存為GeoJSON物件。GeoJSON的座標參考系使用的是 

WGS84 資料。

平面

如果需要計算距離,就像在一個歐幾里德平面上,您可以按照正常座標對的形式儲存位置資料並使用 2d索引。

位置資料

如果您選擇球形表面來計算,您可以選擇把位置資料儲存為如下兩種格式之一:

GeoJSON物件

對 GeoJSON 的查詢總是基於球形表面。GeoJSON的預設座標參考系使用的是 WGS84 資料。

2.4 新版功能: 在版本2.4新引入了對GeoJSON的儲存和查詢支援。在版本2.4以前,所有的地理資料使用座標對的形式。

在 2.6 版更改: 支援更多GeoJSON型別:多點, 多線段, MultiPolygon, 幾何體集合。

MongoDB支援如下GeoJSON物件:

  • 單點

  • 線段

  • 多邊形

  • 多點

  • 多線段

  • MultiPolygon
  • 幾何體集合

普通座標對

MongoDB支援對使用 2dsphere 索引的 legacy coordinate pairs (普通座標對)資料進行球面計算,方式是把資料轉換成GeoJSON Point型別。

如果您選擇的是平面計算且使用 2d 索引,那麼您可以把資料儲存為僅 :term:`legacy coordinate pairs`格式。

查詢操作

MongoDB地理空間查詢操作允許您查詢:

包含

MongoDB可以查詢被完全包含於一個指定多邊形區域中的位置。包含查詢使用的是 

$geoWithin 操作符。

兩種索引 2d 和 2dsphere 索引都支援包含查詢。在版本2.2.3之後,對於包含查詢,MongoDB不再要求有索引。但是,這些索引可以提升查詢效能。

交叉

MongoDB可以查詢位置和一個指定幾何圖形的交叉。這些查詢僅可以被用於查詢儲存在球形平面上的資料。這些查詢使用 $geoIntersects 操作符。

只有 2dsphere 索引才支援交叉。

鄰近

MongoDB可以查詢和某個點最近的其他點。鄰近查詢使用 $near 操作符。 $near 操作符要求有 2d 或者2dsphere 索引。

地理空間索引

MongoDB提供瞭如下的地理索引型別來支援地理查詢。

2dsphere

  • 在球形平面上的計算

  • GeoJSON物件和對普通座標對的向後相容。

  • 複合索引。這個複合索引可以包含一個 2dsphere 索引欄位以及一些按升序或降序建立的普通索引欄位(作為 2dsphere 索引的字首或者字尾)。

2.4 新版功能: 在版本2.4之前``2dsphere`` 索引是不可用的。

參見

2d

2d 索引支援如下特性:

  • 使用平面幾何的方式計算

  • 普通座標對(比如,在一個平面座標系中的點)

  • 作為複合索引,額外索引一個鍵。方法是,把額外的一個鍵作為 2d 索引鍵的字尾

參見

地理空間索引和分片

您 不能 使用地理索引來作為 shard key 索引。

您可以在一個被分片的集合上建立並維護一個一個地理空間索引,使用的不能是分片鍵。

對於被分片的幾何,使用了 $near 操作的查詢是不被支援的。作為替代,您可以使用 geoNear 命令或者$geoNear 在聚合階段的時候。

您還可以使用 $geoWithin 來查詢地理空間資料。

其它資源

以下頁面提供了關於地理空間索引和查詢的完整文件

MongoDB的 2dsphere 索引支援查詢在一個類地球的球面上進行幾何計算。 索引支援以GeoJSON物件或者普通座標對的方式儲存資料。

2d 索引

MongoDB的 2d 索引支援以普通座標對的方式儲存資料,用於MongoDB2.2版及以前

haystack索引是一個被特殊優化過的索引,用於返回小區域結果。對於那些使用球面幾何的查詢而言, 2dsphere 會是一個更好的選擇。

提供了對地理索引更深層次本質的闡釋。這份材料對於普通操作者不是必須的,但是對於正在排除障礙或者想要更深入理解的使用者也許有點幫助。

參見

二.示例

建立places集合,來存放地點, loc欄位用來存放地區資料GeoJSON Point。

db.places.insert(
   {
      loc : { type: "Point", coordinates: [ -73.97, 40.77 ] },
      name: "Central Park",
      category : "Parks"
   }
)
 
db.places.insert(
   {
      loc : { type: "Point", coordinates: [ -73.88, 40.78 ] },
      name: "La Guardia Airport",
      category : "Airport"
   }
)

建立索引

db.places.ensureIndex( { loc : "2dsphere" } )

引數不是1或-1,為2dsphere。還可以建立組合索引。

db.places.ensureIndex( { loc : "2dsphere" , category : -1, name: 1 } )

3. 查詢

$geometry表示查詢的幾何圖片.

3.1 查詢多邊形範圍的值

type表示型別:polygon 多邊形

db.places.find( { loc :
                  { $geoWithin :
                    { $geometry :
                      { type : "Polygon" ,
                        coordinates : [ [
                                          [ 0 , 0 ] ,
                                          [ 3 , 6 ] ,
                                          [ 6 , 1 ] ,
                                          [ 0 , 0 ]
                                        ] ]
                } } } } )

3.2 查詢附近的值

使用$near來查詢附近的地點。

db.places.find( { loc :
                        { $near :
                          { $geometry :
                             { type : "Point" ,
                               coordinates : [ <longitude> , <latitude> ] } ,
                            $maxDistance : <distance in meters>
                     } } } )

3.3 查詢圓形內的值

查詢圓時,需要指定圓心, 半徑。

db.places.find( { loc :
                  { $geoWithin :
                    { $centerSphere :
                       [ [ -88 , 30 ] , 10 ]
                } } } )

二.專案中springMVC中是用mongoDb查詢範圍得點

  2.1建立索引

/deliver資料
deliver:{
"deliverArea": [
                {
                    "area": [
                        {
                            "district": "叢臺區",
                            "location": {
                                "lat": 36.613143702791,
                                "lng": 114.50521301419
                            },
                            "street": "朝陽路",
                            "street_number": "5號"
                        },
                        {
                            "district": "叢臺區",
                            "location": {
                                "lat": 36.612694686043,
                                "lng": 114.50516800908
                            },
                            "street": "朝陽路",
                            "street_number": "5號"
                        },
                        {
                            "district": "叢臺區",
                            "location": {
                                "lat": 36.612744657392,
                                "lng": 114.50573403138
                            },
                            "street": "朝陽路",
                            "street_number": "5號"
                        },
                        {
                            "district": "叢臺區",
                            "location": {
                                "lat": 36.61310669522,
                                "lng": 114.50577903649
                            },
                            "street": "朝陽路",
                            "street_number": "14號"
                        }
                    ]
                }
            ],
            "deliverId": "D011122"
}
db.deliver.ensureIndex({"deliverArea.area.location":"2dsphere"})

2.2查詢命令

//mongoDB shell
db.deliver.aggregate([
   {
     $geoNear: {
        near: { type: "Point", coordinates: [ 114.495539 , 36.597626 ] },
        distanceField: "deliverArea.area.location",
        maxDistance: 10,     
        num: 5,
        spherical: true
     }
   }
])
/spingMvc 使用Aggregation 
Point location = new Point(114.495539 , 36.597626);
NearQuery query = NearQuery.near(location).maxDistance(new Distance(distance, Metrics.MILES)).num(5).spherical(true); 
Aggregation aggregation = newAggregation( geoNear(query,"deliver") ); 
AggregationResults<Deliver> results = mongoTemplate.aggregate(aggregation,"deliver",Deliver.class);

//spring 使用MongoOperations
Point location = new Point(-73.99171, 40.738868);
NearQuery query = NearQuery.near(location).maxDistance(new Distance(10, Metrics.MILES));

GeoResults<Restaurant> = operations.geoNear(query, Restaurant.class);

其中需要注意的是 maxDistance(new Distance(10, Metrics.MILES));表示的是英里,可以指定為KM或者單位換算