`
panshaobinSB
  • 浏览: 202875 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Hadoop中map/reduce编程中关于mapper和reducer的Format问题(转)

 
阅读更多
http://www.linuxidc.com/Linux/2012-01/51627.htm
Hadoop中的map/reduce编程中有几个非常关键的组件,其中包括 Mapper,Reducer,InputFormat,OutputFormat,OutputKeyClass,OutputValueClass 等,在刚接触map/reduce编程的时候很容易由于 InputFormat,OutputFormat,OutputKeyClass,OutputValueClass在程序中的设置 不正确导致程序出错,有时候试来试去没准能让程序跑的通过,但是结果不一定如预期的那样,即使结果也如预期,但是也没有明白hadoop 的mapred框架内部到底是如何处理的细节,等下次编程的时候还是会面临相同的问题,所以干脆一下狠心,开始研究hadoop的源码了解其实现细节。做笔记 如下:

程序出错描述
以一个mapreduce运行实例 为例:
比如运行命令 :
bin/hadoop jar hadoop-0.19.0-streaming.jar -input /home/luoli/input/goodman -output /home/luoli/output -mapper org.apache.hadoop.mapred.lib.IdentityMapper -reducer /usr/bin/wc

这其实是一个很简单的mapreduce运行instance,就是把一个文件 读入到mapper中,mapper不做任何计算就把中间结果传递给reducer,reducer对中间结果进行行,字和字节的统计,最后将统计信息输出到HDFS相应的目录下。但仅仅是这么简单的一个 mapreduce run instance,却提示出错,job运行失败,查看日志 ,记录的错误信息如下
java .io.IOException: Type mismatch in key from map: expected org.apache.hadoop.io.Text, recieved org.apache.hadoop.io.LongWritable
    at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.collect(MapTask.java:548)
    at org.apache.hadoop.mapred.lib.IdentityMapper.map(IdentityMapper.java:37)
    at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:50)
    at org.apache.hadoop.mapred.MapTask.run(MapTask.java:332)
    at org.apache.hadoop.mapred.Child.main(Child.java:155)

这是几乎所有人在编写hadoop mapreduce程序时会遇到的最常见的错误,程序提示说是格式错误,出错的地方在Mapper从InputFormat中读取input并产生中间结果时发生了格式错误,Mapper在collect时期待Key的类型是Text,而收到的确实LongWritable类型的key。
究其原因,主要是因为,程序中没有明确指定要使用那种InputFormat来读取输入数据 ,hadoop就使用默认的TextInputFormat,通过查看源码,这个TextInputFormat是扩展自FileInputFormat,
public class TextInputFormat extends FileInputFormat<LongWritable, Text>{...}
并且可以看出父类的范型中已经明确指定了 keyClass为LongWritable类型,而value Class为Text类型,并且这个InputFormat的实现为将输入文件的行数作为key,而将每一行的文本作为value。因此,在从文件到 mapper的过程中,数据就被分割成了<LongWritable, Text>的对,并传输给Mapper,这也就是说Mapper需要以同样的格式来接收来自InputFormat的数据。程序到这个时候都是没有问题的。这里使用的Mapper实例是org.apache.hadoop.mapred.lib.IdentityMapper,这个Mapper的实现是将读到的数据不做任何的处理,直接传给Reducer,问题在于:从IdentiryMapper类的实现代码来看,如下:
public void map(K key, V val,
                  OutputCollector<K, V> output, Reporter reporter)
    throws IOException {
    output.collect(key, val);
  }

实际上它是按照接收到的<key,value>对,并接受key 和value原本的类型类进行数据传递。因此Mapper进行分割的时候,要启动很多的Map的Task来分布的运行,到了MapTask后,会调用 MapTask的内部类MapOutputBuffer.collet()方法,问题就处在了这个方法里面。
从这个方法的代码来看:
public synchronized void collect(K key, V value)
        throws IOException {...}

key和value接收来以后仍然是保持了key和value原本的类型,这时仍然没有问题,但是方法内部,会判断key和 value的类型,是不是等于MapOutputBuffer中保存的keyClass和valueClass类型:
if (key.getClass() != keyClass) {
        throw new IOException("Type mismatch in key from map: expected "
                              + keyClass.getName() + ", recieved "
                              + key.getClass().getName());
      }
      if (value.getClass() != valClass) {
        throw new IOException("Type mismatch in value from map: expected "
                              + valClass.getName() + ", recieved "
                              + value.getClass().getName());
      }

而MapOutputBuffer保存的keyClass和 valueClass类型是在MapOutputBuffer初始化的时候被赋予的:
keyClass = (Class<K>)job.getMapOutputKeyClass();
valClass = (Class<V>)job.getMapOutputValueClass();

所以可以看出,实际上keyClass和 valueClass的class类型实际上是由这个job的JobConf来决定的,继续跟进这两个方法,可以发现,实际上 job.getMapOutputKeyClass()的代码实现为:
public Class<?> getMapOutputKeyClass() {
    Class<?> retv = getClass("mapred.mapoutput.key.class", null, Object.class);
    if (retv == null) {
      retv = getOutputKeyClass();
    }
    return retv;
  }

也就是说,keyClass的类型首先会读取mapred.mapoutput.key.class对应的value值,这个类型可以在hadoop-site.xml中指定,可以在JobConf设置中在代码中指定,通常是后者,如果没有设置这个值(就是上例的情况),那么代码中retv就会返回null,此时的代码逻辑是:将keyClass设置成JobConf的 getOutputKeyClass()的返回值,也就是在代码中设置的setOutputKeyClass()中指定的类型,所以如果程序出现以上这种错误,在jobConf中指定OutputKeyClass就是一种解决 的方法。回到这里,getOutputKeyClass()的代码实现为:
public Class<?> getOutputKeyClass() {
    return getClass("mapred.output.key.class",
                    LongWritable.class, Object.class);
  }

从程序中就可以看出,它会采用 mapred.output.key.class指定的类类型为keyClass,如果仍然没有指定,就最终使用默认的LongWritable类型,这就是上述程序出错的所在了。因为所有的判断都没有得到,所以最终使用了LongWritable
类型作为keyClass,所以就导致了 MapOutputBuffer在读取InputFormat中过来的数据,并准备向Reducer发送时,由于Reducer使用的是/usr/bin /wc程序,所以它期待的是文本的读入和输出,所以此时发生了类型不匹配的错误。

解决之道:
在bin/hadoop jar hadoop-0.19.0-streaming.jar -input /home/luoli/input/goodman -output /home/luoli/output -mapper org.apache.hadoop.mapred.lib.IdentityMapper -reducer /usr/bin/wc命令后加上-jobconf 设置,并指定map的输出时准备的key类型是LongWritable类型的。-jobconf mapred.mapoutput.key.class=org.apache.hadoop.io.LongWritable,或者是-D  mapred.mapoutput.key.class=org.apache.hadoop.io.LongWritable.

总结:
hadoop的mapreduce程序的数据流分成几个阶段,首先是从原始输入文件到InputFormat,InputFormat根据它自己的实现和输入文件的格式为Mapper准备数据 (<key,value>),然后这些数据被Mapper读入,并在map函数中进行处理,同样map中也会输出一定格式的中间结果,这些中间结果也同样是<key,value>的对,而且读入和输出的key和value类型不一定要相同。然后Reducer从Mapper的输出中按照同样的格式读入数据,并在reduce方法中进行处理,最后按照OutputFormat的格式进行输出。这中间的任何一个过程如果出现了格式不匹配或者无法转型,就会报出上述类似的错误,其实如果仔细查看自己的程序的数据流向中的格式是否匹配,通常就能解决问题了。

------------------------具体问题--------------------------
其实我遇到这个问题是因为不小心在那个map方法里面调用了父类的方法,导致一直是默认的输入的key与输出的key是不同的,因为我无论如何修改那个配置都没用。
	@Override
	public void map(LongWritable key, Text value,
			Context context)//innerclass Context
			throws IOException, InterruptedException {
              super.map(key,value,context);//就是这一句了
分享到:
评论

相关推荐

    Hadoop演示文稿jjjjjjjjj

    MapReduce程序包括Mapper和Reducer两个阶段,Mapper负责数据的Map操作,而Reducer负责数据的Reduce操作。 七、Hadoop集群管理 1. 格式化NameNode(第一次启动时格式化,以后不需要总格式化) 2. 启动、停止和禁用...

    hadoop-eclipse-2.75插件 centos6.5 +eclipse编译

    3. 编写MapReduce程序:在项目中创建Java类,实现Mapper和Reducer接口。 4. 运行作业:右键点击项目,选择`Run As &gt; Hadoop Job`,然后选择运行的Hadoop集群配置。 文件`hadoop-eclipse-plugin.txt`可能包含关于...

    hive参数配置说明大全

    该参数决定了是否开启合并Map/Reduce小文件,对于Hadoop 0.20以前的版本,起一首新的Map/Reduce Job,对于0.20以后的版本,则是起使用CombineInputFormat的MapOnly Job。如果设置为true,则Hive将开启合并Map/Reduce...

    hadoop-3.1.4.tar.gz

    MapReduce则是一种编程模型,用于大规模数据集的并行计算,它将复杂任务分解为两个阶段——Map阶段和Reduce阶段,从而实现数据的分布式处理。 在安装Hadoop 3.1.4之前,首先确保你的CentOS 6系统已经配置了Java环境...

    尚硅谷大数据技术之Hadoop

    3. MapReduce原理与编程模型:深入解析Map函数和Reduce函数的实现,以及如何编写Mapper和Reducer类,理解job、task、input/output format等概念。 4. Hadoop实战:通过实际案例分析,演示如何使用Hadoop解决实际问题...

    最新Hadoop学习笔记

    1. 编写Mapper和Reducer类,实现`map()`和`reduce()`方法。 2. 使用`InputFormat`和`OutputFormat`定义输入和输出格式。 3. 运行MapReduce作业,通过`Job`对象设置作业参数并提交。 ### 六、Hadoop与JavaWeb整合 ...

    hadoop3.0+工具

    - **MapReduce编程模型**:理解Map和Reduce阶段,学习如何处理键值对数据。 - **Pig和Hive**:基于Hadoop的数据处理工具,提供SQL-like语句简化大数据处理。 - **Spark on YARN**:结合Apache Spark的高性能计算...

    Hadoop&Spark安装、环境配置、使用教程.pdf

    - **操作系统要求**:Hadoop和Spark推荐在Linux环境下运行,如Ubuntu或CentOS等发行版。 ##### 2. 安装Hadoop **步骤1: 下载Hadoop** - 访问Apache官网下载Hadoop最新稳定版,例如`...

    Hadoop进行分布式计算的入门资料

    MapReduce则是一种编程模型,用于处理和生成大数据集,它将大型任务拆分为许多小任务并在集群中并行执行。 二、Hadoop环境搭建 在开始Hadoop分布式计算之前,我们需要先搭建Hadoop环境。这通常包括以下步骤: 1. ...

    Hadoop学习时间轴

    根据提供的信息,我们可以详细地解析出关于Hadoop学习时间轴中的关键知识点,这些知识点主要集中在Hadoop的基础架构、MapReduce工作原理以及Hive在实际应用中的优化等方面。 ### Hadoop学习时间轴概述 Hadoop是一...

    大数据运维技术第5章 Hadoop集群运行课件.pptx

    Reduce阶段则负责将Map阶段的结果进行聚合和处理,通过Reducer任务生成最终结果。 在Map阶段,InputFileSplit是数据的基本单位,会被拆分成多个部分,每个部分对应一个Map任务。Mapper接收这些数据,通常是对每一行...

    hadoop进行数据分析教程.docx

    它主要由两部分组成:HDFS(Hadoop Distributed File System)和MapReduce编程模型。 - **HDFS**:提供了一个高可靠性的分布式文件系统,用于存储海量数据。 - **MapReduce**:是一种编程模型,用于处理和生成大...

    hadoop常见笔试题答案.pdf

    Mapper 和 Reducer 类中包含的四个主要方法分别是:`map()`, `setup()`, `cleanup()`, `reduce()`。 10. **YARN**:YARN 是 Hadoop 的资源管理系统,它将资源管理和作业调度/监控功能分离,提高了集群资源的利用率...

    hadoop-2.7.5-with-centos7.6.tar.gz

    1. MapReduce编程模型:理解Map函数和Reduce函数的工作原理,编写自定义的Mapper和Reducer实现业务逻辑。 2. HDFS操作:学习使用hadoop fs命令进行文件的上传、下载、查看等操作。 3. YARN调度:了解如何配置和使用...

    hive配置说明

    Hive 是一款基于 Hadoop 的数据仓库工具,可以帮助对在存储在 Hadoop 文件系统中的数据集进行数据整理、特殊查询和分析存储。为了更好地管理和优化Hive查询的性能,了解并合理设置Hive的相关配置参数至关重要。本文...

    Hadoop技术MapReduce工作原理共9页.pdf

    MapReduce是Apache Hadoop框架的核心组件之一,用于处理和生成大数据集。这个技术的主要目标是分布式计算,将大型数据集...通过理解MapReduce的工作原理和核心概念,我们可以更有效地利用Hadoop框架解决大数据问题。

    Hadoop应用开发-实验指导书.doc

    - WordCount程序中Mapper和Reducer是如何协同工作的? - 如何优化WordCount程序的性能? 通过以上几个实验的学习,可以全面掌握Hadoop的基本操作和应用开发流程,为进一步深入学习Hadoop的大数据处理技术打下坚实的...

Global site tag (gtag.js) - Google Analytics