我们正试图在EMR上运行ETL。在S3中有大约2000万个事件作为gzipped json线。它们总共约有30个文件。我正在使用pyspark。
这是代码,
def value_to_list(columns):
def value_map(values):
data = []
for val in values:
d = val.asDict()
data.append([d[column] for column in columns])
return data
return value_map
def main():
sc = SparkContext()
sql_context = SQLContenxt(sc)
all_events = SQLContenxt(sc).read.json("s3n://...", schema=StructType(fields), timestampFormat="yyyy-MM-dd HH:mm:ss")
all_events.registerTempTable('allevents')
for event_type in event_types:
process_event(sc, event_type, "allevents")
def process_event(sparkcontext, etype, tablename):
query = "select app_id, source, type, {time_cols}, count(*) as total " \
"from {table} where type = '{event_type}' " \
"group by app_id, source, type, {time_cols}"
time_cols_spec = [('hour', 'day', 'month', 'year'),
('day', 'month', 'year'),
('month', 'year'),
('year')]
for time_cols in time_cols_spec:
final_query = query.format(time_cols=", ".join(time_cols),
table=tablename,
event_type=etype)
dataframe = sql_context.sql(final_query)
dataframe.rdd.groupBy(lambda r: r['app_id'])\
.mapValues(value_to_list(['source'] + time_cols))\
.saveAsTextFile("s3n://...")
因此,我们有大约30种类型的活动,每次活动我都会按小时,日,月和年的4种组合进行汇总。所以4查询每个。我们总共有大约2000M的活动。
我正在运行
m3.2xlarge
问题是,最后的保存需要很长时间。上次我查询它花了14个小时进行2次组合和一次活动:(
我知道我不是平行时尚。循环是顺序的。并且有2个循环。但我希望rdd,groupBy
,mapValues
能够并行运行。当我看到事件时间表时,我看到saveAsTextFile
占据了99%的时间。可能是因为火花懒散地执行了。
我需要使这个过程平行且快速。我怎样才能做到这一点?
答案 0 :(得分:2)
您可以应用4种主要优化:
您正在对普通json文件执行聚合,这些文件未针对进行查询进行优化。将它们重写为镶木地板,按事件类型重新分区并在S3上存储 - 它们将占用更少的空间,您的应用程序将获得良好的速度提升。
提高并行度。没有必要在这样强大的虚拟机上安装驱动程序(主服务器),而是生成一个较小的实例(例如m3.medium
),并为工作人员使用所有3个大实例。
将RDD API调用替换为Dataframe:.rdd.groupBy().mapValues()
可以替换为.groupBy(dataframe.app_id).agg(collect_list())
,然后替换为某些映射。
您可以对(小时,日,月,年)数据集的原始数据执行查询,然后使用此聚合来调用给定事件的所有剩余查询。