Pyspark-不持久的父数据帧也会从缓存中删除子数据帧

时间:2019-02-05 10:58:23

标签: pyspark apache-spark-sql pyspark-sql

我正在做这样的事情:

import pandas as pd

pdf = pd.DataFrame({
    'a': [1, 2, 3],
    'b': ['a', 'b', 'c']
})

parent_df = spark.createDataFrame(pdf)
parent_df.cache().count()  

child_df = parent_df.replace('c', 'x')
child_df.cache().count()

parent_df.unpersist()

基本上,我想缓存parent_df,因为在接下来的步骤中,我将对其进行一些繁重的转换。完成这些操作后,我又回到了child_df,我不再需要parent_df了,因此想从缓存中释放它。但是,这样做还不会持久保存新缓存的child_df

很明显,问题是:

  • 为什么会这样?
  • 我该如何完成我想要的工作(从缓存中释放parent_df,同时将新的child_df保留在缓存中)?

有趣的是,相反的情况也可行-即如果我坚持不使用child_df而不是最后一行的parent_df,则parent_df将按预期保留,而释放child_df

PS:我在Understanding Spark's caching处发现了类似的问题。但是,在这种情况下,该问题的答案似乎不起作用,因为在这里我们已经在缓存后立即调用了一个动作(.count())。

2 个答案:

答案 0 :(得分:1)

这是基于数据一致性的有意识的设计决策。使父项不持久的一种可能原因是,您希望其源数据发生变化。父母拥有新数据,而明显的孩子则使用旧数据,可能会导致意外和不一致的结果。因此,当父级缓存时,父级的所有缓存子级都将失效。

the PR that implemented this changein this bug report after the change was introduced中有一些讨论。

如第二个链接中所述,如果您确实需要保留孩子,则可以使用saveAsTable将其具体化为表格。

答案 1 :(得分:0)

好吧,我想我找到了解决方法:

  • 首先,我对发生这种情况的猜测是parent_df缓存点是child_df世系的一部分。即即使child_df使用的是更高版本的缓存点,其DAG仍包含来自parent_df的更早的位。因此,删除该缓存点会以某种方式影响以后的缓存点。

  • 关于如何防止这种情况的发生,请执行以下工作:

import pandas as pd

pdf = pd.DataFrame({
    'a': [1, 2, 3],
    'b': ['a', 'b', 'c']
})

parent_df = spark.createDataFrame(pdf)
parent_df.cache().count()  

# this is the relevant line
child_df = spark.createDataFrame(parent_df.rdd, schema=parent_df.schema) 

child_df = child_df.replace('c', 'x')
child_df.cache().count()

parent_df.unpersist()

在相关行(标有注释)发生的情况是,child_df的谱系被剪切为不包括与parent_df对应的段,并以“新RDD”开头。解除parent_df的保留后,child_df的世系不会受到影响。

再次-尽管此方法似乎可行,但我欢迎对此理论进行更多的解释/确认,作为可接受的答案!