自定义RecordReader
Hadoop默认的InputFormat
为TextInputFormat
,对应的数据解析器默认为LineRecordReader
。
我们可以根据需要自定义InputFormat
和RecordReader
来个性化对输入的处理。
下面这个例子是我学习过程中参考视频教程做的一个练习,查了很多资料,大概弄懂,满心欢喜,兴致勃勃,欲记之,研墨毕,惊觉早有此例之详述,吾至而立之年以来,渐得一习:凡所经苦思冥想之事,必记之,以为缅。遂得此文,不究雷同与否。
实验环境:
操作系统: Ubuntu 16.04 LTS
Hadoop版本: Apache Hadoop2.6.5
JDK版本: JDK1.7
集群配置: 伪分布式模式
问题描述
需求:对如下文件,分别统计奇数行和偶数行总和
问题分析
问题的难点在于:
我们如何区分读入的数据是奇数行还是偶数行
Hadoop默认的InputFormat
处理类为TextInputFormat
,将数据分片对应的数据读入,划分为 <offset,text>
这样的形式 , 对此例中的要求,我们可以通过指定自定义InputFormat
子类来实现对原始数据进行自定义的处理规则。
这里采用的方法是,通过自定义的InputFormat
,读取记录时记录当前行号line_number
,将number.txt
中的数据转化成<line_number,text>
这样的形式,根据line_number
确定奇偶行,对map的输出进行partitioner操作,对应到处理奇数行之和与偶数行之和的reducer中。
注:在这个例子中,不对数据文件进行分片
编码
MyInputFormat.java
自定义的InputFormat,用自定义的RecordReader对象读入分片对应的数据 , 不允许文件分片
package mr;
import java.io.IOException;
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.JobContext;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
//这里从文件读取分片,继承FileInputFormat类
public class MyInputFormat extends FileInputFormat<LongWritable, Text> {
// 自定义的RecordReader,负责解析分片对应的数据
private MyRecordReader myRecordReader=null;
//RecordReader负责处理分片对应的数据
@Override
public RecordReader<LongWritable, Text> createRecordReader(InputSplit inputSplit, TaskAttemptContext context)
throws IOException, InterruptedException {
myRecordReader=nwe MyRecordReader(inputSplit,context);
//初始化自定义的RecordReader对象
myRecordReader.initialize();
return myRecordReader;
}
//是否可分割文件,在这个例子中,不需要对输入进行分片,直接返回false
@Override</