如何在重新计算后替换spark数据帧中的值?

时间:2017-07-26 11:19:21

标签: scala apache-spark

我在spark中有一个架构

root
|-- atom: array (nullable = true)
|    |-- element: struct (containsNull = true)
|    |    |-- dailydata: array (nullable = true)
|    |    |    |-- element: struct (containsNull = true)
|    |    |    |    |-- datatimezone: string (nullable = true)
|    |    |    |    |-- intervaltime: long (nullable = true)
|    |    |    |    |-- intervalvalue: long (nullable = true)
|    |    |    |    |-- utcacquisitiontime: string (nullable = true)
|    |    |-- usage: string (nullable = true)
| -- titlename: string (nullable = true)

我从上面的架构

中提取了utcacquisitiontimedatatimezone,如下所示
val result=q.selectExpr("explode(dailydata) as r").select("r.utcacquisitiontime","r.datatimezone")

+--------------------+------------+
|  utcacquisitiontime|datatimezone|
+--------------------+------------+
|2017-03-27T22:00:00Z|      +02:00|
|2017-03-27T22:15:00Z|      +02:00|
|2017-03-27T22:30:00Z|      +02:00|
|2017-03-27T22:45:00Z|      +02:00|
|2017-03-27T23:00:00Z|      +02:00|
|2017-03-27T23:15:00Z|      +02:00|
|2017-03-27T23:30:00Z|      +02:00|
|2017-03-27T23:45:00Z|      +02:00|
|2017-03-28T00:00:00Z|      +02:00|
|2017-03-28T00:15:00Z|      +02:00|
|2017-03-28T00:30:00Z|      +02:00|
|2017-03-28T00:45:00Z|      +02:00|
|2017-03-28T01:00:00Z|      +02:00|
|2017-03-28T01:15:00Z|      +02:00|
|2017-03-28T01:30:00Z|      +02:00|
|2017-03-28T01:45:00Z|      +02:00|
|2017-03-28T02:00:00Z|      +02:00|
|2017-03-28T02:15:00Z|      +02:00|
|2017-03-28T02:30:00Z|      +02:00|
|2017-03-28T02:45:00Z|      +02:00|
+--------------------+------------+

我需要使用这两列计算localtime,并在计算后将其替换为localtime。我该如何计算localtime并替换它?

2 个答案:

答案 0 :(得分:2)

你可以依靠spark(用户自定义函数)中的udf函数。同样在org.apache.sql.functions._中有很多已经预定义的函数可以帮助你。但这是你如何做这项工作

+-------------------+------------+
| utcacquisitiontime|datatimezone|
+-------------------+------------+
|2017-03-27T22:00:00|      +02:00|
+-------------------+------------+

请注意,我已从时间列中删除了不必要的“Z”。 使用JodaTime依赖项定义一个像这样的udf函数:

val toTimestamp = udf((time:String, zone:String) => {
      val timezone = DateTimeZone.forID(zone)
     val df = DateTimeFormat.forPattern("yyyy-mm-dd'T'HH:mm:ss")
     new java.sql.Timestamp(df.withZone(timezone).parseDateTime(time).getMillis)
     }) 

将其应用于withColumn

的列
df.withColumn("timestamp", toTimestamp(col("utcacquisitiontime"), col("datatimezone"))

显示结果(请注意,在模式中,列时间戳的类型为Timestamp,因此您可以对其执行日期操作)

+-------------------+------------+--------------------+
| utcacquisitiontime|datatimezone|           timestamp|
+-------------------+------------+--------------------+
|2017-03-27T22:00:00|      +02:00|2017-01-27 22:00:...|
+-------------------+------------+--------------------+

root
 |-- utcacquisitiontime: string (nullable = true)
 |-- datatimezone: string (nullable = true)
 |-- timestamp: timestamp (nullable = true)

答案 1 :(得分:0)

您可以使用Joda Time API将df列中的时间转换为本地时间,例如,

def convertToLocal(str:String):String = new DateTime(str).toLocalDateTime().toString 

接下来你导入sql implicits,

import ss.implicits._

其中ss是SparkSession的实例。要将utcacquisitiontime列的每个元素转换为localDateTime,请执行以下操作

val df=result map(r=>(convertToLocal(r.getString(0)),r.getString(1)))

df show

如果这有帮助,请告诉我。欢呼声。