编写Spark数据集的最佳方法[U]

时间:2019-07-11 22:44:07

标签: apache-spark apache-spark-sql apache-spark-dataset

好吧,所以我知道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]
}

我设法使这个例子适用于普通的例子,但是需要进一步评估。我想知道是否有替代的方法,也许是内置的方法来实现这样的目标?

0 个答案:

没有答案