在Spark和Scala中转换数据框架构

时间:2016-10-25 06:15:50

标签: scala apache-spark apache-spark-sql spark-dataframe

我想转换数据框架构以更改某些列的类型 使用Spark和Scala。

具体来说,我试图用作[U]函数,其描述如下: “返回一个新的数据集,其中每条记录都已映射到指定的类型。 用于映射列的方法取决于U

的类型

原则上这正是我想要的,但我无法让它发挥作用。

这是一个简单的例子 https://github.com/apache/spark/blob/master/sql/core/src/test/scala/org/apache/spark/sql/DatasetSuite.scala



    // definition of data
    val data = Seq(("a", 1), ("b", 2)).toDF("a", "b")

正如所料,数据架构是:


    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)
    

我想将列“b”强制转换为Double。所以我尝试以下方法:



    import session.implicits._;

    println(" --------------------------- Casting using (String Double)")

    val data_TupleCast=data.as[(String, Double)]
    data_TupleCast.show()
    data_TupleCast.printSchema()

    println(" --------------------------- Casting using ClassData_Double")

    case class ClassData_Double(a: String, b: Double)

    val data_ClassCast= data.as[ClassData_Double]
    data_ClassCast.show()
    data_ClassCast.printSchema()

据我了解as [u]的定义,新的DataFrames应具有以下架构


    root
     |-- a: string (nullable = true)
     |-- b: double (nullable = false)

但输出是


     --------------------------- Casting using (String Double)
    +---+---+
    |  a|  b|
    +---+---+
    |  a|  1|
    |  b|  2|
    +---+---+

    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)

     --------------------------- Casting using ClassData_Double
    +---+---+
    |  a|  b|
    +---+---+
    |  a|  1|
    |  b|  2|
    +---+---+

    root
     |-- a: string (nullable = true)
     |-- b: integer (nullable = false)

表示列“b”尚未转换为加倍。

我做错了什么提示?

BTW:我知道上一篇文章“如何在Spark SQL的DataFrame中更改列类型?” (见How to change column types in Spark SQL's DataFrame?)。我知道我可以一次更改一个列的类型,但我正在寻找一个更通用的解决方案,一次性改变整个数据的模式(我正在尝试理解过程中的Spark)。

1 个答案:

答案 0 :(得分:4)

好吧,因为函数被链接而且Spark做了懒惰的评估, 它实际上 一次性改变整个数据的模式,即使你把它写成当时更改一列,如下所示:

import spark.implicits._

df.withColumn("x", 'x.cast(DoubleType)).withColumn("y", 'y.cast(StringType))...

作为替代方案,我想你可以一次性使用map进行演员表,例如:

df.map{t => (t._1, t._2.asInstanceOf[Double], t._3.asInstanceOf[], ...)}