我想创建一个包含 ADT 列的数据集。基于这个问题:Encode an ADT / seal 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]|
+---------+------+
请注意,声音是 a Struct
,但提取元素很简单:
ds.select("name", "sound.*").show()
+---------+-----+
|name |sound|
+---------+-----+
|Tom |miau |
|Beethoven|wuff |
+---------+-----+
实际上这是我想要实现的最终结构。我面临两个问题。
- 通常从案例类继承不是一个好主意
- 详尽的模式匹配要求默认情况
问题 2 的示例:
def getSound(animal: Animal): String = animal match {
case Cat => Cat.sound
case Dog => Dog.sound
case _ => ""
}
为了克服问题 2,我想创建一个密封的抽象类。我也想把它做成产品
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的实现,它也是一个密封的抽象类,所以我错过了什么?数据集的选项是如何编码的?
更新
抱歉, Option的最后一部分在这里没有太大意义,因为您需要在数据集中最后明确地写入您希望看到的值。
但问题仍然存在,我如何使用正确的模式匹配对从 ADT 创建的列进行编码。