在Spark数据集中添加ADT列?

问题描述 投票:0回答:1

我想创建一个包含ADT列的数据集。基于以下问题:Encode an ADT / sealed trait hierarchy into Spark DataSet column我知道,有一种使用kryo编码的解决方案,但这并没有真正的帮助。还有另一种解决问题的方法,它更好。让我们定义以下ADT:

sealed case class Animal(sound: String)
object Cat extends Animal("miau")
object Dog extends Animal("wuff") 

并定义一个使用Animal的案例类>

case class Pet(name: String, sound: Animal)

我现在可以轻松地从Pet创建数据集

val ds = List(Pet("Tom", Cat), Pet("Beethoven", Dog)).toDS
ds.show()
+---------+------+
|     name| sound|
+---------+------+
|      Tom|[miau]|
|Beethoven|[wuff]|
+---------+------+

注意,声音

Struct,但是提取元素很简单:
ds.select("name", "sound.*").show()
+---------+-----+
|name     |sound|
+---------+-----+
|Tom      |miau |
|Beethoven|wuff |
+---------+-----+

实际上,这是我要实现的最终结构。我面临两个问题。

  1. 通常,从案例类继承不是一个好主意
  2. 详尽的模式匹配要求默认情况
  3. 问题2的示例:

 def getSound(animal: Animal): String = animal match {
   case Cat => Cat.sound
   case Dog => Dog.sound
   case _ => ""
 }

为了克服问题2,我尽管创建了一个[[sealed abstract class

。我也想把它制作成产品sealed abstract class Animal(sound: String) extends Product case object Cat extends Animal("miau") case object Dog extends Animal("wuff")
现在解决了问题2,并且不再需要任何默认情况。但是我无法从Animal创建数据集。我得到以下异常:java.lang.RuntimeException: Error while encoding: java.lang.RuntimeException: Couldn't find sound on class Animal

我真正想要获得的是获得与Option相同的行为。我们可以创建一个包含可选字段的案例类:

case class Person(name: String, age: Option[Int]) List(Person("Jack", Some(26)), Person("Julia", None)).toDS.show() +-----+----+ | name| age| +-----+----+ | Jack| 26| |Julia|null| +-----+----+

我检查了

Option

的实现,它也是一个密封的抽象类,所以我缺少了什么?选项如何对数据集进行编码?

UPDATE

对不起,用

Option

的最后一部分在这里没有太大意义,因为您需要在其中明确编写要在数据集中最后看到的值。
但是问题仍然存在,如何对具有正确模式匹配的ADT创建的列进行编码。

我想创建一个包含ADT列的数据集。基于这个问题:我知道,将ADT /密封特征层次结构编码到Spark DataSet列中,有一种解决方案,它使用...

scala apache-spark apache-spark-dataset algebraic-data-types apache-spark-encoders
1个回答
1
投票
sealed abstract class Animal(val sound: String) extends Product with Serializable case object Cat extends Animal(sound = "miau") case object Dog extends Animal(sound = "wuff") object Animal { def apply(animal: Animal): String = animal match { case Cat => Cat.sound case Dog => Dog.sound } }

使用这个我可以获得几乎想要的结果:val ds = List(Pet("Tom", Cat), Pet("Beethoven", Dog)).toDS ds.show() +---------+------+ | name| sound| +---------+------+ | Tom|[miau]| |Beethoven|[wuff]| +---------+------+

© www.soinside.com 2019 - 2024. All rights reserved.