我有一堆用我编写的可写子类编写的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)
...
处理此问题的几种选择是显而易见的。我可以简单地重新运行所有先前的作业,以使用最新的 key 类名称重新生成输出,从而依次运行任何相关的作业。显然,这可能非常耗时,有时甚至是不可能的。
另一种可能是编写一个简单的作业,该作业将SequenceFile作为文本读取,并用新的替换类名称的任何实例。基本上,这是方法#1,但进行了一些调整,使其操作变得简单。如果我有很多大文件,那仍然是不切实际的。
有没有更好的方法来处理SequenceFiles中使用的完全合格的类名的重构?理想情况下,如果没有找到指定的后备类名,我正在寻找一种方法来指定新的后备类名,以允许针对此SequenceFile的过时和更新类型运行。
最佳答案
异常堆栈跟踪中提到的org.apache.hadoop.io.WritableName
类具有一些有用的方法。
从the doc:
// 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");
这样,当尝试从旧的SequenceFile中读取
com.mammals.fishes.FishWritable
时,将使用新的com.vertebrates.fishes.FishWritable
类。PS:为什么首先将哺乳动物包装中的鱼包起来? ;)