将数据框投射到数据集后 select 是否优化?
Is a select after casting a data frame to dataset optimized?
我有以下场景:
case class A(name:String,age:Int)
val df = List(A("s",2)).toDF
df.write.parquet("filePath")
val result = spark.read.parquet("filePath").as[A].select("age")
以上是否仅针对 select age
进行了优化?看到 result.explain
我看到以下
'Project [unresolvedalias('age, None)]
+- Relation[name#48,age#49] parquet
== Analyzed Logical Plan ==
age: int
Project [age#49]
+- Relation[name#48,age#49] parquet
== Optimized Logical Plan ==
Project [age#49]
+- Relation[name#48,age#49] parquet
== Physical Plan ==
*(1) FileScan parquet [age#49] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/Volumes/Unix/workplace/Reconciliation/src/TFSReconciliationCore/~/Downloa..., PartitionFilters: [], PushedFilters: [], ReadSchema: struct<age:int>
好像只读了age
。但是 as
有什么用呢?我阅读物理计划是否正确?
是的,你没看错。 Parquet 文件有两列 - name
和 age
:
Relation[name#48,age#49] parquet
但实际上只有age
会被读取:
Project [age#49]
But then what purpose does as serve?
对于像上面那样的优化,Spark 需要创建一个内部模式。
在某些情况下,例如 parquet
文件,我们有一个页脚包含带有架构的元数据,但默认情况下 Spark 必须读取所有页脚以合并(可能)不同的架构。
在其他情况下(csv
、json
等),如果用户不提供模式,Spark 需要扫描数据并创建它。
我们还需要一些通用容器来访问这些值,我们有一个名为 Row
的容器。
Row is a generic row object with an ordered collection of fields
that can be accessed by an ordinal / an index (aka generic access by
ordinal), a name (aka native primitive access) or using Scala's
pattern matching.
在您的示例中,编写以下代码完全没问题:
spark.read.parquet("filePath").select("age")
读取方法returnsDataframe
,其实就是一个Dataset of Rows
.
当我们使用 as
时,我们将 Dataset[Row]
转换为 Dataset[A]
,其中 A
几乎可以是任何情况 - class。
在我看来,它使代码更清晰、更易读。使用类似 SQL 的方法并没有太大区别,但是当我们需要添加 map/flatMap 或自定义聚合时,代码将变得更容易理解。
我有以下场景:
case class A(name:String,age:Int)
val df = List(A("s",2)).toDF
df.write.parquet("filePath")
val result = spark.read.parquet("filePath").as[A].select("age")
以上是否仅针对 select age
进行了优化?看到 result.explain
我看到以下
'Project [unresolvedalias('age, None)]
+- Relation[name#48,age#49] parquet
== Analyzed Logical Plan ==
age: int
Project [age#49]
+- Relation[name#48,age#49] parquet
== Optimized Logical Plan ==
Project [age#49]
+- Relation[name#48,age#49] parquet
== Physical Plan ==
*(1) FileScan parquet [age#49] Batched: true, Format: Parquet, Location: InMemoryFileIndex[file:/Volumes/Unix/workplace/Reconciliation/src/TFSReconciliationCore/~/Downloa..., PartitionFilters: [], PushedFilters: [], ReadSchema: struct<age:int>
好像只读了age
。但是 as
有什么用呢?我阅读物理计划是否正确?
是的,你没看错。 Parquet 文件有两列 - name
和 age
:
Relation[name#48,age#49] parquet
但实际上只有age
会被读取:
Project [age#49]
But then what purpose does as serve?
对于像上面那样的优化,Spark 需要创建一个内部模式。
在某些情况下,例如 parquet
文件,我们有一个页脚包含带有架构的元数据,但默认情况下 Spark 必须读取所有页脚以合并(可能)不同的架构。
在其他情况下(csv
、json
等),如果用户不提供模式,Spark 需要扫描数据并创建它。
我们还需要一些通用容器来访问这些值,我们有一个名为 Row
的容器。
Row is a generic row object with an ordered collection of fields that can be accessed by an ordinal / an index (aka generic access by ordinal), a name (aka native primitive access) or using Scala's pattern matching.
在您的示例中,编写以下代码完全没问题:
spark.read.parquet("filePath").select("age")
读取方法returnsDataframe
,其实就是一个Dataset of Rows
.
当我们使用 as
时,我们将 Dataset[Row]
转换为 Dataset[A]
,其中 A
几乎可以是任何情况 - class。
在我看来,它使代码更清晰、更易读。使用类似 SQL 的方法并没有太大区别,但是当我们需要添加 map/flatMap 或自定义聚合时,代码将变得更容易理解。