MapReduce之RecordReader理解

来源:互联网 发布:数据分析师证书有哪些 编辑:程序博客网 时间:2024/05/21 22:23

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 staticclass CombineFileLineRecordReader

    extends RecordReader<WordOffset, Text> {

 

    private longstartOffset; //offset of the chunk;

    private longend; //end of the chunk;

    private longpos; // current pos

    private FileSystemfs;

    private Pathpath;

    private WordOffsetkey;

    private Textvalue;

   

    private FSDataInputStreamfileIn;

    private LineReaderreader;

   

    public CombineFileLineRecordReader(CombineFileSplitsplit,

       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 voidinitialize(InputSplitsplit,TaskAttemptContextcontext)

       throws IOException, InterruptedException {

    }

 

    public voidclose() throws IOException { }

 

    public floatgetProgress() throws IOException {

      if (startOffset ==end) {

       return0.0f;

      }else {

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

      }

    }

 

    public booleannextKeyValue() 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;

    }

  }

原创粉丝点击