【问题标题】:Hive: why to use partition by in selects?Hive:为什么在选择中使用分区?
【发布时间】:2021-02-02 09:40:10
【问题描述】:

我无法完全理解 Hive 中的分区概念。 我了解什么是分区以及如何创建它们。我无法理解的是为什么人们要编写带有“partition by”子句的 select 语句,就像这里所做的那样:SQL most recent using row_number() over partition

SELECT user_id, page_name, recent_click
FROM (
  SELECT user_id,
         page_name,
         row_number() over (partition by session_id order by ts desc) as recent_click
  from clicks_data
) T
WHERE recent_click = 1

为什么要在选择中指定分区键?在任何情况下,分区键都是在表创建期间定义的。 Select 语句将使用在 Create Table 语句中定义的分区方案。那么为什么要添加 over (partition by session_id order by ts desc)? 如果我跳过 over (partition by session_id order by ts desc) 怎么办?

【问题讨论】:

    标签: sql hive hiveql hadoop-partitioning hive-partitions


    【解决方案1】:

    了解 Hive Windowing and Analytics Functions

    row-number() 是一个分析函数,它对行进行编号并且需要over()

    over() 中,您可以指定将针对哪个组(分区)进行计算。 over 中的partition by 与create table DDL 中的partitioned by 不同,没有任何共同点。 在create table 中表示数据的存储方式(每个分区都是单独的hive 中的文件夹),分区表用于优化过滤或加载数据。

    over() 中的partition by 确定计算函数的组。类似于select中的GROUP BY,但不同的是analytics函数不会改变行数。
    Row_number 越过分区边界时重新初始化并以 1 开始

    row_number 在 over() 中也需要 order byorder by 确定行编号的顺序。

    如果您不指定partition by,row_number 将作为单个分区对整个数据集起作用。它将产生单个 1,最大数量将等于整个数据集中的行数。表分区不会影响分析函数的行为。

    如果您不指定order by,则row_number 将以不确定的顺序对行进行编号,并且可能不同的行将在每次运行中标记为1。这就是您需要指定order by 的原因。在您的示例中,order by ts desc 表示将 1 分配给具有最大 ts 的行(对于每个 session_id)。

    说,如果每个会话中有 3 个不同的 session_id 和 3 个不同 ts 的点击(总共 9 行),那么示例中的 row_number 将为每个会话分配 1 到最后一次点击,在过滤 recent_click = 1 后,您将获得 3行而不是最初的 9。 row_number() over() 没有分区依据将按随机顺序从 1 到 9 对所有行进行编号(可能因运行而异),并且相同的过滤将为您提供来自所有 3 个会话的 8 行混合。

    另请参阅此答案https://stackoverflow.com/a/55909947/2700344 了解更多详细信息,了解它在 Hive 中的工作原理,还有关于 cmets 中表分区与 over() 的类似问题。

    试试这个例子,它可能比阅读太长的解释要好:

    with clicks_data as (
    select stack (9, 
    --session1            
    1, 1, 'page1', '2020-01-01 01:01:01.123',
    1, 1, 'page1', '2020-01-01 01:01:01.124',
    1, 1, 'page2', '2020-01-01 01:01:01.125',
    --session2            
    1, 2, 'page1', '2020-01-01 01:02:02.123',
    1, 2, 'page2', '2020-01-01 01:02:02.124',
    1, 2, 'page1', '2020-01-01 01:02:02.125',
    --session 3           
    1, 3, 'page1', '2020-01-01 01:03:01.123',
    1, 3, 'page2', '2020-01-01 01:03:01.124',
    1, 3, 'page1', '2020-01-01 01:03:01.125'                          
        ) as(user_id, session_id, page_name, ts)
    )
    
    
        SELECT
             user_id
            ,session_id
            ,page_name
            ,ts
            ,ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY ts DESC) AS rn1
            ,ROW_NUMBER() OVER() AS rn2 
        FROM clicks_data
    

    结果:

    user_id session_id  page_name   ts                     rn1  rn2
    1        2          page1      2020-01-01 01:02:02.125  1   1
    1        2          page2      2020-01-01 01:02:02.124  2   2
    1        2          page1      2020-01-01 01:02:02.123  3   3
    1        1          page2      2020-01-01 01:01:01.125  1   4
    1        1          page1      2020-01-01 01:01:01.124  2   5
    1        1          page1      2020-01-01 01:01:01.123  3   6
    1        3          page1      2020-01-01 01:03:01.125  1   7
    1        3          page2      2020-01-01 01:03:01.124  2   8
    1        3          page1      2020-01-01 01:03:01.123  3   9
         
    

    第一个 row_number 为每个会话(分区)中具有最大时间戳的行分配 1。没有指定分区和顺序的第二行编号为从 1 到 9 的所有行编号。为什么 rn2=1 用于 session2 和 session=2 中的最大时间戳,它是否应该是随机的?因为为了计算第一个 row_number,所有行都按 session_id 分布并按时间戳 desc 排序,并且恰好 row_number2 首先收到 session2(它在 mapper 准备的其他两个文件之前由 reducer 读取)并且因为它已经为计算 rn1 排序, rn2 以相同的顺序接收行。如果它不是 row_number1,它可能是“更随机的”。数据集越大,看起来越随机的 rn2 顺序。

    【讨论】:

    • 很好的解释!谢谢你,左加入!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-17
    • 1970-01-01
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    相关资源
    最近更新 更多