简单来说,Hive是一个翻译官,而MapReduce是执行苦力的工人。Hive将用户编写的、看似简单的类SQL语句(HiveQL)“翻译”成一连串复杂的、可以在Hadoop分布式集群上执行的MapReduce任务。


一、核心关系:编译器与执行引擎

  1. Hive的角色:编译器与优化器

    • Hive本身不直接处理或存储数据。数据始终存放在HDFS上。
    • Hive的主要工作是将HiveQL查询“编译”成一个或多个MapReduce作业。
    • 这个过程包括:解析SQL、进行语义检查、生成逻辑执行计划、进行逻辑优化(如谓词下推)、生成物理执行计划(即MapReduce作业)、进行物理优化(如Map端Join),最终打包成一个MapReduce作业的JAR包。
  2. 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)
  1. 输入分片(Input Splits):Hadoop根据HDFS上employees表数据块的大小,将数据分成若干个输入分片(例如,128MB一个分片)。每个分片会由一个Map任务处理。
  2. 执行Map任务:在每个Map任务中:
    • 读取数据:从HDFS读取一条条记录(行)。
    • 应用WHERE条件(过滤)WHERE country = 'China'。Map任务会检查每一条记录,如果country不是’China’,则直接丢弃这条记录。这被称为谓词下推,是一种重要优化,在最早阶段减少数据量。
    • 投影(选择字段):对于通过过滤的记录,Map任务只提取出后续计算所需的字段,这里是dept_nameemp_id等其他字段被丢弃,减少网络传输开销。
    • 输出键值对:Map任务输出一个中间键值对。这里,dept_name作为Key,数字1作为Value(表示这个部门有一条记录)。输出类似于:(‘R&D’, 1), (‘Sales’, 1), (‘R&D’, 1)
阶段二:Shuffle和排序 (Shuffle & Sort)

这是MapReduce框架自动完成的,非常关键的一步,但也是开销最大的一步。

  1. 分区(Partitioning):框架根据Key(dept_name)的哈希值,决定每个键值对应该被发送到哪个Reduce任务进行处理。确保相同Key的数据最终到达同一个Reduce任务。
  2. 排序(Sorting):在每个Reduce任务所在的节点上,在数据开始处理之前,框架会将所有传入的键值对按照Key进行排序。所以Reduce任务接收到的数据是类似这样的:(‘R&D’, [1,1,1,...]), (‘Sales’, [1,1,...])
阶段三:Reduce阶段 (Reducer)
  1. 执行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)

三、更复杂查询:多个MapReduce作业

复杂的HiveQL语句(如包含JOINDISTINCTORDER BY等)通常会被编译成多个串联的MapReduce作业

示例:包含JOIN的查询

SELECT a.*, b.order_date
FROM users a
JOIN orders b
ON a.uid = b.uid;

Hive可能会将其编译成两个MapReduce作业:

  1. 第一个Job:负责处理JOIN。一个Map阶段读取两张表,以uid作为Key输出,Reduce阶段在同一个Reducer中完成相同uid的记录的连接操作。
  2. 第二个Job:负责处理SELECT投影,将连接后的结果写入最终输出目录。

四、为什么现在不总是用MapReduce了?

尽管MapReduce强大可靠,但它有一个致命缺点:。慢的主要原因在于每个MapReduce作业的中间结果都会落盘(写入HDFS),磁盘I/O开销巨大。对于复杂的、多步骤的查询,这种反复的磁盘读写造成了极高的延迟。

因此,Hive发展了更现代的执行引擎:

  1. Apache Tez:它将整个查询流程建模为一个有向无环图(DAG),而不是一连串的MapReduce作业。Tez允许任务之间直接在内存中交换数据,只有在必要时才写入磁盘,极大地提升了执行效率。Hive on Tez是目前非常流行的生产环境配置。
  2. 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工作原理的基石。

Logo

惟楚有才,于斯为盛。欢迎来到长沙!!! 茶颜悦色、臭豆腐、CSDN和你一个都不能少~

更多推荐