如何更新Spark DataFrame的架构(在我的情况下,Dataset.withColumn和Datset.select之类的方法不起作用)

时间:2018-07-19 17:16:36

标签: scala apache-spark dataframe

我的问题是,是否有任何方法无需显式调用SparkSession.createDataFrame(dataframe.rdd, newSchema)即可更新DataFrame的架构。

详细信息如下。

我有一个原始的Spark DataFrame,其架构如下:

root
 |-- column11: string (nullable = true)
 |-- column12: string (nullable = true)
 |-- column13: string (nullable = true)
 |-- column14: string (nullable = true)
 |-- column15: string (nullable = true)
 |-- column16: string (nullable = true)
 |-- column17: string (nullable = true)
 |-- column18: string (nullable = true)
 |-- column19: string (nullable = true)

我在原始DataFrame上应用了Dataset.mapPartitions,并得到了一个新的DataFrame(由Dataset.mapPartitions返回)。 使用Dataset.mapPartitions而不使用Dataset.map的原因是更好的转换速度。

在这个新的DataFrame中,每一行都应具有如下所示的模式:

root
 |-- column21: string (nullable = true)
 |-- column22: long (nullable = true)
 |-- column23: string (nullable = true)
 |-- column24: long (nullable = true)
 |-- column25: struct (nullable = true)
 |    |-- column251: string (nullable = true)
 |    |-- column252: string (nullable = true)
 |    |-- column253: string (nullable = true)
 |    |-- column254: string (nullable = true)
 |    |-- column255: string (nullable = true)
 |    |-- column256: string (nullable = true)

因此,新DataFrame的架构应与上面的相同。

但是,新DataFrame的架构不会自动更新。在新的DataFrame上应用Dataset.printSchema方法的输出仍然是原始的:

root
 |-- column11: string (nullable = true)
 |-- column12: string (nullable = true)
 |-- column13: string (nullable = true)
 |-- column14: string (nullable = true)
 |-- column15: string (nullable = true)
 |-- column16: string (nullable = true)
 |-- column17: string (nullable = true)
 |-- column18: string (nullable = true)
 |-- column19: string (nullable = true)

因此,为了获得正确的(更新的)架构,我正在使用SparkSession.createDataFrame(newDataFrame.rdd, newSchema)。 我在这里担心的是,由于Spark Catalyst不能同时处理RDD和Dataset / DataFrame,因此回到RDD(newDataFrame.rdd)会损害转换速度。

我的问题是,是否有任何方法可以在不显式调用SparkSession.createDataFrame(newDataFrame.rdd, newSchema)的情况下更新新DataFrame的架构。

非常感谢。

1 个答案:

答案 0 :(得分:0)

您可以使用RowEncoder定义newDataFrame的架构。 请参见以下示例。

val originalDF = spark.sparkContext.parallelize(List(("Tonny", "city1"), ("Rogger", "city2"), ("Michal", "city3"))).toDF("name", "city")
val r = scala.util.Random
val encoderForNewDF = RowEncoder(StructType(Array(
  StructField("name", StringType),
  StructField("num", IntegerType),
  StructField("city", StringType)
)))
val newDF = originalDF.mapPartitions { partition =>
  partition.map{ row =>
    val name = row.getAs[String]("name")
    val city = row.getAs[String]("city")
    val num = r.nextInt
    Row.fromSeq(Array[Any](name, num, city))
  }
} (encoderForNewDF)

newDF.printSchema()  
|-- name: string (nullable = true)  
|-- num: integer (nullable = true)  
|-- city: string (nullable = true)  

用于火花的行编码器:https://jaceklaskowski.gitbooks.io/mastering-spark-sql/spark-sql-RowEncoder.html