在“DataFrame”,“RDD”和之后转换的性能影响是什么?

时间:2016-05-07 12:23:05

标签: scala apache-spark

虽然我的第一直觉是将DataFrames用于所有事情,但这是不可能的 - 某些操作显然更容易和/或更好地执行RDD操作,更不用说确定了像GraphX这样的API仅适用于RDDs

这些天我似乎花了很多时间在DataFramesRDDs之间来回转换 - 那么性能如何?拿RDD.checkpoint - 那里没有DataFrame等价物,所以当我这样做时会发生什么:

val df = Seq((1,2),(3,4)).toDF("key","value")
val rdd = df.rdd.map(...)
val newDf = rdd.map(r => (r.getInt(0), r.getInt(1))).toDF("key","value")

显然,这是一个非常小的例子,但是很高兴知道转换中场景背后会发生什么。

1 个答案:

答案 0 :(得分:3)

让我们先看看df.rdd。这被定义为:

lazy val rdd: RDD[Row] = {
  // use a local variable to make sure the map closure doesn't capture the whole DataFrame
  val schema = this.schema
  queryExecution.toRdd.mapPartitions { rows =>
    val converter = CatalystTypeConverters.createToScalaConverter(schema)
    rows.map(converter(_).asInstanceOf[Row])
  }
}

首先,它运行queryExecution.toRdd,它基本上根据用于构建DataFrame的运算符准备执行计划,并计算表示计划结果的RDD[InternalRow]

接下来,该RDD的这些InternalRow(仅供内部使用)将映射到普通Row。每行需要以下内容:

override def toScala(row: InternalRow): Row = {
  if (row == null) {
    null
  } else {
    val ar = new Array[Any](row.numFields)
    var idx = 0
    while (idx < row.numFields) {
      ar(idx) = converters(idx).toScala(row, idx)
      idx += 1
    }
    new GenericRowWithSchema(ar, structType)
  }
}

所以它遍历所有元素,将它们转换为'scala'空间(来自Catalyst空间),并用它们创建最后一行。 toDf几乎可以反过来做这些事情。

这一切确实会对您的表现产生一些影响。多少取决于这些操作与您使用数据执行的操作相比的复杂程度。然而,更大的可能影响是Spark的Catalyst优化器只能优化RDD转换之间的操作,而不是优化整个执行计划。看看哪些操作有问题会很有趣,我发现大多数事情都可以使用基本表达式或UDF来完成。使用仅适用于RDD的模块是一个非常有效的用例!