【问题标题】:Spark SQL Window over interval of between two specified time boundaries - between 3 hours and 2 hours agoSpark SQL 窗口超过两个指定时间边界之间的间隔 - 3 小时到 2 小时前
【发布时间】:2019-10-08 02:12:15
【问题描述】:

使用两个预定义的边界在 Spark SQL 中指定窗口间隔的正确方法是什么?

我正在尝试在“3 小时前到 2 小时前”的窗口中汇总表中的值。

当我运行这个查询时:

select *, sum(value) over (
partition by a, b
order by cast(time_value as timestamp)
range between interval 2 hours preceding and current row
) as sum_value
from my_temp_table;

这行得通。我得到了我期望的结果,即落在 2 小时滚动窗口内的值的总和。

现在,我需要的是让滚动窗口不绑定到当前行,而是考虑 3 小时前和 2 小时前之间的行。 我试过了:

select *, sum(value) over (
partition by a, b
order by cast(time_value as timestamp)
range between interval 3 hours preceding and 2 hours preceding
) as sum_value
from my_temp_table;

但我收到extraneous input 'hours' expecting {'PRECEDING', 'FOLLOWING'} 错误。

我也试过了:

select *, sum(value) over (
partition by a, b
order by cast(time_value as timestamp)
range between interval 3 hours preceding and interval 2 hours preceding
) as sum_value
from my_temp_table;

然后我得到不同的错误scala.MatchError: CalendarIntervalType (of class org.apache.spark.sql.types.CalendarIntervalType$)

我尝试的第三个选项是:

select *, sum(value) over (
partition by a, b
order by cast(time_value as timestamp)
range between interval 3 hours preceding and 2 preceding
) as sum_value
from my_temp_table;

它并没有像我们预期的那样工作:cannot resolve 'RANGE BETWEEN interval 3 hours PRECEDING AND 2 PRECEDING' due to data type mismatch

我很难找到间隔类型的文档,因为this link 说得不够多,其他信息也有点半生不熟。至少我发现了什么。

【问题讨论】:

标签: apache-spark apache-spark-sql window-functions


【解决方案1】:

获得相同结果的解决方法是计算过去 3 小时内的值的总和,然后减去过去 2 小时内的值的总和:

select *, 
sum(value) over (
     partition by a, b
     order by cast(time_value as timestamp)
     range between interval 3 hours preceding and current row) 
- 
sum(value) over (
     partition by a, b
     order by cast(time_value as timestamp)
     range between interval 2 hours preceding and current row) 
as sum_value
from my_temp_table;

【讨论】:

    【解决方案2】:

    遇到了同样的问题,找到了一个简单的解决方案。给你:

    unix_timestamp(datestamp) - unix_timestamp(datestamp) < 10800 --3 hours in seconds 
    

    您也可以使用时间戳来提高可读性。 (想知道是否需要):

    select unix_timestamp(date_format(current_timestamp, 'HH:mm:ss'), 'HH:mm:ss') <
           unix_timestamp('03:00:00', 'HH:mm:ss') --Used timestamp for readibility
    

    【讨论】:

      【解决方案3】:

      由于范围间隔不起作用,我不得不转向另一种方法。 它是这样的:

      • 准备需要执行计算的区间列表
      • 对于每个间隔,运行计算
        • 每次迭代都会产生一个数据框
      • 迭代后,我们有一个数据帧列表
      • 将列表中的数据框合并为一个更大的数据框
      • 写出结果

      就我而言,我必须在一天中的每个小时运行计算并将这些“每小时”结果(即 24 个数据帧的列表)组合成一个“每日”数据帧。

      从非常高级的角度来看,代码如下所示:

      val hourlyDFs = for ((hourStart, hourEnd) <- (hoursToStart, hoursToEnd).zipped) yield {
          val data = data.where($"hour" <= lit(hourEnd) && $"hour" >= lit(hourStart))
          // do stuff
          // return a data frame
      }
      hourlyDFs.toSeq().reduce(_.union(_))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多