2011-04-10 55 views
8

我想在Mongo shell中做一個簡單的map reduce,但reduce函數永遠不會被調用。這是我的代碼:Mongo DB Map/Reduce - Reduce不被調用

db.sellers.mapReduce( 
    function(){ emit(this._id, 'Map') } , 
    function(k,vs){ return 'Reduce' }, 
    { out: { inline: 1}}) 

,其結果是

{ 
"results" : [ 
    { 
     "_id" : ObjectId("4da0bdb56bd728c276911e1a"), 
     "value" : "Map" 
    }, 
    { 
     "_id" : ObjectId("4da0df9a6bd728c276911e1b"), 
     "value" : "Map" 
    } 
], 
"timeMillis" : 0, 
"counts" : { 
    "input" : 2, 
    "emit" : 2, 
    "output" : 2 
}, 
"ok" : 1, 

}

的哪些錯誤?

我使用的MongoDB 1.8.1 32位在Ubuntu 10.10

回答

17

reduce目的是,ekhem,減少與給定鍵相關聯的值成一個值(綜合結果) 。如果您只爲每個MapReduce鍵發出一個值,則不需要減少,所有工作都已完成。但是,如果你發出兩對給定_id,減少將被稱爲:

emit(this._id, 'Map1'); 
emit(this._id, 'Map2'); 

這將調用減少與下列參數:

reduce(_id, ['Map1', 'Map2']) 

更有可能的是,你將要使用_id爲MapReduce的關鍵當過濾數據集時:emit只有當給定的記錄滿足某些條件時。但是,在這種情況下,reduce不會被調用,這是預期的。

+0

你是對的Tomasz。我從MongoDB文檔中挑選了這個示例。如果明確提到這一點,它將有助於Map/Reduce像我這樣的新手。一個謙虛的「綠色檢查」給你! – Adil 2011-04-10 13:45:12

+3

仍然可以推斷,減少會收到,使用你的例子,減少(_id,['Map1'])的情況下,只有一個項目發射。不通過減少打破我的結果集。 – 2012-02-24 02:27:44

+3

我認爲不調用單個值減少是一個奇怪的實現選擇。所以每次你改變'map'結果的結構時,你還必須調整'reduce',以便在單個值'map'結果的情況下得到統一的結果。 – Chaquotay 2013-05-18 10:15:51

6

那麼,如果只有一個值的話,MongoDB不會調用Key的Reduce函數。

在我看來,這是不好的。應該由我的reducer代碼決定是跳過一個奇異值還是對其進行一些操作。

現在,如果我必須對奇異值進行一些操作,我最終會編寫最終確定函數,並且在最終確定中,我嘗試區分哪些值已經通過了reducer或哪些不是。

我很肯定,在Hadoop的情況下,這種情況不會發生。

+0

謝謝!這是非常直觀的,減速機的一部分工作是以某種方式構建物品,這可能會有所不同。 – 2017-08-07 16:23:18

1

地圖縮減將收集具有共同密鑰的值爲單個值。

在這種情況下,由於map發出的每個值都有不同的鍵,因此不會做任何事情。不需要減少。

db.sellers.mapReduce( 
    function(){ emit(this._id, 'Map') } , 
    function(k,vs){ return 'Reduce' }, 
    { out: { inline: 1}}) 

這從閱讀文檔並不完全清楚。

如果你想打電話降低,則可能硬編碼的ID是這樣的:

db.sellers.mapReduce( 
    function(){ emit(1, 'Map') } , 
    function(k,vs){ return 'Reduce' }, 
    { out: { inline: 1}}) 

現在,通過地圖發出的所有值將減少,直到只有一個仍然存在。

0

還應該提到的是,根據documentation,「MongoDB可以爲同一個鍵多次調用reduce函數,在這種情況下,該鍵的reduce函數的前一個輸出將成爲將輸入值輸入到該密鑰的下一個減少函數調用中。「。

此外,reduce應該是聯想,交換和冪等:

reduce(key, [ C, reduce(key, [ A, B ]) ]) == reduce(key, [ C, A, B ]) 
reduce(key, [ reduce(key, valuesArray) ]) == reduce(key, valuesArray) 
reduce(key, [ A, B ]) == reduce(key, [ B, A ]) 

因此,這意味着reduce功能應該準備好接受這是自己以前調用的結果的對象。其中(至少對我個人而言)意味着實現mapReduce的最佳方法是使map函數(如果可能)以與reduce函數返回的格式相同的格式發出值。然後可以實現reduce函數以僅支持一種輸入格式。結果,即使只有一個由map發出的對象(並且因此跳過reduce的調用),在mapReduce的最終結果中,reduce從未被調用的密鑰的值將會仍然與其他鍵的值格式相同。

舉例來說,如果我們有如下的文件結構:

{ 
    "foo": <some_string>, 
    "status": ("foo"|"bar") 
} 

map功能可能如下:

function() { 
    var value = { 
     "num_total": 1, 
     "num_foos": 0, 
     "num_bars": 0 
    }; 

    if (this.status == "foo") { 
     value["num_foos"] += 1; 
    } 

    if (this.status == "bar") { 
     value["num_bars"] += 1; 
    } 

    emit(this.foo, value); 
} 

reduce功能將是:

function(key, values) { 
    var reduced = { 
     "num_total": 0, 
     "num_foos": 0, 
     "num_bars": 0 
    }; 

    values.forEach(function(val) { 
     reduced["num_total"] += val["num_total"]; 
     reduced["num_foos"] += val["num_foos"]; 
     reduced["num_bars"] += val["num_bars"]; 
    }); 

    return reduced; 
}