我有一堆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的日期和更新类型运行。
答案 0 :(得分:3)
查看sequencefile的规范,似乎很清楚没有考虑替代类名。
如果我无法重新写入数据,还有一个选择是让com.mammals.fishes.writable扩展com.vertebrates.fishes.writable并将其注释为已弃用,这样就没有人意外添加代码到空包装器。经过足够长的时间后,用旧班写的数据将被淘汰,你将能够安全地删除哺乳动物班。
答案 1 :(得分:1)
异常堆栈跟踪中提到的org.apache.hadoop.io.WritableName
类有一些有用的方法。
来自the doc:
允许重命名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");
这样,当尝试从旧的SequenceFile中读取com.mammals.fishes.FishWritable
时,将使用新的com.vertebrates.fishes.FishWritable
类。
PS:为什么哺乳动物中的鱼首先包装? ;)