从Spark源代码:
/**
* Represents the content of the Dataset as an `RDD` of `T`.
*
* @group basic
* @since 1.6.0
*/
lazy val rdd: RDD[T] = {
val objectType = exprEnc.deserializer.dataType
rddQueryExecution.toRdd.mapPartitions { rows =>
rows.map(_.get(0, objectType).asInstanceOf[T])
}
}
mapPartitions
可能需要很长的时间才能计算出RDD
。因此,这使得诸如
df.rdd.getNumPartitions
非常昂贵。假设DataFrame
是DataSet[Row]
并且DataSet
由RDD
组成,为什么需要重新映射?任何见解都很感激。
答案 0 :(得分:6)
TL; DR 这是因为内部RDD
不是RDD[Row]
。
鉴于DataFrame为
DataSet[Row]
,而DataSet
由RDD组成
这太过简单了。首先DataSet[T]
并不意味着您与T
的容器进行交互。这意味着,如果您使用类似集合的API(通常称为强类型),则内部表示形式将被解码到T
中。
内部表示形式是Tungsten内部使用的一种二进制格式。这种表示形式是内部的,并且有变化的主题,并且太低了,无法在实践中使用。
公开此数据的中间表示形式是InternalRow
-rddQueryExecution.toRDD
实际上是RDD[InternalRow]
。此表示形式(存在不同的实现)仍然公开内部类型,被视为“弱”私有的,因为o.a.s.sql.catalyst
中的所有对象(访问没有明确限制,但未记录API),并且很难交互
在解码中发挥作用的原因以及为什么需要完整的“重新映射”-将内部(通常是不安全的)对象转换为供公共使用的外部类型。
最后,to reiterate是我的上一个语句-调用getNumPartitions
时将不会执行有问题的代码。