Hadoop Map выводит IOException при выдаче подкласса класса, определенного в Configuration как выходной - PullRequest
1 голос
/ 18 декабря 2011

У меня есть 3 простых класса:

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

Фаза карты была настроена как таковая

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)

Почему я не могу вернуть подкласс класса, который был определен в конфигурации? Есть ли способ обойти это? Проблема в том, что моя фаза карты должна излучать два разных типа объектов.

Ответы [ 2 ]

2 голосов
/ 27 июня 2012

Я столкнулся с той же проблемой сегодня. Существует 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.

2 голосов
/ 18 декабря 2011

Вы не можете вернуть подкласс класса, который был определен в конфигурации, потому что Hadoop явно проверяет тип класса, указанный в setMapOutputValueClass, и тип, который он получает от Mappers.

Это происходит потому, что ему нужно сериализовать / десериализовать объекты, которые вы излучаете из картографов. Когда он выполняет десериализацию, он создает новый объект типа, указанного в вызове 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 { ... }

...