Кодировщик Spark kryo ArrayIndexOutOfBoundsException

Я пытаюсь создать набор данных с некоторыми геоданными, используя Spark и Esri. Если Foo имеет только поле Point, это будет работать, но если я добавлю некоторые другие поля помимо Point, я получу ArrayIndexOutOfBoundsException.

import com.esri.core.geometry.Point
import org.apache.spark.sql.{Encoder, Encoders, SQLContext}
import org.apache.spark.{SparkConf, SparkContext}

object Main {

  case class Foo(position: Point, name: String)

  object MyEncoders {
    implicit def PointEncoder: Encoder[Point] = Encoders.kryo[Point]

    implicit def FooEncoder: Encoder[Foo] = Encoders.kryo[Foo]
  }

  def main(args: Array[String]): Unit = {
    val sc = new SparkContext(new SparkConf().setAppName("app").setMaster("local"))
    val sqlContext = new SQLContext(sc)
    import MyEncoders.{FooEncoder, PointEncoder}
    import sqlContext.implicits._
    Seq(new Foo(new Point(0, 0), "bar")).toDS.show
  }
}

Исключение в потоке «main» java.lang.ArrayIndexOutOfBoundsException: 1 в org.apache.spark.sql.execution.Queryable $$ anonfun $ formatString $ 1 $$ anonfun $ apply $ 2.apply (Queryable.scala: 71) в org.apache .spark.sql.execution.Queryable $$ anonfun $ formatString $ 1 $$ anonfun $ apply $ 2.apply (Queryable.scala: 70) в scala.collection.TraversableLike $ WithFilter $$ anonfun $ foreach $ 1.apply (TraversableLike.scala: 772) в scala.collection.mutable.ResizableArray $ class.foreach (ResizableArray.scala: 59) в scala.collection.mutable.ArrayBuffer.foreach (ArrayBuffer.scala: 47) в scala.collection.TraversableLike $ WithFilter.foreach (TraversableLike .scala: 771) в org.apache.spark.sql.execution.Queryable $$ anonfun $ formatString $ 1.apply (Queryable.scala: 70) в org.apache.spark.sql.execution.Queryable $$ anonfun $ formatString $ 1 .apply (Queryable.scala: 69) в scala.collection.mutable.ArraySeq.foreach (ArraySeq.scala: 73) в org.apache.spark.sql.execution.Queryable $ class.formatString (Que ryable.scala: 69) в org.apache.spark.sql.Dataset.formatString (Dataset.scala: 65) в org.apache.spark.sql.Dataset.showString (Dataset.scala: 263) в org.apache.spark .sql.Dataset.show (Dataset.scala: 230) в org.apache.spark.sql.Dataset.show (Dataset.scala: 193) в org.apache.spark.sql.Dataset.show (Dataset.scala: 201 ) в Main $ .main (Main.scala: 24) в Main.main (Main.scala)


person Mehraban    schedule 21.07.2016    source источник


Ответы (1)


Kryo создает кодировщик для сложных типов данных на основе Spark SQL Типы данных. Итак, проверьте результат схемы, которую создает крио:

val enc: Encoder[Foo] = Encoders.kryo[Foo]
println(enc.schema)  // StructType(StructField(value,BinaryType,true))
val numCols = schema.fieldNames.length // 1

Итак, у вас есть данные в одном столбце в наборе данных в двоичном формате. Но странно, почему Spark пытается показать набор данных более чем в одном столбце (и возникает эта ошибка). Чтобы исправить это, обновите версию Spark до 2.0.0.

При использовании Spark 2.0.0 у вас все еще есть проблема с типами данных столбцов. Я надеюсь, что написание схемы вручную сработает, если вы можете написать StructType для класса esri Point:

val schema = StructType(
   Seq(
     StructField("point", StructType(...), true), 
     StructField("name", StringType, true)
   )
)

val rdd = sc.parallelize(Seq(Row(new Point(0,0), "bar")))

sqlContext.createDataFrame(rdd, schema).toDS
person Milad Khajavi    schedule 22.07.2016
comment
Согласно this, я думаю, что было бы лучше не использовать пользовательский StructType. Я буду придерживаться RDD. - person Mehraban; 22.07.2016
comment
Это не должно быть StructType, должно быть BinaryType. - person Mehraban; 22.07.2016
comment
Это зависит от ваших потребностей, нужна ли вам вложенная схема или нет, и насколько сложен класс Point. - person Milad Khajavi; 22.07.2016
comment
Конечно, я могу создать свой собственный класс для Point, но дело в том, что я хочу использовать Point от esri. ;) - person Mehraban; 23.07.2016