Hadoop(十七) mapreduce Outputformat输出格式

Outputformat介绍

OutputFormat发生在ReduceTask之后,接收ReduceTask产生的数据,然后将结果按照指定格式来写出。OutputFormat是MapReduce输出的基类,所有实现MapReduce输出都实现了OutputFormat接口。

在MapReduce中,如果不指定,默认使用的是TextOutputFormat。 TextOutputFroamt继承了FileOutputFormat。其中,FileOutputFormat负责对输出路径进行校验,TextOutputFormat则是对数据进行写出。

在MapReduce中,也支持自定义输出格式以及多源数据,但是注意,实际开发中自定义输出格式以及多源输出用的非常少。

1、文本输出TextOutputFormat 默认的输出格式是TextOutputFormat,它把每条记录写为文本行。它的键和值可以是任意类型,疑问TextOutputFormat调用toString()方法把他们转换为字符串。

2、SequenceFileOutputFormat 将SequenceFileOutputFormat输出作为后续MapReduce任务的输入,这便是一种好的输出格式,因为它的格式紧凑,很容易被压缩。

3、自定义OutputFormat 根据用户需求,自定义实现输出。

它的作用是

a. 校验输出路径,例如检查输出路径不存在。

b. 提供输出流用于将数据写出。

案例自定义OutputFormat

1、使用场景 为了实现控制最终文件的输出路径和输出格式,可以自定义OutputFormat。

例如:要在一个MapReduce程序中根据数据的不同输出两类结果到不同的目录,这类灵活的输出需求可以通过自定义OutputFormat来实现。

2、自定义OUtputFormat步骤 (1)自定义一个类继承FileOutputFormat。 (2)改写RecordWriter,具体改写输出数据的方法write()。

数据准备,有订单数据如下:ordersource.txt

mobile,20241214,orderid1231231

windows,20241213,orderid1231232

我们将含有mobile数据放到 mobile.log里,将含有windows数据放到windows.log里

编写程序如下

自定义format类

package outputf;

import org.apache.hadoop.io.NullWritable;

import java.io.IOException;
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 org.apache.hadoop.mapreduce.RecordWriter;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class SelfOutputFormat  extends FileOutputFormat<Text, NullWritable> {

    @Override
    public RecordWriter<Text, NullWritable> getRecordWriter(TaskAttemptContext job)			throws IOException, InterruptedException {

        // 创建一个RecordWriter
        return new FileRecordWriter(job);
    }
}

RecordWriter类

package outputf;

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 FileRecordWriter  extends RecordWriter<Text, NullWritable> {

    FSDataOutputStream windowsout = null;
    FSDataOutputStream mobileout = null;

    public FileRecordWriter(TaskAttemptContext job) {
        // 1 获取文件系统
        FileSystem fs;

        try {
            fs = FileSystem.get(job.getConfiguration());

            // 2 创建输出文件路径
            Path mobilepath = new Path("/output/mobile.log");
            Path windowspath = new Path("/output/windows.log");

            // 3 创建输出流
            windowsout = fs.create(windowspath);
            mobileout = fs.create(mobilepath);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void write(Text key, NullWritable value) throws IOException, InterruptedException {
        // 判断是否包含“windows”输出到不同文件
        if (key.toString().contains("windows")) {
            windowsout.write(key.toString().getBytes());
        } else {
            mobileout.write(key.toString().getBytes());
        }
    }

    @Override
    public void close(TaskAttemptContext context) throws IOException, InterruptedException {
        // 关闭资源
        IOUtils.closeStream(windowsout);
        IOUtils.closeStream(mobileout);
    }
}

Mapper类

package outputf;


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;

/**

 * @description Map 阶段,分别计算每行每个单词出现的次数,key 是单词,value 为 1(表示 1 个单词)。
 */
public class OutputMapper extends Mapper<LongWritable, Text, Text, NullWritable> {

@Override
protected void map(LongWritable key,Text value,Mapper<LongWritable, Text, Text, NullWritable>.Context context)throws IOException,InterruptedException{
        // 写出
        context.write(value,NullWritable.get());
        }
}

 Reducer

package outputf;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**

 * @description Reduce 阶段
 */
public class OutputReducer extends Reducer<Text, NullWritable, Text, NullWritable> {

    Text k = new Text();
    @Override
    protected void reduce(Text key, Iterable<NullWritable> values, Reducer<Text, NullWritable, Text, NullWritable>.Context context) throws IOException, InterruptedException {
        // 1 获取一行
        String line = key.toString();

        // 2 拼接
        line = line + "\r\n";

        // 3 设置key
        k.set(line);

        // 4 输出
        context.write(k, NullWritable.get());
    }
}

JobMain

 

package outputf;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.util.GenericOptionsParser;
import org.apache.log4j.BasicConfigurator;

import java.io.IOException;

public class JobMain {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        BasicConfigurator.configure(); //自动快速地使用缺省Log4j环境
        //一、初始化Job
        Configuration configuration = new Configuration();

        Job job = Job.getInstance(configuration, "mr");
        job.setJarByClass(JobMain.class);

        args = new String[] { "/ordersource.txt", "/output" };

        Configuration conf = new Configuration();

        job.setJarByClass(JobMain.class);
        job.setMapperClass(OutputMapper.class);
        job.setReducerClass(OutputReducer.class);

        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(NullWritable.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(NullWritable.class);

        // 要将自定义的输出格式组件设置到job中
        job.setOutputFormatClass(SelfOutputFormat.class);

        Path input = new Path(args[0]);
        Path output = new Path(args[1]);
        // 如果输出路径存在,则进行删除
        FileSystem fs = FileSystem.get(conf);
        if (fs.exists(output)) {
            fs.delete(output,true);
        }
        FileInputFormat.setInputPaths(job, input);

        // 虽然我们自定义了outputformat,但是因为我们的outputformat继承自fileoutputformat
        // 而fileoutputformat要输出一个_SUCCESS文件,所以,在这还得指定一个输出目录
        SelfOutputFormat.setOutputPath(job, output);

        boolean result = job.waitForCompletion(true);
        System.exit(result ? 0 : 1);

    }
}

打jar包运行

 hadoop jar /hadoopmapreduce-1.0-SNAPSHOT.jar outputf.JobMain

结果如下,我们看到mobile的数据输出到mobile.log里,windows的数据输出到windows.log里

26453cb11fcb4d3db6b737bbd585136e.png

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫1981

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值