Hive 中 Order By、Sort By、Cluster By 和 Distribute By 的详细解析
在 Hive 数据查询与处理操作中,Order By
、Sort By
、Cluster By
和 Distribute By
这些语句对于数据的排序、分区以及在 Reduce 阶段的处理起着关键作用。本文将详细解析它们各自的语法、区别以及一些使用要点,帮助大家深入理解并正确运用这些功能。
一、Order By 语法
Hive QL 中的 ORDER BY
语法与 SQL 语言中的 ORDER BY
语法相似。
(一)语法组成
sql
colOrder: ( ASC | DESC )
colNullOrder: (NULLS FIRST | NULLS LAST) -- (注意:在 Hive 2.1.0 及之后版本可用)
orderBy: ORDER BY colName colOrder? colNullOrder? (',' colName colOrder? colNullOrder?)*
query: SELECT expression (',' expression)* FROM src orderBy
(二)使用限制与注意事项
- 在严格模式(即
hive.mapred.mode=strict
)下,ORDER BY
子句后面必须跟LIMIT
子句;若将hive.mapred.mode
设置为非严格模式,则不需要LIMIT
子句。这是因为要对所有结果施加全局排序,就需要一个 Reducer 来对最终输出进行排序,如果输出的行数过多,单个 Reducer 可能会花费很长时间来完成排序工作。 - 通常是按列名指定列进行排序,不过在 Hive 0.11.0 及之后版本,若进行如下配置,则可以按位置指定列:
- 对于 Hive 0.11.0 到 2.1.x 版本,设置
hive.groupby.orderby.position.alias
为true
(默认值为false
)。 - 对于 Hive 2.2.0 及之后版本,
hive.orderby.position.alias
默认值为true
。
- 对于 Hive 0.11.0 到 2.1.x 版本,设置
- 默认的排序顺序是升序(
ASC
)。在 Hive 2.1.0 及之后版本,支持为ORDER BY
子句中的每个列指定空值排序顺序,升序(ASC
)时默认空值排序顺序为NULLS FIRST
,降序(DESC
)时默认空值排序顺序为NULLS LAST
。 - 在 Hive 3.0.0 及之后版本,子查询和视图中不带
LIMIT
的ORDER BY
语句会被优化器移除,若要禁用此功能,可设置hive.remove.orderby.in.subquery
为false
。
二、Sort By 语法
SORT BY
语法同样与 SQL 语言中的 ORDER BY
语法类似,其语法如下:
sql
colOrder: ( ASC | DESC )
sortBy: SORT BY colName colOrder? (',' colName colOrder?)*
query: SELECT expression (',' expression)* FROM src sortBy
Hive 会依据 SORT BY
中指定的列在将数据行发送给 Reducer 之前对其进行排序,排序顺序取决于列的数据类型。如果列是数值类型,则按数值顺序排序;若是字符串类型,则按字典序排序。另外,在 Hive 3.0.0 及之后版本,子查询和视图中不带 LIMIT
的 SORT BY
语句会被优化器移除,同样可通过设置 hive.remove.orderby.in.subquery
为 false
来禁用此移除操作。
三、Sort By 和 Order By 的区别
Hive 支持 SORT BY
对每个 Reducer 内的数据进行排序,而 ORDER BY
和 SORT BY
的区别在于:前者保证输出结果的全局有序性,后者仅保证在每个 Reducer 内数据行的有序性。如果存在多个 Reducer,使用 SORT BY
可能会得到部分有序的最终结果。
需要注意的是,单独的单列 SORT BY
和 CLUSTER BY
之间的区别可能容易混淆。区别在于 CLUSTER BY
是依据字段进行分区,而 SORT BY
在有多个 Reducer 时会随机分区以便在各个 Reducer 间均匀分配数据(和负载)。例如:
sql
SELECT key, value FROM src SORT BY key ASC, value DESC
假设有 2 个 Reducer,每个 Reducer 的输出可能是如下这样部分有序的情况:
0 5
0 3
3 6
9 1
0 4
0 3
1 1
2 5
四、Sort By 的类型设置
在进行数据转换后,变量类型通常会被视为字符串,这意味着数值数据将按字典序排序。为解决这个问题,可以在使用 SORT BY
之前使用带有类型转换(cast
)的第二个 SELECT
语句,示例如下:
sql
FROM (FROM (FROM src
SELECT TRANSFORM(value)
USING 'mapper'
AS value, count) mapped
SELECT cast(value as double) AS value, cast(count as int) AS count
SORT BY value, count) sorted
SELECT TRANSFORM(value, count)
USING 'reducer'
AS whatever
五、Cluster By 和 Distribute By 语法
Cluster By
和 Distribute By
主要在转换/Map - Reduce 脚本中使用,但在某些情况下,如果需要对查询输出进行分区和排序以供后续查询使用,在 SELECT
语句中也很有用。
(一)Cluster By
Cluster By
是 Distribute By
和 SORT BY
的快捷方式,它会根据指定列同时进行数据的分区和排序操作。
(二)Distribute By
Hive 使用 Distribute By
中的列将数据行分配到各个 Reducer 中,所有具有相同 Distribute By
列值的行都会被分配到同一个 Reducer,但 Distribute By
并不保证对分配的键具有聚类或排序属性。例如,对以下 5 行数据基于 x
进行 Distribute By
分配到 2 个 Reducer 中:
x1
x2
x4
x3
x1
则可能出现如下分配情况:
Reducer 1 得到:
x1
x2
x1
Reducer 2 得到:
x4
x3
可以看到,虽然能保证相同键 x1
的行被分配到同一个 Reducer(此处为 Reducer 1),但并不能保证它们在 Reducer 内是相邻聚集的。
而如果使用 Cluster By x
,两个 Reducer 会进一步依据 x
对行进行排序,例如:
Reducer 1 得到:
x1
x1
x2
Reducer 2 得到:
x3
x4
用户也可以分别指定 Distribute By
和 SORT BY
,此时分区列和排序列可以不同,通常情况下分区列是排序列的前缀,但这并非强制要求,示例如下:
sql
SELECT col1, col2 FROM t1 CLUSTER BY col1
SELECT col1, col2 FROM t1 DISTRIBUTE BY col1
SELECT col1, col2 FROM t1 DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC
FROM (
FROM pv_users
MAP ( pv_users.userid, pv_users.date )
USING 'map_script'
AS c1, c2, c3
DISTRIBUTE BY c2
SORT BY c2, c1) map_output
INSERT OVERWRITE TABLE pv_users_reduced
REDUCE ( map_output.c1, map_output.c2, map_output.c3 )
USING 'reducer'
AS date, count;