火花数据框密封特征类型

Posted

技术标签:

【中文标题】火花数据框密封特征类型【英文标题】:spark dataframe to sealed trait type 【发布时间】:2018-06-19 10:48:06 【问题描述】:

我有一些数据存储为 parquet 文件和与数据模式匹配的案例类。 Spark 可以很好地处理常规产品类型,所以如果我有

case class A(s:String, i:Int)

我可以轻松做到

spark.read.parquet(file).as[A]

但据我了解,Spark 不处理析取类型,所以当我在镶木地板中有枚举时,以前编码为整数,以及像这样的 scala 表示

sealed trait E
case object A extends E
case object B extends E

我做不到

spark.read.parquet(file).as[E]
// java.lang.UnsupportedOperationException: No Encoder found for E

到目前为止是有道理的,但是,可能太天真了,我尝试了

implicit val eEncoder = new org.apache.spark.sql.Encoder[E] 
 def clsTag = ClassTag(classOf[E])
 def schema = StructType(StructField("e", IntegerType, nullable = false)::Nil)

我仍然得到相同的“找不到 E 编码器”:(

此时我的问题是,为什么范围内的隐含缺失? (或不被识别为编码器[E]),即使是这样,这样的接口如何允许我实际解码数据?我仍然需要将值映射到正确的案例对象。

我确实读过a related answer,上面写着“TL;DR 目前没有好的解决方案,鉴于 Spark SQL / Dataset 的实施,在可预见的将来不太可能有这样的解决方案。”但我很难理解为什么自定义编码器无法做到这一点。

【问题讨论】:

【参考方案1】:

但我很难理解为什么自定义编码器无法做到这一点。

两个主要原因:

没有自定义 Encoders 的 API。公开可用的只有“二进制”Kryo 和 Java Encoders,它们会创建无用的(在 DataFrame / Dataset[Row] 的情况下)不支持任何有意义的 SQL / DataFrame 操作的 blob。

这样的代码可以正常工作

import org.apache.spark.sql.Encoders

spark.createDataset(Seq(A, B): Seq[E])(Encoders.kryo[E])

但这只不过是一种好奇心。

DataFrame 是一个商店。在此结构之上编码类型层次结构在技术上是可能的(私有 UserDefinedType API 会这样做),但它很麻烦(因为您必须为所有可能的变体提供存储,例如参见 How to define schema for custom type in Spark SQL?)并且效率低下(通常在 Spark SQL 中,复杂类型在某种程度上是二等公民,许多优化无法通过复杂模式访问,未来可能会发生变化)。

从更广泛的意义上讲,DataFrame API 是有效的关系型(如在 relational algebra 中),元组(关系的主要构建块)在定义上是同质的,因此通过扩展,SQL / DataFrame API 中没有位置,因为异构结构。

【讨论】:

感谢您的回答。真正手头的案例是包含枚举作为其某些字段的案例类。其中 enum 只不过是一个 int 上的名称,所以在简单的情况下,我们不处理异构类型,这个限制非常令人沮丧,因为我们所有的案例类都不可用(不是你的错):)

以上是关于火花数据框密封特征类型的主要内容,如果未能解决你的问题,请参考以下文章

数据类型转换火花数据框列 - pyspark

将多个火花数据框列转换为具有列表类型的单列

在火花数据框中的每一行的地图类型列中按键排序

散列火花数据框的多列

如何从带有火花的数据框中找到最大长度的唯一行?

PySpark:无法创建火花数据框