hadoop10--mapreduce组件之Combiner

Combiner

Combiner 是 MapReduce 程序中 Mapper 和 Reducer 之外的一种组件,它的作用是在 maptask
之后给 maptask 的结果进行局部汇总,以减轻 reducetask 的计算负载,减少网络传输。

使用

Combiner 和 Reducer 一样,编写一个类,然后继承 Reducer,reduce 方法中写具体的 Combiner逻辑,然后在 job 中设置 Combiner 组件:job.setCombinerClass(FlowSumCombine.class)

注意事项

  • 1、Combiner 和 Reducer 的区别在于运行的位置:
    Combiner 是在每一个 MapTask 所在的节点运行
    Reducer 是接收全局所有 Mapper 的输出结果
  • 2、Combiner 的输出 kv 类型应该跟 Reducer 的输入 kv 类型对应起来
    Combiner 的输入 kv 类型应该跟 Mapper 的输出 kv 类型对应起来
  • 3、Combiner 的使用要非常谨慎,因为 Combiner 在 MapReduce 过程中可能调用也可能不调用,可能调一次也可能调多次,有时会影响处理结果。所以:
    Combiner 使用的原则是:有或没有都不能影响业务逻辑,都不能影响最终结果。
例如求平均值:
maptask011:4    1:5   1:3
    2:4    2:6 
maptask02:
    1:6    1:8
    2:7     2:8    2:9  
没有combiner组件:
    reduce求平均值:
    14+5+3+6+8/5=5.2
添加combinermaptask01:1:4+5+3/3=4
    maptask02:1:6+8/2=7
reduce:
    1:4    1:7
    :4+7)/2=5.5!=5.2   结果会有偏差

案例:wordcount用上Combiner

WordCountMapper


import java.io.IOException;
import java.io.Serializable;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;


public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{

    @Override
    protected void map(LongWritable key,
            Text value, 
            Context context)
            throws IOException, InterruptedException {
        //拿到每一行的内容  进行分割  
        //将text---String
        String line = value.toString();
        //拆分单词
        String[] words = line.split("\t");
        //循环遍历每一个单词  进行打标机  1  发送给reduce进行统一统计
        for(String w:words){
            //参数1:key   参数2:value
            //String--text
            Text k=new Text(w);
            IntWritable v=new IntWritable(1);
            context.write(k, v);
        }

    }

}

Reducer


import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
    /**
     * 这个方法的调用频率:每组调用一次     有几组会调用几次
     * 分组规则:
     *  key相同的为一组
     * hello,1   hello,1 hadoop,1  hello,1
     * key:reduce输入的  这里指的是单词   每一组中的一个key
     * values:每一组中的所有value   <1,1,1>
     */
    @Override
    protected void reduce(Text key, 
            Iterable values,
            Context context) throws IOException, InterruptedException {
        //进行词频统计
        int sum=0;
        //循环变遍历values   求和
        for(IntWritable v:values){
            //v.get()  这个是将intwritable转换为int
            sum+=v.get();
        }
        context.write(key, new IntWritable(sum));
    }
}

combiner

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class MyCombiner extends Reducer<Text, IntWritable, Text, IntWritable>{
    @Override
    protected void reduce(Text key, Iterable values,
            Reducer.Context context) throws IOException, InterruptedException {
        int sum=0;
        for(IntWritable i:values){
            sum+=i.get();
        }
        context.write(key, new IntWritable(sum));
    }

}

driver

package com.ghgj.cn.combiner;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.CombineFileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;


public class Driver {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        System.setProperty("HADOOP_USER_NAME", "hadoop");
        //加载配置文件
        Configuration conf=new Configuration();
        //启动一个job  一个map  reduce程序  这里叫做一个job
        Job job=Job.getInstance(conf);

        //指定job运行的主类
        job.setJarByClass(Driver.class);

        //指定这个job的mapper类和reduce类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);

        //指定map的输出的key  和  value的类型
        //这里为什么还要指定     泛型的只在编译的时候有作用  运行会自动擦除   所以在这里需要指定一下
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);

        //指定reduce输出的key和value类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //指定combiner组件
        job.setCombinerClass(MyCombiner.class);
        //job.setCombinerClass(WordCountReducer.class);


        FileInputFormat.addInputPath(job, new Path("hdfs://hadoop01:9000/in"));
        //添加输出路径    输出路径一定不能存在     怕如果存在会进行覆盖
        FileOutputFormat.setOutputPath(job, new Path("hdfs://hadoop01:9000/combine02"));
        //提交job
        job.waitForCompletion(true);
    }

}

分析:我们发现combiner和reducer的逻辑是一样的,只是在maptask来完成这项工作而已。所以这里可以省略combiner的代码,只需要将job.setCombinerClass(MyCombiner.class);改成job.setCombinerClass(WordCountReducer.class);指向reducer的代码处理逻辑就可以。

你可能感兴趣的:(hadoop)