Apache Spark SQL:如何优化数据帧的链式联接

时间:2019-04-12 12:30:55

标签: scala apache-spark join

我必须在原理数据帧和几个参考数据帧之间进行左联接,因此需要进行链联接计算。而且我想知道如何使该操作高效且可扩展。

方法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来说太重了,对我的应用程序没用,但是我不知道如何通过有效的 action 触发联接计算。实际上,这种行动就是对这个问题的答案。

  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()

  ...

3 个答案:

答案 0 :(得分:2)

当您要在Spark中强制计算给定的join(或任何非最终的转换)时,可以在{{上使用简单的showcount 1}}。这种终点将迫使结果计算,因为否则根本无法执行该动作。

只有这样,您的DataFrame才会有效地存储在缓存中。

完成给定的DataFrame后,请不要犹豫。如果您的集群需要更多空间来进行进一步的计算,这将使您的数据失去持久性。

答案 1 :(得分:0)

在调用联接转换之前,需要用列对数据集重新分区。

示例:

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")) &....)

答案 2 :(得分:0)

尝试基于它创建一个新的数据框。 例如: val dfTest = session.createDataFrame(df.rdd,df.schema).cache() dfTest .storageLevel.useMemory //结果应该为true。