Обработка полностью изменяемых имен перезаписываемых имен в Hadoop SequenceFile
У меня есть несколько файлов Hadoop SequenceFiles, которые были написаны с помощью некоторого записываемого подкласса, который я написал. Давайте назовем это FishWritable.
Некоторое время этот Writable работал хорошо, пока я не решил, что для ясности нужно переименовать пакет. Так что теперь полностью квалифицированное имя FishWritable com.vertebrates.fishes.FishWritable
вместо com.mammals.fishes.FishWritable
, Это было разумное изменение, учитывая то, как развивалась сфера применения данного пакета.
Затем я обнаружил, что ни одно из моих заданий MapReduce не будет запущено, так как они аварийно завершают работу при попытке инициализировать SequenceFileRecordReader:
java.lang.RuntimeException: java.io.IOException: WritableName can't load class: com.mammals.fishes.FishWritable
at org.apache.hadoop.io.SequenceFile$Reader.getKeyClass(SequenceFile.java:1949)
at org.apache.hadoop.io.SequenceFile$Reader.init(SequenceFile.java:1899)
...
Несколько вариантов решения этой проблемы очевидны. Я могу просто перезапустить все мои предыдущие задания, чтобы сгенерировать вывод с обновленным именем класса ключа, последовательно выполняя любые зависимые задания. Очевидно, что это может занять довольно много времени, а иногда даже невозможно.
Другой возможностью может быть написание простой работы, которая читает SequenceFile как текст и заменяет любые экземпляры имени класса новым. Это в основном метод № 1 с твиком, который делает его менее сложным. Если у меня много больших файлов, это все еще довольно непрактично.
Есть ли лучший способ справиться с рефакторингами полностью определенных имен классов, используемых в SequenceFiles? В идеале я ищу какой-то способ указать новое резервное имя класса, если указанное не найдено, чтобы можно было работать как с датированными, так и с обновленными типами этого SequenceFile.
2 ответа
org.apache.hadoop.io.WritableName
Класс, упомянутый в трассировке стека исключений, имеет несколько полезных методов.
Из документа:
Утилита, позволяющая переименовывать записываемые классы реализации без аннулирования файлов, содержащих их имя класса.
// Add an alternate name for a class.
public static void addName(Class writableClass, String name)
В вашем случае вы можете вызвать это перед чтением из вашего SequenceFiles:
WritableName.addName(com.vertebrates.fishes.FishWritable.class, "com.mammals.fishes.FishWritable");
Таким образом, при попытке прочитать com.mammals.fishes.FishWritable
из старого SequenceFile, нового com.vertebrates.fishes.FishWritable
класс будет использоваться.
PS: Почему рыба была в пакете млекопитающих в первую очередь? ;)
Глядя на спецификацию для sequencefile, становится ясно, что альтернативные имена классов не рассматриваются.
Если бы у меня не было возможности переписать данные, еще одним вариантом было бы иметь com.mammals.fishes.writable extension com.vertebrates.fishes.writable и просто аннотировать его как устаревшее, чтобы никто случайно не добавил код в пустое обертка. По прошествии достаточно длительного времени данные, записанные в старом классе, будут устаревшими, и вы сможете безопасно удалить класс млекопитающих.