指定Hive插入操作生成的最小文件数

4
我在AWS EMR上使用Hive将查询结果插入日期分区的Hive表中。尽管每天的总输出大小相似,但生成的文件数不同,通常在6到8之间,但有些天只创建一个大文件。我重新运行了查询几次,以防文件数量受群集中节点可用性的影响,但似乎是一致的。 (a) 是什么确定生成的文件数? (b) 是否有一种方法可以指定最小文件数或(更好的)每个文件的最大大小?
1个回答

10

INSERT ... SELECT生成的文件数量取决于最终Reducer上运行的进程数(如果在Tez上运行,则为最终Reducer顶点)加上配置的每个Reducer字节数。

如果表被分区且未指定DISTRIBUTE BY,则在最坏情况下,每个Reducer都会在每个分区中创建文件。这会对Reducer造成很大的压力,并可能导致OOM异常。

为确保Reducers仅编写一个分区文件,请在查询末尾添加DISTRIBUTE BY partition_column

如果数据量太大,您希望增加并行性并在每个分区中创建更多文件,则将随机数添加到分布式中,例如使用此代码:FLOOR(RAND()*100.0)%10 - 它将通过随机10个桶将数据额外分配,因此每个分区将有10个文件。

最后,您的INSERT语句将如下所示:

INSERT OVERWRITE table PARTITION(part_col)
SELECT * 
  FROM src
DISTRIBUTE BY  part_col, FLOOR(RAND()*100.0)%10; --10 files per partition

此配置设置还影响生成的文件数量:

set hive.exec.reducers.bytes.per.reducer=67108864; 

如果数据过多,Hive会启动更多的reducers来处理每个reducer进程上指定的不超过{{bytes per reducer}}字节。reducers越多,生成的文件就越多。减少此设置可能导致增加运行的reducers数量,并且它们将为每个reducer创建至少一个文件。如果分区列不在{{distribute by}}中,则每个reducer可能在每个分区中创建文件。
简而言之,请使用:
DISTRIBUTE BY  part_col, FLOOR(RAND()*100.0)%10 -- 10 files per partition

如果您希望每个分区有20个文件,请使用FLOOR(RAND()* 100.0)% 20; - 这将保证每个分区的最小文件数为20个,如果数据足够,但不保证每个文件的最大大小。
每个reducer的字节数设置不能保证它是固定最小文件数。文件数取决于总数据大小/字节。 per.reducer。此设置将确保每个文件的最大大小。
但是,最好使用一些低基数的均匀分布键或组合,而不是随机键,因为在容器重新启动的情况下,rand()可能会产生与相同行的不同值,并且可能会导致数据重复或丢失(已经存在某个reducer输出中的相同数据将再次分发到另一个reducer)。您可以在一些可用的密钥上计算类似的函数,而不是rand(),以获得基本上均匀分布的低基数键。
您可以结合使用两种方法:每个reducer的字节数限制+按分布进行控制,以控制最小文件数和最大文件大小。
还应阅读有关使用distribute by将数据均匀分布在reducer之间的答案:https://dev59.com/qJnga4cB1Zd3GeqPTRSE#38475807

谢谢,了解到“DISTRIBUTE BY”的信息很好,尽管我最终在表定义中使用了“CLUSTER BY”。您对每种方法的优缺点有什么想法吗? - gsakkis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接