Hadoop MultipleInputs завершается ошибкой с ClassCastException
Моя версия hadoop 1.0.3, когда я использую несколько входов, я получил эту ошибку.
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);
Я гуглил и нашел эту ссылку https://issues.apache.org/jira/browse/MAPREDUCE-1178 которой говорилось, что 0.21 имеет эту ошибку. Но я использую 1.0.3, эта ошибка возвращается снова. У кого-нибудь есть такая же проблема или кто-нибудь может подсказать как это исправить? Спасибо
Вот код установки программы отображения изображений, в 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();
}
}
2 ответа
В продолжение моего комментария, Javadocs для 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
}
}
Размышление Hackery объяснил:
Так как TaggedInputSplit объявлен защищенной областью, он невидим для классов вне org.apache.hadoop.mapreduce.lib.input
пакет, и, следовательно, вы не можете ссылаться на этот класс в вашем методе установки. Чтобы обойти это, мы выполняем ряд операций на основе отражения:
Изучив имя класса, мы можем проверить тип TaggedInputSplit, используя его полное имя
splitClass.getName().equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")
Мы знаем, что хотим позвонить
TaggedInputSplit.getInputSplit()
метод для восстановления разделенного ввода, поэтому мы используемClass.getMethod(..)
Метод отражения для получения ссылки на метод:Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");
Класс по-прежнему не является общедоступным, поэтому мы используем метод setAccessible(..), чтобы переопределить это, не давая менеджеру безопасности вызвать исключение
getInputSplitMethod.setAccessible(true);
Наконец, мы вызываем метод для ссылки на входное разбиение и приводим результат к FileSplit (оптимистично надеясь, что это экземпляр этого типа!):
fileSplit = (FileSplit) getInputSplitMethod.invoke(split);
У меня была такая же проблема, но реальная проблема была в том, что я все еще настраивал InputFormat после настройки MultipleInputs:
job.setInputFormatClass(SequenceFileInputFormat.class);
Как только я удалил эту строку, все работало нормально.