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フレームワークには集計に便利なオペレータが用意されており,
たとえば以下のような,
リスト1 テストの平均点を求めるSQL
SELECT name as '_id', AVG(score) as 'average' FROM scores
WHERE year = 'junior'
GROUP BY = name
上記のSQLをAggregationフレームワークで表現すると,
リスト2 テストの平均点を求める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