Python将.json文件从GCS并行读取到DF中

Python将.json文件从GCS并行读取到DF中,python,pandas,parallel-processing,google-cloud-storage,python-asyncio,Python,Pandas,Parallel Processing,Google Cloud Storage,Python Asyncio,TL;DR:asynciovsmulti-processingvsthreadingvs 我想创建一个并行python函数,该函数从GCS目录中读取数十万个小型.json文件,然后将这些.json转换为pandas数据帧,然后将pandas数据帧写入BigQuery表 以下是函数的非并行版本: import gcsfs import pandas as pd from my.helpers import get_gcs_file_list def load_gcs_to_bq(gcs_direc

TL;DR:
asyncio
vs
multi-processing
vs
threading
vs

我想创建一个并行python函数,该函数从GCS目录中读取数十万个小型.json文件,然后将这些.json转换为pandas数据帧,然后将pandas数据帧写入BigQuery表

以下是函数的非并行版本:

import gcsfs
import pandas as pd
from my.helpers import get_gcs_file_list
def load_gcs_to_bq(gcs_directory, bq_table):

    # my own function to get list of filenames from GCS directory
    files = get_gcs_file_list(directory=gcs_directory) # 

    # Create new table
    output_df = pd.DataFrame()
    fs = gcsfs.GCSFileSystem() # Google Cloud Storage (GCS) File System (FS)
    counter = 0
    for file in files:

        # read files from GCS
        with fs.open(file, 'r') as f:
            gcs_data = json.loads(f.read())
            data = [gcs_data] if isinstance(gcs_data, dict) else gcs_data
            this_df = pd.DataFrame(data)
            output_df = output_df.append(this_df)

        # Write to BigQuery for every 5K rows of data
        counter += 1
        if (counter % 5000 == 0):
            pd.DataFrame.to_gbq(output_df, bq_table, project_id=my_id, if_exists='append')
            output_df = pd.DataFrame() # and reset the dataframe


    # Write remaining rows to BigQuery
    pd.DataFrame.to_gbq(output_df, bq_table, project_id=my_id, if_exists='append')
此函数非常简单:

  • 抓取
    ['gcs_dir/file1.json','gcs_dir/file2.json',…]
    ,gcs中的文件名列表
  • 在每个文件名上循环,然后:
    • 从GCS读取文件
    • 将数据转换为数据类型
    • 附加到主目录的
    • 每5K循环一次,写入BigQuery(因为随着DF变大,追加的速度会变慢)
我必须在几个GCS目录上运行这个函数,每个目录都有大约500K个文件。由于读/写这么多小文件的瓶颈,单个目录的读/写过程大约需要24小时。。。如果我能使它更加并行以加快速度,那将是非常棒的,因为它似乎是一个适合并行化的任务


编辑:下面的解决方案很有帮助,但我对从python脚本中并行运行特别感兴趣。Pandas正在处理一些数据清理,使用
bq load
将抛出错误。这和这两个任务对于这个任务可能是有用的,可能是比线程处理或多重处理更好的选择…

,而不是将并行处理添加到Python代码中,而是考虑并行调用多个Python程序。这是一个技巧,它使在命令行上获取文件列表的程序更容易使用。因此,为了这个帖子,让我们考虑改变你的程序中的一行:

您的线路:

# my own function to get list of filenames from GCS directory
files = get_gcs_file_list(directory=gcs_directory) # 
新行:

files = sys.argv[1:]  # ok, import sys, too
现在,您可以通过以下方式调用程序:

PROCESSES=100
get_gcs_file_list.py | xargs -P $PROCESSES your_program

xargs
现在将获取由
get_gcs_file_list.py
输出的文件名,并并行调用
您的_程序
多达100次,在每一行上匹配尽可能多的文件名。我相信文件名的数量限制在shell允许的最大命令大小之内。如果100个进程不足以处理您的所有文件,xargs将再次(一次又一次)调用您的_程序,直到它从stdin读取的所有文件名都得到处理
xargs
确保同时运行的\u程序
调用不超过100次。您可以根据主机可用的资源更改进程数。

您可以直接使用
bq
命令来代替此操作

bq命令行工具是用于BigQuery的基于Python的命令行工具

当您使用这个命令时,加载在google的网络中进行,这比我们创建数据帧并加载到表中要快得多

    bq load \
    --autodetect \
    --source_format=NEWLINE_DELIMITED_JSON \
    mydataset.mytable \
    gs://mybucket/my_json_folder/*.json

有关详细信息-

您为什么要这样做?您可以直接使用
bq
命令在bigquery中提供GCS文件夹的路径和表名。这将是快速的
bq
命令你指的是什么?我已经给出了一个答案,让其他面临同样问题的人可以看看这个好主意。谢谢分享。目前,我在每天运行的Airflow
DAG
中以
tasks
的形式调用我的程序,我不太确定如何将此模式引入Airflow。我将尝试此方法。我担心我的数据会出现
类型
问题,这可能是因为数据混乱,尽管您的共享命令似乎有一个
--autodetect
标志来处理这个问题?
--autodetect
将自动检测类型并尝试应用类型,否则它将抛出错误