递归案例类到DataFrame

时间:2016-04-19 19:33:54

标签: apache-spark apache-spark-sql

如何让DataFrame给出一个引用自己的case class?请采取以下措施:

case class TestCase(id: Long, parent: Option[TestCase])

如果我这样做:

val testCases = Seq(TestCase(1L, None), TestCase(2L, Some(TestCase(1L, None)))).toDF

它引发了一个很大的'olde ScalaReflection错误。当然,我可以这样做:

case class TestCase(id: Long, parentId: Option[Long])

但那不是我想要的。

顺便说一句,Avro没有问题编码和解码递归模式。我不认为我在问这个不可能的事。这似乎是处理父子关系的一个非常正常的用例。

更新

我可以手动创建一个模式,但据我所知,我必须通过重复嵌套StructType来硬编码你可以走多远的链。像这样:

val schema = StructType(Array(
  StructField("id", LongType, false),
  StructField("parent", StructType(Array(
    StructField("id", LongType, false),
    StructField("parent", StructType(Array(
      StructField("id", LongType, false),
      StructField("parent", NullType)
    )))
  )))
))

请注意,对于链的最后parent,其类型为NullType。使用上面的模式,以下所有工作:

df.select($"parent")
df.select($"parent.parent")
df.select($"parent.parent.parent")

根据上面的架构,前两个可能会返回null或父级。第三个总是返回null

有趣的是,要为数据框创建Row个对象,我只需要这样做:

val testCaseSeq = Seq[TestCase](...)
val df = sqlContext.createDataFrame(
  sc.parallelize(testCaseSeq.map(tc => Row(tc.id, tc.parent))),
  schema
)

我猜这或多或少有效。我只需要提前弄清楚要支持多少级的父子层次结构。哪种糟透了。但是,任何人都可以比这更好吗?

0 个答案:

没有答案