Apache spark For循环在EMR中保持重新启动(pyspark)
我有一个嵌套的for循环,它在内部循环中对一个数据帧执行10次操作,并在完成内部循环后将生成的10个数据帧合并到一个数据帧中 更新:我使用字典创建数据帧列表来存储每个操作,然后在内部循环结束时合并它们 然后,它将其写入带有outloop迭代编号的拼花地板文件。 outerloop有6次迭代,因此应生成6个拼花文件 事情是这样的:Apache spark For循环在EMR中保持重新启动(pyspark),apache-spark,pyspark,memory-leaks,nested-loops,amazon-emr,Apache Spark,Pyspark,Memory Leaks,Nested Loops,Amazon Emr,我有一个嵌套的for循环,它在内部循环中对一个数据帧执行10次操作,并在完成内部循环后将生成的10个数据帧合并到一个数据帧中 更新:我使用字典创建数据帧列表来存储每个操作,然后在内部循环结束时合并它们 然后,它将其写入带有outloop迭代编号的拼花地板文件。 outerloop有6次迭代,因此应生成6个拼花文件 事情是这样的: train=0 for i in range(0,6): train=train+30 #For loop to aggregate input and
train=0
for i in range(0,6):
train=train+30
#For loop to aggregate input and create 10 output dataframes
dfnames={}
for j in range(0,10):
ident="_"+str(j)
#Load dataframe of around 1M rows
df=spark.read.parquet("s3://path")
dfnames['df'+ident]= #Perform aggregations and operations
#Combine the 10 datframes into a single df
df_out=df_1.uniionByName(d_2).unionByName(df_3)...unionByName(df_10)
#Write to output parquet file
df_out.write.mode('overwrite').parquet("s3://path/" + str(train) +".parquet"
在完成外循环的第三次迭代之前,它似乎工作得很好。然后出于某种原因,它使用另一个尝试id重新启动循环。
因此,我得到了前3个文件,但它没有进入第4次迭代,而是重新启动以重新生成第一个文件。我没有得到任何失败的阶段或工作
我已经尝试过单独使用伪变量和打印语句运行for循环(不加载大型数据帧等),它们可以很好地完成。
我认为这与循环后刷新内存的方式有关
以下是我的EMR Spark运行条件:
我在一个EMR集群上运行它,该集群有5个执行器、5个驱动程序节点和10个实例,总共有50个核心。spark executor和driver内存分别为45G,总共约583G。
典型的随机读取为250G,随机写入为331G
一些相关的Spark环境变量如下所示:
在循环或内存管理方面,我有没有做错什么?
如有任何见解,将不胜感激 您是如何获得df1、df2。。。在这条线之前
#将10个数据帧组合成一个单独的df df_out=df1.uniionByName(d2).unionByName(df3)…unionByName(df10)
我的猜测是,您的数据帧计划正在变得越来越大,这可能会引起问题
我建议在内部循环中创建一个数据帧列表,并使用reduce
方法合并它们
像下面这样
from functools import reduce
from pyspark.sql import DataFrame
df_list = []
for j in range(0,10):
#Load dataframe of around 1M rows
df = spark.read.parquet("s3://path")
transformed_df = #do your transforms
df_list.append(transformed_df)
final_df = reduce(DataFrame.unionByName, df_list)
你是如何得到你的df1,df2。。。在这条线之前
#将10个数据帧组合成一个单独的df df_out=df1.uniionByName(d2).unionByName(df3)…unionByName(df10)
我的猜测是,您的数据帧计划正在变得越来越大,这可能会引起问题
我建议在内部循环中创建一个数据帧列表,并使用reduce
方法合并它们
像下面这样
from functools import reduce
from pyspark.sql import DataFrame
df_list = []
for j in range(0,10):
#Load dataframe of around 1M rows
df = spark.read.parquet("s3://path")
transformed_df = #do your transforms
df_list.append(transformed_df)
final_df = reduce(DataFrame.unionByName, df_list)
尽量不要将Python数据结构与Spark数据结构相结合 您希望将for循环转换为设计形式的map reduce,foreach。 除此之外,您还可以在每次迭代中创建一个缓存/火花检查点,以避免从头开始重新运行整个DAG 要缓存数据,请执行以下操作:
df.cache()
检查点
spark.sparkContext.setCheckpointDir('<some path>')
df.checkpoint()
spark.sparkContext.setCheckpointDir(“”)
df.checkpoint()
一旦您使用spark结构而不是python结构,这些将显示性能和规模的改进。例如,用foreach替换For循环,用map reduce替换列表的并集。尽量不要将Python数据结构与Spark数据结构结合起来 您希望将for循环转换为设计形式的map reduce,foreach。 除此之外,您还可以在每次迭代中创建一个缓存/火花检查点,以避免从头开始重新运行整个DAG 要缓存数据,请执行以下操作:
df.cache()
检查点
spark.sparkContext.setCheckpointDir('<some path>')
df.checkpoint()
spark.sparkContext.setCheckpointDir(“”)
df.checkpoint()
一旦您使用spark结构而不是python结构,这些将显示性能和规模的改进。例如,用foreach替换For循环,用map reduce替换列表的并集。我更新了帖子以显示该部分。我使用字典
dfnames
将生成的10个数据帧存储为df_1
、df_2
、df_3`等。。然后是名字。这10个数据帧中的每一个都是唯一的,我想在内部循环之后简单地合并它们。“reduce”方法会以任何方式修改内容吗?另外,append
函数是否会将追加的dfs的内容保留在单个节点中而不是分布式节点中?reduce
方法不会修改内容。它只是将在其参数中传递的特定函数应用于所有列表元素append
只是将数据帧追加到列表中,而数据帧只是计划,它们不包含任何数据。基本上,您的列表将有对每个迭代的每个转换的引用。类似这样的[DataFrame[comment:bigint,inp\u col:string,inp\u val:string],DataFrame[comment:bigint,inp\u col:string,inp\u val:string],DataFrame[comment:bigint,inp\u col:string,inp\u val:string]
我尝试了append
方法。但我有一个内存堆错误:(我更新了我的帖子来展示这一部分。我使用字典dfnames
将生成的10个数据帧存储为dfu 1
,dfu 2
,df_3`等,然后是unionByName。这10个数据帧中的每一个都是唯一的,我只想在内部循环后合并它们。“reduce”方法会以任何方式修改内容吗lsoappend
函数是否将附加dfs的内容保留在单个节点中,而不是分布式的?reduce
方法不会修改内容。它只是将参数中传递的特定函数应用于所有列表元素。append
只是将数据帧附加到列表中,而数据帧是我们只是计划,它们不包含任何数据。基本上,您的列表将对每次迭代的每个转换都有引用。类似这样的[DataFrame[comment:bigint,inp\u col:string,inp\u val:string],DataFrame[comment:bigint,inp\u col:string,inp\u col:string],DataFrame[comment:bigint,inp\u col:st]