Map/Reduce解读

一、程序框架

整个程序写一个class,在里面一般有三块:map、reduce、main;

主要继承Mapper类去定义map方法,继承Reducer类去定义reduce方法,设计main函数去设置输出

二、函数构造

1.InputFormat:

public interface InputFormat<K, V> {
 
      InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
 
      RecordReader<K, V> getRecordReader(InputSplit split,
 
      JobConf job,
 
      Reporter reporter) throws IOException;
 
}

这里由用户定义需要的输入文件的内容格式

  getSplits:用于将所有输入数据分成numSplits个split(即InputSplit[]数组),每个split分片(并不是一定是个文件)交给一个map task任务去处理。特别地,在输入文件多,但每个文件都很小,基于每个输入文件至少产生一个map task的原则,就会产生很多map增加调度开销,作业变慢。

  RecordReader:用于定义每个map task任务是怎么去读取一个split的数据(即<K,V>)。默认下,RecordReader是LineRecordReader,以每行偏移量定为key(存储的概念,即改行数据在磁盘空间上相对于文件开始的地址偏移),每行的数据定为value。

142113_Wh2D_2698055.jpg

 

2.Map:

 public static class Map extends Mapper<Object,Text,IntWritable,IntWritable>{}

继承Mapper类:

设置输入的<key,values>类型,Object是粗类,这里随便不使用输入的key;输出的<key,values>类型,IntWritable是数字类

public void map(K1 key,V1 value,OutputCollector<K2,V2> output,Reporter reporter) throws IOException{}

定义map方法:

设置输入的<key,values>类型,OutputCollector获取map()的输出结果,Reporter保存了当前task处理进度,一般只定义一个全局变量context来传递

 

3.Partitioner

  继承Partitioner类去定义,各个map task产生的<key,value>交给哪个recude task处理。最好把相近节点,处理的数据平均分布,从而达到负载均衡和减少传输。

  getPartition(K2 key,V2 value,int numPartitions)

  返回<k2,v2>对应的reduce task ID。 如果不定义,默认使用hash函数去分配。

 

4.Combiner

  用于使map/reduce间的数据传输量减小,提高性能。一般与Reduce相同。

5.Reduce:

 public static class Reduce extends Reducer<IntWritable,IntWritable,IntWritable,IntWritable>{}

继承Reducer类:

设置接收的<key,values>类型,跟map的类型基本一致;输出的<key,values>类型,即最终输出

 public void reduce(IntWritable key,Iterable<IntWritable> values,Context context) throws IOException,InterruptedException{}

定义reduce方法:

设置接收的<key,values>类型,跟map类型基本一致,有时候会定义values为数组,保存key相同的数据;context供读取,即最终输出

 

6.main:

通用代码段:

public static void main(String[] args) throws Exception{
    Configuration conf = new Configuration();
    conf.set("mapred.job.tracker", "192.168.47.141:9001");
    String[] ioArgs=new String[]{"dedup_in","dedup_out"};
    String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();
    if (otherArgs.length != 2){  //判断程序参数是否有两个:输入,输出
    System.err.println("Usage: Data Deduplication <in> <out>");
    System.exit(2);
    }
    Job job = new Job(conf, "Data Deduplication");
    job.setJarByClass(Dedup.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);
}

 

三、案例代码例解

map:

  1. 设计变量去保存需要的数据:

    private static Text line=new Text();

    private static IntWritable data=new IntWritable();

  2. 处理数据,输出<key,values>

    String line=value.toString();       // Text的value变量转为string 赋值给line

    data.set(Integer.parseInt(line));   // 把line 转为Integer

    context.write(data, new IntWritable(1));    //把data以key写入上下文变量,values值只是为了标识多个同key数据

    context.write(line, new Text(""));   //输出以line为key的数据,键值对<line,"">,任意的values

  3. 分割数据

 String line = value.toString();
 StringTokenizer tokenizerArticle = new StringTokenizer(line, "\n");//将value数据以行分隔,一般value只有一行
 while (tokenizerArticle.hasMoreElements()) {//一般只循环了一次,相同key就多次
//将行数据value以空格分隔
    StringTokenizer tokenizerLine = new StringTokenizer(tokenizerArticle.nextToken());

    String strName = tokenizerLine.nextToken(); //取第一段
    String strScore = tokenizerLine.nextToken();//取第二段
    Text name = new Text(strName);
    int scoreInt = Integer.parseInt(strScore);
    context.write(name, new IntWritable(scoreInt));
 }

 

reduce:

  1. 直接输出

    context.write(key, new Text(""));   直接输出key和""

    for(IntWritable val:values){        //遍历values数组,只是为了处理重复数据

        context.write(linenum, key);        // reduce自带排序,以key

        linenum = new IntWritable(linenum.get()+1);    // 设计行数,累加

    }

转载于:https://my.oschina.net/charlock/blog/657243

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值