一、OutputFormat接口实现类
OutputFormat是MapReduce输出的基类,所有实现MapReduce输出都实现了OutputFormat接口。
-
文本输出
TextOutputFormat
默认的输出格式是
TextOutputFormat
,它把每条记录写为文本行。它的键和值可以是任意类型,因为TextOutputFormat
调用toString()
方法把它们转换为字符串。 -
SequenceFileOutputFormat
将
SequenceFileOutputFormat
输出作为后续MapReduce
任务的输入,这便是一种好的输出格式,因为它的格式紧凑,很容易被压缩。 -
自定义
OutputFormat
根据用户需求,自定义实现输出。
二、自定义OutputFormat
-
使用场景
为了实现控制最终文件的输出路径和输出格式,可以自定义OutputFormat。
例如:要在一个
MapReduce
程序中根据数据的不同输出两类结果到不同目录,这类灵活的输出需求可以通过自定义OutputFormat
来实现。 -
自定义
OutputFormat
步骤:(1)自定义一个类继承
FileOutputFormat
。(2)改写
RecordWriter
,具体改写输出数据的方法write()
。
三、自定义OutputFormat案例
-
需求
过滤输入的
log
日志,包含easysir
的网站输出到easysir.log
,不包含easysir
的网站输出到other.log
。 -
输入数据
http://www.baidu.com http://www.google.com http://cn.bing.com http://www.easysir.com http://www.sohu.com http://www.sina.com http://www.sin2a.com http://www.sin2desa.com http://www.sindsafa.com
-
创建包名:
com.easysir.outputformat
-
创建
FilterMapper
类:package com.easysir.outputformat; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class FilterMapper extends Mapper<LongWritable, Text, Text, NullWritable>{ @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 写出 context.write(value, NullWritable.get()); } }
-
创建
FilterReducer
类:package com.easysir.outputformat; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class FilterReducer extends Reducer<Text, NullWritable, Text, NullWritable> { Text k = new Text(); @Override protected void reduce(Text key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException { String line = key.toString(); // 使输出的结果有换行,更加清晰 line = line + "\r\n"; k.set(line); // 防止有重复数据 for (NullWritable nullWritable : values) { context.write(k, NullWritable.get()); } } }
-
创建
OutputFormat
类:package com.easysir.outputformat; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.RecordWriter; import org.apache.hadoop.mapreduce.TaskAttemptContext; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; public class OutputFormat extends FileOutputFormat<Text, NullWritable> { @Override public RecordWriter<Text, NullWritable> getRecordWriter(TaskAttemptContext job) throws IOException, InterruptedException { return new FRecordWriter(job); } }
-
创建
FRecordWriter
类:package com.easysir.outputformat; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IOUtils; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.RecordWriter; import org.apache.hadoop.mapreduce.TaskAttemptContext; import java.io.IOException; public class FRecordWriter extends RecordWriter<Text, NullWritable> { FSDataOutputStream fos_easysir; FSDataOutputStream fos_other; public FRecordWriter(TaskAttemptContext job) { try { // 1 获取文件系统 FileSystem fs = FileSystem.get(job.getConfiguration()); // 2 创建输出到easysir.log的输出流 fos_easysir = fs.create(new Path("E:\\idea-workspace\\mrWordCount\\output\\easysir.log")); // 3 创建输出到other.log的输出流 fos_other = fs.create(new Path("E:\\idea-workspace\\mrWordCount\\output\\other.log")); } catch (IOException e) { e.printStackTrace(); } } @Override public void write(Text key, NullWritable value) throws IOException, InterruptedException { // 判断key中是否又easysir if (key.toString().contains("easysir")){ fos_easysir.write(key.toString().getBytes()); }else { fos_other.write(key.toString().getBytes()); } } @Override public void close(TaskAttemptContext context) throws IOException, InterruptedException { IOUtils.closeStream(fos_easysir); IOUtils.closeStream(fos_other); } }
-
创建
FilterDriver
类:package com.easysir.outputformat; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; public class FilterDriver { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { // 输入输出路径需要根据自己电脑上实际的输入输出路径设置 args = new String[] { "E:\\idea-workspace\\mrWordCount\\input\\output_data.txt", "E:\\idea-workspace\\mrWordCount\\output1" }; // 1 获取配置信息 Configuration conf = new Configuration(); Job job = Job.getInstance(conf); // 2 配置本地jar包所在路径 job.setJarByClass(FilterDriver.class); // 3 配置mapper和reducer路径 job.setMapperClass(FilterMapper.class); job.setReducerClass(FilterReducer.class); // 4 配置map阶段输出kv值类型 job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(NullWritable.class); // 5 配置最终输出kv值类型 job.setOutputKeyClass(Text.class); job.setOutputValueClass(NullWritable.class); // 要将自定义的输出格式组件设置到job中 job.setOutputFormatClass(OutputFormat.class); // 6 配置输入输出路径 FileInputFormat.setInputPaths(job, new Path(args[0])); // 虽然我们自定义了outputformat,但是因为我们的outputformat继承自fileoutputformat // 而fileoutputformat要输出一个_SUCCESS文件,所以,在这还得指定一个输出目录 FileOutputFormat.setOutputPath(job, new Path(args[1])); // 7 提交job boolean result = job.waitForCompletion(true); System.exit(result ? 0 : 1); } }