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

问题描述

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

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

为什么要在selects中指定分区键?无论如何,分区键是在表创建期间定义的。 Select语句将使用Create Table语句中定义的分区方案。那么,为什么要添加 (按ts desc按session_id顺序划分分区) ? 如果我跳过 (按ts desc按session_id顺序划分) 怎么办?

解决方法

了解Hive Windowing and Analytics Functions

row-number()是一种分析功能,它对行进行编号并需要over()

over()中,您可以指定要针对哪个组(分区)进行计算。 partition by中的 over与创建表DDL中的partitioned by不同,并且没有什么共同点。在创建表中,这意味着如何存储数据(每个分区在hive中是一个单独的文件夹),分区表用于优化过滤或加载数据。

partition by中的

over()确定计算函数的组。与select中的GROUP BY类似,但区别在于分析功能不会更改行数。
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)。

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

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

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

with clicks_data as (
select stack (9,--session1            
1,1,'page1','2020-01-01 01:01:01.123','2020-01-01 01:01:01.124','page2','2020-01-01 01:01:01.125',--session2            
1,2,'2020-01-01 01:02:02.123','2020-01-01 01:02:02.124','2020-01-01 01:02:02.125',--session 3           
1,3,'2020-01-01 01:03:01.123','2020-01-01 01:03:01.124','2020-01-01 01:03:01.125'                          
    ) as(user_id,session_id,page_name,ts)
)


    SELECT
         user_id,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。第二个未指定分区和顺序的row_number编号为从1到9的所有行。为什么rn2 = 1代表session2,而max timestamp代表session = 2,它应该是随机的吗?因为为了计算第一个row_number,所有行均按session_id分配并按时间戳记desc排序,因此发生了row_number2首先接收session2的情况(由reducer读取,然后由mapper准备的其他两个文件),并且由于已经被排序以计算rn1, rn2以相同顺序接收行。如果不是row_number1,则可能是“更加随机”。数据集越大,rn2顺序将越随机。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...