Hadoop自定义linereader,实现按行分块

来源:互联网 发布:官路淘宝 元宝 小说 编辑:程序博客网 时间:2024/06/05 22:59

最近想用Hadoop实现一个A的转置乘以A的矩阵运算,假设A是100w*100的矩阵,想把100w行特征分成100个map,每个map处理1w行,每个map一次性处理1w行,而不是一行一行处理。
hadoop0.21.0这个版本已经实现了NLineInputFormat这个方法

job.setInputFormatClass(NLineInputFormat.class);NLineInputFormat.addInputPath(job, in);NLineInputFormat.setNumLinesPerSplit(job,10000); 

这样可以实现每个map处理10000行的需求,100万行就是100个map,而不是默认的按物理块大小分配map,但是这个接口内部调用map方法的时候,仍是一行一行处理的,map方法会被执行10000次,现在改写linereader,让map方法只执行一次,每次处理10000行。

首先定义myLineInputFormat类,将job的读入方式设成myLineInputFormat。

job.setInputFormatClass(myLineInputFormat.class);myLineInputFormat.addInputPath(job, in);myLineInputFormat.setNumLinesPerSplit(job,10000);

myLineInputFormat的源码直接拷贝NLineInputFormat的源码,myLineInputFormat这个类里面的RecordReader返回的LongWritable, Text返回的是每个map方法里的文件偏移量和文本内容,每次读10000行,偏移量就是10000行的偏移量,text自然是10000行的文本内容。
重写myLineInputFormat类里的RecordReader方法:

public RecordReader<LongWritable, Text> createRecordReader(      InputSplit genericSplit, TaskAttemptContext context)       throws IOException {    context.setStatus(genericSplit.toString());    return new mylinereader();  }

定义myLineReader类,先源码拷贝LineRecordReader类,getFilePosition方法就是返回的每次文本的偏移量,每次的偏移量根据LineReader的readLine方法来确定,所以myLineReader的LineReader引用自己的LineReader,把import的类包改一下就成。
定义LineReader类,放在自定义的package里面,源码拷贝原先hadoop里的LineReader类,修改readLine方法:

      if(appendLength > 0)         appendLength = (appendLength+1) * 10000 ;      if (appendLength > 0) {        str.append(buffer, startPosn, appendLength);        txtLength += appendLength;      }

第一个if是修改文件的长度,自己添加,第二个if是原来方法里的,如果10000行内容太多,这里append会报数组越界,所以修改LineReader的构造方法,如下,DEFAULT_BUFFER_SIZE是类属性,值也可以自己修改

 public LineReader(InputStream in, Configuration conf) throws IOException {    //this(in, conf.getInt("io.file.buffer.size", DEFAULT_BUFFER_SIZE));      this(in, DEFAULT_BUFFER_SIZE);  }

同时修改readLine方法的返回值,原始是返回一行的偏移量,现在改成返回10000行的偏移量

  return (int)bytesConsumed * 10000 ;
0 0
原创粉丝点击