MapReduce 编程实战

MapReduce 采用了「分而治之」的思想。在分布式计算中,MapReduce 框架负责处理并行编程中分布式存储、工作调度、负载均衡、容错均衡、容错处理以及网络通信等复杂问题,把处理过程高度抽象为两个函数:map,把一个任务分解成多个任务;reduce,将任务的处理结果汇总。MapReduce 处理的数据集(或任务)必须具备这样的特点:待处理的数据集可以分解成许多小的数据集,而且每一个小数据集都可以完全并行地进行处理。

在 Hadoop 中,每个 MapReduce 任务都被初始化为一个 Job,每个 Job 又可以分为两种阶段:map 阶段和 reduce 阶段,分别用两个函数表示。map 函数接收一个 <key, value> 形式的输入,同样产生一个 <key, value> 形式的输出;Hadoop 函数接收一个如 <key, List> 形式的输入,然后对 list 进行处理,每个 reduce 产生 0 或 1 个输出,reduce 的输出也是 <key, value> 形式的。

 

数据去重 

编写测试文件并上传

cat

 cat

put

put 

 

上传jar包,执行程序

jar

jar

查看输出文件

cat

 cat

数据排序

编写测试文件并上传

cat

cat

 

put

put

 

上传jar包,并执行程序

jar

查看输出文件

cat

cat

 

单表关联

编写测试文件并上传

cat

cat

 

上传jar包,并执行程序

jar

jar

 

查看输出文件

cat

cat

 

参考代码

数据去重

public class RemoveDeduplication {

    /**
     * map 将输入中的 value 复制到输出数据的 key 上,并直接输出
     */
    public static class Map extends Mapper<Object, Text, Text, Text> {
        // 每行数据
        private static Text line = new Text();

        @Override
        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            line = value;
            context.write(line, new Text(""));
        }

    }

    /**
     * reduce 将输入中的 key 复制到输出数据的 key 上,并直接输出
     */
    public static class Reduce extends Reducer<Text, Text, Text, Text> {

        @Override
        public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            context.write(key, new Text(""));
        }

    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        // 这句话很关键
        // conf.set("mapred.job.tracker", "192.168.1.2:9001");
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.err.println("Usage: Data Deduplication <in> <out>");
            System.exit(2);
        }
        Job job = Job.getInstance(conf, "Data Deduplication");
        job.setJarByClass(RemoveDeduplication.class);

        // 设置 Map、Combine 和 Reduce 处理类
        job.setMapperClass(Map.class);
        job.setCombinerClass(Reduce.class);
        job.setReducerClass(Reduce.class);

        // 设置输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        // 设置输入和输出目录
        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }

}

 

数据排序

public class DataSort {

    /**
     * map 将输入中的 value 化成 IntWritable 类型,作为输出的 key
     */
    public static class Map extends Mapper<Object, Text, IntWritable, IntWritable> {
        private static IntWritable data = new IntWritable();

        @Override
        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String line = value.toString();
            data.set(Integer.parseInt(line));
            context.write(data, new IntWritable(1));
        }

    }

    /**
     * reduce 将输入中的 key 复制到输出数据的 key 上,然后根据输入的 value-list 中元素的个数决定 key 的输出次数。
     * 用全局 lineNum 来代表 key 的位次
     */
    public static class Reduce extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable> {
        private static IntWritable lineNum = new IntWritable(1);

        @Override
        public void reduce(IntWritable key, Iterable<IntWritable> values, Context context)
                throws IOException, InterruptedException {
            for (IntWritable val : values) {
                context.write(lineNum, key);
                lineNum = new IntWritable(lineNum.get() + 1);
            }
        }

    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        // 这句话很关键
        // conf.set("mapred.job.tracker", "192.168.1.2:9001");
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.err.println("Usage: Data Sort <in> <out>");
            System.exit(2);
        }
        Job job = Job.getInstance(conf, "Data Sort");
        job.setJarByClass(DataSort.class);

        // 设置 Map 和 Reduce 处理类
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);

        // 设置输出类型
        job.setOutputKeyClass(IntWritable.class);
        job.setOutputValueClass(IntWritable.class);

        // 设置输入和输出目录
        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }

}

 

单表关联

public class SimpleTableJoin {
    public static int time = 0;

    /**
     * map 将输出分割 child 和 parent,然后正序输出一次作为右表,
     * 反序输出一次作为左表,需要注意的是在输出的 value 中必须加上左右表的区别标识。
     */
    public static class Map extends Mapper<Object, Text, Text, Text> {

        @Override
        public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
            String childName;
            String parentName;
            // 左右表标识
            String relationType;

            // 输入的一行预处理文本
            StringTokenizer itr = new StringTokenizer(value.toString());
            String[] values = new String[2];
            if (itr.hasMoreTokens()) {
                values[0] = itr.nextToken();
            }
            if (itr.hasMoreTokens()) {
                values[1] = itr.nextToken();
            }

            if (values[0].compareTo("child") != 0) {
                childName = values[0];
                parentName = values[1];
                // 输出左表
                relationType = "1";
                context.write(new Text(values[1]), new Text(relationType + "+" + childName + "+" + parentName));
                // 输出右表
                relationType = "2";
                context.write(new Text(values[0]), new Text(relationType + "+" + childName + "+" + parentName));
            }
        }

    }

    public static class Reduce extends Reducer<Text, Text, Text, Text> {

        @Override
        public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
            // 输出表头
            if (0 == time) {
                context.write(new Text("grandchild"), new Text("grandparent"));
                time++;
            }
            int grandchildnum = 0;
            String[] grandchild = new String[10];
            int grandparentnum = 0;
            String[] grandparent = new String[10];

            for (Text value : values) {
                String record = value.toString();
                int len = record.length();
                int i = 2;
                if (0 == len) {
                    continue;
                }
                // 取得左右表标识
                char relationType = record.charAt(0);
                // 定义孩子和父母变量
                StringBuilder childName = new StringBuilder();
                StringBuilder parentName = new StringBuilder();
                // 获取 value-list 中 value 的 child
                while (record.charAt(i) != '+') {
                    childName.append(record.charAt(i));
                    i++;
                }
                i = i + 1;

                // 获取 value-list 中 value 的 parent
                while (i < len) {
                    parentName.append(record.charAt(i));
                    i++;
                }
                // 左表,取出 child 放入 grandchildren
                if ('1' == relationType) {
                    grandchild[grandchildnum] = childName.toString();
                    grandchildnum++;
                }
                // 右表,取出 parent 放入 grandparent
                if ('2' == relationType) {
                    grandparent[grandparentnum] = parentName.toString();
                    grandparentnum++;
                }
            }

            // grandchild 和 grandparent 数组求笛卡尔儿积
            if (0 != grandchildnum && 0 != grandparentnum) {
                for (int m = 0; m < grandchildnum; m++) {
                    for (int n = 0; n < grandparentnum; n++) {
                        // 输出结果
                        context.write(new Text(grandchild[m]), new Text(grandparent[n]));
                    }
                }
            }
        }

    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        // 这句话很关键
        // conf.set("mapred.job.tracker", "192.168.1.2:9001");
        String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
        if (otherArgs.length != 2) {
            System.err.println("Usage: Single Table Join <in> <out>");
            System.exit(2);
        }
        Job job = Job.getInstance(conf, "Single Table Join");
        job.setJarByClass(SimpleTableJoin.class);

        // 设置 Map 和 Reduce 处理类
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);

        // 设置输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);

        // 设置输入和输出目录
        FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
        FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }

}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

像向日葵一样~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值