合并小文件汇总(Hive/Spark)

合并小文件的原因:过多的小文件会导致HDFS上元数据负载增加。并且小文件也会导致计算性能下降。

1. 使用hive时

1.1. 使用hive.merge参数,开启文件合并

-- 控制在map阶段结束后合并输出的小文件,默认值为true
SET hive.merge.mapfiles = true;
-- 控制在reduce阶段结束后合并输出小文件,默认值为false
SET hive.merge.mapredfiles = true;

-- 合并文件时每个任务的目标文件的大小,默认为256MB。是硬性设置,确保合并后的每个文件大小不会超过该值。
SET hive.merge.size.per.task = 268435456;
-- 只有当输入文件的平均大小小于该值时,才会触发合并操作,默认为1GB
SET hive.merge.smallfiles.avgsize = 1073741824;

这些设置可以在查询执行时动态调整,或者在 hive-site.xml 配置文件中进行全局设置。

1.2. 动态分区插入

可以使用 Hive 的动态合并功能,在数据加载时自动合并小文件。

动态合并设置
-- 启用动态分区,默认为false表示禁用
SET hive.exec.dynamic.partition=true;
-- 动态分区的插入模式,strict严格模式(必须显示指定所有分区列的值),nonstrict非严格模式(无需显示指定所有分区的值,hive会根据出入的数据动态创建分区)
SET hive.exec.dynamic.partition.mode=nonstrict;
-- 设置动态分区插入语句可以创建的最大分区数
SET hive.exec.max.dynamic.partitions=1000;
-- 设置每个节点可以处理的最大动态分区数
SET hive.exec.max.dynamic.partitions.pernode=100;

动态分区插入可能会导致生成大量的小文件,特别是在分区较多的情况下,建议结合hive.merge参数,设置小文件合并策略。

-- 在动态分区插入时对分区列进行排序,以减少生成的小文件数量,默认为false
-- 启动后,动态分区列将进行全局排序,使得reducer端每个分区只有一个文件写入
SET hive.optimize.sort.dynamic.partition=true
-- 分桶表时,启用此参数来优化分桶的排序
SET hive.optimize.bucketingsorting=true

1.3. HIVE CONCATENATE命令

Hive 提供了 ALTER TABLE ... CONCATENATE 命令,可以将小文件合并成更大的文件。这种方法适用于已经存在的表。但是该命令只能在存储格式支持合并的情况下使用,如orc或parquet格式。

ALTER TABLE table_name [PARTITION (partition_key = 'partition_value')] CONCATENATE;

未指定分区值,将合并整个表中的小文件,指定分区时,将合并指定分区内的小文件。

该命令名受hive.merge参数控制。

对于非常大的表,合并过程可能需要较长的时间。

2. 使用spark时

调整并行度和分区大小来减少小文件的数量

spark.conf.set("spark.sql.shuffle.partitions", "200")

数据写入前显示的使用coalesce 或 repartition方法。

修改SQL逻辑增加distribute by xxx方式增加一次shuffle来减少落到hdfs上的小文件。

自定义参数和代码,实现任务提交时文件合并。

3. hdfs工具

可以使用 Hadoop DistCp 或者 HDFS 的 getmerge 命令来合并小文件。

使用 Hadoop DistCp,工具是一个用于在Hadoop集群之间或集群内部复制大量数据的命令行工具
hadoop distcp  
hadoop distcp hdfs://namenode:8020/source_directory hdfs://namenode:8020/destination_directory
使用 getmerge 命令,Hadoop命令行工具中的一个命令,它用于将HDFS上的多个文件合并成一个文件并下载到本地文件系统。
hadoop fs -getmerge /source_directory /destination_directory/merged_file

你可能感兴趣的:(Spark/Hive,hive,spark,hadoop)