您的位置:首页 > 数据库

MapReduce实现基本SQL操作的原理

2015-05-19 20:20 756 查看

1、MapReduce实现基本SQL操作的原理

详细讲解SQL编译为MapReduce之前,我们先来看看MapReduce框架实现SQL基本操作的原理

1.1 Join的实现原理

select u.name, o.orderid from order o join user u on o.uid = u.uid;


在map的输出value中为不同表的数据打上tag标记,在reduce阶段根据tag判断数据来源。MapReduce的过程如下(这里只是说明最基本的Join的实现,还有其他的实现方式)

回到顶部

1.2Group By的实现原理(group by的操作一定是两个属性,这样子才方便讲解)

select rank, isonline, count(*) from city group by rank, isonline;


将GroupBy的字段组合为map的输出key值,利用MapReduce的排序,在reduce阶段保存LastKey区分不同的key。MapReduce的过程如下(当然这里只是说明Reduce端的非Hash聚合过程)

回到顶部

1.3Distinct的实现原理

select dealid, count(distinct uid) num from order group by dealid;


当 只有一个distinct字段时,如果不考虑Map阶段的Hash GroupBy,只需要将GroupBy字段和Distinct字段组合为map输出key,利用mapreduce的排序,同时将GroupBy字段作 为reduce的key,在reduce阶段保存LastKey即可完成去重

 

 

 

 

 

了解了MapReduce实现SQL基本操作之后,我们来看看Hive是如何将SQL转化为MapReduce任务的,整个编译过程分为六个阶段:
1.   Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST
Tree
2.   遍历ASTTree,抽象出查询的基本组成单元QueryBlock
3.   遍历QueryBlock,翻译为执行操作树OperatorTree
4.   逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
5.   遍历OperatorTree,翻译为MapReduce任务
6.   物理层优化器进行MapReduce任务的变换,生成最终的执行计划
下面分别对这六个阶段进行介绍

2.1 Phase1 SQL词法,语法解析

2.1.1Antlr

Hive使用Antlr实现SQL的词法和语法解析。Antlr是一种语言识别的工具,可以用来构造领域语言。
这里不详细介绍Antlr,只需要了解使用Antlr构造特定的语言只需要编写一个语法文件,定义词法和语法替换规则即可,Antlr完成了词法分析、语法分析、语义分析、中间代码生成的过程。

Hive 中语法规则的定义文件在0.10版本以前是Hive.g一个文件,随着语法规则越来越复杂,由语法规则生成的Java解析类可能超过Java类文件的最大 上限,0.11版本将Hive.g拆成了5个文件,词法规则HiveLexer.g和语法规则的4个文件 SelectClauseParser.g,FromClauseParser.g,IdentifiersParser.g,HiveParser.g。

2.1.2抽象语法树AST Tree

经过词法和语法解析后,如果需要对表达式做进一步的处理,使用 Antlr 的抽象语法树语法Abstract Syntax Tree,在语法分析的同时将输入语句转换成抽象语法树,后续在遍历语法树时完成进一步的处理。

下面的一段语法是Hive SQL中SelectStatement的语法规则,从中可以看出,SelectStatement包含select, from, where,groupby, having, orderby等子句。
(在下面的语法规则中,箭头表示对于原语句的改写,改写后会加入一些特殊词标示特定语法,比如TOK_QUERY标示一个查询块)

selectStatement

   :

   selectClause

   fromClause

   whereClause?

   groupByClause?

   havingClause?

   orderByClause?

   clusterByClause?

   distributeByClause?

   sortByClause?

   limitClause? -> ^(TOK_QUERY fromClause ^(TOK_INSERT ^(TOK_DESTINATION ^(TOK_DIR TOK_TMP_FILE))

                     selectClause whereClause? groupByClause? havingClause? orderByClause? clusterByClause?

                     distributeByClause? sortByClause? limitClause?))

   ;


2.1.3样例SQL

为了详细说明SQL翻译为MapReduce的过程,这里以一条简单的SQL为例,SQL中包含一个子查询,最终将数据写入到一张表中

FROM

(

  SELECT

    p.datekey datekey,

    p.userid userid,

    c.clienttype

  FROM

    detail.usersequence_client c

    JOIN fact.orderpayment p ON p.orderid = c.orderid

    JOIN default.user du ON du.userid = p.userid

  WHERE p.datekey = 20131118

) base

INSERT OVERWRITE TABLE `test`.`customer_kpi`

SELECT

  base.datekey,

  base.clienttype,

  count(distinct base.userid) buyer_count

GROUP BY base.datekey, base.clienttype


2.1.3SQL生成AST Tree

Antlr对Hive SQL解析的代码如下,HiveLexerX,HiveParser分别是Antlr对语法文件Hive.g编译后自动生成的词法解析和语法解析类,在这两个类中进行复杂的解析。

