MapReduce之RecordReader理解

RecordReader:其作用就是将数据切分成key/value的形式然后作为输入传给Mapper。

 

一 方法分析:

1.1initialize: 初始化RecordReader,只能被调用一次。

1.2nextKeyValue: 读取下一个key/value键值对

1.3getCurrentKey: 获取当前的key

1.4getCurrentValue: 获取当前的value

1.5getProgress: 进度

1.6close: 关闭RecordReader

 

二 RecordReader运行流程

2.1 MapTask会构造一个NewTrackingRecordReader对象

2.2在执行Mapper#run方法之前会调用RecordReader的initialize方法初始化一些东西。

2.3在这个初始化方法里面,它会调用InputFormat#createRecordRead

er方法,我们知道默认的InputFormat就是TextInputFormat,所以这里就回到用TextInputFormat#createRecordReader,返回LineRecordRead

er。

2.4 初始化方法他会干这几样事情:

#将InputSplit转成FileSplit

#获取每一行能读取的最大的长度默认是Integer.MAX_VALUE

#获取当前FileSplit的开始位置

#获取当前FileSplit的结束位置

#获取当前FileSplit的文件路径

2.5 然后进入Mapper#run方法,首先会判断是否有下一个key/value,如果有则传入当前的key和value到map方法.

2.6 LineRecordReader是将当前行开始位置的offset作为key,当前行的值作为value传入给map方法

2.7 程序运行完毕,关闭RecordReader

 

三 常见的RecordReader

LineRecordReader:将文本行开始的便宜量作为key,整个文本行作为value

CombineFileRecordReader:处理CombineInputSplit里的每一个chunk

的RecordReader,CombineInputSplit包含不同的小文件chunk信息

但是具体读取每一个文件的数据,是由单独的RecordReader来读取的,CombineFileRecordReader只负责操作chunk数据

 

DBRecordReader:从数据库表中读取数据

KeyValueRecordReader:根据指定的分割符却切分每一行数据,如果没有指定分割符,那么key就是整行的文本,value就是空

 

 

四 自定义RecordReader

  public static class CombineFileLineRecordReader

    extends RecordReader {

 

    private long startOffset; //offset of the chunk;

    private long end; //end of the chunk;

    private long pos; // current pos

    private FileSystem fs;

    private Pathpath;

    private WordOffsetkey;

    private Textvalue;

   

    private FSDataInputStreamfileIn;

    private LineReaderreader;

   

    public CombineFileLineRecordReader(CombineFileSplit split,

        TaskAttemptContext context, Integer index) throws IOException {

     

      this.path =split.getPath(index);

      fs = this.path.getFileSystem(context.getConfiguration());

      this.startOffset =split.getOffset(index);

      this.end =startOffset + split.getLength(index);

      boolean skipFirstLine = false;

     

      //open the file

      fileIn = fs.open(path);

      if (startOffset !=0) {

        skipFirstLine = true;

        --startOffset;

        fileIn.seek(startOffset);

      }

      reader = newLineReader(fileIn);

      if (skipFirstLine) { // skip first line and re-establish "startOffset".

        startOffset += reader.readLine(newText(), 0,

                    (int)Math.min((long)Integer.MAX_VALUE,end - startOffset));

      }

      this.pos =startOffset;

    }

 

    public void initialize(InputSplitsplit, TaskAttemptContextcontext)

        throws IOException, InterruptedException {

    }

 

    public void close() throws IOException { }

 

    public float getProgress() throws IOException {

      if (startOffset ==end) {

        return0.0f;

      } else {

        return Math.min(1.0f, (pos -startOffset) / (float)(end -startOffset));

      }

    }

 

    public boolean nextKeyValue() throws IOException {

      if (key ==null) {

        key = newWordOffset();

        key.fileName =path.getName();

      }

      key.offset =pos;

      if (value ==null) {

        value = newText();

      }

      int newSize = 0;

      if (pos <end) {

        newSize = reader.readLine(value);

        pos += newSize;

      }

      if (newSize ==0) {

        key = null;

        value = null;

        return false;

      } else {

        return true;

      }

    }

 

    public WordOffsetgetCurrentKey()

        throws IOException, InterruptedException {

      return key;

    }

 

    public TextgetCurrentValue() throws IOException, InterruptedException {

      return value;

    }

  }

你可能感兴趣的:(大数据/Hadoop)