2013-10-11 77 views
6

在MongoDB中,我正在嘗試編寫僅在符合特定條件時才保存數據的Map-Reduce函數。如何不在MongoDB的reduce()函數中保存數據?

我不知道如何而不是從我的reducer emit()。它總是以這種或那種方式保存數據。

這是一個通用的例子。忽略數據的上下文 - 我僅爲這個問題的目的創建了這些數據和代碼。

數據集:

{ "_id" : ObjectId("52583b3a58da9769dda48853"), "date" : "01-01-2013", "count" : 1 } 
{ "_id" : ObjectId("52583b3d58da9769dda48854"), "date" : "01-01-2013", "count" : 1 } 
{ "_id" : ObjectId("52583b4258da9769dda48855"), "date" : "01-02-2013", "count" : 1 } 
{ "_id" : ObjectId("52583b4f58da9769dda48856"), "date" : "01-03-2013", "count" : 4 } 

地圖功能:

// Map all data by (date, count) 
var map = function() { 
    var key = this.date; 
    var value = this.count; 
    emit(key, value); 
} 

減速,簡單地忽略不需要的數據。

// Only save dates which have count > 2 
var reducer = function(date, counts) { 
    var sum = Array.sum(counts); 
    if (sum > 2) { 
     return sum; 
    } 
} 

結果(1的價值並沒有被忽略):

{ "_id" : "01-01-2013", "value" : null } 
{ "_id" : "01-02-2013", "value" : 1 } 
{ "_id" : "01-03-2013", "value" : 4 } 

我還添加了一個空的return語句,但得到了同樣的結果:

// Only save dates which have count > 2 
var reducer = function(date, counts) { 
    var sum = Array.sum(counts); 
    if (sum > 2) { 
     return sum; 
    } 
    else return; 
} 

我想什麼在運行Map-Reduce之後,只有以下數據存在於我的輸出集合中。 我該如何做到這一點?

{ "_id" : "01-03-2013", "value" : 4 } 

回答

3

你可以運行其他精簡操作,具有以下功能:

var second_map = function() { 
    if(this.value > 2) { 
     emit(this._id, this.value); 
    } 
} 

var second_reduce = function() {} 

reduce函數可以是空的,因爲not having multiple values per key will cause it to not even be called在這種情況下。

所以,跑步,像這樣的MapReduce:

db.map_reduce_example.mapReduce(
    second_map, second_reduce, {out: 'final_mapreduce_result'}); 

將產生如下集合:

> db.final_mapreduce_result.find() 
{ "_id" : "01-03-2013", "value" : 4 } 

請注意,如果你決定使用這種方法,您可以刪除從該if (sum > 2)條件先減少功能。

+0

這很聰明!我將不得不運行它來觀察運行在真實數據上的速度,但這是實現目標的一個很好的技巧。謝謝。 – Kurtis

+3

如果你只是想過濾一些結果,我不會做一個map/reduce。只需在第一張map/reduce之後執行刪除操作:db.mroutput.remove({value:{$ lte:2}})。 remove()將比map/reduce運行得更快。 –

+0

@RobMoore你是對的;這是一個更簡單,更有效的解決方案。我認爲你應該把它作爲一個單獨的答案發布。 – GolfWolf

2

我們需要記住,如果只有1發出的值(從地圖())爲重點減速器可以跳過。我們也不應該嘗試過濾reduce中的結果,因爲reduce可以爲同一個鍵調用多個時間(每次使用一個發射值的子集)。

唯一的其他選擇是finalize方法,但是這會導致null值不是從結果中刪除條目。

我認爲獲得您想要的結果的唯一方法是使用聚合框架而不是map reduce。這條管道將如下所示:

db.test.aggregate( 
    { 
    "$project" : { 
     "_id" : 0, 
     "date" : 1, 
     "count" : 1 
    } 
    }, 
    { 
    "$group" : { 
     "_id" : "$date", 
     "value" : { "$sum" : "$count" } 
    } 
    }, 
    { 
    "$match" : { 
     "value" : { "$gt" : 2 } 
    } 
    } 
); 
{ "result" : [ { "_id" : "01-03-2013", "value" : 4 } ], "ok" : 1 } 

唯一的主要一面以這種方法的結果要回來內嵌其中將結果限制爲16MB的大小。這將在2.6版本中修正/補救:https://jira.mongodb.org/browse/SERVER-10097

HTH, Rob。

+0

我不喜歡Aggregation框架的主要內容是輸出格式。它獲取所有結果並將其存儲到單個對象中。不過,我絕對讚賞這個建議!而且知道16MB的限制很快就會被修復,這也是一個好消息。謝謝! – Kurtis

+2

2.5.2(dev release)已經實現了這個功能 - 聚合框架可以返回一個遊標,或者你可以指定輸出到一個集合。考慮到聚合框架比map-reduce更快,我鼓勵你儘可能地使用它。 –

+1

此外,如果您必須擁有MapReduce,請投票https://jira.mongodb.org/browse/SERVER-2340請求此功能。有東西agg框架不能做那個地圖縮小可以,所以這仍然是一個有用的增強。 –

相關問題