2011-11-11 17 views
2

我只是在學習mapReduce。我在用戶集合上調用了以下映射reduce函數。在Mongo中重新加入Split MapReduce陣列

function() { 

    m = function() { 
      emit(this.city, {num:1, arr:this}); 
    } 

    r = function (key, arr_values) { 
      var resultArray = []; 
      var count = 0; 
      arr_values.forEach(function (value) { 
            resultArray.push(value); 
            count++; 
           }); 
      return {num:count, arr:resultArray}; 
    } 

    res = db.AdsOnPage.mapReduce(m, r, {out:"ReducedCollection"}); 


} 

這最終給我什麼,我需要 - 「城市」作爲重點,然後用戶在那個城市作爲值的數組。但它實際上是給了我一個荒謬的嵌套數組。我認爲這是由於分片而發生的?但我如何重新加入一切?現在,結果看起來像這樣:

{ 
    "city":"Chicago", 
    "value" : { 
    "num" : 2.0, 
    "arr" : [{ 
     "num" : 2.0, 
     "arr" : [{ 
      "num" : 1.0, 
      "arr" : [{ 
       <user doc is here> 
       }] 
      }, { 
      "num" : 1.0, 
      "arr" : [{ 
       <user doc is here> 
       }] 
      }] 
     } 
....... 
for many many arrays 

爲什麼會發生這種情況?有什麼方法可以將我的結果重新加入到一個連貫的單個數組中嗎?

回答

1

無關與分片,這必須與地圖/減少邏輯。

map函數的value函數需要具有與從reduce返回相同的形狀。

請記住,reduce可以運行多次。實際上,在分片的情況下,它將針對每個分片運行一次,然後由mongos再發出請求。

你在想,當你運行

reduce(key, [a,b,c])

map/reduce的工作會發生什麼,輸出必須是相同的,如下:

reduce(key, [a, reduce(key, [b,c])) OR

reduce(key, [reduce(key, [a,b]), c])

在你的情況下reduce(key, [b,c])是returni納克數組所以你會得到如下:

reduce(key, [a, reduce(key, [b,c])) =>reduce(key, [a, [b,c] ])

注意額外的陣列?這就是爲什麼你要嵌套。

解決此問題需要兩部分。

  1. 如果values將是一個數組,那麼emit應該輸出在它一個項目的陣列。
  2. 當你做這個改變arr_values將是一個「陣列數組」。你將不得不把它們正確地結合起來。

希望能夠指出您正確的方向。有關更詳細的調試方法,您可能需要查看Troubleshooting M/R上的頁面。

+0

謝謝,@蓋茨。但我想真正的問題是,即使解決了嵌套後,我的結果被返回分裂成多個數組。你說「正確地結合它們」。我會怎麼做? – carlbenson

+0

在'reduce'方法中'arr_values'是一個值數組。每個值本身就是一個數組。所以你不能執行'resultArray.push(value);',你所推送的'value'是一個數組。所以你需要在reduce中循環每個值的另一個循環。 –

0

我使用數組函數Array.isArray(param)和indexOf(param)來解決這類問題,但是我在我的堆棧數組中推入了獨特的元素。

if(Array.isArray(param)) { 
    for(var i in param) { 
     if(stack.indexOf(param[i]) == -1) 
      arr.push(param[i]) ; 
    } 
} 
else { 
    if(stack.indexOf(param) == -1) 
     arr.push(param) ; 
} 

您可以嘗試Array.isArray()。