Присоединиться к операции с MongoDB MapReduce - PullRequest
6 голосов
/ 18 мая 2011

Ранее я использовал MapReduce для выполнения классической операции MR, эквивалентной GROUP BY в SQL.

Мне было интересно, возможно ли концептуально выполнить операцию JOIN с MapReduce.Есть идеи, как это можно реализовать?Имеет ли смысл использовать MapReduce для такого рода операций?

Спасибо!

Ответы [ 2 ]

4 голосов
/ 19 мая 2011

MongoDB не поддерживает реляционные операции, такие как объединения.Вместо этого вы можете денормализовать ваши данные, встраивая строки, к которым вы присоединяетесь, во внешний документ.Таким образом, вместо присоединения продуктов к продажам у вас может быть коллекция products с этой схемой:

продуктов

{
    _id: 123,
    name: "Widget",
    price: 9.99
    sales:
    [ 
        { id:1, date: "20100316", howMany: 2 },
        { id:2, date: "20100316", howMany: 5 }
    ]
}

Затем, когда вы получаете продукт, вытакже получите данные о продажах, чтобы не нужно было объединять или искать информацию где-то еще.

В качестве альтернативы, вы можете разделить на две коллекции, как вы могли бы с реляционной базой данных, а затем использовать дополнительный запрос, чтобы получить продажи продукта, что-то вроде этого:

SQL: SELECT Sales WHERE ProductId = 123

MongoDB: db.sales.find( { productid: 123 } )

продуктов

{
    _id: 123,
    name: "Widget",
    price: 9.99
}

продажи

{
    id: 1,
    productid: 123,
    date: "20100316",
    howMany: 2 
}

{
    id: 2,
    productid: 123,
    date: "20100316",
    howMany: 5
}
3 голосов
/ 12 августа 2011

Мой подход ниже:

, глядя на hadoop Я нашел подход CompositeInputFormat кратко, он принимает две или более коллекций в качестве входных данных для задания сокращения карты

согласно моему исследованиюmongodb пока не предоставляет этого.mongodb mapReduce выполняется для одной коллекции за раз. (пожалуйста, исправьте, если я беспокоюсь)

, поэтому я решил поместить коллекции, которые необходимо объединить, в одну коллекцию, для которой я буду выполнять mapreduce для "sql right join "

это из моего проекта репортера журналов.первого фазового сокращения карты достаточно, чтобы выполнить правильное объединение в случае "отсутствия часов".вторая фазовая карта-уменьшение имеет целью исключить лишнее правое соединение, вызванное полем часов.

db.test.drop();
db.test.insert({"username" : 1, "day" : 1, "clock" : 0 });
db.test.insert({"username" : 1, "day" : 1, "clock" : 1 });
db.test.insert({"username" : 1,  startDay : 1,endDay:2, "table" : "user" });

//startDay : 1,endDay:2 are used to define the employers working day (join to company - left the company)
//you can use an array instedad of array here. for example day:[1,2,3, ...]

m1 = function(){
   if( typeof this.table!= "undefined" && this.table!=null){
       username = this.username;
       startDay = this.startDay;
       endDay   = this.endDay;
       while(startDay<=endDay){
           emit({username:username,day:startDay},{clocks:["join"]});
          // emit({username:username,day:startDay},1);
           startDay++;
       }
   }else{
       emit({username:this.username,day:this.day},{clocks:[this.clock]});
   }
}
r1 = function(key,values){
    result = {clocks:[]}
    values.forEach(function(x){
        result.clocks = x.clocks.concat(result.clocks);
        result.clocks=result.clocks.filter(function(element, index, array){
            return element!="join";            
        })
    })
    return result;
}

db.test.mapReduce(m1,r1,{out:"result1"})
db.test.find();
db.result1.find();

m2=function(){
   key=this._id;
   this.value.clocks.forEach(function(x){
       key.clock=x;
       emit(key,1);       
   })   
}
r2 = function(key,values){
    value=0;
    values.forEach(function(x){
        value+=1;      
    })
    return result;
}

db.result1.mapReduce(m2,r2,{out:"result2"})
db.test.find();
db.result2.find();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...