簡體   English   中英

Hadoop Map Reduce CustomSplit / CustomRecordReader

[英]Hadoop Map Reduce CustomSplit/CustomRecordReader

我有一個巨大的文本文件,我想分割文件,以便每個塊有5行。 我實現了自己的GWASInputFormat和GWASRecordReader類。 但是我的問題是,在下面的代碼中(我從http://bigdatacircus.com/2012/08/01/wordcount-with-custom-record-reader-of-textinputformat/復制),在initialize()方法中我有以下幾行

FileSplit split = (FileSplit) genericSplit;
final Path file = split.getPath();
Configuration conf = context.getConfiguration();

我的問題是,在我的GWASRecordReader類中調用initialize()方法時文件是否已被拆分? 我以為是在GWASRecordReader類中進行的(拆分)。 如果我的思考過程就在這里,請告訴我。

package com.test;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.util.LineReader;

public class GWASRecordReader extends RecordReader<LongWritable, Text> {

private final int NLINESTOPROCESS = 5;
private LineReader in;
private LongWritable key;
private Text value = new Text();
private long start = 0;
private long pos = 0;
private long end = 0;
private int maxLineLength;

public void close() throws IOException {
    if(in != null) {
        in.close();
    }
}

public LongWritable getCurrentKey() throws IOException, InterruptedException {
    return key;
}

public Text getCurrentValue() throws IOException, InterruptedException {
    return value;
}

public float getProgress() throws IOException, InterruptedException {
    if(start == end) {
        return 0.0f;
    }
    else {
        return Math.min(1.0f, (pos - start)/(float) (end - start));
    }
}

public void initialize(InputSplit genericSplit, TaskAttemptContext context) throws IOException {
    FileSplit split = (FileSplit) genericSplit;
    final Path file = split.getPath();
    Configuration conf = context.getConfiguration();
    this.maxLineLength = conf.getInt("mapred.linerecordreader.maxlength",Integer.MAX_VALUE);
    FileSystem fs = file.getFileSystem(conf);
    start = split.getStart();
    end = start + split.getLength();
    System.out.println("---------------SPLIT LENGTH---------------------" + split.getLength());
    boolean skipFirstLine = false;
    FSDataInputStream filein = fs.open(split.getPath());

    if(start != 0) {
        skipFirstLine = true;
        --start;
        filein.seek(start);
    }

    in = new LineReader(filein, conf);
    if(skipFirstLine) {
        start += in.readLine(new Text(),0,(int)Math.min((long)Integer.MAX_VALUE, end - start));
    }
    this.pos = start;
}

public boolean nextKeyValue() throws IOException, InterruptedException {
    if (key == null) {
        key = new LongWritable();
    }

    key.set(pos);

    if (value == null) {
        value = new Text();
    }
    value.clear();
    final Text endline = new Text("\n");
    int newSize = 0;
    for(int i=0; i<NLINESTOPROCESS;i++) {
        Text v = new Text();
        while( pos < end) {
            newSize = in.readLine(v ,maxLineLength, Math.max((int)Math.min(Integer.MAX_VALUE, end - pos), maxLineLength));
            value.append(v.getBytes(), 0, v.getLength());
            value.append(endline.getBytes(),0,endline.getLength());
            if(newSize == 0) {
                break;
            }
            pos += newSize;
            if(newSize < maxLineLength) {
                break;
            }
        }
    }

    if(newSize == 0) {
        key = null;
        value = null;
        return false;
    } else {
        return true;
    }
}
}

是的,輸入文件已經拆分。 它基本上是這樣的:

your input file(s) -> InputSplit -> RecordReader -> Mapper...

基本上, InputSplit將輸入分成多個塊, RecordReader將這些塊分成鍵/值對。 請注意, InputSplitRecordReader將由您使用的InputFormat確定。 例如, TextInputFormat使用FileSplit分隔輸入,然后使用LineRecordReader處理每個單獨的行,其中位置作為鍵,行本身作為值。 因此,在您的GWASInputFormat您需要查看使用哪種FileSplit來查看它傳遞給GWASRecordReader

我建議調查NLineInputFormat “將N行輸入分成一個分割”的NLineInputFormat 它可能能夠完全按照您自己想要的方式完成。

如果您想一次獲取5行作為值,而第一行的行號作為鍵,我想說您可以使用自定義的NLineInputFormat和自定義的LineRecordReader做到這LineRecordReader 我認為您不必擔心輸入拆分,因為輸入格式可以將其拆分為這5行。 您的RecordReaderLineRecordReader非常相似,但不是獲取塊的開頭的字節位置,而是獲取行號。 所以代碼幾乎完全相同,除了那個小小的變化。 因此,您基本上可以復制並粘貼NLineInputFormatLineRecordReader但輸入格式使用您的記錄閱讀器來獲取行號。 代碼非常相似。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM