2011-04-10 97 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; 
}