hadoop MultipleInputs因ClassCastException而失败

ton*_*rbo 17 hadoop classcastexception

我的hadoop版本是1.0.3,当我使用multipleinputs时,我收到了这个错误.

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)
Run Code Online (Sandbox Code Playgroud)

我测试了单输入路径,没问题.只有我用的时候

MultipleInputs.addInputPath(job, TextInputpath, TextInputFormat.class,
            TextMapper.class);
    MultipleInputs.addInputPath(job, ImageInputpath,
            WholeFileInputFormat.class, ImageMapper.class); 
Run Code Online (Sandbox Code Playgroud)

我用Google搜索并发现此链接https://issues.apache.org/jira/browse/MAPREDUCE-1178,其中说0.21有此错误.但是我使用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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

Chr*_*ite 32

继续我的评论,Javadocs TaggedInputSplit确认您可能错误地将输入拆分转换为FileSplit:

/**
 * An {@link InputSplit} that tags another InputSplit with extra data for use
 * by {@link DelegatingInputFormat}s and {@link DelegatingMapper}s.
 */
Run Code Online (Sandbox Code Playgroud)

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

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

不幸的TaggedInputSplit是不公开可见,所以你不能轻易地进行instanceof样式检查,然后进行强制转换,然后调用TaggedInputSplit.getInputSplit()以获取实际的底层FileSplit.因此,您需要自己更新源代码并重新编译和部署,发布JIRA票证,要求在未来的版本中修复它(如果它已经没有在2+中执行)或执行一些令人讨厌的讨厌反思hackery到达底层的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
    }
}
Run Code Online (Sandbox Code Playgroud)

反思Hackery解释:

TaggedInputSplit被声明为受保护的作用域,它对org.apache.hadoop.mapreduce.lib.input包外的类是不可见的,因此您无法在setup方法中引用该类.为了解决这个问题,我们执行了许多基于反射的操作:

  1. 检查类名,我们可以使用它的完全限定名称来测试TaggedInputSplit类型

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

  2. 我们知道我们想调用TaggedInputSplit.getInputSplit()方法来恢复包装的输入分割,所以我们利用Class.getMethod(..)反射方法获取对方法的引用:

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

  3. 该类仍然不公开,因此我们使用setAccessible(..)方法来覆盖它,阻止安全管理器抛出异常

    getInputSplitMethod.setAccessible(true);

  4. 最后,我们在对输入拆分的引用上调用方法,并将结果转换为FileSplit(乐观地希望它是这种类型的实例!):

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

  • 这种解决方法很棒但是有没有人知道使用MultipleInputs将信息从Job传递到Mapper的方法不那么简单?FWIW,有https://issues.apache.org/jira/browse/MAPREDUCE-2226 (2认同)