Hive:为什么要在选择中使用分区?

Hive: why to use partition by in selects?

我无法完全理解 Hive 中的分区概念。 我了解什么是分区以及如何创建分区。我无法理解的是为什么人们正在编写 select 语句,其中包含“partition by”子句,就像这里所做的那样: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

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

了解 Hive Windowing and Analytics Functions

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

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

over()中的

partition by决定函数计算所在的组。类似于select中的GROUP BY,不同的是分析函数不改变行数。
Row_number re-initializes 当它越过分区边界并从 1

开始时

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

如果您不指定 partition by,row_number 将作为单个分区处理整个数据集。它将产生单个 1 并且最大数量将等于整个数据集中的行数。 Table 分区不影响分析功能行为。

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

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

另请参阅此答案 了解它在 Hive 中的工作原理的更多详细信息,评论中也有关于 table partition vs 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 分配给每个会话(分区)中具有最大时间戳的行。第二个 row_number 没有指定分区和顺序编号所有行从 1 到 9。为什么 rn2=1 用于 session2 和 max timestamp in session=2,它应该是随机的还是不是?因为首先计算 row_number,所有行都按 session_id 分配并按时间戳 desc 排序,碰巧 row_number2 首先收到 session2(它在由 准备的其他两个文件之前被 reducer 读取)映射器)并且因为它已经为 rn1 的计算排序,rn2 以相同的顺序接收行。如果不是 row_number1,它可能会“更随机”。数据集越大,rn2顺序看起来越随机。