2012-09-30 30 views
3

我存储微小MongoDB中的性能数据,每个集合是一种类型的性能报告,并且每个文件是在该点的测量时间在阵列上的端口:如何规范化/减少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 }); 
}; 

我会在精简函数的值和计数相加,并获得在敲定功能可按平均。

正如你所看到的,这将平均数据的时间不考虑“端口名称”值,我需要为每个“array_serial”上的每个“端口名称”随时间平均值。

那么,如何可以包括上述地图功能的端口名称?发射的关键点应该是我稍后拆分的复合“array_serial,PortName,DateTime”值吗?或者,我应该使用查询功能来查询每个不同的序列,端口和时间?我是否正确地将这些数据存储在数据库中?

而且,据我所知,这个数据会保存出它自己的收藏,什么是集合中与此替代数据的标准做法平均数据?


这是你的意思吗?因为它不是分组四舍五入到低5分钟的文档(顺便说一句,我改变了“日期时间”到“日期时间”):

$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 
} 

从我可以告诉“$国防部”运营商将返回的剩余分钟除以五,对吗?

这将真正帮助我,如果我能得到的聚合框架做这个操作,而不是mapreduce的。

+0

你真的应该使用这个聚合框架而不是map/reduce。你可以用map/reduce来做到这一点,你只需要输出端口号和时间值就可以了。聚合框架会使它简单得多。你在用2.2吗? –

+0

我正在使用2.2,我还没有开始研究聚合框架,我会看看。谢谢! –

+0

是你的数据点统一吗?即超过60分钟,你保证得到相同数量的测量结果?并且测量是绝对的?不是相对于前一个或下一个,是的?你的数据点是否统一?即超过60分钟,你保证得到相同数量的测量结果?并且测量是绝对的?不是相对于前一个或下一个,是的?你看到了问题,对吧?如果你在一个小时内得到一次较高的测量结果,而在一小时内得到一个较低的测量结果,如果不是相同的时间段,那么你应该权衡它们,而不是做一个平均值。 –

回答

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 
    } 
} 

希望你将能够扩展您的具体数据和要求。

+0

当然这适用于每小时或每月的平均时间,但是这种技术可以用来平均超过五分钟的时间吗?你可以将$项目中的日期时间调整为平均值吗? –

+0

绝对如此。在投影中做同样的事情为$小时,但在$分钟使用$ mod运算符与$ mod:[“$ min”,5]将所有分钟“舍入”到下一个较低的5或0分钟。 –

+0

好啊,我会给它一个镜头。感谢您继续帮助Asya! –

2

“什么是集合中替换数据与该平均数据标准的做法?”

标准的做法是保留原有的数据,并分别存储所有导出的数据。

在你的情况下,它的意思是:

  • 不要删除原始数据
  • 使用另一个集合(在相同的MongoDB数据库)来存储平均值