Scala 为什么是;找不到数据集中存储的类型的编码器;创建自定义案例类的数据集时?

Scala 为什么是;找不到数据集中存储的类型的编码器;创建自定义案例类的数据集时?,scala,apache-spark,apache-spark-dataset,apache-spark-encoders,Scala,Apache Spark,Apache Spark Dataset,Apache Spark Encoders,Spark 2.0(最终版)和Scala 2.11.8。下面的超级简单代码产生编译错误error:(17,45)找不到数据集中存储的类型的编码器。导入spark.implicits支持基元类型(Int、String等)和产品类型(case类)。\在将来的版本中将添加对序列化其他类型的支持。 import org.apache.spark.sql.SparkSession case class SimpleTuple(id: Int, desc: String) object DatasetT

Spark 2.0(最终版)和Scala 2.11.8。下面的超级简单代码产生编译错误
error:(17,45)找不到数据集中存储的类型的编码器。导入spark.implicits支持基元类型(Int、String等)和产品类型(case类)。\在将来的版本中将添加对序列化其他类型的支持。

import org.apache.spark.sql.SparkSession

case class SimpleTuple(id: Int, desc: String)

object DatasetTest {
  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder.
      master("local")
      .appName("example")
      .getOrCreate()

    val dataset = sparkSession.createDataset(dataList)
  }
}

Spark
数据集
需要
编码器
来存储即将存储的数据类型。对于常见类型(原子、产品类型),有许多预定义的编码器可用,但您必须首先从导入这些编码器才能使其工作:

val sparkSession: SparkSession = ???
import sparkSession.implicits._
val dataset = sparkSession.createDataset(dataList)
或者,您可以直接提供一个显式

import org.apache.spark.sql.{Encoder, Encoders}

val dataset = sparkSession.createDataset(dataList)(Encoders.product[SimpleTuple])
或含蓄

implicit val enc: Encoder[SimpleTuple] = Encoders.product[SimpleTuple]
val dataset = sparkSession.createDataset(dataList)
存储类型的编码器

请注意,
编码器
还为原子类型提供了许多预定义的
编码器
,而对于复杂类型的
编码器
,可以通过派生

进一步阅读:

  • 有关内置编码器未涵盖的自定义对象,请参见
  • 对于
    对象,必须明确提供
    编码器
    ,如中所示
  • 对于调试案例,案例类必须在主类之外定义

Spark
数据集
需要
编码器
用于即将存储的数据类型。对于常见类型(原子、产品类型),有许多预定义的编码器可用,但您必须首先从导入这些编码器才能使其工作:

val sparkSession: SparkSession = ???
import sparkSession.implicits._
val dataset = sparkSession.createDataset(dataList)
或者,您可以直接提供一个显式

import org.apache.spark.sql.{Encoder, Encoders}

val dataset = sparkSession.createDataset(dataList)(Encoders.product[SimpleTuple])
或含蓄

implicit val enc: Encoder[SimpleTuple] = Encoders.product[SimpleTuple]
val dataset = sparkSession.createDataset(dataList)
存储类型的编码器

请注意,
编码器
还为原子类型提供了许多预定义的
编码器
,而对于复杂类型的
编码器
,可以通过派生

进一步阅读:

  • 有关内置编码器未涵盖的自定义对象,请参见
  • 对于
    对象,必须明确提供
    编码器
    ,如中所示
  • 对于调试案例,案例类必须在主类之外定义
对于其他用户(您的是正确的),请注意,
案例类
对象
范围之外定义也很重要。因此:

失败:

object DatasetTest {
  case class SimpleTuple(id: Int, desc: String)

  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()
    val dataset = sparkSession.createDataset(dataList)
  }
}
添加隐式,仍然失败,并出现相同错误:

object DatasetTest {
  case class SimpleTuple(id: Int, desc: String)

  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()

    import sparkSession.implicits._
    val dataset = sparkSession.createDataset(dataList)
  }
}
作品:

case class SimpleTuple(id: Int, desc: String)

object DatasetTest {   
  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()

    import sparkSession.implicits._
    val dataset = sparkSession.createDataset(dataList)
  }
}
下面是相关的bug:,希望它能在Spark 2的下一版本中修复

