0

我有以下情况:

 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")

上面是否优化为仅选择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呢?我在阅读物理计划时是否正确?

4

1 回答 1

1

是的,你没看错。Parquet 文件有两列 -nameage

 Relation[name#48,age#49] parquet

但实际上,只有age将被读取:

 Project [age#49]

但是那么 as 有什么作用呢?

对于优化,如上面的优化,Spark 需要创建一个内部模式。

在某些情况下,比如parquet文件,我们有一个包含带有模式的元数据的页脚,尽管默认情况下 Spark 必须读取所有页脚以合并可能不同的模式。
在其他情况下(csvjson等),如果用户不提供模式,Spark 需要扫描数据并创建它。

我们还需要一些通用容器,它可以让我们访问这些值,我们有一个叫做Row.

Row 是一个通用的行对象,它具有有序的字段集合,可以通过序数/索引(也称为按序数的通用访问)、名称(也称为本机原始访问)或使用 Scala 的模式匹配来访问。

在您的示例中,编写以下代码非常好:

spark.read.parquet("filePath").select("age")

Read 方法返回Dataframe,这实际上只是一个Dataset of Rows.
当我们使用时,as我们正在转换Dataset[Row]到几乎可以是任何案例类的 Dataset[A]地方。A

在我看来,它使代码更简洁、更易读。在使用类似 SQL 的方法时并没有太大区别,但是当我们需要将 map/flatMap 或自定义聚合添加到混合中时,代码将变得更容易理解。

于 2019-08-03T18:15:26.410 回答