8

我试图在 Mongo shell 中做一个简单的 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,

}

怎么了?

我在 Ubuntu 10.10 上使用 MongoDB 1.8.1 32 位

4

4 回答 4

18

的目的reduce是,ekhem,将与给定键关联的一组值减少为一个值(聚合结果)。如果您为每个 MapReduce 键只发出一个值,则不需要 reduce,所有工作都已完成。但是如果你为一个给定的发出两对_id,reduce 将被调用:

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

这将使用以下参数调用reduce:

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

在过滤数据集时,您更有可能希望使用_idMapReduce 键:emit仅当给定记录满足某些条件时。但同样,reduce在这种情况下不会被调用,这是预期的。

于 2011-04-10T12:53:30.000 回答
6

好吧,如果键只有一个值,MongoDB 不会在键上调用 Reduce 函数。

在我看来,这很糟糕。它应该留给我的减速器代码来决定是跳过一个奇异值还是对其进行一些操作。

现在,如果我必须对奇异值进行一些操作,我最终会编写 finalize 函数,并且在 finalize 中,我会尝试区分哪个值通过了 reducer,哪个没有。

我很确定,在 Hadoop 的情况下不会发生这种情况。

于 2014-07-18T14:20:00.300 回答
1

Map reduce 会将具有公共键的值收集到单个值中。

在这种情况下,什么都不做,因为 map 发出的每个值都有不同的键。不需要减少。

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

阅读文档并不完全清楚这一点。

如果你想调用 reduce,你可以像这样硬编码一个 ID:

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

现在 map 发出的所有值都将减少,直到只剩下一个。

于 2015-07-22T20:54:59.473 回答
1

还应该提到的是,根据文档,“MongoDB 可以为同一个键多次调用 reduce 函数。在这种情况下,该键的 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,即使只有一个由与其余键的值格式相同。reducemapReducereduce

例如,如果我们有以下文档结构:

{ 
    "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;
}
于 2016-05-23T15:19:58.493 回答