Dataset 是特定领域对象的强类型集合,可通过功能或关系操作进行并行转换。当 Dataset 的泛型类型是 Row 时,Dataset 还可以作为 DataFrame。DataFrame 的类型定义如下。
type DataFrame = Dataset[Row]
有了行的数据集合,DataFrame 看起来更像是关系数据库中的表。DataFrame 是专门为了数据科学应用设计,支持从 KB 到 PB 级的数据量。Spark 支持从文本文件、CSV 文件、Oracle 脚本文件、JSON 文件及所有支持 JDBC 的数据源(例如,MySQL 和 Hive)转换为 DataFrame。
ofRows
ofRows 是 Dataset 的伴生对象中提供的方法,用于将逻辑执行计划 LogicalPlan㊟转换为泛型是 Row 的 Dataset(即 DataFrame)。
def ofRows(sparkSession: SparkSession, logicalPlan: LogicalPlan): DataFrame = {
val qe = sparkSession.sessionState.executePlan(logicalPlan)
qe.assertAnalyzed()
new Dataset[Row](sparkSession, qe, RowEncoder(qe.analyzed.schema))
}
select
Dataset 提供了多个重载的 select 方法,以实现类似于 SQL 中的 SELECT 语句的选择功能。Dataset 虽然提供了多个 select 操作的 API,但这些 API 最终都将转换为调用下面展示的 select 方法
@scala.annotation.varargs
def select(cols: Column*): DataFrame = withPlan {
Project(cols.map(_.named), logicalPlan)
}
rdd
rdd 是 Dataset 的属性之一,由于被关键字 lazy 修饰,因此在需要 rdd 的值时才会进行「懒」执行。
lazy val rdd: RDD[T] = {
val objectType = exprEnc.deserializer.dataType
val deserialized = CatalystSerde.deserialize[T](logicalPlan)
sparkSession.sessionState.executePlan(deserialized).toRdd.mapPartitions { rows =>
rows.map(_.get(0, objectType).asInstanceOf[T])
}
}
rdd 的语句块执行的步骤如下。
- SessionState 的 executePlan 方法将逻辑执行计划封装为 QueryExecution。
- QueryExecution 的 toRdd 方法将促使执行物理执行计划,并返回 RDD[InternalRow]。
- 调用 RDD 的 mapPartitions 方法将 RDD 封装为 MapPartitionsRDD。
注意
RDD 的很多方法(如 javaRDD 方法)都会使用 rdd,从而让定义 rdd 的语句块执行。
javaRDD
javaRDD 方法用于将 Dataset 内部的 RDD 转换为 JavaRDD,这样就可以用 JavaRDD 提供的 Java API 来操作底层的 Scala RDD 了,其实现如下。
def toJavaRDD: JavaRDD[T] = rdd.toJavaRDD()
def javaRDD: JavaRDD[T] = toJavaRDD
根据上述代码,javaRDD 方法实际调用了 RDD 的 toJavaRDD 方法