如果我想在StructType
中创建DataFrame.schema
(即case class
),有没有办法在不创建DataFrame
的情况下执行此操作?我很容易做到:
case class TestCase(id: Long)
val schema = Seq[TestCase]().toDF.schema
但是,当我想要的只是架构时,实际创建DataFrame
似乎有些过分。
(如果你很好奇,问题背后的原因是我定义了一个UserDefinedAggregateFunction
,并且这样做会覆盖几个返回StructTypes
的方法并使用case类。)
答案 0 :(得分:62)
您可以采用与SQLContext.createDataFrame
相同的方式执行此操作:
import org.apache.spark.sql.catalyst.ScalaReflection
val schema = ScalaReflection.schemaFor[TestCase].dataType.asInstanceOf[StructType]
答案 1 :(得分:53)
我知道这个问题已经差不多一年了,但我遇到过这个问题并且认为其他人也可能想知道我刚学会使用这种方法:
import org.apache.spark.sql.Encoders
val mySchema = Encoders.product[MyCaseClass].schema
答案 2 :(得分:6)
如果有人想为自定义Java bean执行此操作:
ExpressionEncoder.javaBean(Event.class).schema().json()
答案 3 :(得分:1)
与其手动复制用于创建传递给Encoder
的隐式toDF
对象的逻辑,不如直接使用它(或更准确地说,以与{{1}相同的方式隐式使用) }):
toDF
不幸的是,这实际上遇到了与使用// spark: SparkSession
import spark.implicits._
implicitly[Encoder[MyCaseClass]].schema
或org.apache.spark.sql.catalyst
相同的问题,就像其他答案一样:the Encoder
trait是实验性的。
这是如何工作的? Encoders
上的toDF
方法来自Seq
,该方法是通过隐式localSeqToDatasetHolder
创建的通过DatasetHolder
导入。该函数的定义如下:
spark.implicits._
如您所见,它需要一个implicit def localSeqToDatasetHolder[T](s: Seq[T])(implicit arg0: Encoder[T]): DatasetHolder[T]
implicit
参数,对于Encoder[T]
,可以通过newProductEncoder
计算(也可以通过{{1}导入) }。我们可以通过方便性的scala.Predef.implicitly
(默认情况下,因为它来自case class
)来重现此隐式逻辑,以便为案例类获取spark.implicits._
,它将仅返回其请求的隐式参数:
Encoder