Искра рекурсивно исправить круговые ссылки в классе - PullRequest
2 голосов
/ 23 апреля 2019

Моя исходная структура данных содержит собственные ссылки, которые не поддерживаются искрой:

initial.toDF
java.lang.UnsupportedOperationException: cannot have circular references in class, but got the circular reference

Исходная структура данных:

case class FooInitial(bar:String, otherSelf:Option[FooInitial])
val initial = Seq(FooInitial("first", Some(FooInitial("i1", Some(FooInitial("i2", Some(FooInitial("finish", None))))))))

Чтобы исправить это, семантически похожее и желаемое представление может быть:

case class Inner(value:String)
case class Foo(bar:String, otherSelf:Option[Seq[Inner]])
val first = Foo("first", None)
val intermediate1 = Inner("i1")//Foo("i1", None)
val intermediate2 = Inner("i2")//Foo("i2", None)
val finish = Foo("finish", Some(Seq(intermediate1, intermediate2)))
val basic = Seq(first, finish)

basic.foreach(println)
val df = basic.toDF
df.printSchema
df.show
+------+------------+
|   bar|   otherSelf|
+------+------------+
| first|        null|
|finish|[[i1], [i2]]|
+------+------------+

Какой хороший функциональный способ преобразования из начального в другой, не ссылающийся на себя представление

1 Ответ

0 голосов
/ 24 апреля 2019

Это рекурсивно разыменовывает объекты:

class MyCollector {
    val intermediateElems = new ListBuffer[Foo]

    def addElement(initialElement : FooInitial) : MyCollector = {

      intermediateElems += Foo(initialElement.bar, None)
      intermediateElems ++ addIntermediateElement(initialElement.otherSelf, ListBuffer.empty[Foo])
      this
    }

    @tailrec private def addIntermediateElement(intermediate:Option[FooInitial], l:ListBuffer[Foo]) : ListBuffer[Foo] = {

      intermediate match {
        case None => l
        case Some(s) => {
          intermediatePoints += Foo(s.bar + "_inner", None)
          addIntermediateElement(s.otherSelf,intermediatePoints)
        }
      }

    }
  }

  initial.foldLeft(new MyCollector)((myColl,stay)=>myColl.addElement(stay)).intermediatePoints.toArray.foreach(println)

В результате получается список:

Foo(first,None)
Foo(i1_inner,None)
Foo(i2_inner,None)
Foo(finish_inner,None)

, который теперь прекрасно работает для искры.

ПРИМЕЧАНИЕ: это не 1: 1 для того, что я просил изначально, но достаточно хорошо для меня на данный момент.

...