我正在尝试在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中的错误还是我遗漏了什么?
答案 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()
的功能要强大得多,因为它可以让您添加年/月/日/小时/分钟/秒的任意组合。