(编辑:看起来该错误修复程序实际上在Spark 2.0.0中…所以我不确定为什么仍然失败)。

对于其他用户(您的是正确的),请注意,
案例类
对象
范围之外定义也很重要。因此:

失败:

object DatasetTest {
  case class SimpleTuple(id: Int, desc: String)

  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()
    val dataset = sparkSession.createDataset(dataList)
  }
}
添加隐式,仍然失败,并出现相同错误:

object DatasetTest {
  case class SimpleTuple(id: Int, desc: String)

  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()

    import sparkSession.implicits._
    val dataset = sparkSession.createDataset(dataList)
  }
}
作品:

case class SimpleTuple(id: Int, desc: String)

object DatasetTest {   
  val dataList = List(
    SimpleTuple(5, "abc"),
    SimpleTuple(6, "bcd")
  )

  def main(args: Array[String]): Unit = {
    val sparkSession = SparkSession.builder
      .master("local")
      .appName("example")
      .getOrCreate()

    import sparkSession.implicits._
    val dataset = sparkSession.createDataset(dataList)
  }
}
下面是相关的bug:,希望它能在Spark 2的下一版本中修复


(编辑:看起来该错误修复实际上在Spark 2.0.0中…所以我不确定为什么仍然失败)。

我想用我自己问题的答案澄清一下,如果目标是定义一个简单的文本SparkData框架,而不是使用Scala元组和隐式转换,那么更简单的方法是直接使用Spark API,如下所示:

  import org.apache.spark.sql._
  import org.apache.spark.sql.types._
  import scala.collection.JavaConverters._

  val simpleSchema = StructType(
    StructField("a", StringType) ::
    StructField("b", IntegerType) ::
    StructField("c", IntegerType) ::
    StructField("d", IntegerType) ::
    StructField("e", IntegerType) :: Nil)

  val data = List(
    Row("001", 1, 0, 3, 4),
    Row("001", 3, 4, 1, 7),
    Row("001", null, 0, 6, 4),
    Row("003", 1, 4, 5, 7),
    Row("003", 5, 4, null, 2),
    Row("003", 4, null, 9, 2),
    Row("003", 2, 3, 0, 1)
  )

  val df = spark.createDataFrame(data.asJava, simpleSchema)

我想通过回答我自己的问题来澄清一下,如果目标是定义一个简单的文本SparkData框架,而不是使用Scala元组和隐式转换,那么更简单的方法是直接使用Spark API,如下所示:

  import org.apache.spark.sql._
  import org.apache.spark.sql.types._
  import scala.collection.JavaConverters._

  val simpleSchema = StructType(
    StructField("a", StringType) ::
    StructField("b", IntegerType) ::
    StructField("c", IntegerType) ::
    StructField("d", IntegerType) ::
    StructField("e", IntegerType) :: Nil)

  val data = List(
    Row("001", 1, 0, 3, 4),
    Row("001", 3, 4, 1, 7),
    Row("001", null, 0, 6, 4),
    Row("003", 1, 4, 5, 7),
    Row("003", 5, 4, null, 2),
    Row("003", 4, null, 9, 2),
    Row("003", 2, 3, 0, 1)
  )

  val df = spark.createDataFrame(data.asJava, simpleSchema)

也许这对scala开发人员来说是显而易见的,但我知道的spark比scala多。。。为什么使用<代码> =???/代码> OK,或者更好地实际上声明它?@ DangyBoWorksMsf>代码>??/代码>是-换句话说,根据您的要求填充空白。这对Scala开发人员来说是显而易见的,但我知道Scala和Scala的更多火花…为什么使用<代码> =???/代码> OK,或者更好地实际上声明它?@ DangyBoWorksMsf>代码>??/代码>是-换句话说,根据您的要求填充空白。山羊是创建数据集,而不是数据文件。山羊是创建数据集,而不是数据文件。但是,在SARK 2.4中,这似乎仍然是一个问题。非常重要的
案例类是在对象范围之外定义的。
谢谢!对于spark 3.0.1,它仍然失败,并且案例类需要在对象范围之外。这似乎仍然是spark 2.4为我工作的一个问题!非常重要的
案例类是在对象范围之外定义的。
谢谢!对于spark 3.0.1,它仍然失败,并且案例类需要在对象范围之外。