Обработка изменений полного имени Writables в Hadoop SequenceFile

У меня есть куча файлов Hadoop SequenceFiles, которые были написаны с помощью написанного мной подкласса Writable. Назовем его 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.


person Alex A.    schedule 19.09.2013    source источник
comment
Не могли бы вы написать новое задание MR, которое считывает входное значение типа com.mammals.fishes.FishWritable и выдает значение типа com.vertebrates.fishes.FishWritable? Конечно, вам нужно будет добавить JAR-файлы, содержащие оба classdef, через -libjars.   -  person jtravaglini    schedule 20.09.2013
comment
Да, это еще один вариант. По сути, это то же самое, что и метод № 2, за исключением того, что для этого используется Java API. Я бы предпочел какой-то способ сообщить InputFormat, что com.vertebrates.fishes.FishWritable — это ключ, который он должен использовать на этапе ввода для будущих заданий. По сути, нет причин, по которым он должен потерпеть неудачу, поскольку класс тот же самый - я просто не знаю, как сообщить ему новое имя класса, поскольку он предполагает, что имя в существующем файле SequenceFile является правильным.   -  person Alex A.    schedule 20.09.2013
comment
Если кому-то интересно, я ответил на свой вопрос, используя вместо этого Avro для сериализации. Если вы используете Avro, вам вообще не нужно задавать этот вопрос, плюс несколько других преимуществ.   -  person Alex A.    schedule 28.09.2013
comment
Не могли бы вы дать ответ на свой вопрос, описывающий решение Avro? Я сам немного использовал Avro, но мне интересно посмотреть, как вы подошли к этому.   -  person jtravaglini    schedule 14.10.2013
comment
На самом деле, мое решение не разрешило мой первоначальный вопрос, поэтому мое утверждение было неверным. У меня не было слишком много данных, которые мне нужно было регенерировать, поэтому в итоге я сделал это, а затем оставил SequenceFiles с несколькими простыми заданиями по преобразованию файлов из SequenceFile в схемы Avro, которые я определил как первый шаг к перемещению всего в Avro. Я бы, конечно, посоветовал всем, кто начинает работать с Hadoop, сразу же перейти на автономную среду сериализации, такую ​​​​как Avro. Я бы не хотел оказаться в ситуации, когда у меня есть кластер, полный данных, который зависит от фиксированной структуры пакета.   -  person Alex A.    schedule 14.10.2013


Ответы (2)


Класс org.apache.hadoop.io.WritableName, упомянутый в трассировке стека исключений, имеет несколько полезных методов.

Из документа:

Утилита, позволяющая переименовывать классы реализации Writable без аннулирования файлов, содержащих имя их класса.

// 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: Почему в пакете с млекопитающими вообще была рыба? ;)

person Thomas W    schedule 08.11.2017
comment
Это похоже на правильный ответ. Вы проверяли это? Я больше не использую SequenceFiles, поэтому не могу легко проверить. Если кто-то может подтвердить, что эти методы работают, я отмечу это как ответ. - person Alex A.; 09.11.2017
comment
Да, я протестировал этот метод и в настоящее время использую его в некоторых проектах. - person Thomas W; 09.11.2017

Глядя на спецификацию для файла последовательности, кажется очевидным, что альтернативные имена классов не рассматриваются.

Если бы я не был в состоянии переписать данные, есть еще один вариант: com.mammals.fishes.writable расширить com.vertebrates.fishes.writable и просто аннотировать его как устаревший, чтобы никто случайно не добавил код в пустой обертка. По прошествии достаточно долгого времени данные, записанные с помощью старого класса, устареют, и вы сможете безопасно удалить класс млекопитающих.

person Simplefish    schedule 30.12.2013
comment
Я ставлю этому галочку. На момент моего последнего исследования в среде Hadoop просто не было реализованного механизма для этого. - person Alex A.; 06.03.2014