在DataFrame联合

时间:2016-09-08 01:17:38

标签: apache-spark distributed-computing partitioning spark-dataframe unions

我有一个Spark应用程序需要大量使用unions,我将在不同情况下在不同时间将大量DataFrame联合在一起。我正努力尽可能高效地运行。我仍然非常喜欢Spark的新品牌,并且有些事情发生在我身上:

如果我有DataFrame'A'(dfA),其中包含X个分区(numAPartitions),我将其与具有Y的DataFrame'B'(dfB)联合起来分区数(numBPartitions),那么生成的联合DataFrame(unionedDF)会是什么样子,结果是分区?

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

对我而言,这似乎非常重要,因为看到Spark性能似乎严重依赖DataFrames采用的分区策略。因此,如果我左右联合DataFrames,我需要确保我不断管理生成的联合DataFrames的分区。

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

val unionedDF : DataFrame = dfA.unionAll(dfB)
unionedDF.repartition(optimalNumberOfPartitions).persist(StorageLevel.MEMORY_AND_DISK)

这样,一旦它们被联合起来,我们就会对它们进行重新分区,以便将它们正确地分布在可用的worker / executors上,然后persist(...)调用告诉Spark不要从内存中驱逐DataFrame,所以我们可以继续努力。

问题是,声音的重新分区是昂贵的,但可能不像替代品那样昂贵(根本不管理分区)。是否有关于如何在Spark-land中有效管理工会的普遍接受的指导方针?

2 个答案:

答案 0 :(得分:1)

是的,分区对非常重要。

我想知道你是否可以通过致电来找到答案:

yourResultedRDD.getNumPartitions()
  

我必须坚持,发布工会吗?

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

例如,如果您打算仅使用生成的RDD一次,那么坚持使用它是安全的。

  

我必须重新分配吗?

由于您不关心查找分区数量,因此您可以在memoryOverhead issue in Spark 中阅读有关分区数量如何影响您的应用程序的信息。

通常,您拥有的分区越多,每个执行程序将处理的数据块越小。

回想一下,一个worker可以托管多个执行器,你可以把它想象成一个worker作为你的集群的机器/节点,而执行器就是一个在该worker上运行的进程(在一个核心中执行)。 p>

  

Dataframe不一直在内存中吗?

不是真的。这对于非常可爱,因为当你处理时,你不希望不必要的东西存在于记忆中,因为这会威胁你的应用程序的安全。

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

更多阅读:Should I always cache my RDD's and DataFrames?

答案 1 :(得分:0)

联合只是将数据帧1和数据帧2中的分区数量加起来。两个数据帧具有相同的列数和相同的顺序来执行联合操作。因此,不用担心,如果两个数据帧中的分区列都不同,则将有最多m + n个分区。

加入后您无需重新分区数据帧,我的建议是使用合并代替重新分区,合并合并公用分区或合并一些小分区,并避免/减少分区中的数据改组。

如果在每个联合之后缓存/持久化数据帧,则会降低性能,并且血统不会被缓存/持久化破坏,在这种情况下,垃圾回收将清理缓存/内存,以防某些占用大量内存的操作,并且重新计算将增加相同的计算时间,也许这是清除/删除数据需要部分计算的时间。

由于火花转换是惰性的,即; unionAll是惰性操作,合并/分区也是惰性操作,在第一个操作时生效,因此尝试在间隔为8的间隔后合并unionall结果,并减少结果数据帧中的分区。如果您的解决方案中有大量的内存密集型操作,请使用检查点来中断沿袭并存储数据。