一、概述
- MapReduce开始阶段阶段,InputFormat类用来产生InputSplit,并把基于RecordReader它切分成record(即KEYIN-VALUEIN),形成Mapper的输入。
- Hadoop本身提供了若干内置的InputFormat,其中如果不明确指定默认使用TextInputFormat。
二、常见子类
- TextInputFormat:作为默认的文件输入格式,用于读取纯文本文件,文件被分为一系列以LF(Line-Feed 换行)或者CR(Carriage-Return 回车)结束的行,key是每一行的数据位置偏移量,是LongWritable类型的,value是每一行的内容,为Text类型。
- KeyValueTextInputFormat:同样用于读取文本文件,如果行被分隔符(默认是\t)分割为两部分,第一部分为key,剩下的部分为value;如果没有分隔符,整行作为 key,value为空。
- SequenceFileInputFormat:用于读取sequence file。 sequence file是Hadoop用于存储数据自定义格式的binary文件。它有两个子类:SequenceFileAsBinaryInputFormat,将 key和value以BytesWritable的类型读出;SequenceFileAsTextInputFormat,将key和value以Text类型读出。
- SequenceFileInputFilter:根据filter从sequence文件中取得部分满足条件的数据,通过 setFilterClass指定Filter,内置了三种 Filter,RegexFilter取key值满足指定的正则表达式的记录;PercentFilter通过指定参数f,取记录行数%f==0的记录;MD5Filter通过指定参数f,取MD5(key)%f==0的记录。
- NLineInputFormat:0.18.x新加入,可以将文件以行为单位进行split,将文件的每一行对应一个mapper。得到的key是每一行的位置偏移量(LongWritable类型),value是每一行的内容,Text类型。适合于行数不多但是每一行的字段较多的场景
- CompositeInputFormat:用于多个数据源的join
- DBInputFormat:把数据库表数据读入到HDFS
三、自定义输入格式
概述
- 所有InputFormat都要直接或间接的继承InputFormat抽象类
- InputFormat中主要定义了如下两个方法:getSplits以及createRecordReader
- 如果数据来源是文件,那么可以继承FileInputFormat。FileInputFormat实现了InputFormat接口,实现了getSplits方法,根据配置去逻辑切割文件,返回FileSplit的集合,并提供了isSplitable()方法,子类可以通过在这个方法中返回boolean类型的值表明是否要对文件进行逻辑切割,如果返回false则无论文件是否超过一个Block大小都不会进行切割,而将这个文件作为一个逻辑块返回。而对createRecordReader方法则没有提供实现,设置为了抽象方法,要求子类实现。
- TextInputFormat继承了FileInputFormat
案例
// 格式类
public class AutoInputFormat extends FileInputFormat<Text, Text>{
@Override
protected boolean isSplitable(JobContext context, Path filename) {
return false;
}
@Override
public RecordReader<Text, Text> createRecordReader(InputSplit split, TaskAttemptContext context)
throws IOException, InterruptedException {
return new AutoRecordReader();
}
}
// 读取类
public class AutoRecordReader extends RecordReader<Text, Text> {
private LineReader reader;
private Text key;
private Text value;
@Override
public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
// 获取文件分片
FileSplit fs = (FileSplit) split;
// 通过分片获取文件路径
Path path = fs.getPath();
// 获取环境配置
Configuration conf = context.getConfiguration();
// 获取文件系统
FileSystem system = FileSystem.get(URI.create(path.toString()), conf);
// 获取输入流
FSDataInputStream in = system.open(path);
// 将该字节流包装成一个LineReader对象方便按行读取
reader = new LineReader(in);
}
@Override
public boolean nextKeyValue() throws IOException, InterruptedException {
// 初始化键值对
key = new Text();
value = new Text();
Text temp = new Text();
if (reader.readLine(temp) == 0)
return false;
key.set(temp.getBytes());
for (int i = 0; i < 2; i++) {
if (reader.readLine(temp) == 0)
return false;
value.append(temp.getBytes(), 0, temp.getLength());
value.append(new Text(" ").getBytes(), 0, 1);
}
return true;
}
@Override
public Text getCurrentKey() throws IOException, InterruptedException {
return key;
}
@Override
public Text getCurrentValue() throws IOException, InterruptedException {
return value;
}
@Override
public float getProgress() throws IOException, InterruptedException {
return 0;
}
@Override
public void close() throws IOException {
if (reader != null)
reader.close();
}
}
// Mapper
public class AutoMapper extends Mapper<Text, Text, Text, Text> {
public void map(Text key, Text value, Context context) throws IOException, InterruptedException {
context.write(key, value);
}
}
// Driver
public class AutoDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "JobName");
job.setJarByClass(cn.tedu.autoinput.AutoDriver.class);
job.setMapperClass(AutoMapper.class);
job.setInputFormatClass(AutoInputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job, new Path("hdfs://192.168.32.147:9000/txt/score3.txt"));
FileOutputFormat.setOutputPath(job, new Path("hdfs://192.168.32.147:9000/result"));
if (!job.waitForCompletion(true))
return;
}
}
四、多源输入
public class AutoDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "JobName");
job.setJarByClass(cn.tedu.autoinput.AutoDriver.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 如果多源输入的文件处理格式都一致,可以使用统一的Mapper类
// 如果多源输入的文件处理格式不一致,则需要分别指定Mapper类
MultipleInputs.addInputPath(job, new Path("hdfs://192.168.32.147:9000/txt/score.txt"), TextInputFormat.class, AutoMapper1.class);
MultipleInputs.addInputPath(job, new Path("hdfs://192.168.32.147:9000/txt/score3.txt"), AutoInputFormat.class, AutoMapper2.class);
FileOutputFormat.setOutputPath(job, new Path("hdfs://192.168.32.147:9000/result2"));
if (!job.waitForCompletion(true))
return;
}
}