大型文件安全读取到高效写入MongoDB——生成器、文件拆分、多进程

本文介绍了如何使用Python的生成器读取大文件,批量写入MongoDB,并通过文件拆分和多进程实现效率提升。在1千万行数据的测试中,68秒完成写入。文章详细讲解了生成器读取、批量插入、多进程并行写入的实现方法和代码示例。

记录最近一个大文件数据处理入库任务,需求大致是这样:

数据处理需求:

需要定期拉取一个千万行级的大型文件,文件内容是按照指定分隔符进行分割的数据表内容.

  • 每行结束按照\n换行,类似下面这种格式:
1;female;Micky;19746;
2;male;Tom;749573;
3;male;Bob;465926;
...
  • 字段名分别为:idgendernamecode

分析思路

在进行代码编写之前,先整理思路,需要考虑的问题。
整体思路倒是简单:读取文件–>将每行转换key:value字典格式–>插入MongoDB
但是这里不得不考虑两个问题,内存问题、效率问题。

  • 大文件一般不能直接读取到内存,也许你的开发机器足够好能刚好承受,但你的代码如果直接放到生产上,可能直接就读取失败或者让生产机器的内存爆掉了。。
  • 写入效率第一点考虑,在insert_one和insert_many中必然是优先选用insert_many,即一次将一个列表的dict数据插入到MongoDB,这样的效率远高于逐条遍历的insert_one。
  • 写入效率第二点考虑,需考虑将数据并发写入MongoDB,具体究竟该使用协程、多线程还是多进程的方式呢?我们后面再说。

我的整体代码在最后部分,不想看中间啰嗦部分的可直接跳到最后~

本地数据库测试效率:1千万行数据,68秒写入完成

1. 生成器方式读取大文件

自定义一个生成器函数如下,使用next()方法每次可获取一行文件数据。
每行数据需要转换为字典格式返回,以便于可直接插如MongoDB。

FILEDS = ["id", "gender", "name", "code"]
def gen_file(filepath):
    """将大型文件转化为生成器对象,每次返回一行对应的字典格式数据"""
   with open(filepath, "r", encoding="utf-8") as f:
        while True:
            line = f.readline()
            if not line:
                break
            filed_list = line.split(";")[:-1]
            doc_dict = {
   
   k: v for k, v in zip(FILEDS, filed_list)
            yield doc_dict

可使用如下方式获取指定一行数据:

# example
gen = gen_file("./example_file.dat")
# 获取一行字典数据
doc = next(gen)
2.将数据批量写入MongoDB

每次读取1000行数据,使用insert_many批量插入MongoDB,你也可以自定义一次插入多少数据量。最好不要使用insert_one一次插入一条数据,数据量大时效率非常低下。
代码示例:

def insert_mongo():
    # 连接到指定MongoDB集合
    client = MongoClient(host=MONGO_HOST, 
    port=MONGO_PORT)
    coll = client[MONGO_DB][MONGO_COLLECTION]
     # 获取大文件生成器对象
    gen =gen_file("example_file.dat")
    # 循环读取生成器,一次写入1000条文档到MongoDB,直到生成器读取完全
    while True:
        docs = []
        try:
            for i in range(1000):
                doc = next(sp_gen)
                docs.append(doc)
        except StopIteration
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值