无法使用案例类从RDD的Row创建数据框

时间:2016-09-01 20:02:53

标签: scala apache-spark apache-spark-sql

使用Spark 2.x,我似乎无法使用由案例类组成的行的RDD来创建Dataframe。

它在Spark 1.6.x上运行良好,但在2.x运行异常时失败:

java.lang.RuntimeException: Timestamp is not a valid external type for schema of struct<seconds:bigint,nanos:int>

之后是来自Catalyst的一堆生成代码。

这是片段(我正在做的简化版):

package main

import org.apache.spark.sql.{SparkSession, Row}
import org.apache.spark.sql.types.{IntegerType, LongType, StructField, StructType}

object Test {

  case class Timestamp(seconds: Long, nanos: Int)

  val TIMESTAMP_TYPE = StructType(List(
    StructField("seconds", LongType, false),
    StructField("nanos", IntegerType, false)
  ))

  val SCHEMA = StructType(List(
    StructField("created_at", TIMESTAMP_TYPE, true)
  ))

  def main(args: Array[String]) {

    val spark = SparkSession.builder().getOrCreate()

    val rowRDD = spark.sparkContext.parallelize(Seq((0L, 0))).map {
      case (seconds: Long, nanos: Int) => {
        Row(Timestamp(seconds, nanos))
      }
    }

    spark.createDataFrame(rowRDD, SCHEMA).show(1)
  }
}

我不确定这是一个Spark bug还是我在文档中遗漏的东西(我知道Spark 2.x引入了运行时行编码验证,也许这是相关的)

非常感谢

1 个答案:

答案 0 :(得分:5)

我不确定它是否是一个错误,但混合动态类型build.gradle,案例类和显式架构没有多大意义。使用Row和架构:

Rows

或案例类:

import collection.mutable._
import collection.JavaConverters._

spark.createDataFrame(ArrayBuffer(Row(Row(0L, 0))).asJava, SCHEMA)

否则你只是两次做同样的工作。

注意

如果您希望明确表示字段可以为空,请使用import spark.implicits._ Seq(Tuple1(Timestamp(0L, 0))).toDF("created_at") 。例如

Options

将生成case class Record(created_at: Option[Timestamp]) case class Timestamp(seconds: Long, nanos: Option[Int]) Seq(Record(Some(Timestamp(0L, Some(0))))).toDF created_at可以为created_at.milliseconds的架构,但如果NULL不是created_at.seconds,则必须设置created_at