Hadoop2.7.3 mapreduce(二)類型匹配異常解決方案及源碼分析

我們在運行mapreduce時,有時候會出現類型匹配異常。下面我將對出現的兩種情況進行分析:

情況一: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函數改變了默認類型,要記得在啓動作業之前自己設置!!!


發佈了27 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章