首页 > 解决方案 > 使用定义的 StructType 转换 Spark 数据帧的值

问题描述

有没有办法使用 StructType 转换数据框的所有值?

让我用一个例子来解释我的问题:

假设我们在从文件读取后获得了一个数据帧(我提供了一个生成此数据帧的代码,但在我的真实世界项目中,我在从文件读取后获得了这个数据帧):

    import org.apache.spark.sql.{Row, SparkSession}
    import org.apache.spark.sql.types._
    import org.apache.spark.sql.functions._
    import spark.implicits._
    val rows1 = Seq(
      Row("1", Row("a", "b"), "8.00", Row("1","2")),
      Row("2", Row("c", "d"), "9.00", Row("3","4"))
    )

    val rows1Rdd = spark.sparkContext.parallelize(rows1, 4)

    val schema1 = StructType(
      Seq(
        StructField("id", StringType, true),
        StructField("s1", StructType(
          Seq(
            StructField("x", StringType, true),
            StructField("y", StringType, true)
          )
        ), true),
        StructField("d", StringType, true),
        StructField("s2", StructType(
          Seq(
            StructField("u", StringType, true),
            StructField("v", StringType, true)
          )
        ), true)
      )
    )

    val df1 = spark.createDataFrame(rows1Rdd, schema1)

    println("Schema with nested struct")
    df1.printSchema()

    root
    |-- id: string (nullable = true)
    |-- s1: struct (nullable = true)
    |    |-- x: string (nullable = true)
    |    |-- y: string (nullable = true)
    |-- d: string (nullable = true)
    |-- s2: struct (nullable = true)
    |    |-- u: string (nullable = true)
    |    |-- v: string (nullable = true)

现在假设我的客户向我提供了他想要的数据架构(相当于读取数据帧的架构,但具有不同的数据类型(包含 StringTypes、IntegerTypes ...)):

    val wantedSchema = StructType(
      Seq(
        StructField("id", IntegerType, true),
        StructField("s1", StructType(
          Seq(
            StructField("x", StringType, true),
            StructField("y", StringType, true)
          )
        ), true),
        StructField("d", DoubleType, true),
        StructField("s2", StructType(
          Seq(
            StructField("u", IntegerType, true),
            StructField("v", IntegerType, true)
          )
        ), true)
      )
    )

使用提供的 StructType 转换数据框值的最佳方法是什么?

如果有一种方法可以应用于数据帧,那就太好了,它通过自己转换所有值来应用新的 StructTypes。

PS:这是一个用作示例的小型数据框,在我的项目中,数据框包含更多行。如果它是一个包含几列的小型 Dataframe,我可以轻松完成转换,但就我而言,我正在寻找一种智能解决方案,通过应用 StructType 来转换所有值,而无需手动转换每个列/值编码。

我将不胜感激您能提供的任何帮助,非常感谢!

标签: scalaapache-sparkdataframeapache-spark-sql

解决方案


经过大量研究,这里有一个通用的解决方案,可以按照模式转换数据框:

val castedDf = df1.selectExpr(wantedSchema.map(
  field => s"CAST ( ${field.name} As ${field.dataType.sql}) ${field.name}"
): _*)

这是铸造数据框的架构:

castedDf.printSchema
root
|-- id: integer (nullable = true)
|-- s1: struct (nullable = true)
|    |-- x: string (nullable = true)
|    |-- y: string (nullable = true)
|-- d: double (nullable = true)
|-- s2: struct (nullable = true)
|    |-- u: integer (nullable = true)
|    |-- v: integer (nullable = true)

我希望它能对某人有所帮助,我花了 5 天时间寻找这个简单/通用的解决方案。


推荐阅读