베스트 단순히 NLineInputFormat을 무시하고 사용자 정의 MultiLineRecordReader 대신 기본 LineReader를 구현하는 내 자신의 InputFormat을 만들어 최근에이 문제를 해결했다.
NLineInputFormat을 확장하기로 한 이유는 분할 당 정확히 N 줄의 동일한 보장이 있기 때문입니다.
이 기록 독자는 내가 수정 http://bigdatacircus.com/2012/08/01/wordcount-with-custom-record-reader-of-textinputformat/
유일한 것들에서와 같이 거의 이제 새 API를 사용 maxLineLength
의 속성, 그리고 하드 코딩되는 NLineInputFormat의 setNumLinesPerSplit()
INSEAD에서 읽을됩니다 NLINESTOPROCESS
의 값은 촬영 (더 많은 유연성을 위해). 여기
은 결과입니다
public class MultiLineInputFormat extends NLineInputFormat{
@Override
public RecordReader<LongWritable, Text> createRecordReader(InputSplit genericSplit, TaskAttemptContext context) {
context.setStatus(genericSplit.toString());
return new MultiLineRecordReader();
}
public static class MultiLineRecordReader extends RecordReader<LongWritable, Text>{
private int NLINESTOPROCESS;
private LineReader in;
private LongWritable key;
private Text value = new Text();
private long start =0;
private long end =0;
private long pos =0;
private int maxLineLength;
@Override
public void close() throws IOException {
if (in != null) {
in.close();
}
}
@Override
public LongWritable getCurrentKey() throws IOException,InterruptedException {
return key;
}
@Override
public Text getCurrentValue() throws IOException, InterruptedException {
return value;
}
@Override
public float getProgress() throws IOException, InterruptedException {
if (start == end) {
return 0.0f;
}
else {
return Math.min(1.0f, (pos - start)/(float)(end - start));
}
}
@Override
public void initialize(InputSplit genericSplit, TaskAttemptContext context)throws IOException, InterruptedException {
NLINESTOPROCESS = getNumLinesPerSplit(context);
FileSplit split = (FileSplit) genericSplit;
final Path file = split.getPath();
Configuration conf = context.getConfiguration();
this.maxLineLength = conf.getInt("mapreduce.input.linerecordreader.line.maxlength",Integer.MAX_VALUE);
FileSystem fs = file.getFileSystem(conf);
start = split.getStart();
end= start + 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;
}
@Override
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;
}
}
}
}
왜이 작업을 수행하려고? 어떤 의미에서 여러 줄이 하나의 레코드를 구성합니까? –
나는 N 개의 랜덤 라인이 [세트로] 필요하지만, 결과적으로 살 수 있습니다. 오른쪽 감속기로 보내야합니다. – monksy
질문에 대답하려면 예. – monksy