hadoop学习(10)----map端的执行过程

1、介绍

在经过split阶段后,将会在RecordReader的类或者其子类中将split(分片的数据)读取成<key,value>键值对,这样就可以讲split分片中的数据以键值对的方式读入到map端去了。

2、详解

首先我们看一下org.apache.hadoop.mapreduce.Mapper类中的结构

<span style="font-size:18px;">public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {

  public abstract class Context
    implements MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
  }
  

  protected void setup(Context context
                       ) throws IOException, InterruptedException {
    // NOTHING
  }

 @SuppressWarnings("unchecked")
  protected void map(KEYIN key, VALUEIN value, 
                     Context context) throws IOException, InterruptedException {
    context.write((KEYOUT) key, (VALUEOUT) value);
  }

  protected void cleanup(Context context
                         ) throws IOException, InterruptedException {
    // NOTHING
  }
  
  public void run(Context context) throws IOException, InterruptedException {
    setup(context);
    try {
      while (context.nextKeyValue()) {
        map(context.getCurrentKey(), context.getCurrentValue(), context);
      }
    } finally {
      cleanup(context);
    }
  }
}</span>

A、从Mapper类中的run()方法看来,Mapper任务过程中,限制性setup(),方法,在setup()方法中可以在map()函数之前进行一些预备的工作,例如简历布隆过滤器、读取分布式缓存等操作。

B、执行完setup()函数以后将会执行context.nextKeyValue()方法。而在一个任务被执行后,context的实际对象是MapContextImpl对象,下面我们看一下这个类中的方法:

<span style="font-size:18px;">public class MapContextImpl<KEYIN,VALUEIN,KEYOUT,VALUEOUT> 
    extends TaskInputOutputContextImpl<KEYIN,VALUEIN,KEYOUT,VALUEOUT> 
    implements MapContext<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
  private RecordReader<KEYIN,VALUEIN> reader;
  private InputSplit split;

  public MapContextImpl(Configuration conf, TaskAttemptID taskid,
                        RecordReader<KEYIN,VALUEIN> reader,
                        RecordWriter<KEYOUT,VALUEOUT> writer,
                        OutputCommitter committer,
                        StatusReporter reporter,
                        InputSplit split) {
    super(conf, taskid, writer, committer, reporter);
    this.reader = reader;
    this.split = split;
  }

  /**
   * Get the input split for this map.
   */
  public InputSplit getInputSplit() {
    return split;
  }

  @Override
  public KEYIN getCurrentKey() throws IOException, InterruptedException {
    return reader.getCurrentKey();
  }

  @Override
  public VALUEIN getCurrentValue() throws IOException, InterruptedException {
    return reader.getCurrentValue();
  }

  @Override
  public boolean nextKeyValue() throws IOException, InterruptedException {
    return reader.nextKeyValue();
  }

}</span>

我们从MapContextImpl类中可以看出,在该示例对象调用nextKeyValue()方法就是通过封装的方式执行RecordReader类中的nextKeyValue()方法,这样就从RecordReader类或者其子类中获取了Split分片<key,value>的数据。然后使用同样的封装方式调用RecordReader方法中的getCurrentKey和getCurrentValue方法获取相应的key值和value值,接着执行相应的map函数

C、map()方法使我们实现MapReduce功能需要进行自定义的主要方法,通过重写map()方法,我们让map()函数实现相应的业务逻辑。并且我们从run()方法中可以看出,每当生成一个KeyValue键值对时就会执行一次map()方法,对产生的keyvalue键值对进行相应的处理。

D、最后执行的cleanup()函数。因为cleanup()方法时在finally结构体中,所以其必然会执行,这是我们可以通过cleanup()方法去关闭一些全局资源,例如DataInputStream类等。同样我们可以讲较少的结果存储在一个静态数据中,在cleanup()方法中调用context.write()方法,将map的结果写入到上下文对象中,例如求出topn案例等。

E、当run、setup、map、cleanup方法都执行完成后,经过处理里所形成新的<key,value>键值对将通过context.write()方法写入到上下文中。

3、总结

Map端是自定义进行处理<key,value>键值对的,通过不同的设计模式,可以针对不同的数据和业务需求进行相应的处理,从而实现客户的需求。

你可能感兴趣的:(mapreduce,map,hadoop2.x)