MongoDBでゆるふわDB体験

第10回 MongoDBでの集計処理

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

MongoDBのMap/Reduce

これまでにAggregationフレームワークで実行した集計を,今度はMap/Reduceを使って集計します。Map/ReduceにはJavaScriptで記述したMap関数とReduce関数が必要となりますので,準備しましょう。

Map関数の準備

Map関数は,おおまかに言うとReduce関数で使用するためのkeyとvalueを作成するための処理です。Map関数では集計処理はまだ行いません。

keyにはグルーピングするキーを指定します。先ほどと同様に,まずはURLごとのアクセス数を集計しますので,HTTPステータスコードは無視します。HTTPステータスコードも利用した複数キーの集計は,後ほど紹介します。

Map関数内部でkeyとvalueを作成するために,emit関数を使用します。第1引数にkey, 第2引数に集計方法を記述します。ここでは,第1引数this.url_path,第2引数{count : 1}を指定します。

> map = function() {
  emit(this.url_path, {count: 1});
}

Reduce関数の準備

Reduce関数には,Map関数内のemit関数で指定したkeyでグルーピングされた状態で,keyとvalueが渡ってきます。今回は,URLごとにアクセス数を数えるため,countを加算していく処理を記述します。

> reduce = function(key, values) {
  var count = 0;
  values.forEach(function(v) {
    count += v['count'];
  });
  return {count: count};
}

Map/Reduceで集計する

Map関数とReduce関数が作成できたら,集計してみましょう。集計には,集計するコレクションのmapReduce関数の引数に第1引数にMap関数,第2引数にReduce関数を渡します。第3引数はオプションを渡します。{out: {inline:1}}を指定することで,結果をコンソールに出力することができます。

それでは,mapReduce関数を実行してみましょう。

> db.httplogs.mapReduce( map, reduce, {out: {inline:1}} );
{
        "results" : [
                {
                        "_id" : "/",
                        "value" : {
                                "count" : 4
                        }
                },
                {
                        "_id" : "/top",
                        "value" : {
                                "count" : 3
                        }
                },
                {
                        "_id" : "/user",
                        "value" : {
                                "count" : 3
                        }
                }
        ],
        "timeMillis" : 1,
        "counts" : {
                "input" : 10,
                "emit" : 10,
                "reduce" : 3,
                "output" : 3
        },
        "ok" : 1,
}

URLアクセス数の合計が,countで集計されていることが確認できました。

次はURLとHTTPステータスコードの2つをキーとして集計してみましょう。

※)
オプションでは,結果を保存するコレクションの指定や,最後に実施するfinalize関数の指定が可能です。詳細は公式マニュアルを参照ください。

複数キーで集計する

複数キーで集計するためには,emit関数の第1引数にハッシュで指定します。Map関数を修正します。

URLとHTTPステータスコードをキーとするために,第1引数を下記のように変更します。

> map = function() {
  emit({url_path: this.url_path, status: this.status}, {count: 1});
}

Reduce関数は先ほどのままで良いので,mapReduce関数を実行してみましょう。

> db.httplogs.mapReduce( map, reduce, {out: {inline:1}} );
{
        "results" : [
                {
                        "_id" : {
                                "url_path" : "/",
                                "status" : "200"
                        },
                        "value" : {
                                "count" : 2
                        }
                },
                {
                        "_id" : {
                                "url_path" : "/",
                                "status" : "500"
                        },
                        "value" : {
                                "count" : 2
                        }
                },
...

URLとHTTPステータスコードが集計のキーとなっていることが確認できました。

Map/Reduceでできること

Map/Reduceでは,JavaScriptを用いて自由にMap関数とReduce関数を定義できることが大きな特徴です。Aggregationフレームワークではできない,ifなどの制御構文やその他のJavaScriptの関数を使用した処理を実装することが可能です。

それでは最後に,Hadoopとの連携を紹介します。

その他集計処理ミドル(Hadoop)との連携

Hadoopと組み合わせて使う

Hadoopは,大量のデータを複数のマシンで分散処理可能なプラットフォームです。MongoDBの開発元である10genは,HadoopとのコネクターとしてMongoDB Hadoop Adapter(mongo-hadoop)をgithubで公開しています。

公式マニュアルも充実しており,コマンドレベルでのGetting Started with Hadoopや,バッチシステム・データウェアハウス・ETLシステムの3つが紹介されたHadoop and MongoDB Use Casesがあります。

MongoDBとHadoopを組み合わせて使用することによって,データストアにMongoDBを使いながら,Hadoopの強力な分散機能により並列処理を行うことが可能となります図2参照⁠⁠。レプリカセット,シャーディング,Mongo Shellによる柔軟なクエリというデータストアとしてのMongoDBのメリットを活かしながら,Hadoopの分散処理機能を使えるという,お互いを補完し合う組み合わせが実現できます。

図2 MongoDBとHadoopの組み合わせ

図2 MongoDBとHadoopの組み合わせ

今回の記事では,MongoDB Hadoop Adapterについての紹介のみといたします。実際の使い方は公式マニュアルを参照ください。

まとめと次回のテーマ

今回はMongoDBで集計を実施する方法を紹介しました。MongoDBには,クエリライクに集計を実施できるAggregationフレームワークと,自分で処理内容を記述できるMap/Reduce機能とがあります。用途に応じて使い分けることが可能です。

また,近年需要が増加しているビッグデータへの集計処理には,Hadoopと組み合わせて使用するという方式があります。MongoDB開発元の10genがHadoop用のコネクタを提供しています。

次回はMongoDBの運用について紹介する予定です。お楽しみに!

著者プロフィール

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

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

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

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

Twitter:@syokenz


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

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

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

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

Twitter:@fetarodc


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

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

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

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

Facebook:Atsushi Hayashida