通过createDataFrame将带有Array [String]的RDD转换为DF时出现SPARK Scala错误

时间:2018-09-30 12:09:37

标签: apache-spark

以下操作正常:

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

val df = sc.parallelize(Seq((1.0, 2.0), (0.0, -1.0), (3.0, 4.0), (6.0, -2.3))).toDF("x", "y")
val newSchema = StructType(df.schema.fields ++ Array(StructField("rowid", LongType, false)))

val rddWithId = df.rdd.zipWithIndex
val dfZippedWithId =  spark.createDataFrame(rddWithId.map{ case (row, index) => Row.fromSeq(row.toSeq ++ Array(index))}, newSchema)

此结构:

rddWithZipId: org.apache.spark.rdd.RDD[((String, Int, Array[String]), Long)] = ZippedWithIndexRDD[149] at zipWithIndex at command-2467674133341972:32
当我做与先前示例完全相同的操作时,

会产生错误。唯一的区别是Array [String]。

产生的错误是:

notebook:45: error: value toSeq is not a member of (String, Int, Array[String])
val dfPosts =  spark.createDataFrame(rddWithZipId.map{ case (row, index) => Row.fromSeq(row.toSeq ++ Array(index))}, newSchema)

环顾四周,我看不到为什么这行不通。我注意到,即使我在RDD中看到4个类型/元素,也可以观察到Row被视为1个结构。

有什么想法吗?还有其他可能的方法,但是我不明白为什么第一个示例有效而第二个示例无效? Array [String]似乎是罪魁祸首。实际上必须如此,但是如何解决呢?

只需这样做:

val dfPosts =  rddWithZipId.toDF()

按如下所示返回嵌套模式,所以可能是这样,但是尽管如此,问题依旧。嵌套结构意味着我可以实现我想做的事情,这不是问题。

root
  |-- _1: struct (nullable = true)
  |    |-- _1: string (nullable = true)
  |    |-- _2: integer (nullable = false)
  |    |-- _3: array (nullable = true)
  |    |    |-- element: string (containsNull = true)
  |-- _2: long (nullable = false)

我认为需要以某种方式定义嵌套结构。

谢谢。

1 个答案:

答案 0 :(得分:0)

  

还有其他可能的方法,但是我不明白为什么第一个示例有效而第二个示例无效? Array [String]似乎是罪魁祸首。

与第一个元素的内容无关。这都是关于类型的。如果您查看类型rddWithId

RDD[(Row, Long)]

第二个结构是

RDD[((String, Int, Array[String]), Long)]

因此,在第一种情况下,_1是提供org.apache.spark.sql.Row方法的toSeq,而在第二种情况下,_1Tuple3[_, _, _],它没有提供这种方法方法。

如果要使其正常运行

Row.fromSeq(row.toSeq ++ Array(index))

替换

Row.fromSeq(("a", 1, Array("foo")).productIterator.toSeq ++ Array(index))

或更好(为什么要为每个呼叫初始化额外的Array?)

Row.fromSeq(("a", 1, Array("foo")).productIterator.toSeq :+ index)