0

我正在尝试使用 MapReduce 合并两个集合。它们具有相同的结构,例如:

db.tableR.insert({product:"A", quantity:150});
db.tableR.insert({product:"B", quantity:100});
db.tableR.insert({product:"C", quantity:60});
db.tableR.insert({product:"D", quantity:200});

db.tableS.insert({product:"A", quantity:150});
db.tableS.insert({product:"B", quantity:100});
db.tableS.insert({product:"F", quantity:220});
db.tableS.insert({product:"G", quantity:130});

我希望 MapReduce 删除重复项。

我正在创建一个根据数量划分集合的地图:

map = function(){
    if (this.quantity<150){
        var key=0;
    }else{
    var key=1;
    }
    var value = {"product":this.product, "quantity":this.quantity};
    emit(key,value);
};

现在我希望reduce函数删除重复项,但我找不到将新函数添加到reduced var的方法。

这是我尝试过的:

reduce = function(keys,values){
var reduced = {
    product:"",
    quantity:""
};
for (var i=0; i < values.length;i++)
{
    if(values[i].product !== null) {reduced.insert({product: values[i].product, quantity: values[i].quantity})}

}
return reduced;};

db.tableR.mapReduce(map,reduce,{out:'map_reduce_result'});
db.tableS.mapReduce(map,reduce,{out:'map_reduce_result'});
db.map_reduce_result.find();

我可以使用什么功能?

我的预期输出:

   {"_id" : 0, "value" : {"product" : "B","quantity" : 100}}
   {"_id" : 0, "value" : {"product" : "C","quantity" : 60}}
   {"_id" : 0, "value" : {"product" : "G","quantity" : 130}}
   {"_id" : 1, "value" : {"product" : "A","quantity" : 150}}
   {"_id" : 1, "value" : {"product" : "D","quantity" : 200}}
   {"_id" : 1, "value" : {"product" : "F","quantity" : 220}}
4

1 回答 1

0

reduce 函数只能返回一个值,因此您希望它对每一行都执行。对于 map 函数中返回的每个唯一键,都会调用 reduce 函数。您的键是 0 和 1,因此每个集合只会调用两次 - 键 0 一次,键 1 一次。因此,每个集合的最大结果数仅为 2。

您需要做的是在地图功能中设置产品的密钥:

map = function(){
    emit(this.product,{product:this.product,quantity:this.quantity});
};

现在,reduce 函数将为每个唯一的产品值调用。我们的新 map 函数只返回数组中的第一个值(如果在同一个集合中有重复的值,它将只取第一个。你可以在这里很聪明,取最高或最低的数量 - 或数量的总和等) .

reduce = function(keys,values){
    return values[0];
};

运行你的第一个 map reduce 作业:

db.tableR.mapReduce(map,reduce,{out:'map_reduce_result'});

运行你的第二个,但这次merge是结果:

db.tableS.mapReduce(map,reduce,{out: {merge: 'map_reduce_result'}});

现在db.map_reduce_result.find()返回:

{ "_id" : "A", "value" : { "product" : "A", "quantity" : 150 } }
{ "_id" : "B", "value" : { "product" : "B", "quantity" : 100 } }
{ "_id" : "C", "value" : { "product" : "C", "quantity" : 60 } }
{ "_id" : "D", "value" : { "product" : "D", "quantity" : 200 } }
{ "_id" : "F", "value" : { "product" : "F", "quantity" : 220 } }
{ "_id" : "G", "value" : { "product" : "G", "quantity" : 130 } }

显然,_id与您要查找的内容不符。如果您绝对需要,可以像这样使用聚合框架:

db.map_reduce_result.aggregate([{$project:{
  _id:{$cond: { if: { $gte: [ "$value.quantity", 150 ] }, then: 1, else: 0 }},
  value:1
}}]);

这导致:

{ "_id" : 1, "value" : { "product" : "A", "quantity" : 150 } }
{ "_id" : 0, "value" : { "product" : "B", "quantity" : 100 } }
{ "_id" : 0, "value" : { "product" : "C", "quantity" : 60 } }
{ "_id" : 1, "value" : { "product" : "D", "quantity" : 200 } }
{ "_id" : 1, "value" : { "product" : "F", "quantity" : 220 } }
{ "_id" : 0, "value" : { "product" : "G", "quantity" : 130 } }

注意:如果来自不同集合的两行具有相同的产品 ID,但数量不同,我不确定将返回哪一个。

于 2016-04-21T03:19:24.820 回答