hive on spark 动态解决小文件太多的办法

在做项目时,有个ETL需要处理,数据都在HIVE里面,需要对数据进行统计分析转换。开始直接用的HIVE的JDBC,效率不高。后来想到用hive on spark的方式处理。底层不再使用MapReduce进行计算,避免shuffle引起的大量读写硬盘和rpc网络拷贝带来的性能底下问题,程序效率有了明显提高。但是随之而来的是用sparksql往hive表中插入数据时,会产生很多小文件。用hive时,可以通过以下设置来合并输出的小文件:

#在Map-only的任务结束时合并小文件 
set hive.merge.mapfiles = true
#在Map-Reduce的任务结束时合并小文件 
set hive.merge.mapredfiles= true
#合并后文件的大小为1GB左右 
set hive.merge.size.per.task = 1024000000
#当输出文件的平均大小小于1GB时,启动一个独立的map-reduce任务进行文件merge
set zhive.merge.smallfiles.avgsize=1024000000

但是我用hiveContext设置了后并没有作用,因为底层计算是spark的,而不是MapReduce。
这里spark任务,可以设定启动参数中的executor和task来控制任务并行度从而防止太多小文件的情况,但是我这边需要程序启动后不停地运行,所以一个启动参数并不能一直解决问题,而是需要能动态调整的方法。
于是我想到了对hiveContext计算出的要插入的数据进行重分区,从而可以动态调整输出文件的个数,从而防止小文件的产生。

private static void syncRsUserBehavior(HiveContext hiveContext) throws IllegalArgumentException, IOException {
        StringBuffer sqlBuffer = new StringBuffer();
        sqlBuffer.append(" select * from rs_user_behavior_inc    ");
        sqlBuffer.append(" union all select id,c_userid,c_newsid,l_savetime,i_type,");
        sqlBuffer.append(" i_score,i_recommendtype from rs_user_behavior ");
        sqlBuffer.append(" where datetime ='" + ConstantTool.YESTERDAY + "'");
        log.info("##### rs_user_behavior " + ConstantTool.TODAY + " 数据同步开始");
// repartition 数据重分区
hiveContext.sql(sqlBuffer.toString()).repartition(getShufflePartitions("rs_user_behavior"))
.registerTempTable("rs_user_behavior_mix");
        sqlBuffer = new StringBuffer();
        sqlBuffer.append(" insert overwrite table rs_user_behavior partition (datetime='" + ConstantTool.TODAY
                + "') select * from rs_user_behavior_mix");
        hiveContext.sql(sqlBuffer.toString());
        log.info("##### rs_user_behavior " + ConstantTool.TODAY + " 数据同步完毕");
    }

猜你喜欢

转载自blog.csdn.net/longyangaaoo/article/details/78645839