0

在我的 spark 工作中,我必须对 2 个用例的多列进行转换:

  • 铸柱

在我的个人用例中,我在 150 列的 Df 上使用它

  def castColumns(inputDf: DataFrame, columnsDefs: Array[(String, DataType)]): DataFrame = {
    columnsDefs.foldLeft(inputDf) {
      (acc, col) => acc.withColumn(col._1, inputDf(col._1).cast(col._2))
    }
  }
  • 转型

在我的个人用例中,我使用它来执行计算 n 多列以创建 n 新列(1 个输入列用于 1 个输出列,n 次)

    ListOfCol.foldLeft(dataFrame) {
      (tmpDf, m) => 
          tmpDf.withColumn(addSuffixToCol(m), UDF(m))
    }

如您所见,我使用 FoldLeft 方法和 withColumn。但是我最近在文档中发现,多次使用withColumn并不是那么好:

此方法在内部引入了投影。因此,多次调用它,例如,通过循环以添加多个列可能会生成大计划,这可能会导致性能问题甚至 StackOverflowException。为避免这种情况,请同时对多列使用 select。

我还发现foldleft减速会激发应用程序,因为每次迭代都会执行完整的计划分析。我认为这是真的,因为我在代码中添加了 foldleft,我的 spark 开始工作需要比以前更多的时间。

在多列上应用转换时有好的做法吗?

Spark 版本:2.2 语言:Scala

4

1 回答 1

0

在铸造的情况下,您可以通过以下方式实现您正在寻找的东西:

val df: DataFrame = ???
val cols = Array(("a", StringType), ("b", BooleanType), ("c", LongType)).map(c => col(c._1).cast(c._2))
val renamed = df.select(cols:_*)

它使用采用s集合的方法select(cols: Column*): DataFrameSpark 2.2 文档Column) 。变量上的映射cols创建列表达式。

在转换的情况下,我并不完全清楚你在做什么,但可以应用类似的逻辑。我从您的示例中对类型签名做出了一些最佳猜测:

def addSuffixToCol(c: Column): String = ???
def UDF(c: Column): Column = ???
val ListOfCol: List[Column] = ???
val dataFrame: DataFrame = ???
dataFrame.select(ListOfCol.map(c => UDF(c).as(addSuffixToCol(c))):_*)

如上所述,我们在ListOfCol用于从中选择的列上应用转换dataFrame

如果要包含其他列,请将它们添加到 select 语句中,例如:

dataFrame.select(col("foo"), col("bar"), ListOfCol.map(c => UDF(c).as(addSuffixToCol(c))):_*)
于 2021-11-02T08:26:42.143 回答