SparkSQL中的日期和间隔添加

时间:2017-07-28 19:20:14

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

我正在尝试在spark-shell中的某些数据帧上执行一个简单的SQL查询,查询将某个日期的间隔增加到某个日期,如下所示:

原始查询:

scala> spark.sql("select Cast(table1.date2 as Date) + interval 1 week from table1").show()

现在我做了一些测试:

scala> spark.sql("select Cast('1999-09-19' as Date) + interval 1 week from table1").show()

我正确得到了结果

+----------------------------------------------------------------------------+
|CAST(CAST(CAST(1999-09-19 AS DATE) AS TIMESTAMP) + interval 1 weeks AS DATE)|
+----------------------------------------------------------------------------+
|                                                                  1999-09-26|
+----------------------------------------------------------------------------+

(仅增加7天到19 = 26)

但是当我把这一年改为1997而不是1999年时,结果发生了变化!

scala> spark.sql("select Cast('1997-09-19' as Date) + interval 1 week from table1").show()

+----------------------------------------------------------------------------+
|CAST(CAST(CAST(1997-09-19 AS DATE) AS TIMESTAMP) + interval 1 weeks AS DATE)|
+----------------------------------------------------------------------------+
|                                                                  1997-09-25|
+----------------------------------------------------------------------------+

为什么重新改变?难道不是26岁而不是25岁吗?

那么,这是一个与某些类型的计算损失有关的sparkSQL中的错误还是我遗漏了什么?

2 个答案:

答案 0 :(得分:6)

这可能是当地时间转换的问题。 INTERVAL将数据投放到TIMESTAMP,然后再投放回DATE

scala> spark.sql("SELECT CAST('1997-09-19' AS DATE) + INTERVAL 1 weeks").explain
== Physical Plan ==
*Project [10130 AS CAST(CAST(CAST(1997-09-19 AS DATE) AS TIMESTAMP) + interval 1 weeks AS DATE)#19]
+- Scan OneRowRelation[]

(注意第二个和第三个CASTs)和Spark已知为inconsequent when handling timestamps

DATE_ADD应表现出更稳定的行为:

scala> spark.sql("SELECT DATE_ADD(CAST('1997-09-19' AS DATE), 7)").explain
== Physical Plan ==
*Project [10130 AS date_add(CAST(1997-09-19 AS DATE), 7)#27]
+- Scan OneRowRelation[]

答案 1 :(得分:1)

从 Spark 3 开始,此错误已得到修复。让我们用您提到的日期创建一个 DataFrame 并添加一个星期的间隔。创建数据帧。

import java.sql.Date

val df = Seq(
  (Date.valueOf("1999-09-19")),
  (Date.valueOf("1997-09-19"))
).toDF("some_date")

添加一周间隔:

df
  .withColumn("plus_one_week", expr("some_date + INTERVAL 1 week"))
  .show()
+----------+-------------+
| some_date|plus_one_week|
+----------+-------------+
|1999-09-19|   1999-09-26|
|1997-09-19|   1997-09-26|
+----------+-------------+

您也可以使用 make_interval() SQL 函数获得相同的结果:

df
  .withColumn("plus_one_week", expr("some_date + make_interval(0, 0, 1, 0, 0, 0, 0)"))
  .show()

我们正在研究 getting make_interval() exposed as Scala/PySpark functions,因此没有必要使用 expr 来访问该函数。

date_add 仅适用于添加天数,因此它是有限的。 make_interval() 的功能要强大得多,因为它可以让您添加年/月/日/小时/分钟/秒的任意组合。