了解 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 by。 order 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 顺序。