HiveLexerX lexer = new HiveLexerX(new ANTLRNoCaseStringStream(command));    //词法解析,忽略关键词的大小写

TokenRewriteStream tokens = new TokenRewriteStream(lexer);

if (ctx != null) {

  ctx.setTokenRewriteStream(tokens);

}

HiveParser parser = new HiveParser(tokens);                                 //语法解析

parser.setTreeAdaptor(adaptor);

HiveParser.statement_return r = null;

try {

  r = parser.statement();                                                   //转化为AST Tree

} catch (RecognitionException e) {

  e.printStackTrace();

  throw new ParseException(parser.errors);

}


最终生成的AST Tree如下图右侧(使用AntlrWorks生成,Antlr Works是Antlr提供的编写语法文件的编辑器),图中只是展开了骨架的几个节点,没有完全展开。
子查询1/2,分别对应右侧第1/2两个部分。

这 里注意一下内层子查询也会生成一个TOK_DESTINATION节点。请看上面SelectStatement的语法规则,这个节点是在语法改写中特意 增加了的一个节点。原因是Hive中所有查询的数据均会保存在HDFS临时的文件中,无论是中间的子查询还是查询最终的结果,Insert语句最终会将数 据写入表所在的HDFS目录下。

详细来看,将内存子查询的from子句展开后,得到如下AST Tree,每个表生成一个TOK_TABREF节点,Join条件生成一个“=”节点。其他SQL部分类似,不一一详述。

回到顶部

2.2 Phase2 SQL基本组成单元QueryBlock

AST Tree仍然非常复杂,不够结构化,不方便直接翻译为MapReduce程序,AST Tree转化为QueryBlock就是将SQL进一部抽象和结构化。

2.2.1QueryBlock

QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出。简单来讲一个QueryBlock就是一个子查询。

下图为Hive中QueryBlock相关对象的类图,解释图中几个重要的属性

·        QB#aliasToSubq(表示QB类的aliasToSubq属性)保存子查询的QB对象,aliasToSubq key值是子查询的别名
·        QB#qbp
即QBParseInfo保存一个基本SQL单元中的给个操作部分的AST Tree结构,QBParseInfo#nameToDest这个HashMap保存查询单元的输出,key的形式是inclause-i(由于Hive支持Multi Insert语句,所以可能有多个输出),value是对应的ASTNode节点,即TOK_DESTINATION节点。类QBParseInfo其余
HashMap属性分别保存输出和各个操作的ASTNode节点的对应关系。
·        QBParseInfo#JoinExpr保存TOK_JOIN节点。QB#QBJoinTree是对Join语法树的结构化。
·        QB#qbm保存每个输入表的元信息,比如表在HDFS上的路径,保存表数据的文件格式等。
·        QBExpr这个对象是为了表示Union操作。

2.2.2AST Tree生成QueryBlock

AST Tree生成QueryBlock的过程是一个递归的过程,先序遍历AST Tree,遇到不同的Token节点,保存到相应的属性中,主要包含以下几个过程

·        TOK_QUERY =>
创建QB对象,循环递归子节点
·        TOK_FROM =>
将表名语法部分保存到QB对象的aliasToTabs等属性中
·        TOK_INSERT =>
循环递归子节点
·        TOK_DESTINATION =>
将输出目标的语法部分保存在QBParseInfo对象的nameToDest属性中
·        TOK_SELECT =>
分别将查询表达式的语法部分保存在destToSelExpr、destToAggregationExprs、destToDistinctFuncExprs三个属性中
·        TOK_WHERE =>
将Where部分的语法保存在QBParseInfo对象的destToWhereExpr属性中
最终样例SQL生成两个QB对象,QB对象的关系如下,QB1是外层查询,QB2是子查询

QB1

 

  \

 

   QB2


回到顶部

2.3 Phase3 逻辑操作符Operator

2.3.1Operator

Hive最终生成的MapReduce任务,Map阶段和Reduce阶段均由OperatorTree组成。逻辑操作符,就是在Map阶段或者Reduce阶段完成单一特定的操作。

基本的操作符包括TableScanOperator,SelectOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator

从名字就能猜出各个操作符完成的功能,TableScanOperator从MapReduce框架的Map接口原始输入表的数据,控制扫描表的数据行数,标记是从原表中取数据。JoinOperator完成Join操作。FilterOperator完成过滤操作

ReduceSinkOperator将Map端的字段组合序列化为Reduce Key/value, Partition Key,只可能出现在Map阶段,同时也标志着Hive生成的MapReduce程序中Map阶段的结束。

Operator在Map Reduce阶段之间的数据传递都是一个流式的过程。每一个Operator对一行数据完成操作后之后将数据传递给childOperator计算。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