2012-03-25 75 views
4

我一直在試圖將許多大型數據集合放入一個集合中,但我遇到了編寫MapReduce函數的問題。MongoDB集合上的MapReduce變爲空

這是我的數據是什麼樣子(這裏有17行,在現實中我有4+萬元):

{"user": 1, "day": 1, "type": "a", "sum": 10} 
{"user": 1, "day": 2, "type": "a", "sum": 32} 
{"user": 1, "day": 1, "type": "b", "sum": 11} 
{"user": 2, "day": 4, "type": "b", "sum": 2} 
{"user": 1, "day": 2, "type": "b", "sum": 1} 
{"user": 1, "day": 3, "type": "b", "sum": 9} 
{"user": 1, "day": 4, "type": "b", "sum": 12} 
{"user": 2, "day": 2, "type": "a", "sum": 3} 
{"user": 3, "day": 2, "type": "b", "sum": 81} 
{"user": 1, "day": 4, "type": "a", "sum": 22} 
{"user": 1, "day": 5, "type": "a", "sum": 39} 
{"user": 2, "day": 5, "type": "a", "sum": 8} 
{"user": 2, "day": 3, "type": "b", "sum": 1} 
{"user": 3, "day": 3, "type": "b", "sum": 99} 
{"user": 2, "day": 3, "type": "a", "sum": 5} 
{"user": 1, "day": 3, "type": "a", "sum": 41} 
{"user": 3, "day": 4, "type": "b", "sum": 106} 
... 

我試圖讓它看起來像這樣到底(數組每種類型的,其中的內容都只是由天決定,如果那天沒有該類型存在合適的索引的總和,它只是0):

{"user": 1, "type_a_sums": [10, 32, 41, 22, 39], "type_b_sums": [11, 1, 9, 12, 0]} 
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]} 
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 81, 99, 106, 0]} 
... 

這是MapReduce的我一直嘗試:

var mapsum = function(){ 
    var output = {user: this.user, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: this.type, tempSum: this.sum, tempDay: this.day} 

    if(this.type == "a") { 
     output.type_a_sums[this.day-1] = this.sum; 
    } 

    if(this.type == "b") { 
     output.type_b_sums[this.day-1] = this.sum; 
    } 

    emit(this.user, output); 
}; 

var r = function(key, values) { 
    var outs = {user: 0, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: -1, tempSum: -1, tempDay: -1} 

    values.forEach(function(v){ 

     outs.user = v.user; 

     if(v.tempType == "a") { 
      outs.type_a_sums[v.tempDay-1] = v.tempSum; 
     } 

     if(v.tempType == "b") { 
      outs.type_b_sums[v.tempDay-1] = v.tempSum; 
     } 

    }); 

    return outs; 
}; 


res = db.sums.mapReduce(mapsum, r, {out: 'joined_sums'}) 

這給了我,我在小樣本輸出,但是當我運行在所有4個萬I得到一噸的輸出看起來像這樣:

{"user": 1, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]} 
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]} 
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]} 

users很大一部分應該有它們的數組中的和實際上只是填充了reduce函數outs對象中虛擬數組中的0,然後才用實際函數填充它們。

真奇怪的是,如果我在同一個集合上運行相同的確切函數,但只檢查一個用戶res = db.sums.mapReduce(mapsum, r, {query: {user: 1}, out: 'joined_sums'}),我知道他們的數組中應該有總和,但以前一直都是0,我會實際得到我只需要該用戶的輸出。再次運行400萬,我回到0的地方。這就好像它只是寫了所有與虛擬填充陣列相關的工作。

我有太多數據嗎?考慮到時間,它不應該能夠通過它嗎?或者我遇到了一些我不知道的障礙?

+0

有沒有機會在過時的MongoDB版本中發現錯誤? – maerics 2012-03-26 04:32:39

+0

我認爲它與'reduce()'每個鍵不止一次被調用有關。我正在嘗試使用'finalize',但我很困惑它是如何工作的。 – TFX 2012-03-26 05:15:53

回答

2

謝謝你提供很多細節。這裏有幾個問題。

讓我們從頂部開始。

我試圖讓它看起來像這樣到底

{ 「用戶」:2, 「type_a_sums」:0,3,5,0,8], 「type_b_sums」 :[0,0,1,2,0]}

它實際上將是這樣的:

{ _id: { "user": 2 }, value: { "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0] } 

注意_id有點像你的 「分組依據」 和value是怎麼樣的像你的「總和」欄。

所以問題1是你發出user作爲你的鑰匙,但它也是你價值的一部分。這不是必需的。的減少只會減少共享同一個密鑰的兩個值,則不需要此行之一:outs.user = v.user;

你也有問題2:你的reduce是不正確

我認爲它與reduce()被稱爲每個鍵不止一次有關。

reduce()的目標是它將被多次調用。它應該跨服務器擴展。因此,一臺服務器可能會調用幾次,這些結果可能會合並併發送到另一臺服務器。

以下是查看它的不同方法。 Reduce獲取一組value對象,並將它們減少爲一個對象value對象

這裏有一些推論:

  • 如果我做reduce([a, b]),它應該是一樣reduce([b, a])
  • 如果我做reduce([a, reduce([b,c]))應該是一樣reduce([reduce([a,b]), c])

所以它不應該不管什麼樣的順序我還是多少倍,價值被降低運行他們,它總是相同的輸出。

如果你看看你的代碼,這不是發生了什麼事情。只要看看type_a_sums。如果我得到以下兩個values即將減少會發生什麼?

reduce([ [0,0,1,0,0], [0,2,0,0,0] ]) => ??? 

對我來說,這看起來像輸出應該是[0,2,1,0,0]。如果這是真的,那麼你不需要所有這些temp_X字段。相反,您需要關注正確的數組,然後正確地合併這些數組。

+0

謝謝!我已經更改了代碼(http://pastie.org/private/dc9gizrsrzckzq6hvjkqq),但直到早上才能運行它。我刪除了temp值,而是改變了'reduce()'中的代碼,將每個'emit()'數組的元素添加到'reduce()'輸出數組中的相應元素。這是否更有意義? 我不明白爲什麼只使用數組會有所幫助。爲什麼不添加'temp'變量中的元素同樣適用。這樣,我只是使用一個數組的元素來代替「int」,但我覺得它是一回事。我需要'敲定'嗎? – TFX 2012-03-26 07:42:56

+0

這*看起來好多了。您不需要臨時工的原因是排放*的輸出可能是最終結果。它可能不是,但它可能是。考慮到一天結束時你真正想要的是數組,你希望數組在每個階段都是正確的。 – 2012-03-26 18:21:17