Serialization 处理Hadoop SequenceFile中的可写完全限定名称更改

Serialization 处理Hadoop SequenceFile中的可写完全限定名称更改,serialization,hadoop,sequencefile,Serialization,Hadoop,Sequencefile,我有一堆Hadoop SequenceFile,它们是用我编写的一些可写子类编写的。我们称之为FishWritable 这个可写文件在一段时间内运行良好,直到我决定为了清晰起见需要对包进行重命名。所以现在fishwriteable的完全限定名是com.脊椎动物.fishes.fishwriteable,而不是com.哺乳类动物.fishes.fishwriteable。鉴于所涉一揽子计划的范围是如何演变的,这是一个合理的变化 然后我发现我的MapReduce作业都不会运行,因为它们在尝试初始化S

我有一堆Hadoop SequenceFile,它们是用我编写的一些可写子类编写的。我们称之为FishWritable

这个可写文件在一段时间内运行良好,直到我决定为了清晰起见需要对包进行重命名。所以现在fishwriteable的完全限定名是
com.脊椎动物.fishes.fishwriteable
,而不是
com.哺乳类动物.fishes.fishwriteable
。鉴于所涉一揽子计划的范围是如何演变的,这是一个合理的变化

然后我发现我的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,有一个调整,使其不那么复杂。如果我有很多大文件,那还是很不切实际的


有没有更好的方法来处理SequenceFile中使用的完全限定类名的重构?理想情况下,如果找不到指定的回退类名,我正在寻找某种方法来指定新的回退类名,以允许在此SequenceFile的已更新类型和已更新类型上运行。

查看SequenceFile的规范,显然没有考虑其他类名


如果我不能重新写入数据,另一个选择是让com.multimates.fishes.writable扩展com.脊椎动物.fishes.writable,并将其注释为不推荐,这样就不会有人意外地将代码添加到空包装器中。经过足够长的时间后,使用旧类编写的数据将被废弃,您将能够安全地删除该类。

异常堆栈跟踪中提到的
org.apache.hadoop.io.WritableName
类有一些有用的方法

发件人:

该实用程序允许重命名可写实现类,而不会使包含其类名的文件无效

在您的情况下,您可以在读取SequenceFile之前调用此选项:

WritableName.addName(com.vertebrates.fishes.FishWritable.class, "com.mammals.fishes.FishWritable");
这样,当尝试从旧的SequenceFile中读取
com.dominals.fishes.FishWritable
时,将使用新的
com.脊椎动物.fishes.FishWritable


PS:为什么哺乳动物包装中的鱼放在首位?;)

您是否可以编写一个新的MR作业,该作业的输入值类型为com.multimates.fishes.fishwriteable,并发出com.脊椎动物.fishes.fishwriteable类型的值?当然,您需要通过-libjars添加包含两个classdef的jar。是的,这是另一个选项。它本质上与方法2相同,只是使用JavaAPI来实现。我更喜欢的是用某种方式告诉大家,com.脊椎动物.fishes.fishwriteable是未来作业的输入步骤中应该使用的关键输入格式。本质上,它没有理由失败,因为类是相同的-我只是不知道如何告诉它新的类名,因为它假设现有SequenceFile中的名称是正确的。对于任何想知道的人,我已经通过使用Avro进行序列化来回答我的问题。如果你使用Avro,你根本不必问这个问题,还有其他一些优点。你介意为你自己的问题提供一个描述Avro解决方案的答案吗?我自己也用过一点Avro,但我很想看看你们是如何做到这一点的。事实上,我的解决方案并没有解决我最初的问题,所以我的陈述是不正确的。我没有太多的数据需要重新生成,所以我最终这样做了,然后留下SequenceFile,做一些简单的工作,将文件从SequenceFile转换为Avro模式,我定义这是将所有内容转移到Avro的第一步。我当然会建议任何进入Hadoop的人立即使用像Avro这样的独立序列化框架。。我不想让集群中的数据依赖于固定的包结构,我给它打勾。在我上一次调查中,Hadoop框架中根本没有实现这种机制。这看起来是正确的答案。你测试过这个吗?我不再使用SequenceFile,因此无法轻松验证。如果有人能确认这些方法有效,我会将其标记为答案。是的,我已经测试过这种方法,目前在一些项目中使用它。
WritableName.addName(com.vertebrates.fishes.FishWritable.class, "com.mammals.fishes.FishWritable");