Json 从清单中读取S3文件并使用Pandas并行处理它们
我需要使用清单文件从S3读取大约50k。我必须将每个(JSON)文件的内容读入一个数据帧并处理这些文件(将它们规范化为数据库表)。现在我有一个工作代码,处理50k文件大约需要15个小时。我必须把这当作日常工作。有什么方法可以并行处理大量文件,或者有什么更好的方法可以加快处理速度 用代码更新问题Json 从清单中读取S3文件并使用Pandas并行处理它们,json,pandas,amazon-web-services,amazon-s3,boto3,Json,Pandas,Amazon Web Services,Amazon S3,Boto3,我需要使用清单文件从S3读取大约50k。我必须将每个(JSON)文件的内容读入一个数据帧并处理这些文件(将它们规范化为数据库表)。现在我有一个工作代码,处理50k文件大约需要15个小时。我必须把这当作日常工作。有什么方法可以并行处理大量文件,或者有什么更好的方法可以加快处理速度 用代码更新问题 import json import pandas as pd import os import gzip import boto3 from datetime import datetime,tim
import json
import pandas as pd
import os
import gzip
import boto3
from datetime import datetime,timezone,timedelta
session = boto3.session.Session()
s3 = session.resource('s3')
client = session.client('s3')
#read the S3 inventory report, get the keys of files that are modified on sysdate-1
dt=(datetime.now(timezone.utc) + timedelta(days=-1)).strftime('%Y-%m-%d')
dtz=dt+'T00-00Z'
print('reading inventory report for', dtz)
inventory_bucket = 'xxx'
manifest_key='s3-bucket'+dtz+'/manifest.json'
manifest = json.load(s3.Object(inventory_bucket, manifest_key).get()['Body'])
df=pd.DataFrame()
for obj in manifest['files']:
gzip_obj = s3.Object(bucket_name=inventory_bucket, key=obj['key'])
print('csv obj:', gzip_obj)
buffer = gzip.open(gzip_obj.get()["Body"], mode='rt')
reader = pd.read_csv(buffer)
reader.columns=['id','key','modified_date']
print('converting csv obj to dataframe')
df=df.append(reader[(reader.modified_date>dt)])
source_keys=list(df['key'])
s3_bucket_source='yyy'
#download the files to a tmp folder
local='/tmp/'
print("downloading from S3")
for k in source_keys:
k_path=k.replace('/', '-')
dest_pathname = os.path.join(local, k_path)
if not os.path.exists(os.path.dirname(dest_pathname)):
os.makedirs(os.path.dirname(dest_pathname))
client.download_file(s3_bucket_source, k, dest_pathname)
#read the latest jsons from tmp folder
path_to_json = os.path.expanduser('/tmp/')
json_files = [pos_json for pos_json in os.listdir(path_to_json) if pos_json.endswith('.json')]
#loop through the jsons and normalize each file contents into df_table1, df_table2, df_table3
for index, js in enumerate(json_files):
with open(os.path.join(path_to_json, js)) as json_file:
print('processing file:', js)
d=json.loads(json_file.read())
v=d['key1'][0]['key2']
if isinstance(v, list):
for i, v2 in enumerate(v):
df_table1, df_table2, df_table3 = normalizeJSON(d,i,v2['id'])
#normalize is the custom function to split the nested json into relational tables
else:
print('invalid json')
我使用S3库存报告从清单中获取最新修改文件的列表,将文件下载到tmp位置,并逐个读取它们,以完成我需要做的事情您可以使用来并行下载JSON文件。
代码包含3个for块。您可以并行地执行其中的每一项。以下是如何为第一个应用程序执行此操作的示例:
第一个是:
变成:
def get_reader(obj):
gzip_obj = s3.Object(bucket_name=inventory_bucket, key=obj['key'])
print('csv obj:', gzip_obj)
buffer = gzip.open(gzip_obj.get()["Body"], mode='rt')
reader = pd.read_csv(buffer)
reader.columns=['id','key','modified_date']
print('converting csv obj to dataframe')
return reader[(reader.modified_date>dt)]
num_of_workers = 4
df = pd.DataFrame()
with multiprocessing.Pool(num_of_workers) as p:
results = p.map(get_reader, manifest['files'])
for result in results:
df = df.append(result)
您可以对其他块执行相同的操作请用代码更新问题。您在AWS基础设施上运行该问题,还是要在工作站上并行化?@Marcin我在AWS基础设施上运行代码,使用AWS胶水moment@Smile用代码段更新了问题最慢的部分是按顺序下载Python中的所有文件。一个简单的改进是使用gnu并行和awscli进行下载。另一个选项是使用gevent并行下载许多文件——当我尝试并行化上一个文件时,请参阅此代码以获得类似的示例,因为我得到以下错误
TypeError:map()从3到4个位置参数,但给出了5个位置参数
,感谢您的回复@pakallis。我修复了错误,并且我能够运行代码。代码中的第三个for块返回8个数据帧。但是map函数的输出是一个列表。因此,本例中的结果是8个数据帧的元组。有没有办法让map函数输出8个数据帧?
def get_reader(obj):
gzip_obj = s3.Object(bucket_name=inventory_bucket, key=obj['key'])
print('csv obj:', gzip_obj)
buffer = gzip.open(gzip_obj.get()["Body"], mode='rt')
reader = pd.read_csv(buffer)
reader.columns=['id','key','modified_date']
print('converting csv obj to dataframe')
return reader[(reader.modified_date>dt)]
num_of_workers = 4
df = pd.DataFrame()
with multiprocessing.Pool(num_of_workers) as p:
results = p.map(get_reader, manifest['files'])
for result in results:
df = df.append(result)