MapReduce 实现 InnerJoin 操作: 在Reduce端实现Join

InnerJoin

表1 DEP.txt: (去除第一行列名)

ID      地名 
1       北京
2       天津
3       河北
4       山西
5       内蒙古
6       辽宁
7       吉林
8       黑龙江

表2 EMP.txt : (去除第一行列名)

ID      年份      数量
1       2010    1962
1       2011    2019
2       2010    1299
2       2011    1355
4       2010    3574
4       2011    3593
9       2010    2303
9       2011    2347

类似数据库中的内连接下的预计效果: InnerJoin

ID      地名      年份      数量
1       北京    2011    2019
1       北京    2010    1962
2       天津    2011    1355
2       天津    2010    1299
4       山西    2011    3593
4       山西    2010    3574

设计模型

  1. 在设计阶段的设想: 在map端对文件进行分别处理 ,把所有记录修改成 key, value 键值对形式,把 id 作为 key, value 值根据数据的来源进行分类 , DEP 的:“a#” + name ,EMP 的:“b#” + score
  2. 在reduce阶段,shuffle功能把数据打乱了,我们根据之前的 value 值得前端 ab 来区分数据来源,分别放入两个 LinkedList ,然后做笛卡尔积,一条条存起来
    MapReduce 实现 InnerJoin 操作: 在Reduce端实现Join_第1张图片

实现代码:

package hadoop.innerjoin;


import java.util.LinkedList;

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.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;



public class InnerJoin {

    public static final String DELIMITER = "\u0009";

    public static class Map extends org.apache.hadoop.mapreduce.Mapper<LongWritable, 
            Text, Text, Text> {


        protected void map(LongWritable key, Text value, Mapper.Context context) throws java.io.IOException, InterruptedException{

            org.apache.hadoop.mapreduce.lib.input.FileSplit split = (org.apache.hadoop.mapreduce.lib.input.FileSplit) context.getInputSplit();

//          获取数据路径
            String fileName = split.getPath().toString();
            String line = value.toString();

//          根据分隔符截取
            String[] values = line.split(DELIMITER);    

//          抛弃空数据
            if (line == null || line.equals("")) 
                return;

//          处理来自 DEP.txt 的数据
            if (fileName.contains("DEP.txt")) {     
                if (values.length < 2) 
                    return;
                String id = values[0];      //ID
                String name = values[1];    //地名

                System.out.println("id: " + id + " name: " + name);

                context.write(new Text(id), new Text("a#" + name));
            } 
//          处理EMP.txt 的数据
            else if (fileName.contains("EMP.txt")) {
                if (values.length < 3) 
                    return;


                String id = values[0];      //ID
                String statyear = values[1];    //年份
                String num = values[2];     //数量


                System.out.println("id: " + id + "  statyear: " + statyear + " num: " + num);

                context.write(new Text(id), new Text("b#" + statyear + DELIMITER + num));
            }
        }
    }


    public static class Reduce extends Reducer<Text, Text, Text, Text> {
        protected void reduce(Text word, Iterable values, Reducer.Context context) throws java.io.IOException, InterruptedException {
            LinkedList linkEMP = new LinkedList(); 
            LinkedList linkDEP = new LinkedList();

            for (Text tval : values) {
                String val = tval.toString();

                if(val.startsWith("a#")) {
                    linkEMP.add(val.substring(2));
                } else if (val.startsWith("b#")) {
                    linkDEP.add(val.substring(2));
                }
            }

            for (String u : linkEMP) {
                for (String l : linkDEP) {
                    context.write(word, new Text(u + DELIMITER + l));
                }
            }

        }
    }




    public static void main(String[] args) throws Exception{
        Configuration conf = new Configuration();
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

        if (otherArgs.length != 2) {
            System.err.println("Usage: InnerJoin");
            System.exit(2);
        }


        Job job = Job.getInstance(conf, "InnerJoin");
        job.setJarByClass(InnerJoin.class);

        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);

        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);


        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));


        System.exit(job.waitForCompletion(true) ? 0 : 1);

    }
}

MapReduce 实现 InnerJoin 操作: 在Reduce端实现Join_第2张图片

参考文献:
MapReduce实现Join操作
使用MapReduce实现Join操作

你可能感兴趣的:(mapreduce)