MongoDBでのMapReduceによるデータ処理
目次- MongoDBでのMapReduceによるデータ処理 - MapReduceコマンド - パラメータの説明: - MapReduceの使用方法 - 一時コレクションのパラメータ
MapReduceは、大量のデータを分割して処理(マッピング)し、その結果を統合(リダクション)して最終結果を生成する計算モデルです。MongoDBが提供するMapReduceは非常に柔軟性が高く、大規模なデータ分析にも実用的です。
MapReduceコマンド
MapReduceの基本的な構文は以下の通りです:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 関数
function(key,values) {return reduceFunction}, //reduce 関数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
MapReduceを使用するには、Map関数とReduce関数を実装する必要があります。Map関数はemit(key, value)を呼び出し、コレクション内のすべてのドキュメントを反復処理し、キーと値をReduce関数に渡して処理します。Map関数は必ずemit(key, value)を呼び出してキーと値のペアを返す必要があります。
パラメータの説明:
- map: マッピング関数(キーと値のペアのシーケンスを生成し、reduce関数のパラメータとして使用)
- reduce: 統計関数。reduce関数の役割は、キーと値のペアを単一の値に変換することです
- out: 統計結果を格納するコレクション(指定しない場合は一時コレクションが使用され、クライアントの接続が切断されると自動的に削除されます)
- query: マップ関数が呼び出されるドキュメントをフィルタリングする条件(query、limit、sortは自由に組み合わせて使用できます)
- sort: limitと組み合わせて使用するソートパラメータ(マップ関数に送られるドキュメントをソートし、グループ化メカニズムを最適化できます)
- limit: マップ関数に送られるドキュメントの最大数(limitがなければ、sort単独ではあまり意味を持ちません)
MapReduceの使用方法
以下のドキュメント構造はユーザーのコメントを保存しており、ドキュメントにはユーザー名とコメントのステータスフィールドが含まれています:
>db.comments.insert({
"comment_text": "この記事はとても参考になりました。",
"commenter_name": "tanaka",
"status":"approved"
})
WriteResult({ "nInserted" : 1 })
>db.comments.insert({
"comment_text": "詳細な説明ありがとうございます。",
"commenter_name": "suzuki",
"status":"approved"
})
WriteResult({ "nInserted" : 1 })
>db.comments.insert({
"comment_text": "追加情報を期待しています。",
"commenter_name": "tanaka",
"status":"pending"
})
WriteResult({ "nInserted" : 1 })
>db.comments.insert({
"comment_text": "素晴らしいコンテンツです。",
"commenter_name": "sato",
"status":"approved"
})
WriteResult({ "nInserted" : 1 })
>db.comments.insert({
"comment_text": "もっと例が必要です。",
"commenter_name": "suzuki",
"status":"rejected"
})
WriteResult({ "nInserted" : 1 })
ここで、commentsコレクションでmapReduce関数を使用して承認されたコメント(status:"approved")を選択し、commenter_nameでグループ化し、各ユーザーのコメント数を計算します:
>db.comments.mapReduce(
function() { emit(this.commenter_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"approved"},
out:"comment_stats"
}
)
上記のmapReduceの出力結果は以下の通りです:
{
"result" : "comment_stats",
"timeMillis" : 23,
"counts" : {
"input" : 3,
"emit" : 3,
"reduce" : 1,
"output" : 3
},
"ok" : 1
}
この結果から、クエリ条件(status:"approved")を満たすドキュメントが3個あり、map関数で3個のキーと値のペアが生成され、最終的にreduce関数で同じキーが3つのグループに分けられたことがわかります。
主なパラメータの説明:
- result: 結果を格納するコレクション名。一時コレクションであり、MapReduceの接続が閉じると自動的に削除されます。
- timeMillis: 実行にかかった時間(ミリ秒単位)
- input: 条件に一致し、map関数に送られたドキュメントの数
- emit: map関数内でemitが呼び出された回数(コレクション内のデータの総量)
- output: 結果コレクション内のドキュメントの数(デバッグに非常に役立ちます)
- ok: 成功した場合は1
- err: 失敗した場合の理由がここに表示されることがありますが、経験上、理由は不明瞭であまり役立ちません
find操作子を使用してmapReduceのクエリ結果を確認します:
>db.comments.mapReduce(
function() { emit(this.commenter_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"approved"},
out:"comment_stats"
}
).find()
上記のクエリは以下の結果を表示します:
{ "_id" : "tanaka", "value" : 1 }
{ "_id" : "suzuki", "value" : 1 }
{ "_id" : "sato", "value" : 1 }
同様の方法で、MapReduceを使用して大規模で複雑な集約クエリを構築できます。
Map関数とReduce関数はJavaScriptで実装できるため、MapReduceの使用は非常に柔軟で強力です。
一時コレクションのパラメータ
out: { inline: 1 }
{inline:1}を設定すると、コレクションは作成されず、Map/Reduce操作はすべてメモリ内で実行されます。 注意:このオプションは、結果セット内の個々のドキュメントのサイズが16MBの制限範囲内の場合にのみ有効です。
db.users.mapReduce(map,reduce,{out:{inline:1}});