2012-06-21 41 views
15

我的hadoop版本是1.0.3,当我使用多输入时,我得到了这个错误。hadoop MultipleInputs ClassCastException失败

java.lang.ClassCastException: org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit cannot be cast to org.apache.hadoop.mapreduce.lib.input.FileSplit 
at org.myorg.textimage$ImageMapper.setup(textimage.java:80) 
at org.apache.hadoop.mapreduce.Mapper.run(Mapper.java:142) 
at org.apache.hadoop.mapreduce.lib.input.DelegatingMapper.run(DelegatingMapper.java:55) 
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:764) 
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:370) 
at org.apache.hadoop.mapred.Child$4.run(Child.java:255) 
at java.security.AccessController.doPrivileged(Native Method) 
at javax.security.auth.Subject.doAs(Subject.java:416) 
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1121) 
at org.apache.hadoop.mapred.Child.main(Child.java:249) 

我测试了单输入路径,没问题。只有当我使用

MultipleInputs.addInputPath(job, TextInputpath, TextInputFormat.class, 
      TextMapper.class); 
    MultipleInputs.addInputPath(job, ImageInputpath, 
      WholeFileInputFormat.class, ImageMapper.class); 

我用Google搜索,发现这个链接https://issues.apache.org/jira/browse/MAPREDUCE-1178其中所说的0.21了这个bug。但是我使用的是1.0.3,这个bug再次回来了。任何人都有同样的问题,或任何人都可以告诉我如何解决它?由于

这里是图像映射的设置代码,第4行发生错误:

protected void setup(Context context) throws IOException, 
      InterruptedException { 
     InputSplit split = context.getInputSplit(); 
     Path path = ((FileSplit) split).getPath(); 
     try { 
      pa = new Text(path.toString()); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
+0

你可以发布你的'ImageMapper'类的代码 - 它看起来像你试图在您的设置方法中将输入拆分转换为FileInputSplit。 –

+0

我有一个类似的问题..是否有任何解决方案存在? – sunitha

回答

29

对我的评论跟进,的Javadoc TaggedInputSplit确认你可能错误地铸造输入分流到一个FileSplit:

/** 
* An {@link InputSplit} that tags another InputSplit with extra data for use 
* by {@link DelegatingInputFormat}s and {@link DelegatingMapper}s. 
*/ 

我的猜测是你的设置方法看起来是这样的:

@Override 
protected void setup(Context context) throws IOException, 
     InterruptedException { 
    FileSplit split = (FileSplit) context.getInputSplit(); 
} 

不幸的是TaggedInputSplit不是公开可见的,所以你不能轻易做一个instanceof样式检查,然后进行演员,然后调用TaggedInputSplit.getInputSplit()来获取实际的底层FileSplit。因此,无论您需要自己更新源代码并重新编译部署,发布JIRA票据以要求在未来版本中修复此问题(如果它未在2+中执行)或执行一些令人讨厌的问题讨厌反射两轮牛车去底层InputSplit

这是完全未经测试:

@Override 
protected void setup(Context context) throws IOException, 
     InterruptedException { 
    InputSplit split = context.getInputSplit(); 
    Class<? extends InputSplit> splitClass = split.getClass(); 

    FileSplit fileSplit = null; 
    if (splitClass.equals(FileSplit.class)) { 
     fileSplit = (FileSplit) split; 
    } else if (splitClass.getName().equals(
      "org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")) { 
     // begin reflection hackery... 

     try { 
      Method getInputSplitMethod = splitClass 
        .getDeclaredMethod("getInputSplit"); 
      getInputSplitMethod.setAccessible(true); 
      fileSplit = (FileSplit) getInputSplitMethod.invoke(split); 
     } catch (Exception e) { 
      // wrap and re-throw error 
      throw new IOException(e); 
     } 

     // end reflection hackery 
    } 
} 

反思两轮牛车解释:

随着TaggedInputSplit正在申报的保护范围,这是不可见到org.apache.hadoop.mapreduce.lib.input包以外的类,因此您不能在您的设置方法中引用该类。为了解决这个问题,我们进行了一些基于反射操作:

  1. 检查类的名称,我们可以使用它的全名

    splitClass.getName().equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")

  2. 我们知道测试的类型TaggedInputSplit我们想调用TaggedInputSplit.getInputSplit()方法来恢复封装的输入分割,所以我们利用Class.getMethod(..)反射方法来获得对该方法的参考:

    Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");

  3. 该类仍然不公开可见,所以我们使用setAccessible(..)方法来覆盖此,从抛出异常

    getInputSplitMethod.setAccessible(true);

  4. 最后,我们调用该方法的参考输入分流停止安全管理器,并把结果向FileSplit(乐观地希望它的一个实例这种类型):

    fileSplit = (FileSplit) getInputSplitMethod.invoke(split);

+1

这与你猜到的完全一样。我试过你的代码,它现在正在工作。你是如此亲! –

+0

我再次阅读代码,但我仍然不确定它是如何工作的。你能对反射hackery做一个简单的解释吗?谢谢。 –

+0

查看已添加的章节末尾 –

0

我有同样的问题,但实际的问题是,我设立后,仍设置InputFormat MultipleInputs:

job.setInputFormatClass(SequenceFileInputFormat.class); 

一旦我删除这条线一切正常。