7

在 MongoDB 中,我正在尝试编写 Map-Reduce 函数,仅在满足某些条件时才保存数据。

我无法弄清楚如何从我的减速器中发出()。它总是以一种或另一种方式保存数据。

这是一个通用示例。忽略数据的上下文——我创建这个数据和代码只是为了这个问题。

数据集:

{ "_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);
}

简单地忽略不需要的数据的 Reducer。

// 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 }

我还添加了一个空的返回语句,但得到了相同的结果:

// 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 }
4

2 回答 2

3

您可以使用以下函数运行额外的 mapReduce 操作:

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

var second_reduce = function() {}

reduce 函数可以为空,因为每个键没有多个值会导致在这种情况下甚至不会调用它。

因此,像这样运行 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)从第一个 reduce 函数中删除条件。

于 2013-10-15T08:37:46.590 回答
2

我们需要记住,如果键只有 1 个发射值(来自 map()),则可以跳过 reducer。我们也不应该尝试在 reduce 中过滤结果,因为可以为同一个键多次调用 reduce(每次都使用发出值的子集)。

唯一的其他选项是 finalize 方法,但这将导致空值而不是从结果中删除条目。

我认为获得所需结果的唯一方法是使用聚合框架而不是 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,罗布。

于 2013-10-15T01:25:17.220 回答