记录最近一个大文件数据处理入库任务,需求大致是这样:
数据处理需求:
需要定期拉取一个千万行级的大型文件,文件内容是按照指定分隔符进行分割的数据表内容.
- 每行结束按照
\n换行,类似下面这种格式:
1;female;Micky;19746;
2;male;Tom;749573;
3;male;Bob;465926;
...
- 字段名分别为:
id、gender、name、code
分析思路
在进行代码编写之前,先整理思路,需要考虑的问题。
整体思路倒是简单:读取文件–>将每行转换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

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





