MongoDB に詳細なパフォーマンス データを保存しています。各コレクションは一種のパフォーマンス レポートであり、各ドキュメントはアレイ上のポートのその時点での測定値です。
{
"DateTime" : ISODate("2012-09-28T15:51:03.671Z"),
"array_serial" : "12345",
"Port Name" : "CL1-A",
"metric" : 104.2
}
「array_serial」ごとに最大 128 の異なる「ポート名」エントリが存在する可能性があります。
データが古くなるにつれて、増加する期間にわたって平均化できるようにしたいと考えています。
- 最大1週間:分
- 1週間~1ヶ月:5分
- 1~3ヶ月:15分
など..時間を短縮できるように時間を平均化する方法は次のとおりです。
var resolution = 5; // How many minutes to average over
var map = function(){
var coeff = 1000 * 60 * resolution;
var roundTime = new Date(Math.round(this.DateTime.getTime() / coeff) * coeff);
emit(roundTime, { value : this.metric, count: 1 } );
};
reduce 関数で値とカウントを合計し、finalize 関数で平均を取得します。
ご覧のとおり、これは「ポート名」の値を除いた時間だけデータを平均化します。各「array_serial」の各「ポート名」の値を経時的に平均化する必要があります。
では、上記のマップ関数にポート名を含めるにはどうすればよいですか? エミットのキーは、後で分割する複合「array_serial、PortName、DateTime」値にする必要がありますか? または、クエリ関数を使用して、シリアル、ポート、および時刻ごとにクエリを実行する必要がありますか? このデータをデータベースに正しく保存していますか?
また、このデータが独自のコレクションに保存されることを知る限り、コレクション内のデータをこの平均化されたデータに置き換える標準的な方法は何ですか?
これはアーシャのことですか?下位 5 分に丸められたドキュメントをグループ化していないため (ところで、「DateTime」を「datetime」に変更しました):
$project: {
"year" : { $year : "$datetime" },
"month" : { $month : "$datetime" },
"day" : { $dayOfMonth : "$datetime" },
"hour" : { $hour : "$datetime" },
"minute" : { $mod : [ {$minute : "$datetime"}, 5] },
array_serial: 1,
port_name: 1,
port_number: 2,
metric: 1
}
私が知る限り、「$mod」演算子は 1 分の残りを 5 で割った値を返しますよね?
mapreduce ではなく、集約フレームワークにこの操作を実行させることができれば、これは本当に役に立ちます。