之前我一直在使用MapReduce执行经典的MR操作,相当于SQL中的GROUP BY。
我想知道在概念上是否可以使用MapReduce执行JOIN操作。知道如何实现吗?使用MapReduce进行此类操作是否有意义?
谢谢!
答案 0 :(得分:4)
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
}
答案 1 :(得分:3)
我的方法如下:
看看hadoop我找到了CompositeInputFormat的方法 简而言之,它需要两个或更多集合作为map-reduce作业的输入
根据我的调查,mongodb还没提供这个。 mongodb mapReduce一次只能在一个集合上执行。(如果我有问题,请更正)
所以我决定把需要加入的集合放进去 在一个集合中,我将为“sql right join”执行mapreduce
这是来自我的日志记者项目。 第一阶段map-reduce足以在“无时钟”的情况下执行右连接。 第二阶段map-reduce的目的是排除由时钟场引起的多余的右连接。
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();