Hive与MapReduce的关系和执行流程总结
特性HiveMapReduce接口/抽象高级,类SQL(HiveQL)低级,Java API目的数据仓库、批处理、查询分布式计算框架角色编译器、优化器、元数据管理执行引擎(默认且经典)易用性高,无需编写Java代码低,需要复杂的Java开发性能依赖底层引擎(MR/Tez/Spark)原生支持分布式,但延迟高Hive与MapReduce是解耦的。Hive负责“想”,即制定执行计划;MapReduce
简单来说,Hive是一个翻译官,而MapReduce是执行苦力的工人。Hive将用户编写的、看似简单的类SQL语句(HiveQL)“翻译”成一连串复杂的、可以在Hadoop分布式集群上执行的MapReduce任务。
一、核心关系:编译器与执行引擎
-
Hive的角色:编译器与优化器
- Hive本身不直接处理或存储数据。数据始终存放在HDFS上。
- Hive的主要工作是将HiveQL查询“编译”成一个或多个MapReduce作业。
- 这个过程包括:解析SQL、进行语义检查、生成逻辑执行计划、进行逻辑优化(如谓词下推)、生成物理执行计划(即MapReduce作业)、进行物理优化(如Map端Join),最终打包成一个MapReduce作业的JAR包。
-
MapReduce的角色:分布式执行引擎
- MapReduce是Hive默认的(也是经典的)执行引擎。它负责接收Hive编译好的JAR包,并在YARN的资源调度下,在Hadoop集群的各个节点上启动Map和Reduce任务。
- Map任务负责读取HDFS数据、过滤、转换(Mapper阶段)。
- Reduce任务负责对Map的输出进行聚合、排序、合并(Reducer阶段)。
- 最终结果再写回HDFS。
一句话总结:Hive是面向用户的、高级的抽象层,它隐藏了MapReduce的复杂性;而MapReduce是面向集群的、底层的执行框架,负责完成实际的分布式计算工作。
二、从HiveQL到MapReduce Job的转换过程(详解)
让我们通过一个具体的查询来看Hive是如何“翻译”的。
示例查询:
SELECT dept_name, COUNT(*) AS emp_count
FROM employees
WHERE country = 'China'
GROUP BY dept_name;
这个查询的目标是统计在中国区的每个部门的员工数量。
Hive将其转换为MapReduce作业的步骤:
阶段一:Map阶段 (Mapper)
- 输入分片(Input Splits):Hadoop根据HDFS上
employees
表数据块的大小,将数据分成若干个输入分片(例如,128MB一个分片)。每个分片会由一个Map任务处理。 - 执行Map任务:在每个Map任务中:
- 读取数据:从HDFS读取一条条记录(行)。
- 应用WHERE条件(过滤):
WHERE country = 'China'
。Map任务会检查每一条记录,如果country
不是’China’,则直接丢弃这条记录。这被称为谓词下推,是一种重要优化,在最早阶段减少数据量。 - 投影(选择字段):对于通过过滤的记录,Map任务只提取出后续计算所需的字段,这里是
dept_name
。emp_id
等其他字段被丢弃,减少网络传输开销。 - 输出键值对:Map任务输出一个中间键值对。这里,
dept_name
作为Key,数字1
作为Value(表示这个部门有一条记录)。输出类似于:(‘R&D’, 1)
,(‘Sales’, 1)
,(‘R&D’, 1)
。
阶段二:Shuffle和排序 (Shuffle & Sort)
这是MapReduce框架自动完成的,非常关键的一步,但也是开销最大的一步。
- 分区(Partitioning):框架根据Key(
dept_name
)的哈希值,决定每个键值对应该被发送到哪个Reduce任务进行处理。确保相同Key的数据最终到达同一个Reduce任务。 - 排序(Sorting):在每个Reduce任务所在的节点上,在数据开始处理之前,框架会将所有传入的键值对按照Key进行排序。所以Reduce任务接收到的数据是类似这样的:
(‘R&D’, [1,1,1,...])
,(‘Sales’, [1,1,...])
。
阶段三:Reduce阶段 (Reducer)
- 执行Reduce任务:每个Reduce任务处理分配给它的、已经分组排序好的数据。
- 分组(Grouping):由于Shuffle阶段已经保证了相同Key的数据都在一起,Reduce任务很容易实现
GROUP BY dept_name
。 - 聚合(Aggregation):Reduce任务遍历每个Key对应的Value列表(
[1,1,1,...]
),并执行COUNT(*)
操作,也就是简单地对列表中的1求和。对于‘R&D’
,求和结果是3
;对于‘Sales’
,求和结果是2
。 - 输出:Reduce任务将最终结果写入HDFS。输出是键值对形式:
(‘R&D’, 3)
,(‘Sales’, 2)
。
- 分组(Grouping):由于Shuffle阶段已经保证了相同Key的数据都在一起,Reduce任务很容易实现
三、更复杂查询:多个MapReduce作业
复杂的HiveQL语句(如包含JOIN
、DISTINCT
、ORDER BY
等)通常会被编译成多个串联的MapReduce作业。
示例:包含JOIN的查询
SELECT a.*, b.order_date
FROM users a
JOIN orders b
ON a.uid = b.uid;
Hive可能会将其编译成两个MapReduce作业:
- 第一个Job:负责处理
JOIN
。一个Map阶段读取两张表,以uid
作为Key输出,Reduce阶段在同一个Reducer中完成相同uid
的记录的连接操作。 - 第二个Job:负责处理
SELECT
投影,将连接后的结果写入最终输出目录。
四、为什么现在不总是用MapReduce了?
尽管MapReduce强大可靠,但它有一个致命缺点:慢。慢的主要原因在于每个MapReduce作业的中间结果都会落盘(写入HDFS),磁盘I/O开销巨大。对于复杂的、多步骤的查询,这种反复的磁盘读写造成了极高的延迟。
因此,Hive发展了更现代的执行引擎:
- Apache Tez:它将整个查询流程建模为一个有向无环图(DAG),而不是一连串的MapReduce作业。Tez允许任务之间直接在内存中交换数据,只有在必要时才写入磁盘,极大地提升了执行效率。Hive on Tez是目前非常流行的生产环境配置。
- Apache Spark:基于内存计算的引擎,尤其适合需要反复迭代的机器学习算法。它的DAG调度器和内存缓存机制比MapReduce快数个量级。Hive可以通过Hive on Spark项目将Spark作为执行引擎。
总结
特性 | Hive | MapReduce |
---|---|---|
接口/抽象 | 高级,类SQL(HiveQL) | 低级,Java API |
目的 | 数据仓库、批处理、查询 | 分布式计算框架 |
角色 | 编译器、优化器、元数据管理 | 执行引擎(默认且经典) |
易用性 | 高,无需编写Java代码 | 低,需要复杂的Java开发 |
性能 | 依赖底层引擎(MR/Tez/Spark) | 原生支持分布式,但延迟高 |
核心关系再强调: Hive与MapReduce是解耦的。Hive负责“想”,即制定执行计划;MapReduce负责“做”,即分布式执行。随着技术发展,Hive现在可以让更高效的“工人”(如Tez和Spark)来“做”这件事,但理解它与MapReduce这个经典“工人”的关系,是理解Hive工作原理的基石。
更多推荐
所有评论(0)