在 DataFrame 联合后管理 Spark 分区

sme*_*eeb 5 partitioning distributed-computing unions apache-spark apache-spark-sql

我有一个 Spark 应用程序,需要大量使用它unions,我将在不同时间、不同情况下将大量 DataFrame 合并在一起。我正在努力使这项工作尽可能高效地进行。我对 Spark 还很陌生,我突然想到了一件事:

如果我有dfA具有 X 个分区 ( ) 的 DataFrame 'A' ( ) numAPartitions,并将其联合到dfB具有 Y 个分区 ( ) 的DataFrame 'B' ( numBPartitions) ,那么生成的联合 DataFrame ( unionedDF) 会是什么样子,结果如何分区?

// How many partitions will unionedDF have?
// X * Y ?
// Something else?
val unionedDF : DataFrame = dfA.unionAll(dfB)
Run Code Online (Sandbox Code Playgroud)

对我来说,理解这一点似乎非常重要,因为 Spark 性能似乎严重依赖于 DataFrames 采用的分区策略。因此,如果我左右合并 DataFrame,我需要确保不断管理合并后的 DataFrame 的分区。

我唯一想到的(以便正确管理联合数据帧的分区)是对它们重新分区,然后在联合它们后立即将数据帧持久保存到内存/磁盘:

val unionedDF : DataFrame = dfA.unionAll(dfB)
unionedDF.repartition(optimalNumberOfPartitions).persist(StorageLevel.MEMORY_AND_DISK)
Run Code Online (Sandbox Code Playgroud)

这样,一旦它们联合起来,我们就重新分区它们,以便将它们正确地分布在可用的工作程序/执行程序上,然后调用persist(...)告诉 Spark 不要从内存中逐出 DataFrame,这样我们就可以继续处理它。

问题是,重新分区听起来很昂贵,但它可能不像替代方案(根本不管理分区)那么昂贵。Spark-land 是否有关于如何有效管理工会的普遍接受的准则?

gsa*_*ras 2

很重要。

我想知道您是否可以通过拨打以下电话自己找到答案:

yourResultedRDD.getNumPartitions()
Run Code Online (Sandbox Code Playgroud)

结合后我必须坚持吗?

一般来说,如果要多次使用 RDD,则必须持久/缓存 RDD(无论它是联合的结果还是土豆:))。这样做可以防止再次在内存中获取它,并且在某些情况下可以将应用程序的性能提高 15%!

例如,如果您只想使用生成的 RDD 一次,那么不持久化它是安全的。

我必须重新分区吗?

由于您不关心查找分区数量,因此您可以阅读我的Spark 中的内存开销问题 ,了解分区数量如何影响您的应用程序。

一般来说,分区越多,每个执行器处理的数据块就越小。

回想一下,一个工作线程可以托管多个执行程序,您可以将其视为集群的机器/节点,而执行程序则是在该工作线程上运行的进程(在核心中执行)。

Dataframe不是一直在内存中吗?

并不真地。这对于来说真的很可爱,因为当你处理时,你不希望内存中存有不必要的东西,因为这会威胁你的应用程序的安全。

DataFrame 可以存储在为您创建的临时文件中,并且仅在需要时才加载到应用程序的内存中。

欲了解更多信息,请阅读:我应该始终缓存我的 RDD 和 DataFrame 吗?