当在配置中定义的类的子类作为输出时,Hadoop Map输出IOException



我有三个简单的类:

public abstract class Container implements WritableComparable<Container> {} //empty
public class WeightedEdge extends Container { ... }
public class NodeWeightContainer extends Container { ... }

Map阶段配置如下

JobConf createGraphPConf = new JobConf(new Configuration());
Job job = new Job(createGraphPConf);
...
createGraphPConf.setMapOutputValueClass(Container.class);

但是我收到这个错误:

java.io.IOException: Type mismatch in value from map: expected org.hadoop.test.data.util.Container, recieved org.hadoop.test.data.WeightedEdge
at org.apache.hadoop.mapred.MapTask$MapOutputBuffer.collect(MapTask.java:1018)
at org.apache.hadoop.mapred.MapTask$OldOutputCollector.collect(MapTask.java:591)
at org.hadoop.test.map.CreateGPMap.map(CreateGPMap.java:33)
at org.hadoop.test.map.CreateGPMap.map(CreateGPMap.java:19)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:50)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:435)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:371)
at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:210)

为什么我不能返回在配置中定义的类的子类?有别的办法吗?问题是我的Map阶段必须发出两个不同的对象类型。

你不能返回在配置中定义的类的子类,因为Hadoop显式检查setMapOutputValueClass中指定的类类型和它从映射器接收的类型。

它这样做是因为它需要序列化/反序列化从映射器发出的对象。当它执行反序列化时,它创建在setMapOutputValueClass调用中指定类型的新对象,然后使用WriteableComparable接口的方法将数据填充新创建的对象。

为了能够发出不同的对象类型,你可以定义容器非抽象类,并将实际对象及其类型标识符放在


    public enum ELEM_TYPE { WE, WECONTAINER }
    public class Container implements WritableComparable<Container>
    {
        ELEM_TYPE  type; //actual element type -
                         // WeightedEdge  or NodeWeightContainer 
        object value;
        //WritableComparable implementation
        // that casts value to the appropriate type
    } 
    public class WeightedEdge { ... }
    public class NodeWeightContainer { ... }

今天我遇到了同样的问题。有一个Writableorg.apache.hadoop.io.GenericWritable可以用来解决这个问题。您需要扩展类并实现一个抽象方法:

public class Container extends GenericWritable {
    private static Class[] CLASSES = {
           WeightedEdge.class, 
           NodeWeightContainer.class,
    };
    protected Class[] getTypes() {
       return CLASSES;
    }
}
public class WeightedEdge implemets Writable {...}
public class NodeWeightContainer implements Writable {...}

现在您可以使用类Container作为映射器的输出值类型。

重要:您的实际地图输出类(WeightedEdgeNodeWeightContainer)必须实现Writable接口。

最新更新