我在Scala中写这个并使用Spark 1.6,并且没有选择切换到更新的版本。我试图合并两个数据帧,一个从Hadoop集群上的Avro文件中拉出来,另一个从Teradata数据库中取出。我可以很好地读取它们,并且两者都保证以相同的顺序具有相同的列名,但是当我尝试使用
合并它们时 data1.unionAll(data2)
我遇到了错误,因为Avro会将时间戳转换为long,因此两者的数据类型不匹配这些字段。这个过程将重复几次,我知道表中总会有至少一个时间戳字段,但可能会有更多,我不会总是知道他们的名字,所以我试图做一般方法这会将任意数量的列从timestamp转换为long。这就是我到目前为止所做的:
def transformTimestamps(df: DataFrame): DataFrame = {
val convert_timestamp_udf = udf((time:Timestamp) => time.getTime())
df.dtypes.foreach { f =>
val fName = f._1
val fType = f._2
if (fType == "TimestampType:) {
println("Found timestamp col: " + fName)
df.withColumn(fName, convert_timestamp_udf(df.col(fName)))
df.printSchema()
}
}
return df
}
使用打印输出我可以告诉该方法只能正确识别时间戳列,但.withColumn转换不起作用。在下一行中打印架构不会显示更新的列。此外,我还尝试为转换后的值创建一个全新的列,并且它也没有添加到df中。有谁能发现为什么这不起作用?
答案 0 :(得分:2)
以下行只是transformation
df.withColumn(fName, convert_timestamp_udf(df.col(fName)))
在执行dataframe
之前不会反映在原始action
上。分配将作为一个动作,因此您可以创建一个临时dataframe
并在循环中分配给它
def transformTimestamps(df: DataFrame): DataFrame = {
val convert_timestamp_udf = udf((time:Timestamp) => time.getTime())
var tempDF = df
df.schema.map(f => {
val fName = f.name
val fType = f.dataType
if (fType.toString == "TimestampType") {
println("Found timestamp col: " + fName)
tempDF = tempDF.withColumn(fName, convert_timestamp_udf(df.col(fName)))
tempDF.printSchema()
}
})
return tempDF
}
我希望答案很有帮助
答案 1 :(得分:1)
避免使用可变var
的一种方法是,您可以通过汇总TimestampType
的列列表并通过foldLeft
与您的转化UDF一起浏览列表来执行类型转换:
import java.sql.Timestamp
val df = Seq(
(1, Timestamp.valueOf("2016-05-01 11:30:00"), "a", Timestamp.valueOf("2017-06-01 07:00:30")),
(2, Timestamp.valueOf("2016-06-01 12:30:00"), "b", Timestamp.valueOf("2017-07-01 08:00:30")),
(3, Timestamp.valueOf("2016-07-01 13:30:00"), "c", Timestamp.valueOf("2017-08-01 09:00:30"))
).toDF("id", "date1", "status", "date2")
val convert_timestamp_udf = udf( (time: Timestamp) => time.getTime() )
// Assemble all columns filtered with type TimestampType
val tsColumns = df.dtypes.filter(x => x._2 == "TimestampType")
// Create new dataframe by converting all Timestamps to Longs via foldLeft
val dfNew = tsColumns.foldLeft( df )(
(acc, x) => acc.withColumn(x._1, convert_timestamp_udf(df(x._1)))
)
dfNew.show
+---+-------------+------+-------------+
| id| date1|status| date2|
+---+-------------+------+-------------+
| 1|1462127400000| a|1496325630000|
| 2|1464809400000| b|1498921230000|
| 3|1467405000000| c|1501603230000|
+---+-------------+------+-------------+
答案 2 :(得分:0)
val index = ss.sparkContext.parallelize( Seq((1,"2017-5-5"),
(2,"2017-5-5"),
(3,"2017-5-5"),
(4,"2017-5-5"),
(5,"2017-5-5"))).toDF("ID", "time")
val convert_timestamp_udf = udf((time:Timestamp) => time.getTime())
val newDF = index.withColumn("time", convert_timestamp_udf($"time"))
newDF.show