【问题标题】:HIVE - compute statistics over partitions with window based on dateHIVE - 基于日期计算具有窗口的分区的统计信息
【发布时间】:2021-04-05 08:24:01
【问题描述】:

我已经看到了与我类似的问题的解决方案,但没有一个对我很有效。我也相信应该有办法让它发挥作用。

给定一张桌子

ID Date target
1 2020-01-01 1
1 2020-01-02 1
1 2020-01-03 0
1 2020-01-04 1
1 2020-01-04 0
1 2020-06-01 1
1 2020-06-02 1
1 2020-06-03 0
1 2020-06-04 1
1 2020-06-04 0
2 2020-01-01 1

ID 是 BIGINT,目标是 Int,Date 是 DATE

我想为每个 ID/Date 计算日期前 3 个月和 12 个月(含)内相同 ID 的总和和行数。输出示例:

ID Date Sum_3 Count_3 Sum_12 Count_12
1 2020-01-01 1 1 1 1
1 2020-01-02 2 2 2 2
1 2020-01-03 2 3 2 3
1 2020-01-04 3 5 3 5
1 2020-06-01 1 1 4 6
1 2020-06-02 2 2 5 7
1 2020-06-03 2 3 6 8
1 2020-06-04 3 5 7 10
2 2020-01-01 1 1 1 1

如何在 HIVE 中获得这段时间的结果? 我不确定是否应该使用分析函数(以及如何使用)、分组依据等...?

【问题讨论】:

  • 这能回答你的问题吗? range between interval in Hive
  • 那个答案的问题指向答案的 cmets - 但我会分析它,谢谢 - 而且,它不考虑计数

标签: sql datetime hive window-functions date-arithmetic


【解决方案1】:

如果您可以将几个月的近似值视为天数,那么您可以在 Hive 中使用窗口函数:

select id, date, 
    count(*) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 90 preceding -- 90 days
    ) as count_3,
    sum(target) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 90 preceding
    ) as sum_3,
    count(*) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 360 preceding -- 360 days
    ) as count_12,
    sum(target) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 360 preceding
    ) as sum_12
from mytable

您可以在同一个查询中聚合:

select id, date, 
    sum(count(*)) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 90 preceding -- 90 days
    ) as count_3,
    sum(sum(target)) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 90 preceding
    ) as sum_3,
    sum(count(*)) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 360 preceding -- 360 days
    ) as count_12,
    sum(sum(target)) over(
        partition by id 
        order by unix_timestamp(date)
        range 60 * 60 * 24 * 360 preceding
    ) as sum_12
from mytable
group by id, date, unix_timestamp(date)

【讨论】:

  • 日期在源表中是重复的,但在结果表中是重复的......所以这个查询没有给出预期的结果
  • @mck:啊,好吧,当我第一次回答时,我没有注意到。我添加了另一个查询以根据需要进行聚合。
  • @GMB 有什么理由在日期之前按 unix_timestamp(date) 分组?
  • @DiogoSantos:那是因为unix_timestamp() 表达式出现在窗口函数的order by 子句中。我不知道 Hive 是否会发现这在功能上依赖于date,所以我选择了安全路径。您可以尝试在 group by 子句中不带 unix_timestamp() 的情况下运行查询,看看是否出现编译错误(我手头没有 Hive 数据库可供测试)。
【解决方案2】:

如果您可以估计间隔(1 个月 = 30 天):(GMB 的答案的改进)

with t as (
    select ID, Date,
        sum(target) target,
        count(target) c_target
    from table
    group by ID, Date
)
select ID, Date,
    sum(target) over(
        partition by ID
        order by unix_timestamp(Date, 'yyyy-MM-dd')
        range 60 * 60 * 24 * 90 preceding
    ) sum_3,
    sum(c_target) over(
        partition by ID
        order by unix_timestamp(Date, 'yyyy-MM-dd')
        range 60 * 60 * 24 * 90 preceding
    ) count_3,
    sum(target) over(
        partition by ID
        order by unix_timestamp(Date, 'yyyy-MM-dd')
        range 60 * 60 * 24 * 360 preceding
    ) sum_12,
    sum(c_target) over(
        partition by ID
        order by unix_timestamp(Date, 'yyyy-MM-dd')
        range 60 * 60 * 24 * 360 preceding
    ) count_12
from t

或者,如果您想要精确的间隔,您可以进行自连接(但成本高):

with t as (
    select ID, Date,
        sum(target) target,
        count(target) c_target
    from table
    group by ID, Date
)
select
    t_3month.ID, 
    t_3month.Date, 
    t_3month.sum_3, 
    t_3month.count_3, 
    sum(t3.target) sum_12, 
    sum(t3.c_target) count_12
from (
    select 
        t1.ID, 
        t1.Date,
        sum(t2.target) sum_3,
        sum(t2.c_target) count_3
    from t t1
    left join t t2
    on t2.Date > t1.Date - interval 3 month and
       t2.Date <= t1.Date and
       t1.ID = t2.ID
    group by t1.ID, t1.Date
) t_3month
left join t t3
on t3.Date > t_3month.Date - interval 12 month and
   t3.Date <= t_3month.Date and
   t_3month.ID = t3.ID
group by t_3month.ID, t_3month.Date, t_3month.sum_3, t_3month.count_3
order by ID, Date;

【讨论】:

  • 谢谢 - 我确实尝试过类似的方法,但是连接结果的巨大大小阻止了查询完成(顺便说一句,我认为 Hive 中的连接条件必须是 = 而不是 > 或
  • @DiogoSantos 我编辑了我的答案以提供另一种可能更有效的方法(主要受 GMB 启发)。看看有没有帮助?
  • 我将测试两个答案(您的和 GMB 的更新版本),但看起来它们都可以解决问题。但是,我很想知道是否存在任何性能差异。
  • 顺便说一句,如果我想排除与每一行相关的最后 2 天怎么办 - 例如:我的输出第 4 行变为 2 | 2 ?
  • @DiogoSantos 那么你可以使用range bewteen 60 * 60 * 24 * 90 preceding and 60 * 60 * 24 * 2 preceding
猜你喜欢
  • 2016-01-15
  • 1970-01-01
  • 2015-10-07
  • 2018-09-24
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 2014-09-08
  • 1970-01-01
相关资源
最近更新 更多