【Hadoop】26-MapReduce的输出格式

针对前一节介绍的输人格式,Hadoop都有相应的输出格式。OutputFormat类的层次结构如图所示。

1文本输出

默认的输出格式是TextOutputFormat,它把每条记录写为文本行。它的键和值可以是任意类型,因为Text0utputFormat调用toString()方法把它们转换为字符串。每个键·值对由制表符进行分隔,当然也可以设定mapreduce.output.textoutputformat.separator属性改变默认的分隔符。与TextOutputFormat对应的输人格式是KeyValueTextInputFormat,它通过可配置的分隔符将键.值对文本行分隔,详情参见822节。
可以使用NullWritable来省略输出的键或值(或两者都省略,相当于NullOutputFormat输出格式,后者什么也不输出)。这也会导致无分隔符输出,以使输出适合用TextInputFormat读取。

2二进制输出

2.1关于SequenceFiIeOutputFormat
正如名称所示,SequenceFileOutputFormat将它的输出写为一个顺序文件。如果输出需要作为后续MapReduce任务的输人,这便是一种好的输出格式,因为他的格式紧凑很容易被压缩。压缩由SequenceFileOutputFormat的静态方法来实现,详情参见5.2.3节。9.2节用一个例子展示了如何使用SequenceFileoutputFormat。
2.2关于SequenceFileAsBinaryOuputFormat
SequenceFileAsBinaryOuputFormat与SequenceFileAsBinaryInputFormat相对应,它以原始的二进制格式把键·值对写到一个顺序文件容器中。
2.3关于MapFiIeOutputFormat
MapFileOutputFormat把map文件作为输出。MapFile中的键之须顺序添加,所以必须确保reducer输出的键已经排好序。

reduce输人的键一定是有序的,但输出的键由reduce函数控制,MapReduce框架中没有硬性规定reduce输出键必须是有序的。所以reduce输出的键必须有序是对MapFileOutputFormat的一个额外限制。

3多个输出

FileOutputFormat及其子类产生的文件放在输出目录下。每个reducer一个文件并且文件由分区号命名:part-r-00000,part-r-00001等等。有时可能需要对输出MapReduce的类型与格式的文件名进行控制或让每个reducer输出多个文件。MapReduce为此提供了MuItipIeOutputFormat类。
3.1.范例:数据分割
考虑这样一个需求;按气象站来区分气象数据。这需要运行一个作业,作业的输出是每个气象站一个文件,此文件包含该气象站的所有数据记录。
一种方法是每个气象站对应一个reducer。为此,我们必须做两件事。第一,写一个partitioner,把同一个气象站的数据放到同一个分区。第二,把作业的reducer数设为气象站的个数。partitioner如下:

public class StationPartitioner extends Partitioner<LongWritable,Text>{
    private NcdcRecordParser parser = new NcdcRecordParser();
    @Override
    public int getPartition(LongWritable key,Text value,int numPartitions){
        parser.parse(value);
        return getPartition(parser.getStationId());
    }
    
    private int getPartition(String stationId){
        ...
    }
}

这里没有给出getPartition(String)方法的实现,它将气象站ID转换成分区索引号。为此,它的输人是一个列出所有气象站ID的列表,然后返回列表中气象站的索引。
这样做有两个缺点。第一,需要在作业运行之前知道分区数和气象站的个数。虽然NCDC数据集提供了气象站的元数据,但无法保证数据中的气象站ID与元数据匹配。如果元数据中有某个气象站但数据中却没有该气象站的数据,就会浪费一个reduce任务。更糟糕的是,数据中有但元数据中却没有的气象站,也没有对应的reduce任务,只好将这个气象站扔掉。解决这个问题的方法是写一个作业来抽取唯一的气象站ID,但很遗憾,这需要额外的作业来实现。
第二个缺点更微妙。一般来说,让应用程序来严格限定分区数并不好,因为可能导致分区数少或分区不均。让很多reducer做少量工作不是一个高效的作业组织方法,比较好的办法是使用更少reducer做更多的事情,因为运行任务的额外开销减少了。分区不均的情况也是很难避免的。不同气象站的数据量差异很大:有些气象站是一年前刚投人使用的,而另一些气象站可能已经工作近一个世纪了。如果其中一些reduce任务运行时间远远超过另一些,那么作业执行时间将由它们来决定,从而导致作业运行时间超出预期。
在以下两种特殊情况下,让应用程序来设定分区等价于reducer的个数)是有好处的。

  • 0个reducer这个情况很罕见:没有分区,因为应用只需执行map任务
  • 1个reducer可以很方便地运行若干小作业,把以前作业的输出合并成单个文件。前提是数据量足够小,以便一个reducer能轻松处理

最好让集群为作业决定分区数:可用的集群资源越多,作业完成就越快。这就是默认的HashPartitioner表现如此出色的原因,因为它处理的分区数不限,并且确保每个分区都有一个很好的键组合使分区更均匀。

如果使用HashPartitioner,每个分区就会包含多个气象站,因此,要实现每个气象站输出一个文件,必须安排每个reducer写多个文件,由此就有了MultipleOutput。

