Java 将多行文字复制到单个地图

Java 将多行文字复制到单个地图,java,hadoop,mapreduce,Java,Hadoop,Mapreduce,我一直在尝试使用Hadoop向单个映射发送N行。我不要求线已经分开 我曾尝试使用NLineInputFormat,但是它会将N行文本从数据发送到每个映射器,每次一行[在第N行之后放弃] 我已尝试设置该选项,每次只需N行输入即可将其发送到每个地图: job.setInt("mapred.line.input.format.linespermap", 10); 我发现一个邮件列表建议我重写LineRecordReader::next,但这并不是那么简单,因为内部数据成员都是私有的 我刚刚检

我一直在尝试使用Hadoop向单个映射发送N行。我不要求线已经分开

我曾尝试使用NLineInputFormat,但是它会将N行文本从数据发送到每个映射器,每次一行[在第N行之后放弃]

我已尝试设置该选项,每次只需N行输入即可将其发送到每个地图:

    job.setInt("mapred.line.input.format.linespermap", 10);
我发现一个邮件列表建议我重写LineRecordReader::next,但这并不是那么简单,因为内部数据成员都是私有的

我刚刚检查了NLineInputFormat和它的硬代码LineReader的源代码,所以重写不会有帮助


另外,顺便说一句,我使用Hadoop 0.18与Amazon EC2 MapReduce兼容。

您必须实现自己的输入格式。您还可以定义自己的记录阅读器

不幸的是,您必须定义一个getSplits()方法。在我看来,这将比实现记录读取器更难:这个方法必须实现一个逻辑来分块输入数据

请参阅以下摘自“Hadoop-权威指南”(我总是推荐这本好书!):

以下是界面:

public interface InputFormat<K, V> {
  InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
  RecordReader<K, V> getRecordReader(InputSplit split,
                                     JobConf job, 
                                     Reporter reporter) throws IOException;
}

我认为在您的例子中,您可以遵循委托模式,在LineRecordReader周围实现一个包装器,覆盖必要的方法,即next()(或新API中的nextKeyValue()),将值设置为N行的串联,而不是一行

我在谷歌上搜索了ParagraphRecordReader的示例性实现,它使用LineRecordReader逐行读取输入数据(并连接数据),直到遇到EOF或空行。然后返回pair,其中值是一个段落(而不是一行)。此外,此ParagraphRecordReader的ParagraphInputFormat与标准TextInputFormat一样简单

您可以在下面的帖子中找到指向此实现的必要链接以及关于此实现的几句话:


最好的

我最近解决了这个问题,只需创建自己的InputFormat即可覆盖NLineInputFormat,并实现一个自定义的MultiLineRecordReader,而不是默认的LineReader

我选择扩展NLineInputFormat,因为我希望得到相同的保证,即每次拆分都有N行

这台读录机几乎是原封不动的

我唯一修改的是现在使用新API的
maxLineLength
的属性,以及从NLineInputFormat的
setNumLinesPerSplit()读取的
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;
            }
        }
    }

}
公共类MultiLineInputFormat扩展了NLineInputFormat{
@凌驾
public RecordReader createRecordReader(InputSplit genericSplit,TaskAttemptContext上下文){
setStatus(genericSplit.toString());
返回新的MultiLineRecordReader();
}
公共静态类MultiLineRecordReader扩展了RecordReader{
私有int-NLINESTOPROCESS;
专用线路阅读器;
私钥;
私有文本值=新文本();
专用长启动=0;
专用长端=0;
私人长pos=0;
私有整数maxLineLength;
@凌驾
public void close()引发IOException{
if(in!=null){
in.close();
}
}
@凌驾
public LongWritable getCurrentKey()引发IOException、InterruptedException{
返回键;
}
@凌驾
公共文本getCurrentValue()引发IOException、InterruptedException{
返回值;
}
@凌驾
public float getProgress()引发IOException、InterruptedException{
如果(开始==结束){
返回0.0f;
}
否则{
返回数学最小值(1.0f,(pos-start)/(float)(end-start));
}
}
@凌驾
public void initialize(InputSplit genericSplit,TaskAttemptContext上下文)引发IOException、InterruptedException{
NLINESTOPROCESS=getNumLinesPerSplit(上下文);
FileSplit split=(FileSplit)genericSplit;
最终路径文件=split.getPath();
conf=context.getConfiguration();
this.maxLineLength=conf.getInt(“mapreduce.input.linerecordreader.line.maxlength”,Integer.MAX_值);
FileSystem fs=file.getFileSystem(conf);
start=split.getStart();
end=start+split.getLength();
布尔skipFirstLine=false;
FSDataInputStream filein=fs.open(split.getPath());
如果(开始!=0){
skipFirstLine=true;
--开始;
filein.seek(开始);
}
in=新的LineReader(文件输入,配置);
if(skipFirstLine){
start+=in.readLine(new Text(),0,(int)Math.min((long)Integer.MAX_值,end-start));
}
this.pos=开始;
}
@凌驾
公共布尔值nextKeyValue()引发IOException、InterruptedException{
if(key==null){
key=新的LongWritable();
}
按键设置(pos);
如果(值==null){
值=新文本();
}
value.clear();
最终文本结束行=新文本(“\n”);
int newSize=0;

对于(int i=0;i)你为什么要这样做?从某种意义上说,多行构成一条记录吗?我真的需要N个随机行[作为一个集合],但是我可以接受consequalive。我需要它将它发送到正确的减缩器。要回答你的问题,是的。你问的真正问题是什么?我试图得到N个行[作为一个小组]前往每个地图绘制者,而不是抓取N号
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;
            }
        }
    }

}