实现思想:MR实现表的join操作,实际上是不同文件的join操作,不同文件通过某些列作为连接字段进行连接。
为了实现这一功能,过程如下:
1、在map阶段,将连接的字段组成map的key值(如连接字段有多个,可以将这些字段通过某个分隔符进行连接),将其他字段通过分隔符连接放在map的value中,并在value的开头加上特殊符号(如文件名)来区别这个map来自哪个文件;
2、在reduce阶段,由于同一个key值的所有map会传递到同一个reduce,可以通过解析传入reduce的所有值,将来自不同文件的值放入不同的集合中,然后嵌套遍历两个集合,通过分隔符拆分value值(若map的key值是多字段连接,也需要拆分key值);
注:若要实现左连接,在遍历的时候稍加修改即成
数据
a文件
1 zhangsan
2 lisi
b文件
1 18 male
- 内关联
package first.first_maven;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import first.first_maven.IndexDemo.MyCombiner1;
import first.first_maven.IndexDemo.MyMapper1;
import first.first_maven.IndexDemo.MyReducer1;
public class JoinDemo {
public static class MyMapper extends Mapper<LongWritable,Text,Text,Text>{
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//获取数据文件名
InputSplit is=context.getInputSplit();
String filename=((FileSplit)is).getPath().getName();
if(filename.contains("a")) {
String[] strs=value.toString().split(" ");
if(strs.length<2) return;
context.write(new Text(strs[0]), new Text("a#"+strs[1]));
}else if(filename.contains("b")) {
String[] strs=value.toString().split(" ");
if(strs.length<3) return;
context.write(new Text(strs[0]), new Text("b#"+strs[1]+" "+strs[2])); //通过空格区分字段
}
}
}
public static class MyReducer extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
List<String> a=new ArrayList<String>();
List<String> b=new ArrayList<String>();
for(Text v:values) {
if(v.toString().startsWith("a#")) {
a.add(v.toString().substring(2));
}else if(v.toString().startsWith("b#")) {
b.add(v.toString().substring(2));
}
}
for(int i=0;i<a.size();i++) {
for(int j=0;j<b.size();j++) {
context.write(new Text(key), new Text(a.get(i)+" "+b.get(j)));
}
}
}
}
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
Job job = Job.getInstance(conf, "myjob");
job.setJarByClass(JoinDemo.class);
job.setMapperClass(MyMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
FileInputFormat.addInputPath(job,new Path(args[0]));
job.setReducerClass(MyReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileOutputFormat.setOutputPath(job,new Path(args[1]));
int isok=job.waitForCompletion(true)?0:1;
System.exit(isok);
}
}
结果:1 zhangsan 18 male
- 左关联
只修改reduce即可
public static class MyReducer extends Reducer<Text, Text, Text, Text>{
@Override
protected void reduce(Text key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
List<String> a=new ArrayList<String>();
List<String> b=new ArrayList<String>();
for(Text v:values) {
if(v.toString().startsWith("a#")) {
a.add(v.toString().substring(2));
}else if(v.toString().startsWith("b#")) {
b.add(v.toString().substring(2));
}
}
//实现左关联
for(int i=0;i<a.size();i++) {
if(b.size()==0){ //在b表没数据的时候只输出a的数据
context.write(new Text(key), new Text(a.get(i)));
}else{
for(int j=0;j<b.size();j++) {
context.write(new Text(key), new Text(a.get(i)+" "+b.get(j)));
}
}
}
}
}
结果:1 zhangsan 18 male
2 lisi
本文介绍如何使用MapReduce实现表的Join操作,详细解释了Map和Reduce阶段的实现思想,包括通过连接字段作为key,其他字段作为value,以及在Reduce阶段如何处理来自不同文件的值以完成内连接和左连接。
465

被折叠的 条评论
为什么被折叠?



