Как создать набор данных из пользовательского класса Person?

Я пытался создать Dataset на Java, поэтому пишу следующий код:

public Dataset createDataset(){
  List<Person> list = new ArrayList<>();
  list.add(new Person("name", 10, 10.0));
  Dataset<Person> dateset = sqlContext.createDataset(list, Encoders.bean(Person.class));
  return dataset;
}

Person класс является внутренним классом.

Однако Spark выдает следующее исключение:

org.apache.spark.sql.AnalysisException: Unable to generate an encoder for inner class `....` without access to the scope that this class was defined in. Try moving this class out of its parent class.;

at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder$$anonfun$2.applyOrElse(ExpressionEncoder.scala:264)
at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder$$anonfun$2.applyOrElse(ExpressionEncoder.scala:260)
at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$3.apply(TreeNode.scala:243)
at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$3.apply(TreeNode.scala:243)
at org.apache.spark.sql.catalyst.trees.CurrentOrigin$.withOrigin(TreeNode.scala:53)
at org.apache.spark.sql.catalyst.trees.TreeNode.transformDown(TreeNode.scala:242)

Как это сделать правильно?


person Mahmoud Hanafy    schedule 23.01.2016    source источник


Ответы (3)


tl;dr (только в оболочке Spark) Определите свои классы дел сначала и, как только они будут определены, используйте их. Использование классов case в приложениях Spark/Scala должно работать.

В 2.0.1 в оболочке Spark вы должны сначала определить классы case и только потом обращаться к ним для создания файла Dataset.

$ ./bin/spark-shell --version
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 2.1.0-SNAPSHOT
      /_/

Using Scala version 2.11.8, Java HotSpot(TM) 64-Bit Server VM, 1.8.0_102
Branch master
Compiled by user jacek on 2016-10-25T04:20:04Z
Revision 483c37c581fedc64b218e294ecde1a7bb4b2af9c
Url https://github.com/apache/spark.git
Type --help for more information.

$ ./bin/spark-shell
scala> :pa
// Entering paste mode (ctrl-D to finish)

case class Person(id: Long)

Seq(Person(0)).toDS // <-- this won't work

// Exiting paste mode, now interpreting.

<console>:15: error: value toDS is not a member of Seq[Person]
       Seq(Person(0)).toDS // <-- it won't work
                      ^
scala> case class Person(id: Long)
defined class Person

scala> // the following implicit conversion *will* work

scala> Seq(Person(0)).toDS
res1: org.apache.spark.sql.Dataset[Person] = [id: bigint]

В 43ebf7a9cbd70d6af75e140a6fc91bf0ffc2b877 в мартовское решение добавлено решение SNAP21st. обойти проблему.

В Scala REPL мне пришлось добавить OuterScopes.addOuterScope(this), а :paste полный фрагмент следующим образом:

scala> :pa
// Entering paste mode (ctrl-D to finish)

import sqlContext.implicits._
case class Token(name: String, productId: Int, score: Double)
val data = Token("aaa", 100, 0.12) ::
  Token("aaa", 200, 0.29) ::
  Token("bbb", 200, 0.53) ::
  Token("bbb", 300, 0.42) :: Nil
org.apache.spark.sql.catalyst.encoders.OuterScopes.addOuterScope(this)
val ds = data.toDS
person Jacek Laskowski    schedule 28.02.2016
comment
Использование Spark Notebook с scala 0.11, добавление org.apache.spark.sql.catalyst.encoders.OuterScopes.addOuterScope(this) после определения класса case и до его использования в кадре данных Команда решает проблему. - person Arjen P. De Vries; 17.03.2016
comment
Я спрашиваю о методе addOuterScope, если вы знаете, почему его нужно добавить, чтобы кодировщики работали правильно. - person eliasah; 25.10.2016
comment
Большое спасибо за обновление. Я спросил вас, потому что я изучал это раньше stackoverflow.com/a/40232936/3415409 - person eliasah; 25.10.2016

Решение состояло в том, чтобы добавить этот фрагмент кода в начало метода:

org.apache.spark.sql.catalyst.encoders.OuterScopes.addOuterScope(this);
person Mahmoud Hanafy    schedule 23.01.2016

Для аналогичной проблемы в scala мое решение состояло в том, чтобы сделать именно так, как предложило AnalysisException. Перемещение класса case из его родительского класса. Например, у меня было что-то вроде ниже в Streaming_Base.scala:

abstract class Streaming_Base {
    case class EventBean(id:String, command:String, recordType:String)
    ...
}

Я изменил это на ниже:

case class EventBean(id:String, command:String, recordType:String)
abstract class Streaming_Base {        
    ...
}
person Debajyoti Pathak    schedule 19.02.2018