MongoDBでゆるふわDB体験

第9回 MongoDBの地理空間インデックス

この記事を読むのに必要な時間:およそ 4.5 分

地球の球面を考慮したクエリ

球面空間で近傍の検索には,$nearSphereオペレータを使用します。使い方は$nearオペレータと同じです。

> db.yamanotesen.find({ loc : { $nearSphere : [ 139.701238, 35.658871 ] } }).limit(3)

球面空間でgeoNearコマンドを使用するには,runCommandの中にspherical:trueというオプションを追加します。

> 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コマンドを使用すると,disフィールドは0.0002468278845577094となりました。単位はラジアンなので,地球の半径距離6378kmを乗することで実際の距離になります。

0.0002468278845577094×6378=約1.5km

渋谷駅と恵比寿駅の直線距離として,かなり現実に近い数値が取得できることがわかりました。

2dインデックスと2dsphereインデックス

MongoDB 2.4から,球面空間と,後ほど紹介するGeoJSONを扱うためのインデックスとして,2dsphereインデックスが新しく加えられました。2.4以降では,地理情報を扱うコレクションで,平面空間のものは2dインデックス,球面空間のものは2dsphereインデックスと使い分けるようになります。

範囲内の検索

$geoWithinオペレータ※4と以下のオペレータを使用することで,指定範囲内のドキュメントや,指定点から円形範囲のドキュメントを取得できます。

オペレータ用途
$box指定した四角形内のドキュメントを取得
$polygon指定した多角形内のドキュメントを取得
$center中心と半径を指定した円内のドキュメントを取得
$centerSphere球面空間での$center
※4)
バージョン2.4から,これまでの$withinオペレータに変わって,$geoWithinオペレータが追加されました。$withinオペレータは2.4以降では非推奨となります。

GeoJSONで地理空間インデックスを使ってみる

バージョン2.4からGeoJSONがサポートされました。GeoJSONは,空間上で点や直線や多角形という図形を扱うためのフォーマットです。GeoJSONを使用することで,交差する図形の検索ができるようになりました。また,これまでに紹介した近傍の検索も可能です。概要に関しては,この連載の前回第8回「リリース間近! MongoDB 2.4の新機能」で紹介しましたので,今回はインデックスの作成と,交差する図形の検索クエリを紹介します。

2dsphereインデックスの作成

GeoJSONを使用するには,これまで使用していた2dインデックスではなく,2dsphereインデックスを使用します。geojsonコレクションのgeoフィールドに2dsphereインデックスを作成するクエリは,このようになります。

> db.geojson.ensureIndex( { geo : "2dsphere" } );

GeoJSONオブジェクトのinsert

今回はGeoJSONオブジェクトの一つである,LineStringを使用します。これは空間に直線を表現するオブジェクトです。3つのLineStringをinsertしてみます。

> 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 ] ] }});

上記のクエリにより,図1のように垂直な直線が3本ある状態となりました。

図1 3本の垂直な直線

図1 3本の垂直な直線

交差する図形の検索

交差するGeoJSONオブジェクトを検索するには$geoIntersectsオペレータを使用します。上の3本の直線に対して,水平な直線[ [ 0, 5 ], [ 12, 5 ] ]を引き,交差するオブジェクトを検索してみます。

図2 水平な直線を追加

図2 水平な直線を追加

クエリはこのようになります。

> 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 ] ] } }

検索結果には,横の直線と交差しているオブジェクトであるtate05とtate10の2つが返ってきました。

次回のテーマ

今回はMongoDBの特徴的な機能の一つである地理空間インデックスについて紹介いたしました。すでに多くの位置情報を利用したサービスで使用されていましたが,バージョン2.4でGeoJSONをサポートしたことにより,さらに使用範囲が広くなりました。今後も,位置情報を利用する際の選択肢として,MongoDBは有力な候補となりそうです。

次回はMongoDBでのMap/Reduceについて紹介する予定です。

著者プロフィール

藤崎祥見(ふじさきしょうけん)

野村総合研究所 OpenStandia所属。オープンソースのR&Dとセミナー講師を担当。

Debian,Ubuntu,Liferayのコミュニティで活動した後,MongoDBの翻訳に関わり,丸の内MongoDB勉強会を始める。

実家がお寺で,住職の資格を所持する坊主系エンジニア。

Twitter:@syokenz


渡部徹太郎(わたなべてつたろう)

野村総合研究所 OpenStandia所属。オープンソースを使ったSIやサポートの業務に従事。

藤崎と共同で丸の内MongoDB勉強会を始める。

趣味は自宅サーバ。好きなものはLinuxとRuby。

Twitter:@fetarodc


林田敦(はやしだあつし)

野村総合研究所 OpenStandia所属。オープンソースを使ったSIや製品開発業務に従事。

丸の内MongoDB勉強会では広報兼雑用係を務める。

趣味はレザークラフト,ダイビング,スキー,キャンプ,ジェットスキー,カメラ等々。作って滑って撮って潜れるエンジニア。

Facebook:Atsushi Hayashida