从案例类生成Spark StructType/Schema

Dav*_*fin 47 apache-spark apache-spark-sql

如果我想创建一个StructType(即a DataFrame.schema)a case class,是否有办法在不创建的情况下创建DataFrame?我可以轻松地做到:

case class TestCase(id: Long)
val schema = Seq[TestCase]().toDF.schema
Run Code Online (Sandbox Code Playgroud)

但实际创建一个DataFrame我想要的只是模式似乎有点过分.

(如果你很好奇,问题背后的原因是我正在定义一个UserDefinedAggregateFunction,并且这样做会覆盖一些返回的方法,StructTypes并使用case类.)

Tza*_*har 71

你可以这样做SQLContext.createDataFrame:

import org.apache.spark.sql.catalyst.ScalaReflection
val schema = ScalaReflection.schemaFor[TestCase].dataType.asInstanceOf[StructType]
Run Code Online (Sandbox Code Playgroud)

  • 我只是为了简洁而喜欢`toDF`版本 (2认同)

小智 61

我知道这个问题差不多已经有一年了,但是我发现它并认为其他人也可能想知道我刚学会使用这种方法:

import org.apache.spark.sql.Encoders
val mySchema = Encoders.product[MyCaseClass].schema
Run Code Online (Sandbox Code Playgroud)

  • 请注意-编码器对象带有@Experimental批注标记:“实验性的面向用户的API。实验性的API可能会在次要版本的Spark中更改或删除,或者被用作一流的Spark API。” 发现这一点是为了找出不同方法的利弊(当前答案与公认答案)。 (2认同)

Art*_*Art 6

如果有人想为自定义Java bean执行此操作:

ExpressionEncoder.javaBean(Event.class).schema().json()
Run Code Online (Sandbox Code Playgroud)

  • 还有```Encoders.bean(Event.class).schema()```我认为它也是一样的. (2认同)

huo*_*uon 5

无需手动复制用于创建Encoder传递给的隐式对象的逻辑toDF,您可以直接使用它(或者,更准确地说,以与 相同的方式隐式使用toDF):

// spark: SparkSession

import spark.implicits._

implicitly[Encoder[MyCaseClass]].schema
Run Code Online (Sandbox Code Playgroud)

不幸的是,这实际上是从同一个问题的困扰如使用org.apache.spark.sql.catalystEncoders作为其他答案:Encoder特征是实验性的。

这是如何运作的?toDF方法对Seq来自一个DatasetHolder,其经由隐式创建localSeqToDatasetHolder经由进口spark.implicits._。该函数定义如下:

implicit def localSeqToDatasetHolder[T](s: Seq[T])(implicit arg0: Encoder[T]): DatasetHolder[T]
Run Code Online (Sandbox Code Playgroud)

如您所见,它接受一个implicit Encoder[T]参数,对于 a case class,可以通过newProductEncoder(也可以通过导入spark.implicits._)来计算。我们可以Encoder通过方便scala.Predef.implicitly(默认情况下在范围内,因为它来自 from Predef)来重现这个隐式逻辑来为我们的案例类获取 an ,它只会返回其请求的隐式参数:

def implicitly[T](implicit e: T): T
Run Code Online (Sandbox Code Playgroud)