是否会多次重复计算持久数据帧?

时间:2017-06-21 04:21:45

标签: apache-spark apache-spark-sql

我有以下结构化查询:

val A = 'load somedata from  HDFS'.persist(StorageLevel.MEMORY_AND_DISK_SER)
val B = A.filter('condition 1')
val C = A.filter('condition 2')
val D = A.filter('condition 3')
val E = A.filter('condition 4')
val F = A.filter('condition 5')
val G = A.filter('condition 6')
val H = A.filter('condition 7')

val I = B.union(C).union(D).union(E).union(F).union(G).union(H)

我坚持使用数据帧A,这样当我使用B / C / D / E / F / G / H时,A数据帧应该只计算一次?但这项工作的DAG如下:

enter image description here

从上面的DAG看,第6-12阶段似乎全部执行了,数据帧A计算了7次?

为什么会发生这种情况?

也许DAG只是假的?我发现第7-12阶段的顶部没有线条,其中第6阶段确实有来自其他阶段的两条线

我没有列出所有操作。在union操作后,我将I数据帧保存到HDFS。 I数据框上的此操作是否会使持久操作真正完成?或者我必须在count数据帧上执行A之类的操作操作,以便在重用A数据帧之前触发持久操作吗?

1 个答案:

答案 0 :(得分:3)

执行以下行不会保留数据集。

val A = 'load somedata from  HDFS'.persist(StorageLevel.MEMORY_AND_DISK_SER)

与数据集API一起使用时,缓存/持久性是惰性的,因此您必须使用count运算符或类似操作符触发缓存,然后再提交Spark作业。

之后,以下所有运营商filter都应使用 InMemoryTableScan ,并在计划中使用绿点(如下所示)。

enter image description here

在您的情况下,即使union之后数据集I未被缓存,因为您尚未触发缓存(但仅将其标记为缓存)。

  

联合操作后,我将I数据帧保存到HDFS。 I数据框上的此操作是否会使持久操作真正完成?

是。只有操作(如保存到外部存储)才能触发持久性以供将来重用。

  

或者我必须执行一项操作操作,例如对A数据帧进行计数,以便在重用A数据帧之前触发持久操作吗?

这就是重点!在您的情况下,由于您希望在A运算符之间重用filter数据帧,因此您应首先persistcount(以触发缓存),然后filter

在您的情况下,由filter引起的任何性能提升都不会使persist受益。 persist实际上没有任何对性能的影响,只是让代码审核者认为不是这样。

如果您想查看数据集何时以及是否已缓存,可以在网页用户界面中查看存储标签,或者询问CacheManager

val nums = spark.range(5).cache
nums.count
scala> spark.sharedState.cacheManager.lookupCachedData(nums)
res0: Option[org.apache.spark.sql.execution.CachedData] =
Some(CachedData(Range (0, 5, step=1, splits=Some(8))
,InMemoryRelation [id#0L], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
   +- *Range (0, 5, step=1, splits=8)
))