MongoDBでの集計処理の概要
一般的なNoSQLプロダクトは、
しかし、
- 1. Aggregationフレームワーク
- SQLでいうGroup By句やSum関数を提供します。Mongo Shellからクエリと同じように実施できます。一部の処理
($groupと$sort) はシャーディングに対応しており、 各シャードで処理します。 - 2. MongoDBのMap/
Reduce機能 - Map関数/Reduce関数を独自に定義し、
集計処理を行います。Aggregationフレームワークではできないような、 複雑な集計処理を行うために使用します。シャーディングに対応していますので、 分散処理を実施することが可能です。 - 3. その他集計処理ミドルとの連携
- より大規模に集計処理を行うため、
他の集計処理ミドルとの連携も可能です。今回の記事では、 Hadoopとの連携を紹介します。
それではさっそくAggregationフレームワークを使って、
Aggregationフレームワーク
データの準備
最初に集計するためのデータを準備しましょう。今回はWebサーバーのアクセスログを想定したデータを用います。下記のサンプルデータをMongoDBへ保存します。
> db.httplogs.insert({"url_path":"/", "status":"200"}); > db.httplogs.insert({"url_path":"/", "status":"200"}); > db.httplogs.insert({"url_path":"/", "status":"500"}); > db.httplogs.insert({"url_path":"/", "status":"500"}); > db.httplogs.insert({"url_path":"/top", "status":"200"}); > db.httplogs.insert({"url_path":"/top", "status":"200"}); > db.httplogs.insert({"url_path":"/top", "status":"404"}); > db.httplogs.insert({"url_path":"/user", "status":"200"}); > db.httplogs.insert({"url_path":"/user", "status":"500"}); > db.httplogs.insert({"url_path":"/user", "status":"500"});
Aggregationフレームワークで集計する
それではAggregationフレームワークを使って集計してみましょう。先ほど保存したアクセスログのデータ使用して、
URLごとのアクセス数の集計をAggregationフレームワークで実施するには、
> db.httplogs.aggregate ( { $group : { "_id" : "$url_path", "count" : { "$sum" : 1 } } } );
実行してみます。
> db.httplogs.aggregate ( { $group : { "_id" : "$url_path", "count" : { "$sum" : 1 } } } ); { "result" : [ { "_id" : "/user", "count" : 3 }, { "_id" : "/top", "count" : 3 }, { "_id" : "/", "count" : 4 } ], "ok" : 1 }
集計できました。
複数キーで集計する
次はURLとHTTPステータスコードの2つをキーとして集計してみましょう。 複数キーで集計するには、
> db.httplogs.aggregate( { $group : { "_id" : { "url_path" : "$url_path", "status" : "$status" }, "count" : { "$sum" : 1 } } } );
実行してみます。
> db.httplogs.aggregate( { $group : { "_id" : { "url_path" : "$url_path", "status" : "$status" }, "count" : { "$sum" : 1 } } } ); { "result" : [ { "_id" : { "url_path" : "/user", "status" : "500" }, "count" : 2 }, { "_id" : { "url_path" : "/user", "status" : "200" }, "count" : 1 }, ...
こちらも集計できました。
Aggregationフレームワークでできること
このように、
他にもAggregationフレームワークには集計に便利なオペレータが用意されており、
たとえば以下のような、
SELECT name as '_id', AVG(score) as 'average' FROM scores
WHERE year = 'junior'
GROUP BY = name
上記のSQLをAggregationフレームワークで表現すると、
db.scores.aggregate(
{ $match : { "year" : "junior" } },
{ $project : { "name" : 1, "score" : 1 } },
{ $group : { "_id" : "$name",
"average" : { "$avg" : "$score" } } }
);
このようにオペレータをフィルタのように使い、

その他のオペレータについては、
SQL | Aggregationオペレータ |
---|---|
WHERE | $match |
GROUP BY | $group |
HAVING | $match |
SELECT | $project |
ORDER BY | $sort |
LIMIT | $limit |
SUM() | $sum |
COUNT() | $sum |
公式マニュアルには他にも、
上記のオペレータで可能な範囲は、
それでは、
MongoDBのMap/Reduce
これまでにAggregationフレームワークで実行した集計を、
Map関数の準備
Map関数は、
keyにはグルーピングするキーを指定します。先ほどと同様に、
Map関数内部でkeyとvalueを作成するために、
> map = function() { emit(this.url_path, {count: 1}); }
Reduce関数の準備
Reduce関数には、
> reduce = function(key, values) { var count = 0; values.forEach(function(v) { count += v['count']; }); return {count: count}; }
Map/Reduceで集計する
Map関数とReduce関数が作成できたら、
それでは、
> 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アクセス数の合計が、
次はURLとHTTPステータスコードの2つをキーとして集計してみましょう。
- ※)
- オプションでは、
結果を保存するコレクションの指定や、 最後に実施するfinalize関数の指定が可能です。詳細は公式マニュアルを参照ください。
複数キーで集計する
複数キーで集計するためには、
URLとHTTPステータスコードをキーとするために、
> map = function() { emit({url_path: this.url_path, status: this.status}, {count: 1}); }
Reduce関数は先ほどのままで良いので、
> 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/
それでは最後に、
その他集計処理ミドル(Hadoop)との連携
Hadoopと組み合わせて使う
Hadoopは、
公式マニュアルも充実しており、
MongoDBとHadoopを組み合わせて使用することによって、

今回の記事では、
まとめと次回のテーマ
今回はMongoDBで集計を実施する方法を紹介しました。MongoDBには、
また、
次回はMongoDBの運用について紹介する予定です。お楽しみに!