2012-04-02 93 views
4

我有一些mapreduce問題。如何映射 - 減少組,對排序值進行排序和計數

我想對集合中的某些值進行分組,排序和計數。我有收藏,如:

---------------------------- 
| item_id | date  | 
---------------------------- 
| 1   | 01/15/2012 | 
---------------------------- 
| 2   | 01/01/2012 | 
---------------------------- 
| 1   | 01/15/2012 | 
---------------------------- 
| 1   | 01/01/2012 | 
---------------------------- 
| 2   | 01/03/2012 | 
---------------------------- 
| 2   | 01/03/2012 | 
---------------------------- 
| 1   | 01/01/2012 | 
---------------------------- 
| 1   | 01/01/2012 | 
---------------------------- 
| 2   | 01/01/2012 | 
---------------------------- 
| 2   | 01/01/2012 | 
---------------------------- 

我想組由item_id和計數一天日期爲每個項目和排序日期爲每個項目,並得到結果,如:

value: {{item_id:1, date:{01/01/2012:3, 01/15/2012:2 }},{item_id:2, date:{01/01/2012:3, 01/03/2012:2 }}} 

我用mapReduce

m=function() 
{ 
    emit(this.item_id, this.date); 
} 
r=function(key, values) 
{ 
var res={}; 
values.forEach(function(v) 
{ 
if(typeof res[v]!='undefined') ? res[v]+=1 : res[v]=1; 
}); 
return res; 
} 

但我沒有收到結果,如:

{{item_id:1, date:{01/01/2012:3, 01/15/2012:2 }},{item_id:2, date:{01/01/2012:3, 01/03/2012:2 }}} 

任何想法?

回答

2

形式給定的輸入文件:

> db.dates.findOne() 
{ "_id" : 1, "item_id" : 1, "date" : "1/15/2012" } 
> 

以下Map和Reduce函數應該產生你所尋找的輸出:

var map = function(){ 
    myDate = this.date; 
    var value = {"item_id":this.item_id, "date":{}}; 
    value.date[myDate] = 1; 
    emit(this.item_id, value); 
} 

var reduce = function(key, values){ 
    output = {"item_id":key, "date":{}}; 
    for(v in values){ 
     for(thisDate in values[v].date){ 
      if(output.date[thisDate] == null){ 
       output.date[thisDate] = 1; 
      }else{ 
       output.date[thisDate] += values[v].date[thisDate]; 
      } 
     } 
    } 
    return output; 
} 

> db.runCommand({"mapReduce":"dates", map:map, reduce:reduce, out:{replace:"dates_output"}}) 

> db.dates_output.find() 
{ "_id" : 1, "value" : { "item_id" : 1, "date" : { "1/15/2012" : 2, "1/01/2012" : 3 } } } 
{ "_id" : 2, "value" : { "item_id" : 2, "date" : { "1/01/2012" : 3, "1/03/2012" : 2 } } } 

希望上面會做什麼,你需要它或者至少讓你指出正確的方向。

有關使用地圖與MongoDB的減少的更多信息,請參閱蒙戈文檔: http://www.mongodb.org/display/DOCS/MapReduce

有一些額外的Map Reduce例子MongoDB的食譜: http://cookbook.mongodb.org/

對於逐步的請參閱MongoDB Cookbook配方「使用版本化文檔查找最大值和最小值」的「其他」一節http://cookbook.mongodb.org/patterns/finding_max_and_min/

祝您好運!

+0

Marc,謝謝你的幫助。在此之後,我在排序日期有一些問題。我想要如:{「_id」:1,「value」:{「item_id」:1,「date」:{「2012年1月1日」:3,「1/15/2012」:2}}} 。我在db.runCommand({「mapReduce」:「dates」,map:map,reduce:reduce,sort:{date:1},out:{replace:「dates_output」}}中添加了排序:{date:1} 。但在此操作後,我有:{「_id」:1,「value」:{「item_id」:1,「date」:{「2012年1月1日」:1,「1/15/2012」:1} }}日期是排序,但始終是1 – 2012-04-03 14:51:32

+0

你好。我很高興能夠提供幫助! 「value」中的嵌入元素將按照它們發現的順序添加。對日期鍵上的輸入排序會在嵌入式文檔中按順序排列日期。但是,在此示例中,日期是字符串,並且不能保證日期較晚的字符串的值比早期值的字符串的值大。例如(在js shell中): >「10/01/2012」<「1/01/2013」​​ false 字符串必須先轉換爲日期才能正確比較。 – Marc 2012-04-04 16:12:02

+0

一旦你照顧到了這一點,你應該能夠按照你所希望的順序得到結果: > db.runCommand({「mapReduce」:「日期」,map:map,reduce:reduce,sort:{ 「date」:1},out:{replace:「dates_output」}}) 如果您收到類似於「exception:could not create cursor over test.dates for query」的錯誤,請嘗試將索引添加到「date」鍵入輸入集合。 – Marc 2012-04-04 16:12:36