我在MongoDB中存储了细微的性能数据,每个集合都是一种性能报告,每个文档都是该阵列上端口的测量值:
{
"DateTime" : ISODate("2012-09-28T15:51:03.671Z"),
"array_serial" : "12345",
"Port Name" : "CL1-A",
"metric" : 104.2
}
每个“array_serial”最多可以有128个不同的“端口名称”条目。
随着数据的老化,我希望能够在不断增加的时间范围内对其进行平均化:
等。 这是我如何平均时间以便减少它们:
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”上的每个“端口名称”随时间平均值。
那么如何在上面的地图功能中包含端口名称?如果emit的键是一个复合“array_serial,PortName,DateTime”值,我后来拆分了吗?或者我应该使用查询功能来查询每个不同的串口,端口和时间?我是否正确地将这些数据存储在数据库中?
另外,据我所知,这些数据会保存到自己的集合中,用这些平均数据替换集合中的数据的标准做法是什么?
这就是你的意思Asya?因为它没有将文档分组到较低的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”运算符将返回剩余的分钟除以5,对吗?
如果我可以让聚合框架执行此操作而不是mapreduce,这对我真的有帮助。
答案 0 :(得分:2)
“使用此平均数据替换集合中的数据的标准做法是什么?”
标准做法是保留原始数据并分别存储所有派生数据。
在你的情况下,它意味着:
答案 1 :(得分:2)
以下是如何在聚合框架中执行此操作。我正在使用一个小的简化 - 我只对年,月和日进行分组 - 在您的情况下,您需要为细粒度计算添加小时和分钟。如果您获得的数据样本中的点分布不均匀,您还可以选择是否进行加权平均。
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,端口名称,年/月/日组合的一个结果。您可以使用$ sort将它们放入您想要从中处理它们的顺序。
以下是如何将项目步骤扩展到包括小时和分钟,同时将分钟数舍入为每五分钟平均一次:
{
"$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
}
}
希望您能够将其扩展到您的特定数据和要求。