[英]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
將這些塊分成鍵/值對。 請注意, InputSplit
和RecordReader
將由您使用的InputFormat
確定。 例如, TextInputFormat
使用FileSplit
分隔輸入,然后使用LineRecordReader
處理每個單獨的行,其中位置作為鍵,行本身作為值。 因此,在您的GWASInputFormat
您需要查看使用哪種FileSplit
來查看它傳遞給GWASRecordReader
。
我建議調查NLineInputFormat
“將N行輸入分成一個分割”的NLineInputFormat
。 它可能能夠完全按照您自己想要的方式完成。
如果您想一次獲取5行作為值,而第一行的行號作為鍵,我想說您可以使用自定義的NLineInputFormat
和自定義的LineRecordReader
做到這LineRecordReader
。 我認為您不必擔心輸入拆分,因為輸入格式可以將其拆分為這5行。 您的RecordReader
與LineRecordReader
非常相似,但不是獲取塊的開頭的字節位置,而是獲取行號。 所以代碼幾乎完全相同,除了那個小小的變化。 因此,您基本上可以復制並粘貼NLineInputFormat
和LineRecordReader
但輸入格式使用您的記錄閱讀器來獲取行號。 代碼非常相似。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.