在由于许多工作失败(终止)而努力提高代码性能的同时,我考虑在需要在许多其他操作上使用同一数据帧时在Spark Dataframe上使用persist()
函数。在执行此操作并遵循Spark应用程序用户界面中的工作阶段时,我觉得这样做并非总是最佳选择,它取决于分区的数量和数据大小。我不确定直到由于持久阶段的失败而中止工作。
我在问在数据帧上执行许多操作时使用persist()
的最佳做法是否始终有效? 如果不是,什么时候无效?如何判断?
更具体地说,我将介绍我的代码和中止工作的详细信息:
#create a dataframe from another one df_transf_1 on which I made a lot of transformations but no actions
spark_df = df_transf_1.select('user_id', 'product_id').dropDuplicates()
#persist
spark_df.persist()
products_df = spark_df[['product_id']].distinct()
df_products_indexed = products_df.rdd.map(lambda r: r.product_id).zipWithIndex().toDF(['product_id', 'product_index'])
您可能会问为什么我坚持spark_df
?
这是因为我将像products_df
以及joins
中多次使用它(例如:spark_df = spark_df.join(df_products_indexed,"product_id")
第3阶段失败原因的详细信息
作业由于阶段故障而中止:阶段3.0中的任务40458失败了4次,最近一次失败:阶段3.0中的任务40458.3丢失(TID 60778,xx.xx.yyyy.com,执行程序91):ExecutorLostFailure(执行程序91退出了)由正在运行的任务之一引起)原因:从站丢失 驱动程序堆栈跟踪:
输入数据的大小( 4 TB )很大,在进行持久化处理之前是否有办法检查数据大小?它是选择是否持久化的参数吗?以及persist
> 100,000
答案 0 :(得分:2)
以下是使用persist()
的两种情况:
在使用repartition
后,为了避免在下一步骤使用数据帧时一次又一次地拖曳数据。这仅在您对持久化数据帧/ RDD调用多个动作的情况下才有用,因为持久化是一种转换,因此懒惰被评估。通常,如果您在同一数据框/ RDD上有多个操作。
迭代计算,例如,当您要查询for循环内的数据框时。使用persist
,Spark将保存中间结果,并忽略在每个操作调用上重新评估相同的操作。另一个示例是在here讨论的情况下,在新列上附加join
。
答案 1 :(得分:0)
我的经验告诉我,在对数据帧执行多项操作时,您应该保留该数据帧,以便创建时态表(还可以确保如果某些操作失败,您将具有恢复点)。通过这样做,可以防止庞大的DAG(例如,如果有连接)通常不会结束。所以我的建议是做这样的事情:
# operations
df.write.saveAsTable('database.tablename_temp')
df = spark.table('database.tablename_temp')
# more operations