Hive如何让MapReduce实现SQL操作?

MapReduce实现SQL的原理

先看下面一条常见的SQL分析语句,用MapReduce该如何实现?

1
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;

这是一条非常常见的SQL统计分析语句,统计不同年龄段的用户访问不同网页的兴趣偏好,对于产品运营和设计很有价值。具体输入和执行结果请看下面图示:

左边是要分析的数据表,右边是分析结果。实际上把左边表相同的行进行累加求和,就得到右边的表了,看起来跟WordCount的计算很相似。看下这条SQL语句的MapReduce计算过程:

首先,map函数的输入Key和Value,主要看Value。Value就是在左边表中每一行的数据,比如<1, 25="">这样。map函数的输出就是以输入的Value作为Key,Value统一设为1,比如<<1, 25="">, 1>这样。

map函数的输出经过shuffle以后,相同的Key及其对应的Value被放在一起组成一个,作为输入交给reduce函数处理。比如<<2, 25="">, 1>被map函数输出两次,那么到了reduce这里,就变成输入<<2, 25="">, <1, 1="">>,这里的Key是<2, 25="">, Value集合是<1, 1="">。

在reduce函数内部,Value集合里所有的数字被相加,然后输出。所以reduce输出就是<<2, 25="">, 2>。

看下如,整个流程比较清晰:

这样,这条很实用的SQL语句就被简单的MapReduce计算过程处理好了。

Hive的架构

Hive能够直接处理我们输入的SQL语句(Hive的SQL和数据库标准SQL略有不同),调用MapReduce计算框架完成数据分析操作。下面是它的架构图。

我们通过Hive的Client(Hive的命令行工具,JDBC等)向Hive提交SQL命令。如果是创建数据表的DDL,Hive就会通过执行引擎Driver将数据表的信息记录在Metastore元数据组件中,这个组件通常是一个关系型数据库实现,记录表名、字段名、字段类型、关联HDFS文件路径等这些数据库的元信息。

如果我们提交的是查询分析数据的DQL,Driver就会将改语句提交给自己的编译器Compiler进行语法分析、语法解析、语法优化等一系列操作,最后生成一个MapReduce执行计划。然后根据执行计划生成一个MapReduce的作业,提交给Hadoop MapReduce计算框架处理。

对于一个简单的SQL语句,比如:

1
SELECT * FROM status_updates WHERE status LIKE ‘michael jackson’;

它对应的Hive执行计划如下图:

Hive内部预置了很多函数,Hive的执行计划就是根据SQL语句生成这些函数的DAG(有向无环图),然后封装进MapReduce的map和reduce函数中。这个例子中,map函数调用了三个Hive的内置函数TableScanOperator、FilterOperator、FileOutputOperator,这就完成了map计算,而且无需reduce函数。

Hive如何实现join操作

除了上面这些简单的聚合(group by)、过滤(where)操作,Hive还能执行连接(join on)操作。开头的例子,pv_users表的数据在实际应用中是无法直接得到的,因为pageid数据来自用户访问日志,每个用户进行一次页面浏览,就会生成一条访问记录,保存在page_view表中。而age年龄信息则记录在用户表user中。

这两张表有一个相同的字段userid,根据这个字段可以将两张表连接起来,生成前面例子的pv_users表,SQL命令是

1
SELECT pv.pageid, u.age FROM page_view pv JOIN user u ON (pv.userid = u.userid);

同样,这个SQL命令也可以转化为MapReduce计算,连接的过程如下图所示。

从图上看,join的MapReduce计算过程和前面的group by稍有不同,因为join涉及两张表,来自两个文件,所以需要在map输出的时候进行标记,比如来自第一张表的输出Value就记录为<1, x="">,这里的1表示数据来自第一张表。这样经过shuffle以后,相同的Key被输入到同一个reduce函数,就可以根据表的标记对Value数据求笛卡尔积,用第一张表的每条记录和第二张表的每条记录连接,输出就是join的结果。

如果我们打开Hive的源代码,看join相关代码,会看到一个两层for循环,对来自两张表的记录进行连接操作。

0%