我有一个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中有效管理工会的普遍接受的指导方针?
答案 0 :(得分:1)
是的,分区对spark非常重要。
我想知道你是否可以通过致电来找到答案:
yourResultedRDD.getNumPartitions()
我必须坚持,发布工会吗?
一般情况下,如果要多次使用RDD,则必须持久保存/缓存RDD(无论是联盟的结果还是土豆:))。这样做会阻止spark在内存中再次获取它,并且在某些情况下可以将应用程序的性能提高15%!
例如,如果您打算仅使用生成的RDD一次,那么坚持使用它是安全的。
我必须重新分配吗?
由于您不关心查找分区数量,因此您可以在memoryOverhead issue in Spark 中阅读有关分区数量如何影响您的应用程序的信息。
通常,您拥有的分区越多,每个执行程序将处理的数据块越小。
回想一下,一个worker可以托管多个执行器,你可以把它想象成一个worker作为你的集群的机器/节点,而执行器就是一个在该worker上运行的进程(在一个核心中执行)。 p>
Dataframe不一直在内存中吗?
不是真的。这对于spark非常可爱,因为当你处理bigdata时,你不希望不必要的东西存在于记忆中,因为这会威胁你的应用程序的安全。
DataFrame可以存储在spark为您创建的临时文件中,并且只在需要时才会加载到应用程序的内存中。
答案 1 :(得分:0)
联合只是将数据帧1和数据帧2中的分区数量加起来。两个数据帧具有相同的列数和相同的顺序来执行联合操作。因此,不用担心,如果两个数据帧中的分区列都不同,则将有最多m + n个分区。
加入后您无需重新分区数据帧,我的建议是使用合并代替重新分区,合并合并公用分区或合并一些小分区,并避免/减少分区中的数据改组。
如果在每个联合之后缓存/持久化数据帧,则会降低性能,并且血统不会被缓存/持久化破坏,在这种情况下,垃圾回收将清理缓存/内存,以防某些占用大量内存的操作,并且重新计算将增加相同的计算时间,也许这是清除/删除数据需要部分计算的时间。
由于火花转换是惰性的,即; unionAll是惰性操作,合并/分区也是惰性操作,在第一个操作时生效,因此尝试在间隔为8的间隔后合并unionall结果,并减少结果数据帧中的分区。如果您的解决方案中有大量的内存密集型操作,请使用检查点来中断沿袭并存储数据。