Dataset 和 DataFrame 的区别
DataFrame 就是 Dataset
根据前面的内容, 可以得到如下信息
所以这件事就比较蹊跷了, 两个这么相近的东西为什么会同时出现在 SparkSQL 中呢?
确实, 这两个组件是同一个东西, DataFrame 是 Dataset 的一种特殊情况, 也就是说 DataFrame 是 Dataset[Row] 的别名
DataFrame 和 Dataset 所表达的语义不同
@Test
def dataframe3():Unit = {
val spark = SparkSession.builder()
.master("local[6]")
.appName("dataframe3")
.getOrCreate()
import spark.implicits._
val personList = Seq(Person("zhangsan", 15), Person("lisi", 20))
// DataFrame 是弱类型的
val df:DataFrame = personList.toDF()
// Dataset 是强类型
val ds:Dataset[Person] = personList.toDS()
}
case class Person(name: String, age: Int)
第三点: DataFrame 的操作方式和 Dataset 是一样的, 但是对于强类型操作而言, 它们处理的类型不同
DataFrame
在进行强类型操作时候,例如map
算子,其所处理的据类型永远是Row
df.map((row: Row) => Row(row.get(0), row.getAs[Int](1) * 2))(RowEncoder.apply(df.schema))show()
但是对于Dataset
来讲,其中是什么类型,它就处理什么类型
ds.map((person: Person) => Person(person.name, person.age * 2)).show()
全代码
@Test
def dataframe4(): Unit = {
val spark = SparkSession.builder()
.master("local[6]")
.appName("dataframe4")
.getOrCreate()
import spark.implicits._
val personList = Seq(Person("zhangsan", 15), Person("lisi", 20))
// DataFrame 是弱类型的
val df: DataFrame = personList.toDF()
// DataFrame 永远操作Row对象
df.map((row: Row) => Row(row.get(0), row.getAs[Int](1) * 2))(RowEncoder.apply(df.schema))
.show()
// Dataset 是强类型
val ds: Dataset[Person] = personList.toDS()
// Dataset 里面存放的是什么对象就操作什么对象,这里是 Person
ds.map((person: Person) => Person(person.name, person.age * 2))
.show()
}
第四点: DataFrame 只能做到运行时类型检查, Dataset 能做到编译和运行时都有类型检查
// DataFrame所代表的弱类型操作是编译时不安全,运行时类型安全
df.groupBy("name, school")
// Dataset所代表的操作是类型安全的,编译时安全的
ds.filter(person => person.school) //这行代码明显报错, 无法通过编译
Row 对象的操作
Row 是什么?
Row 对象表示的是一个 行
Row 的操作类似于 Scala 中的 Map 数据类型
@Test
def row(): Unit = {
// 1. Row 如何创建,它是什么
// row 对象必须配合 Schema 对象才会有列名
val p = Person("zhangsan", 15)
val row =Row("zhangsan", 15)
// 2. 如何从 Row 中获取数据
row.getString(0)
row.getInt(1)
// 3. Row 也是样例类
row match {
caseRow(name, age) =>println(name, age)
}
}
case class Person(name: String, age: Int)
DataFrame 和 Dataset 之间可以非常简单的相互转换
case class Person(name:String,age:Int)
val spark = SparkSession.builder()
.appName("df_ds")
.master("local[6]")
.getOrCreate()
import spark.implicits._
val df: DataFrame = Seq(Person("zhangsan", 15), Person("lisi", 15)).toDF()
val ds_fdf: Dataset[Person] = df.as[Person]
val ds: Dataset[Person] = Seq(Person("zhangsan", 15), Person("lisi", 15)).toDS()
val df_fds: DataFrame = ds.toDF()
总结