在Scala Spark中按架构更改Dataframe的数据类型

时间:2018-03-23 01:00:55

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

我有一个没有架构的数据框,每个列都存储为StringType,如:

ID | LOG_IN_DATE | USER
1  | 2017-11-01  | Johns

现在我创建了一个架构数据框为[(ID,"double"),("LOG_IN_DATE","date"),(USER,"string")],我想在Scala 2.11的Spark 2.0.2中应用上面的Dataframe。

我已经尝试过:

schema.map(x => df.withColumn(x._1, col(x._1).cast(x._2)))

运行此命令时没有错误,但之后当我调用df.schema时,没有任何更改。

有关如何以编程方式将架构应用于df的任何想法?我的朋友告诉我,我可以使用foldLeft方法,但我不认为这是Spark 2.0.2中的方法,无论是df还是rdd。

4 个答案:

答案 0 :(得分:6)

如果您已有列表[(ID,"double"),("LOG_IN_DATE","date"),(USER,"string")],则可以使用选择将每列投射到列表中的类型

您的数据框

val df = Seq(("1", "2017-11-01", "Johns"), ("2", "2018-01-03", "jons2")).toDF("ID", "LOG_IN_DATE", "USER")

您的架构

val schema = List(("ID", "double"), ("LOG_IN_DATE", "date"), ("USER", "string"))

从列表

中将所有列投射到其类型
val newColumns = schema.map(c => col(c._1).cast(c._2))

选择所有te terted列

val newDF = df.select(newColumns:_*)

打印架构

newDF.printSchema()

root
 |-- ID: double (nullable = true)
 |-- LOG_IN_DATE: date (nullable = true)
 |-- USER: string (nullable = true)

显示数据框

newDF.show()

输出:

+---+-----------+-----+
|ID |LOG_IN_DATE|USER |
+---+-----------+-----+
|1.0|2017-11-01 |Johns|
|2.0|2018-01-03 |Jons2|
+---+-----------+-----+

答案 1 :(得分:1)

  
    

我的朋友告诉我,我可以使用foldLeft方法,但我不认为这是Spark 2.0.2中的一种方法,无论是df还是rdd

  

是的,foldLeft是要走的路

在使用schema

之前,这是foldLeft
root
 |-- ID: string (nullable = true)
 |-- LOG_IN_DATE: string (nullable = true)
 |-- USER: string (nullable = true)

使用foldLeft

val schema = List(("ID","double"),("LOG_IN_DATE","date"),("USER","string"))

import org.apache.spark.sql.functions._
schema.foldLeft(df){case(tempdf, x)=> tempdf.withColumn(x._1, col(x._1).cast(x._2))}.printSchema()

这是schema

之后的foldLeft
root
 |-- ID: double (nullable = true)
 |-- LOG_IN_DATE: date (nullable = true)
 |-- USER: string (nullable = true)

我希望答案很有帮助

答案 2 :(得分:0)

如果应用Scala的任何功能,它将返回已修改的数据,因此您无法更改现有架构的数据类型。

下面是通过转换列来创建修改模式的新数据框的代码。

1.创建一个新的DataFrame

val df=Seq((1,"2017-11-01","Johns"),(2,"2018-01-03","Alice")).toDF("ID","LOG_IN_DATE","USER")

2.将DataFrame注册为临时表

df.registerTempTable("user")

3.现在通过转换列数据类型

来创建新的DataFrame
val new_df=spark.sql("""SELECT ID,TO_DATE(CAST(UNIX_TIMESTAMP(LOG_IN_DATE, 'yyyy-MM-dd') AS TIMESTAMP)) AS LOG_IN_DATE,USER from user""")

4。显示架构

     new_df.printSchema                                                  
     root                                                                  
         |-- ID: integer (nullable = false)                                
         |-- LOG_IN_DATE: date (nullable = true)                           
         |-- USER: string (nullable = true)

答案 3 :(得分:0)

其实你做了什么:

schema.map(x => df.withColumn(x._1, col(x._1).cast(x._2)))

可行,但您需要将数据框定义为 var 并执行以下操作:

for((name, type) <- schema) {
  df = df.withColumn(name, col(name).cast(type)))
}

您也可以尝试阅读这样的数据框:

case class MyClass(ID: Int, LOG_IN_DATE: Date, USER: String)

//Suppose you are reading from json
val df = spark.read.json(path).as[MyClass]

希望这有帮助!