使用Python 递归合并不同目录下小文件

#背景
项目中, 由网络爬虫爬取的日志文件, 需要导入到 hive 数据仓库中, 但日志文件包含很多的小文件(指代文件大小远小于HDFS块大小的文件,hadoop 2.x之后,HDFS块大小默认未128M,那么1M,3M之类的文件都称为小文件), 散落在许多子文件夹下.

总所周知, 当 hive 的输入端如果由许多小文件组成的话, 每个小文件都会启动一个 map 任务, 每调用一次map()函数将创建一个映射器,如果文件多而小, 会造成 map 任务启动和初始化的时间远大于逻辑处理的时间, 造成数据处理时间大大增加, 甚至会造成 OOM的后果.

另外,HDFS的文件元信息,包括位置、大小、分块信息等,都是保存在NameNode的内存中的。每个对象大约占用150个字节,因此一千万个文件及分块就会占用约3G的内存空间,一旦接近这个量级,NameNode的性能就会开始下降了。

此外,HDFS读写小文件时也会更加耗时,因为每次都需要从NameNode获取元信息,并与对应的DataNode建立连接。对于MapReduce程序来说,小文件还会增加Mapper的个数,每个脚本只处理很少的数据,浪费了大量的调度时间。

鉴于此, 当我们执行一个hive任务时, 当发现数据量不大, 但任务数巨多时, 就要考虑是不是小文件在作祟. 如果是, 请在 Map 前进行输入的合并.

hive 通过设置启动参数的方式, 社区有很多文章介绍, 这里引用一下这篇文章:
Hive小文件合并

以下主要介绍编程方式合并.

#代码
话不多少, 直接上 python 代码:

#!/usr/bin/python
# -*- coding:utf8 -*-

import os
allFileNum = 0
def merge_small_file(level, path):
    global allFileNum

    '''''
    打印一个目录下的所有文件夹和文件
    '''
    # 所有文件夹,第一个字段是次目录的级别
    dirList = []
    # 所有文件
    fileList = []
    # 返回一个列表,其中包含在目录条目的名称(google翻译)
    files = os.listdir(path)
    # 先添加目录级别
    dirList.append(str(level))
    for f in files:
        targetFile = "/data/admin/dong_bao_spider/merge_json_files.json"
        output_json_file = open(targetFile,'a')

        if(os.path.isdir(path + '/' + f)):
            # 排除隐藏文件夹。因为隐藏文件夹过多
            if(f[0] == '.'):
                pass
            else:
                # 添加非隐藏文件夹
                dirList.append(f)
                getJsonFilePath(level, path+'/'+f)
        if(os.path.isfile(path + '/' + f)):
            # 判断文件是以".json"结尾的
            if str(f).endswith('.json'):
                # 添加文件
                fileList.append(path + '/' + f)
                allFileNum += 1

                with open(str(path + '/' + f)) as input_json_file:
                    for r in input_json_file.readlines():
                        # 去掉每一行后面的换行符,先加换行符
                        output_json_file.write(r.strip('\n') + '\n')

        output_json_file.close()

	# 以下代码为演示程序扫描过的文件夹, 分层显示
    # 当一个标志使用,文件夹列表第一个级别不打印
    # i_dl = 0
    # for dl in dirList:
    #     if(i_dl == 0):
    #         i_dl = i_dl + 1
    #     else:
    #         # 打印至控制台,不是第一个的目录
    #         print '-' * (int(dirList[0])), dl
    #         # 打印目录下的所有文件夹和文件,目录级别+1
    #         printPath((int(dirList[0]) + 1), path + '/' + dl)
    # for fl in fileList:
    #     if str(fl).endswith(".json"):
    #         # 打印文件
    #         print '-' * (int(dirList[0])), fl
    #         # 随便计算一下有多少个文件
    #         allFileNum = allFileNum + 1


    # for file in fileList:
    #     print file

if __name__ == '__main__':
    merge_small_file(1, '/Users/david/Downloads/dong_bao_output/')

    print 'Files in total =', allFileNum
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值