3.2MultipleOutput

MultipleOutput类可以将数据写到多个文件,这些文件的名称源于输出的键和值或者任意字符串。这允许每个reducer(或者只有map作业的mapper)创建多个文件。采用name-m-nnnnn形式的文件名用于map输出,name-r-nnnnn形式的文件名用于reduce输出,其中name是由程序设定的任意名字,nnnnn是一个指明块号的整数(从00000开始)0块号保证从不同分区(mapper或reducer)写的输出在相同名字情况下不会冲突。
范例8巧显示了如何使用Mu1tip1e0utputs按照气象站划分数据。
范例8.5.用MultipleOutput类将整个数据集分区到以气象站旧命名的文件

public class PartitionByStationUsingMultipleOutputs extends Configured implements Tool{
    static class StationMapper extends Mapper<LongWritable,Text,Test,Test>{
        private NcdcRecordParser parser=new NcdcRecordParser();
        @Override
        protected void map(LongWritable key,Text value,Context context)throws IOException,InterruptedException{
            parser.parse(value);
            context.write(new Text(parser.getStationId()),value);
        }
    }
    static class MultipleOutputsReducer extends Reducer<Text,Text,NullWritable,Text>{
        private MultipleOutputs<NullWritable,Text> multipleOutputs;
        @Override
        protected void setUp(Context context)throws IOException,InterruptedException{
            multipleOutputs=new MultipleOutputs<>(context);
        }
        @Override
        public void reduce(Text key,Iterable<Text> values,Context context) throws IOException,InterruptedException{
            for(Text value:values){
                multipleOutputs.write(NullWritable.get(),value,key.toString());
            }
        }
        @Override
        protected void cleanup(Context context) throws IOException,InterruptedException{
            multipleOutputs.close();
        }
    }
    @Override
    public int run(String[] args) throws Exception{
        Job job=JobBuilder.parseInputAndOutput(this,getConf(),args);
        if(job==null){
            return -1;
        }
        job.setMapperClass(StationMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setReducerClass(MultipleOutputsReducer.class);
        job.setOutputKeyClass(NullWritable.class);
        return job.waitForCompletion(true)?0:1;
    }

    public static void main(String[] args) {
        int exitCode=ToolRunner.run(new PartitionByStationUsingMultipleOutputs(),args);
        System.exit(exitCode);
    }
}

在生成输出的reducer中,在setup()方法中构造一个Multiple0utputs的实例并将它赋给一个实例变量。在reduce()方法中使用Multiple0utputs实例来写输出,而不是context。write()方法作用于键、值和名字。这里使用气象站标识符作为名字,因此最后产生的输出名字的形式为station_identifier_r-nnnnn。
运行一次后,前面几个输出文件的命名如下:

在Multiple0utputs的write()方法中指定的基本路径相对于输出路径进行解释,因为它可以包含文件路径分隔符(/),创建任意深度的子目录是有可能的。例如,下面的改动将数据根据气象站和年份进行划分,这样每年的数据就被包含到一个名为气象站ID的目录中(例如029070-99999/1901/part-r-00000):

@Override
public void reduce(Text key,Iterable<Text> values,Reducer.Context context) throws IOException,InterruptedException{
    for(Text value:values){
        parser.parse(value);
        String basePath=String.format("%s/%s/part",parser.getStationId(),parser.getYear());
        multipleOutputs.write(NullWritable.get(),value,basePath);
    }
}

MuItipIeOutput传递给mapper的OutputFormat,该例子中为TextOutputFormat,但可能有更复杂的情况。例如,可以创建命名的输出,每个都有自己的OutputForamt、键和值的类型(这可以与mapper或reducer的输出类型不相同)。此外,mapper或reducer可以为每条处理的记录写多个输出文件。

4延迟输出

FileOutputFormat的子类会产生输出文件(part-r-nnnnn),即使文件是空的。有些应用倾向于不创建空文件,此时LazyOutputFormat就有用武之地了。它是一个封装输出格式,可以保证指定分区第一条记录输出时才真正创建文件。要使用它,用JobConf和相关的输出格式作为参数来调用set0utputFormatClass()方法即可。
Streaming支持-LazyOutput选项来启用LazyOutputFormat功能。

5数据库输出

写到关系型数据库和HBase的输出格式可以参见8.2.5节。
 

"C:\Program Files\Java\jdk-17\bin\java.exe" -Didea.launcher.port=54222 "-Didea.launcher.bin.path=D:\hadoop\IntelliJ IDEA Community Edition 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "D:\hadoop\Hadoop\target\classes;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-api-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-runtime-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\client\hadoop-client-minicluster-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-kms-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-nfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-common-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\common\hadoop-common-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-nfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-rbf-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-client-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-httpfs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-rbf-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-client-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-native-client-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\hdfs\hadoop-hdfs-native-client-3.1.4-tests.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-examples-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-hs-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-app-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-core-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-common-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-client-shuffle-3.1.4.jar;D:\hadoop\hadoop-3.1.4\share\hadoop\mapreduce\hadoop-mapreduce-c
最新发布
05-07
<think>好的,我现在需要帮助用户解决Hadoop 3.1.4的启动命令配置问题,特别是关于JDK 17和IDEA Community Edition 2018.3.6的classpath路径分析。首先,我得回顾一下用户提供的引用内容和之前的问题。 用户提到了几个关键点:Hadoop运行配置问题、启动命令的构成,以及classpath路径分析。引用中提到了ClassNotFoundException,JAVA_HOME未设置的问题,还有修改hadoop-env.sh和yarn.application.classpath的配置。此外,用户还提到了完全分布式环境的搭建步骤,比如移动和解压安装包,配置workers文件和环境变量。 首先,ClassNotFoundException通常和类路径有关,可能是驱动类没找到,或者打包的jar文件没有正确包含所需的类。用户使用JDK 17,需要注意Hadoop版本是否兼容,因为Hadoop 3.1.4可能对JDK 17的支持有限,官方文档可能推荐的是JDK 8或11。这时候可能需要确认兼容性,或者调整JDK版本。 接下来是启动命令的配置。Hadoop启动通常通过start-dfs.sh和start-yarn.sh,这些脚本会读取Hadoop的配置文件,比如hadoop-env.sh,里面需要正确设置JAVA_HOME。用户提到使用JDK 17,所以必须确保hadoop-env.sh中的JAVA_HOME指向正确的JDK路径,例如export JAVA_HOME=/usr/lib/jvm/jdk-17。如果路径错误,会导致JAVA_HOME找不到,从而引发各种错误。 关于classpath,用户需要运行hadoop classpath命令获取路径,并将结果添加到yarn.application.classpath的配置中。这确保YARN能够找到所有的依赖库。同时,如果用户使用IDEA进行开发,需要确保项目中的classpath配置正确,包括Hadoop的库和JDK 17的版本。IDEA 2018.3.6可能较旧,可能需要检查是否支持JDK 17,或者是否需要升级插件。 另外,用户的环境变量配置在/etc/profile.d/my_env.sh中,需要确认Hadoop和JDK的路径是否正确设置,并且通过source命令使其生效。同时,workers文件中的节点名称是否正确,比如master、slave1、slave2是否与实际的主机名对应,SSH免密登录是否配置,这些都是启动分布式环境的关键步骤。 可能用户遇到的错误包括:ClassNotFoundException(类路径问题)、JAVA_HOME未设置(环境变量或配置文件错误)、或者节点通信问题(workers配置或SSH问题)。需要一步步检查这些方面,确认每个配置项的正确性。 最后,用户可能需要了解如何在IDEA中配置Hadoop项目,添加正确的依赖库,并设置运行参数,确保打包后的jar包含所有需要的类,并且Hadoop的classpath正确指向这些依赖。同时,考虑到JDK 17的新特性,比如模块化系统,可能需要调整Hadoop的启动脚本或依赖项,避免不兼容的问题。</think>### Hadoop 3.1.4 启动命令配置详解(JDK-17 + IDEA 2018.3.6) #### 一、核心配置项分析 1. **JAVA_HOME配置** 修改 `$HADOOP_HOME/etc/hadoop/hadoop-env.sh` 文件,明确指定JDK-17路径: ```bash export JAVA_HOME=/usr/lib/jvm/jdk-17 ``` 若未配置,会触发 `Error: JAVA_HOME is not set` 错误[^2]。 2. **Classpath动态获取** 运行 `hadoop classpath` 获取当前Hadoop类路径,输出结果需添加到 `yarn-site.xml` 的 `yarn.application.classpath` 配置项中: ```xml <property> <name>yarn.application.classpath</name> <value>/opt/module/hadoop-3.1.4/etc/hadoop:/opt/module/hadoop-3.1.4/share/hadoop/common/lib/*:...</value> </property> ``` 该路径包含Hadoop核心库和第三方依赖[^3]。 3. **IDEA项目配置要点** - 确保 `pom.xml` 中Hadoop依赖版本与集群版本一致(3.1.4) - 设置编译兼容性为JDK-17: ```xml <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> ``` #### 二、典型启动命令结构 完整作业提交命令示例: ```bash hadoop jar your-job.jar com.example.MainClass \ -D mapreduce.job.queuename=default \ /input/path /output/path ``` - `hadoop jar`:Hadoop执行入口 - `-D` 参数:动态配置MapReduce参数 - 末尾参数:程序自定义输入输出路径 #### 三、JDK-17兼容性问题 需注意: 1. Hadoop 3.1.4 官方支持最高JDK11,使用JDK-17需重新编译Hadoop源码: ```bash mvn clean package -Pdist,native -DskipTests -Dmaven.javadoc.skip=true -Djava.version=17 ``` 2. 若出现 `UnsupportedClassVersionError`,需检查IDEA的编译输出目标版本设置 #### 四、调试技巧 1. **环境验证命令**: ```bash # 检查JAVA_HOME echo $JAVA_HOME # 验证Hadoop类路径 hadoop classpath ``` 2. **日志定位**: - NameNode日志:`$HADOOP_HOME/logs/hadoop-*-namenode-*.log` - YARN日志:通过 `yarn logs -applicationId <app_id>` 获取
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值