我正在编写自定义InputFormat(特别是org.apache.hadoop.mapred.FileInputFormat
的一个子类)、OutputFormat和SerDe,用于通过Apache Hive读取的二进制文件并非二进制文件中的所有记录都具有相同的大小。
我发现Hive的默认InputFormat CombineHiveInputFormat并没有将getSplits
委派给我的自定义InputFormat的实现,这会导致所有输入文件都在常规的128MB边界上分割。这样做的问题是,此拆分可能位于记录的中间,因此除了第一个拆分之外,所有拆分都很可能出现损坏的数据。
我已经找到了一些变通办法,但我对其中任何一个都不满意。
一种变通方法是:
set hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;
当在CombineHiveInputFormat
上使用HiveInputFormat
时,对getSplits
的调用被正确地委托给我的InputFormat,一切都很好。然而,我想让我的InputFormat、OutputFormat等易于其他用户使用,所以我不想经历这些。此外,如果可能的话,我希望能够利用组合拆分。
另一个解决方法是创建一个StorageHandler
。但是,我不希望这样做,因为这会使StorageHandler支持的所有表都是非本机的(因此,所有还原程序都写入一个文件,不能将LOAD DATA
写入表中,以及我希望从本机表中保留的其他nicity)。
最后,我可以让我的InputFormat实现CombineHiveInputFormat.AvoidSplitCombination
来绕过大部分CombineHiveInputFormat,但这只在配置单元1.0中可用,我希望我的代码能与早期版本的配置单元一起使用(至少回到0.12)
我在Hive bug跟踪器中提交了一张罚单,以防这种行为是无意的:https://issues.apache.org/jira/browse/HIVE-9771
是否有人编写了一个自定义FileInputFormat
来覆盖getSplits
以便与Hive一起使用?让Hive将呼叫委派给getSplits
时,是否遇到过您必须克服的困难?
通常,在这种情况下,您可以不进行拆分,这样您就可以获得块的数据位置,并让RecordReader
了解如何从块中的第一条记录开始读取(拆分),以及如何读取到下一个块中,在该块中,最终记录没有在拆分的确切末尾结束。这需要一些远程读取,但这是正常的,通常非常少。
TextInputFormat
/LineRecordReader
做到了这一点——它使用换行符来分隔记录,因此一条记录自然可以跨越两个块。它将遍历到拆分中的第一条记录,而不是从第一个字符开始,如果需要读取完整的数据,它将在最后一条记录上读取到下一个块。
其中LineRecordReader
通过查找当前部分记录来开始分割。
其中LineRecordReader
通过读取当前块的末尾来结束分割。
希望这有助于指导您的自定义代码的设计。