2012-09-30 63 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數據庫)來存儲平均值