2016-04-20 19 views
0

Я пытаюсь объединить две коллекции, используя MapReduce. Они имеют идентичную структуру, например:Union Set using MapReduce MongoDB

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 = 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}} 
+0

Не могли бы вы показать нам ожидаемый выходной документ? Причина в том, что было бы легче достичь одной и той же цели с помощью структуры агрегации (с потенциальным использованием индексов и соответствующим приростом производительности), но я не уверен, чего вы хотите достичь. –

+0

@MarkusWMahlberg Конечно, я только что добавил.Я просто хочу реализовать MapReduce – Alejandra

ответ

0

Уменьшить функция может возвращать только одно значение, так что вы хотите, чтобы выполнить для каждой строки. Функция уменьшения вызывает вызов для каждого уникального ключа, возвращаемого в вашей функции карты. Ваши ключи были 0 и 1, поэтому он будет получать только дважды для каждой коллекции - один раз для ключа 0 и один раз для ключа 1. Следовательно, максимальное количество результатов будет всего 2 для каждой коллекции.

Что вам нужно сделать, это установить ключ продукта в функции отображения:

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

Теперь функция снижения будет вызвана для каждого уникального значения продукта. Наша новая функция карты просто возвращает первое значение в массиве (если в одной коллекции есть дубликаты в одной коллекции, она просто займет первое место. Вы можете быть здесь умнее и принимать наивысшее или самое низкое количество - или сумму величин и т. Д.), ,

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

Выполнить свою первую карту сократить работу:

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

Примечание: Если две строки из разных коллекций имеют одинаковый идентификатор продукта, но различные величины I я не уверен, какой из них будет возвращен.

+0

Вы правы! Спасибо! Потребовалось очень много времени, чтобы понять, что функция уменьшения может возвращать только одно значение :) – Alejandra