好吧,所以我知道Dataset.as[U]
只是更改了类型化操作的数据框视图。
如本例所示:
case class One(one: Int)
val df = Seq(
(1,2,3),
(11,22,33),
(111,222,333)
).toDF("one", "two", "thre")
val ds : Dataset[One] = df.as[One]
ds.show
打印
+----+----+-----+
| one| two|three|
+----+----+-----+
| 1| 2| 3|
| 11| 22| 33|
| 111| 222| 333|
+----+----+-----+
这是完全可以的,并且在大多数时候都对我有利。但是现在我需要将ds
写入磁盘,并且仅写入one
列。
要强制执行架构,我可以做
.map(x => x)
,因为这是类型化操作,所以案例类架构将生效。此操作还导致Dataset[One]
,但基础数据减少到列one
。看看执行计划似乎太昂贵了
== Physical Plan ==
*SerializeFromObject [assertnotnull(input[0, $line2012488405320.$read$$iw$$iw$One, true]).one AS one#9408]
+- *MapElements <function1>, obj#9407: $line2012488405320.$read$$iw$$iw$One
+- *DeserializeToObject newInstance(class $line2012488405320.$read$$iw$$iw$One), obj#9406: $line2012488405320.$read$$iw$$iw$One
+- LocalTableScan [one#9391]
要实现的替代实现方式是什么
ds.show
+----+
| one|
+----+
| 1|
| 11|
| 111|
+----+
更新1
我当时正在考虑一种普遍的解决方案。也许符合这些原则?:
def caseClassAccessorNames[T <: Product](implicit tag: TypeTag[T]) = {
typeOf[T]
.members
.collect {
case m: MethodSymbol if m.isCaseAccessor => m.name
}
.map(m => m.toString)
}
def project[T <: Product](ds: Dataset[T])(implicit tag: TypeTag[T]): Dataset[T] = {
import ds.sparkSession.implicits._
val columnsOfT: Seq[Column] =
caseClassAccessorNames
.map(col)(scala.collection.breakOut)
val t: DataFrame = ds.select(columnsOfT: _*)
t.as[T]
}
我设法使这个例子适用于普通的例子,但是需要进一步评估。我想知道是否有替代的方法,也许是内置的方法来实现这样的目标?