我有三个简单的类:
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 { ... }
今天我遇到了同样的问题。有一个Writable
类org.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
作为映射器的输出值类型。
重要:您的实际地图输出类(WeightedEdge
和NodeWeightContainer
)必须实现Writable
接口。