Hadoop2.7.3 mapreduce(二)类型匹配异常解决方案及源码分析
2017-07-16 17:04
459 查看
我们在运行mapreduce时,有时候会出现类型匹配异常。下面我将对出现的两种情况进行分析:
【情况一:map函数输入key-value 类型和默认值不一致,且没有指定】
map函数默认输入格式(在没有指定输入格式前提下)为 TextInputFormat 类
TextInputFormat继承自 FileInputFormat类,也就是说map函数默认输入key-value格式为 LongWritable - Text ,如果我们重写方法时改变了参数类型,要重新指定输入格式,因此我们可以选择封装好的其他格式,也可以自定义输入格式类(自定义LineRecordReader类 和 InputFormat 类)。
然后,在作业启动前,调用setInputFormatClass( ) 指定我们需要的格式。
【情况二:map函数输出key-value 类型和默认值不一致,且没有指定】
根据报错提示,我们通过debug来读源代码
在collect方法的内部会判断 key 和 value 的类型是不是和 MapOutputBuffer 中保留的 keyClass、valClass 一致。
而 MapOutputBuffer 中保留的 keyClass、valClass是初始化的时候被赋值的。
继续进入getMapOutputKeyClass( ) 方法
我们发现keyClass首先会读取JobContext中MAP_OUTPUT_KEY_CLASS 的值
那这个静态变量是在哪里设置的呢?继续读源码,我发现是通过setMapOutKeyClass( ) 方法设置的
因为我们没有使用setMapOutKeyClass( ) 方法,所以 retv == null,getOutputKeyClass( ) 方法被执行了,继续读源代码!!!
我们看出它还会采用JobContext.OUTPUT_KEY_CLASS设置值(再给你一次机会再不写就报错了 O(∩_∩)O 哈哈~),也就是通过下面这个方法设置的值:
很可惜我们也没有使用setOutputKeyClass( ) 设置值。最终使用默认的 LongWritable 类型 ,这就是错误的根源!!!
找到了问题的根源,问题也就非常好解决了,我们只需要在启动作业之前加上(当然这里设置的输出类型要和map函数输出的类型一致)
【总结】
map操作固定性较强,输入输出格式都有一套规定,当我们重写map函数改变了默认类型,要记得在启动作业之前自己设置!!!
【情况一:map函数输入key-value 类型和默认值不一致,且没有指定】
java.lang.Exception: java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.Text at org.apache.hadoop.mapred.LocalJobRunner$Job.runTasks(LocalJobRunner.java:462) at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:522) Caused by: java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.Text at com.yc.hadoop42_003_mapreduce.MyWordCount$MyWordCountMapper.map(MyWordCount.java:1) at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:146) at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:787) at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341) at org.apache.hadoop.mapred.LocalJobRunner$Job$MapTaskRunnable.run(LocalJobRunner.java:243) at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source)通过分析源码,得出以下结论:
map函数默认输入格式(在没有指定输入格式前提下)为 TextInputFormat 类
TextInputFormat继承自 FileInputFormat类,也就是说map函数默认输入key-value格式为 LongWritable - Text ,如果我们重写方法时改变了参数类型,要重新指定输入格式,因此我们可以选择封装好的其他格式,也可以自定义输入格式类(自定义LineRecordReader类 和 InputFormat 类)。
然后,在作业启动前,调用setInputFormatClass( ) 指定我们需要的格式。
【情况二:map函数输出key-value 类型和默认值不一致,且没有指定】
java.lang.Exception: java.io.IOException: Type mismatch in key from map: expected org.apache.hadoop.io.LongWritable, received org.apache.hadoop.io.Text at org.apache.hadoop.mapred.LocalJobRunner$Job.runTasks(LocalJobRunner.java:462) at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:522) Caused by: java.io.IOException: Type mismatch in key from map: expected org.apache.hadoop.io.LongWritable, received org.apache.hadoop.io.Text at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.collect(MapTask.java:1074) at org.apache.hadoop.mapred.MapTask$NewOutputCollector.write(MapTask.java:715) at org.apache.hadoop.mapreduce.task.TaskInputOutputContextImpl.write(TaskInputOutputContextImpl.java:89) at org.apache.hadoop.mapreduce.lib.map.WrappedMapper$Context.write(WrappedMapper.java:112) at com.yc.hadoop42_003_mapreduce.MyWordCount$MyWordCountMapper.map(MyWordCount.java:30) at com.yc.hadoop42_003_mapreduce.MyWordCount$MyWordCountMapper.map(MyWordCount.java:1) at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:146) at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:787) at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341) at org.apache.hadoop.mapred.LocalJobRunner$Job$MapTaskRunnable.run(LocalJobRunner.java:243) at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) [16 17:02:37,173 INFO ] [main] mapreduce.Job - Job job_local438687277_0001 failed with state FAILED due to: NA [16 17:02:37,200 INFO ] [main] mapreduce.Job - Counters: 0
根据报错提示,我们通过debug来读源代码
在collect方法的内部会判断 key 和 value 的类型是不是和 MapOutputBuffer 中保留的 keyClass、valClass 一致。
而 MapOutputBuffer 中保留的 keyClass、valClass是初始化的时候被赋值的。
继续进入getMapOutputKeyClass( ) 方法
我们发现keyClass首先会读取JobContext中MAP_OUTPUT_KEY_CLASS 的值
那这个静态变量是在哪里设置的呢?继续读源码,我发现是通过setMapOutKeyClass( ) 方法设置的
因为我们没有使用setMapOutKeyClass( ) 方法,所以 retv == null,getOutputKeyClass( ) 方法被执行了,继续读源代码!!!
我们看出它还会采用JobContext.OUTPUT_KEY_CLASS设置值(再给你一次机会再不写就报错了 O(∩_∩)O 哈哈~),也就是通过下面这个方法设置的值:
很可惜我们也没有使用setOutputKeyClass( ) 设置值。最终使用默认的 LongWritable 类型 ,这就是错误的根源!!!
找到了问题的根源,问题也就非常好解决了,我们只需要在启动作业之前加上(当然这里设置的输出类型要和map函数输出的类型一致)
job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); 或者 job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class);问题就迎刃而解啦!
【总结】
map操作固定性较强,输入输出格式都有一套规定,当我们重写map函数改变了默认类型,要记得在启动作业之前自己设置!!!
相关文章推荐
- Hadoop基础之MapReduce原理、序列化和源码分析
- Hadoop2 使用 YARN 运行 MapReduce 的过程源码分析
- Hadoop源码分析(MapReduce概论)
- Python之美[从菜鸟到高手]--httplib源码分析及IncompleteRead异常解决方案
- hadoop之MapReduce框架JobTracker端心跳机制分析(源码分析第七篇) 推荐
- hadoop之MapReduce框架TaskTracker端心跳机制分析(源码分析第六篇) 推荐
- 【Java源码分析】ConcurrentModificationException并发修改异常分析与解决方案(快速失败与安全失败)
- hadoop源码分析之MapReduce(一)
- hadoop 2.7.3 源码分析(四):namenode启动流程
- Hadoop-2.7.3源码分析:MapReduce作业提交源码跟踪
- hadoop 2.7.3 源码分析超简单源码修改测试
- Hadoop之wordcount源码分析和MapReduce流程分析
- (转载)Hadoop -- MapReduce源码分析总结
- hadoop 2.7.3 源码分析(二):超简单源码修改测试
- hadoop 2.7.3 源码分析(三):hadoop远程调试
- Hadoop源码分析(mapreduce.lib.partition/reduce/output)
- Hadoop-2.4.1源码分析--MapReduce作业切片(Split)过程
- Hadoop源码分析1 MapReduce的输入
- Hadoop源码分析23:MapReduce的Job提交过程
- Android开发者,必须知道的并且没有遇到的异常,附带简单的解决方案和异常过程、源码的分析从java层到Jni层