我的问题是,是否有任何方法无需显式调用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的架构。
非常感谢。
答案 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