Scala ApacheSparkSQL:如何优化dataframe的链接连接

Scala ApacheSparkSQL:如何优化dataframe的链接连接,scala,apache-spark,join,Scala,Apache Spark,Join,我必须在一个主数据帧和几个参考数据帧之间进行左连接,这样就可以进行链式连接计算。我想知道如何使这一行动高效和可扩展 方法1很容易理解,这也是当前的方法,但我不满意,因为所有转换都已链接,并等待最终操作触发计算。如果我继续添加转换和数据量,spark最终将失败,因此此方法不可扩展 方法1: def pipeline(refDF1: DataFrame, refDF2: DataFrame, refDF3: DataFrame, refDF4: DataFrame, refDF5: DataFr

我必须在一个主数据帧和几个参考数据帧之间进行左连接,这样就可以进行链式连接计算。我想知道如何使这一行动高效和可扩展

方法1很容易理解,这也是当前的方法,但我不满意,因为所有转换都已链接,并等待最终操作触发计算。如果我继续添加转换和数据量,spark最终将失败,因此此方法不可扩展

方法1:

  def pipeline(refDF1: DataFrame, refDF2: DataFrame, refDF3: DataFrame, refDF4: DataFrame, refDF5: DataFrame): DataFrame = {

  val transformations: List[DataFrame => DataFrame] = List(
    castColumnsFromStringToLong(ColumnsToCastToLong),
    castColumnsFromStringToFloat(ColumnsToCastToFloat),
    renameColumns(RenameMapping),
    filterAndDropColumns,
    joinRefDF1(refDF1),
    joinRefDF2(refDF2),
    joinRefDF3(refDF3),
    joinRefDF4(refDF4),
    joinRefDF5(refDF5),
    calculate()
  )

  transformations.reduce(_ andThen _)

  }

  pipeline(refDF1, refDF2, refDF3, refDF4, refDF5)(principleDF)
方法2:我还没有找到一个真正的方法来实现我的想法,但我希望立即触发每个连接的计算

根据我的测试,count()对于spark来说太重了,对我的应用程序来说也没用,但是我不知道如何通过一个有效的操作触发连接计算。事实上,这种行动就是这个问题的答案

  val joinedDF_1 = castColumnsFromStringToLong(principleDF, ColumnsToCastToLong)
  joinedDF_1.cache() // joinedDF is not always used multiple times, but for some data frame, it is, so I add cache() to indicate the usage
  joinedDF_1.count()  

  val joinedDF_2 = castColumnsFromStringToFloat(joinedDF_1, ColumnsToCastToFloat)
  joinedDF_2.cache()
  joinedDF_2.count()

  val joinedDF_3 = renameColumns(joinedDF_2, RenameMapping)
  joinedDF_3.cache()
  joinedDF_3.count()

  val joinedDF_4 = filterAndDropColumns(joinedDF_4)
  joinedDF_4.cache()
  joinedDF_4.count()

  ...

当您想要在Spark中强制计算给定的
连接
(或任何非最终的转换)时,您可以在
数据帧上使用简单的
显示
计数
。这种端点将强制计算结果,因为否则根本不可能执行操作

只有在这之后,
数据帧才能有效地存储在缓存中


一旦完成给定的
数据帧
,请毫不犹豫地取消持久化。如果集群需要更多空间进行进一步计算,这将取消数据的持久化。

在调用联接转换之前,需要使用列重新划分数据集

例如:

df1=df1.repartion(col("col1"),col("col2"))
df2=df2.repartion(col("col1"),col("col2"))
joinDF = df1.join(jf2,df1.col("col1").equals(df2.col("col1")) &....)

尝试基于它创建一个新的数据帧。 前任: val dfTest=session.createDataFrame(df.rdd,df.schema).cache()
dfTest.storageLevel.usemory//result应该为true。

您是否可以尝试使用
persist
方法,将存储级别指定为内存和磁盘?我很想知道为什么您需要正好6个数据帧(而不是不确定的数据帧数),或者为什么您需要正好N个操作(并且不是数量不确定的转换)@belka事实上,数据帧和转换操作的数量尚未确定,我仅举一个示例来说明应用程序的需求。@mingzhao.pro我明白了。尝试在每次转换之间强制缓存,然后+缓存,然后在不再需要以前缓存的数据帧时取消持久化。尝试首先只使用2个操作ons和3个数据帧来检查一个最简单的示例,如果这不是您想要的,则进行迭代。count很重,show将只计算数据帧的一部分,真的没有其他选项吗?我担心,当数据量继续增长时,count的使用也会成为一个弱点。对我来说,这是触发操作exp的唯一方法合法。另一个选项是
持久化
,而不是
缓存
,其级别定义为
存储级别。内存和磁盘
或仅
磁盘
(方便时)如果您的群集上没有这么大的缓存。嘿,我休假了两周,我将继续研究这个主题并不断更新。如果您有任何想法,我将很高兴测试。@mingzhao.pro如果这解决了您的问题,请毫不犹豫地接受答案;)我们为什么需要这个?