地理空間インデックスの概要
MongoDBでは、
MongoDBの地理空間インデックスは、
こちらに、
| バージョン | リリースされた機能 |
|---|---|
| 1. | 地理空間インデックスをサポート |
| 1. | 球面空間でのクエリをサポート |
| 2. | GeoJSONオブジェクトをサポート |
それではさっそく地理空間インデックスを使ってみましょう。
シンプルなデータで地理空間インデックスを使ってみる
2dインデックスの作成
地理空間インデックスを使うためには、
> db.yamanotesen.ensureIndex( { loc : "2d" } );
次にデータのinsertを行います。
データの準備
地理空間インデックスを使うため、
| 駅 | 経度 | 緯度 |
|---|---|---|
| 五反田 | 139. | 35. |
| 恵比寿 | 139. | 35. |
| 新宿 | 139. | 35. |
| 新大久保 | 139. | 35. |
| 池袋 | 139. | 35. |
| 上野 | 139. | 35. |
| 品川 | 139. | 35. |
経度・
> db.yamanotesen.insert({ name:"五反田",loc: [ 139.723822, 35.625974 ] });
> db.yamanotesen.insert({ name:"恵比寿",loc: [ 139.710070, 35.646685 ] });
> db.yamanotesen.insert({ name:"新宿",loc: [ 139.700464, 35.689729 ] });
> db.yamanotesen.insert({ name:"新大久保",loc: [ 139.700261, 35.700875 ] });
> db.yamanotesen.insert({ name:"池袋",loc: [ 139.711086, 35.730256 ] });
> db.yamanotesen.insert({ name:"上野",loc: [ 139.777043, 35.713790 ] });
> db.yamanotesen.insert({ name:"品川",loc: [ 139.738999, 35.628760 ] });
準備は整いましたので、
近傍を検索するクエリ
近傍の検索には、
> db.yamanotesen.find({ loc : { $near : [ 139.701238, 35.658871 ] }}).limit(3)
今回準備した7つの駅で、
> db.yamanotesen.find({ loc : { $near : [ 139.701238, 35.658871 ] }},{"_id":0}).limit(3)
{ "name" : "恵比寿", "loc" : [ 139.71007, 35.646685 ] }
{ "name" : "新宿", "loc" : [ 139.700464, 35.689729 ] }
{ "name" : "五反田", "loc" : [ 139.723822, 35.625974 ] }
検索結果の詳細情報取得
geoNearコマンドを使用することで、
> db.runCommand({'geoNear':'yamanotesen', near : [ 139.701238, 35.658871 ], num: 1})
{
"ns" : "test.yamanotesen",
"near" : "1110100101001011001100110110111110110111011101111101",
"results" : [
{
"dis" : 0.015050010631232593,
"obj" : {
"_id" : ObjectId("514a653517ca6b06a3266e26"),
"name" : "恵比寿",
"loc" : [
139.71007,
35.646685
]
}
}
],
"stats" : {
"time" : 0,
"btreelocs" : 0,
"nscanned" : 5,
"objectsLoaded" : 3,
"avgDistance" : 0.015050010631232593,
"maxDistance" : 0.015066109444883333
},
"ok" : 1
}
経度・
0.
015050010631232593×111. 262283=約1. 7km
となります。
地球は球面なので平面空間で計算すると誤差が出てしまいます。MongoDBは球面空間でのクエリもサポートしていますので、
地球の球面を考慮したクエリ
球面空間で近傍の検索には、
> db.yamanotesen.find({ loc : { $nearSphere : [ 139.701238, 35.658871 ] } }).limit(3)
球面空間でgeoNearコマンドを使用するには、
> db.runCommand({'geoNear':'yamanotesen', near : [ 139.701238, 35.658871 ], num: 1, spherical:true})
{
"ns" : "test.yamanotesen",
"near" : "1110100101001011001100110110111110110111011101111101",
"results" : [
{
"dis" : 0.0002468278845577094,
"obj" : {
"_id" : ObjectId("514a653517ca6b06a3266e26"),
"name" : "恵比寿",
"loc" : [
139.71007,
35.646685
]
}
}
],
"stats" : {
"time" : 0,
"btreelocs" : 0,
"nscanned" : 5,
"objectsLoaded" : 3,
"avgDistance" : 0.0002468278845577094,
"maxDistance" : 0.0002471235288170513
},
"ok" : 1
}
spherical:trueとしてgeoNearコマンドを使用すると、
0.
0002468278845577094×6378=約1. 5km
渋谷駅と恵比寿駅の直線距離として、
範囲内の検索
$geoWithinオペレータ
| オペレータ | 用途 |
|---|---|
| $box | 指定した四角形内のドキュメントを取得 |
| $polygon | 指定した多角形内のドキュメントを取得 |
| $center | 中心と半径を指定した円内のドキュメントを取得 |
| $centerSphere | 球面空間での$center |
GeoJSONで地理空間インデックスを使ってみる
バージョン2.
2dsphereインデックスの作成
GeoJSONを使用するには、
> db.geojson.ensureIndex( { geo : "2dsphere" } );
GeoJSONオブジェクトのinsert
今回はGeoJSONオブジェクトの一つである、
> db.geojson.insert({"name": "tate05", geo:{ "type": "LineString", "coordinates": [ [ 5, 0 ], [ 5, 10 ] ] }});
> db.geojson.insert({"name": "tate10", geo:{ "type": "LineString", "coordinates": [ [ 10, 0 ], [ 10, 10 ] ] }});
> db.geojson.insert({"name": "tate15", geo:{ "type": "LineString", "coordinates": [ [ 15, 0 ], [ 15, 10 ] ] }});
上記のクエリにより、
交差する図形の検索
交差するGeoJSONオブジェクトを検索するには$geoIntersectsオペレータを使用します。上の3本の直線に対して、
クエリはこのようになります。
> db.geojson.find({geo:{ "$geoIntersects": { "$geometry": { "type": "LineString", "coordinates": [ [ 0, 5 ], [ 12, 5 ] ]}} }}, {"_id":0});
{ "name" : "tate05", "geo" : { "type" : "LineString", "coordinates" : [ [ 5, 0 ], [ 5, 10 ] ] } }
{ "name" : "tate10", "geo" : { "type" : "LineString", "coordinates" : [ [ 10, 0 ], [ 10, 10 ] ] } }
検索結果には、
次回のテーマ
今回はMongoDBの特徴的な機能の一つである地理空間インデックスについて紹介いたしました。すでに多くの位置情報を利用したサービスで使用されていましたが、
次回はMongoDBでのMap/


