Scala 将复杂列追加到Spark数据帧

Scala 将复杂列追加到Spark数据帧,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我正在尝试使用下面的代码将包含列表[注释]的列添加到Spark数据框中(我已重新格式化了所有内容,以便可以通过直接复制和粘贴来复制) 但是,运行此代码时出现错误 Caused by: java.lang.RuntimeException: Annotation is not a valid external type for schema of struct<field1:string,field2:string,field3:int,field4:float,field5:int,fie

我正在尝试使用下面的代码将包含
列表[注释]
的列添加到Spark数据框中(我已重新格式化了所有内容,以便可以通过直接复制和粘贴来复制)

但是,运行此代码时出现错误

Caused by: java.lang.RuntimeException: Annotation is not a valid external type for schema of struct<field1:string,field2:string,field3:int,field4:float,field5:int,field6:array<struct<fieldA:string,fieldB:string,fieldC:string,fieldD:string,fieldE:string>>>
编辑2:我对这个问题做了进一步的分析。遗憾的是,我没有直接从case类创建数据帧的选项,这就是为什么我试图使用ScalaReflection将其镜像为一个结构。在本例中,我并没有改变以前的模式,只是尝试从包含case类列表的行的RDD创建一个数据帧。Spark在1.6中遇到了一个问题,它会影响结构数组的解析,结构数组可能是空的,也可能是空的,我想知道这些数组是否是链接的

val spark = SparkSession.builder().master("local[*]").getOrCreate()
    val annotationSchema = ScalaReflection.schemaFor[Annotation].dataType.asInstanceOf[StructType]
    val annotation       = Annotation("1", "2", 1, .5, 1, List(Mapping("a", "b", "c", "d", "e")))
    val testRDD = spark.sparkContext.parallelize(List(List(annotation))).map(x => Row(x))
    val testSchema = StructType(
      Array(StructField("annotations", ArrayType(annotationSchema), false)
    ))
spark.createDataFrame(testRDD, testSchema).show

如果您想在现有数据帧中添加一个复杂列,那么下面的解决方案应该适合您。

val df = List(1).toDF
val annotation = sc.parallelize(List(Annotation("1", "2", 1, .5f, 1, List(Mapping("a", "b", "c", "d", "e")))))
val newDF = df.rdd.zip(annotation).map(x => Merged(x._1.get(0).asInstanceOf[Int], x._2)).toDF
newDF.printSchema
newDF.show(false)
应该给你什么

root
 |-- value: integer (nullable = false)
 |-- annotations: struct (nullable = true)
 |    |-- field1: string (nullable = true)
 |    |-- field2: string (nullable = true)
 |    |-- field3: integer (nullable = false)
 |    |-- field4: float (nullable = false)
 |    |-- field5: integer (nullable = false)
 |    |-- field6: array (nullable = true)
 |    |    |-- element: struct (containsNull = true)
 |    |    |    |-- fieldA: string (nullable = true)
 |    |    |    |-- fieldB: string (nullable = true)
 |    |    |    |-- fieldC: string (nullable = true)
 |    |    |    |-- fieldD: string (nullable = true)
 |    |    |    |-- fieldE: string (nullable = true)

+-----+---------------------------------------+
|value|annotations                            |
+-----+---------------------------------------+
|1    |[1,2,1,0.5,1,WrappedArray([a,b,c,d,e])]|
+-----+---------------------------------------+
使用的案例类与您创建的
合并
案例类相同


使用案例类时,我们不需要定义模式。使用case类和sqlContext.createDataFrame创建列名的过程是不同的。

很可能与模式无关<代码>顺序(注d)。toString看起来像一个明显的罪犯。不幸的是,缺乏/⇒ 投票关闭.Hmm,在不生成任何注释的情况下尝试了它,而只是创建了
Annotation
类的实例,并以类似的方式将其附加到数据帧。收到相同的错误,表明它可能不是map/mappartitions中的任何内容,而是架构本身。重新格式化了所有内容,以便可以在不需要任何其他代码的情况下进行复制。这是一个完全不同的问题,与前一个问题无关(也不解决前一个问题)。不能混合使用外部表示和内部表示。如果要使用
所有
结构
值必须是
。否则-所有值都必须用外部类型(
Product
types for
struct
)表示。不幸的是,这正是我以前遇到的问题。在此之前,我有一个
generateAnnotations
函数,它生成了
List[Annotation]
。然后,我尝试将其附加到原始数据帧,方法是获取其模式并使用
annotationStruct
对其进行修改。我已经分别验证了
seq(notesInd).toString
不是问题的根源,因此我删除了所有分散注意力的代码,只留下了一个我正在处理的问题的核心示例。你能详细说明你所说的混合表示法是什么意思吗?当然,从类型为
List[Annotation]
的RDD创建数据帧是可能的。接受这一点,因为它解决了上述问题-谢谢Ramesh。我应该指出,Edit2中概述的场景仍然不起作用,但这可能是Spark本身的问题。我想问题是Annotation是一个由case类创建的对象,定义了模式,在createDataFrame中使用时无法转换为structType。谢谢你接受
val df = List(1).toDF
val annotation = sc.parallelize(List(Annotation("1", "2", 1, .5f, 1, List(Mapping("a", "b", "c", "d", "e")))))
val newDF = df.rdd.zip(annotation).map(x => Merged(x._1.get(0).asInstanceOf[Int], x._2)).toDF
newDF.printSchema
newDF.show(false)
root
 |-- value: integer (nullable = false)
 |-- annotations: struct (nullable = true)
 |    |-- field1: string (nullable = true)
 |    |-- field2: string (nullable = true)
 |    |-- field3: integer (nullable = false)
 |    |-- field4: float (nullable = false)
 |    |-- field5: integer (nullable = false)
 |    |-- field6: array (nullable = true)
 |    |    |-- element: struct (containsNull = true)
 |    |    |    |-- fieldA: string (nullable = true)
 |    |    |    |-- fieldB: string (nullable = true)
 |    |    |    |-- fieldC: string (nullable = true)
 |    |    |    |-- fieldD: string (nullable = true)
 |    |    |    |-- fieldE: string (nullable = true)

+-----+---------------------------------------+
|value|annotations                            |
+-----+---------------------------------------+
|1    |[1,2,1,0.5,1,WrappedArray([a,b,c,d,e])]|
+-----+---------------------------------------+
case class Merged(value : Int, annotations: Annotation)
case class Annotation(field1: String, field2: String, field3: Int, field4: Float, field5: Int, field6: List[Mapping])
case class Mapping(fieldA: String, fieldB: String, fieldC: String, fieldD: String, fieldE: String)