三、 Hive 逻辑算子及其生成(下)

3.3算子DAG的生成

   在第一章1.4节我们提到Hive首先将抽象语法树AST转换成查询块(QueryBlock),然后在将QueryBlock转化成算子DAG。

3.3.1QueryBlock生成

1) QB数据结构

QueryBlock数据结构定义在QB类中,QB的主要成员变量如下:

HashMap<String, String> aliasToTabs;
HashMap<String, QBExpr> aliasToSubq;
HashMap<String, Map<String, String>> aliasToProps;
List<String> aliases; 
QBParseInfo qbp; 
QBMetaData qbm; 
QBJoinTree qbjoin;

aliasToTabs: 表别名和表名映射关系。

aliasToSubq:子查询语句别名和子查询语句映射关系。其中QBExpr表示子查询语句的集合运算,Hive中定义了以下几种运算类型:

(1) NULLOP:表示单个子查询语句,没有任何运算。其QBExpr#qb字段表示子查询语句的QB。

(2) UNION:表示union运算,包含两个QBExpr对象,分别表示参与运算的两个子查询语句。

(3) INTERSECT:表示表的交集运算,目前尚未实现。

(4) EXCEPT:表示表的差集运算,目前尚未实现。

aliasToProps:表别名和表属性映射关系。

aliases:语句中所有表和子语句的别名。

qbp:QBParseInfo类型,记录该语句相关的信息。主要包括该语句是否为子查询语句、表别名、join语句语法树、where语句语法树、select语句语法树以及body语句的语法树(groupby、where,limit,clusterby,order by等语句)。insert语句还包含insert 目的数据源表名称列表。注意:由于HiveQL insert语句中可以包含多个insert分支(参考第二章insert语法树部分的介绍),每个分支包含select语句以及body语句,因此QBParseInfo使用hash表存放每个分支的select语句语法树以及body语句语法树。其中,hash表的key是分支的名称(Hive称之为dest,即insert的目的地名称),value为语法树。

qbm:QBMetaData类型,存放语句中表和分区的元数据信息。

qbjoin:QBJoinTree类型,记录Join树结构信息。第二章介绍过,join树是一颗左型树,QBJoinTree与之对应也是一棵左型树。关于QBJoinTree的具体介绍,参见下文。

2)QB的生成

Hive通过遍历抽象语法树(AST)生成QB对象,这一部分的核心代码位于SemanticAnalyzer#doPhase1方法中,伪代码如下:

doPhase1(ASTNode ast,dest,QB qb){
QBParseInfo qbb=qb.getParseInfo()//存放语句相关信息
Boolean recursion=false;//ast节点是否需要递归处理
switch(ast.nodeType) {
case TOK_DESTINATION:
  dest=newInsertName(); //生成新分支名称
  qpb.setDest(dest,ast) //保存当前insert分支的目标数据源
case TOK_SELECT:
  //保存当前insert分支的select表达式
  qpb.setSelExpr(dest,ast)
  //保存当前insert分支的聚合函数表达式
  qpb.setAggregationExpr(dest,getAggFunc(ast))
case TOK_WHERE:
  //保存当前insert分支的where表达式
  qbp.setWhereExpr(dest,ast)
case TOK_GROUPBY:
  //保存当前insert分支的group by表达式
  qbp.setGroupByExpr(dest,ast)
case TOK_LIMIT:
  //保存目标insert分支的limit语句
  qbp.setDestLimit(dest,ast)
case 其他body语句节点(sortby,orderby等):
  保存相应内容到当前的insert分支下,这里省略。
case TOK_FROM:
   fromSrc=ast.getChild(0)
   if(fromSrc==TOK_TABREF) {
     processTable(qb,fromSrc)
   } else if(fromSrc==TOK_SUBQUERY) {
     processSubQuery(qb,fromSrc)
   } else if(isJoin(fromSrc) {
     processJoin(qb,frm)
     qb.setJoinExpr(fromSrc)//保存join AST树
   } else 其他fromSrc …
case 其他节点:
     //其他节点递归处理
     recursion=true
 }
 if(recursion)
    for(child:ast.getChildren()) {
       doPhase1(child,dest,qb)
    }
}

doPhase1方法根据ast节点的类型提取相应节点的信息,保存到qb对象中。如对于TOK_SELECT节点,保存select表达式以及聚合函数信息。遇到TOK_DESTINATION节点时,生成新分支名称,同时保存目标数据源信息(目标数据源表名称,临时文件路径等)。后续TOK_SELECT节点和body语句节点(TOK_GROUPBY,TOK_LIMIT等)的信息保存在该Insert分支下面。

对于TOK_FROM节点的处理比较复杂。第二章讲过,from的数据源包含多种类型,

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值