3

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 ではなく、集約フレームワークにこの操作を実行させることができれば、これは本当に役に立ちます。

4

2 に答える 2

3

集約フレームワークでそれを行う方法は次のとおりです。私は小さな単純化を使用しています - 私は年、月、日でのみグループ化しています - あなたの場合、より細かい計算のために時間と分を追加する必要があります. 取得したデータ サンプルで点の分布が均一でない場合は、加重平均を行うかどうかについても選択できます。

project={"$project" : {
        "year" : {
            "$year" : "$DateTime"
        },
        "month" : {
            "$month" : "$DateTime"
        },
        "day" : {
            "$dayOfWeek" : "$DateTime"
        },
        "array_serial" : 1,
        "Port Name" : 1,
        "metric" : 1
    }
};
group={"$group" : {
        "_id" : {
            "a" : "$array_serial",
            "P" : "$Port Name",
            "y" : "$year",
            "m" : "$month",
                    "d" : "$day"
        },
        "avgMetric" : {
            "$avg" : "$metric"
        }
    }
};

db.metrics.aggregate([project, group]).result

これをいくつかのランダムなサンプル データで実行したところ、次のような形式が得られました。

[
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-B",
            "y" : 2012,
            "m" : 9,
            "d" : 6
        },
        "avgMetric" : 100.8
    },
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-B",
            "y" : 2012,
            "m" : 9,
            "d" : 7
        },
        "avgMetric" : 98
    },
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-A",
            "y" : 2012,
            "m" : 9,
            "d" : 6
        },
        "avgMetric" : 105
    }
]

ご覧のとおり、これは array_serial、ポート名、年/月/日の組み合わせごとに 1 つの結果です。$sort を使用して、そこから処理したい順序に並べ替えることができます。

プロジェクト ステップを拡張して時間と分を含め、分を 5 分ごとの平均に丸める方法を次に示します。

{
    "$project" : {
        "year" : {
            "$year" : "$DateTime"
        },
        "month" : {
            "$month" : "$DateTime"
        },
        "day" : {
            "$dayOfWeek" : "$DateTime"
        },
        "hour" : {
            "$hour" : "$DateTime"
        },
        "fmin" : {
            "$subtract" : [
                {
                    "$minute" : "$DateTime"
                },
                {
                    "$mod" : [
                        {
                            "$minute" : "$DateTime"
                        },
                        5
                    ]
                }
            ]
        },
        "array_serial" : 1,
        "Port Name" : 1,
        "metric" : 1
    }
}

それを特定のデータと要件に拡張できることを願っています。

于 2012-10-09T20:26:46.873 に答える
2

「コレクション内のデータをこの平均化されたデータに置き換えるための標準的な方法は何ですか?」

標準的な方法は、元のデータを保持し、すべての派生データを個別に保存することです。

あなたの場合、それは次のことを意味します:

  • 元のデータを削除しないでください
  • 別のコレクション (同じ MongoDB データベース内) を使用して平均値を保存する
于 2012-09-30T15:33:38.310 に答える