【问题标题】:How to store nested custom objects in Spark Dataset?如何在 Spark 数据集中存储嵌套的自定义对象?
【发布时间】:2021-01-19 05:19:57
【问题描述】:

问题是How to store custom objects in Dataset?的后续问题

Spark 版本:3.0.1

可以实现非嵌套的自定义类型:

import spark.implicits._
import org.apache.spark.sql.{Encoder, Encoders}

class AnObj(val a: Int, val b: String)

implicit val myEncoder: Encoder[AnObj] = Encoders.kryo[AnObj] 

val d = spark.createDataset(Seq(new AnObj(1, "a")))

d.printSchema
root
 |-- value: binary (nullable = true)

但是,如果自定义类型嵌套product 类型(即case class)内,则会出现错误:

java.lang.UnsupportedOperationException:找不到 InnerObj 的编码器

import spark.implicits._
import org.apache.spark.sql.{Encoder, Encoders}

class InnerObj(val a: Int, val b: String)
case class MyObj(val i: Int, val j: InnerObj)

implicit val myEncoder: Encoder[InnerObj] = Encoders.kryo[InnerObj] 

// error
val d = spark.createDataset(Seq(new MyObj(1, new InnerObj(0, "a"))))
// it gives Runtime error: java.lang.UnsupportedOperationException: No Encoder found for InnerObj

我们如何创建带有嵌套自定义类型的Dataset

【问题讨论】:

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


    【解决方案1】:

    为 MyObj 和 InnerObj 添加编码器应该可以正常工作。

      class InnerObj(val a:Int, val b: String)
      case class MyObj(val i: Int, j: InnerObj)
    
      implicit val myEncoder: Encoder[InnerObj] = Encoders.kryo[InnerObj]
      implicit val objEncoder: Encoder[MyObj] = Encoders.kryo[MyObj]
    

    上面的sn -p编译运行正常

    【讨论】:

    • 太尴尬了!我想用import spark.implicits._case class,我不需要为它创建编码器。但似乎只要有嵌套的自定义类型,我仍然需要为case class 创建一个。感谢您的回答
    【解决方案2】:

    除了 sujesh 的另一种解决方案:

    import spark.implicits._
    import org.apache.spark.sql.{Encoder, Encoders}
    
    class InnerObj(val a: Int, val b: String)
    case class MyObj[T](val i: Int, val j: T)
    
    implicit val myEncoder: Encoder[MyObj[InnerObj]] = Encoders.kryo[MyObj[InnerObj]] 
    
    // works
    val d = spark.createDataset(Seq(new MyObj(1, new InnerObj(0, "a"))))
    

    这也说明了内部类型可以从type parameter推导出来的情况和不能推导出来的情况之间的区别。

    前一种情况应该做:

    implicit val myEncoder: Encoder[MyObj[InnerObj]] = Encoders.kryo[MyObj[InnerObj]]
    

    后一种情况应该做:

    implicit val myEncoder1: Encoder[InnerObj] = Encoders.kryo[InnerObj]
    implicit val myEncoder2: Encoder[MyObj] = Encoders.kryo[MyObj]
    

    【讨论】:

    • 更精确。当你有类型类和更多抽象时,这将是一个很好的模式。
    猜你喜欢
    • 1970-01-01
    • 2016-08-07
    • 2011-08-26
    • 1970-01-01
    • 2019-03-18
    • 2011-10-24
    • 2023-03-21
    相关资源
    最近更新 更多