2021SC@SDUSC
目录
概述
补充说明doPhase1()
getmetaData(QB, ReadEntity)分析
概述
上一篇文章中,我分析了doPhase1()函数,这是语义分析的起始阶段,程序的最终目标是将AST的数据载入QB,doPhase1这一阶段主要思想是递归地遍历AST,建立一些必要的映射关系,从而将一些关键信息传给QB,如表、子查询的别名信息、内部子句的名字、聚合 *** 作信息等,进而上面所有这些映射关系都保存在QB/QBParseInfo 中。
补充说明doPhase1()再来看一次此处代码的大致结构和工作流程
public boolean doPhase1(ASTNode ast, QB qb, Phase1Ctx ctx_1, PlannerContext plannerCtx) throws SemanticException { 。。。。。。。。。。。。。。。。略。。。。。。。。 case HiveParser.TOK_SELECt://select类型的token qb.countSel();//对qb做标记 qbp.setSelExprForClause(ctx_1.dest, ast); 。。。。。。。。。。。。。。。。。略。。。。。。 case HiveParser.TOK_WHERe://where类型token //对where的孩子进行处理,为什么是ast.getChild(0)?这个是和之前的HiveParser.g结构相辅相成的。 qbp.setWhrExprForClause(ctx_1.dest, ast); if (!SubQueryUtils.findSubQueries((ASTNode) ast.getChild(0)).isEmpty()) queryProperties.setFilterWithSubQuery(true); break; 。。。。。。。。。。。。。。。。略。。。。。。。。 case HiveParser.TOK_GROUPBY: case HiveParser.TOK_ROLLUP_GROUPBY: case HiveParser.TOK_CUBE_GROUPBY: case HiveParser.TOK_GROUPING_SETS: 。。。。。。。。。。。。略。。。。。。。。 if (!skipRecursion) { // Iterate over the rest of the children int child_count = ast.getChildCount(); for (int child_pos = 0; child_pos < child_count && phase1Result; ++child_pos) { // Recurse phase1Result = phase1Result && doPhase1( (ASTNode)ast.getChild(child_pos), qb, ctx_1, plannerCtx); } } 。。。。。。。。。。。。。。。略。。。。。。。。。
大体过程:
doPhase1对ASTTree中的每个元素的TOK类型进行case,针对于不同的case对节点数据进行填充。for遍历整棵ASTTree,中间对每个元素递归调用doPhase1,这种方式是一种深度优先搜索的算法。
经过一轮深度优先遍历,不带元数据的QB树就生成了。
getmetaData(QB, ReadEntity)分析doPhase1执行完毕之后得到QB,QB里边的只是一些关键字还有一些表的名字,但是和hdfs的文件路径对应不起来,所以需要元数据metaData映射关系,之后在SemanticAnalyzer中调用了 getmetaData()函数。
private void getmetaData(QB qb, ReadEntity parentInput) throws HiveException { LOG.info("Get metadata for source tables");
根据日志信息,可以知道,该函数的目标是从源头表中获取元数据
ListtabAliases = new ArrayList (qb.getTabAliases());
上面这个列表记录了别名,因为别名可能在中间被修改
Map> aliasToViewInfo = new HashMap >();
上面这个MAP的作用,我的理解是:
跟踪视图别名,查看名称和读取实体
例如:对于像'select * from V3'的查询,其中V3 -> V2, V2 -> V1, V1 -> T
map用于跟踪输入的依赖项及其父类。
MapsqAliasToCTEName = new HashMap (); for (String alias : tabAliases) { String tabName = qb.getTabNameForAlias(alias); String cteName = tabName.toLowerCase();
从tabNameToTabObject缓存中获取表的详细信息:
Table tab = getTableObjectByName(tabName, false); if (tab != null) { // do a deep copy, in case downstream changes it. tab = new Table(tab.getTTable().deepCopy()); } if (tab == null || tab.getDbName().equals(SessionState.get().getCurrentDatabase())) { Table materializedTab = ctx.getMaterializedTable(cteName); if (materializedTab == null) { // we first look for this alias from CTE, and then from catalog. CTEClause cte = findCTEFromName(qb, cteName); if (cte != null) { if (!cte.materialize) { addCTEAsSubQuery(qb, cteName, alias); sqAliasToCTEName.put(alias, cteName); continue; } tab = materializeCTE(cteName, cte); } } else { tab = materializedTab; } } throw new SemanticException(e.getMessage(), e); } }
这个函数多次出现词CTE,而且程序中有很多涉及CTE的函数,这个CTE是做什么的?查阅资料了解到,CTE是很多数据库系统中常用的一种公用表达式。
公用表表达式(CTE)可以被认为是在单个SELECT,INSERT,UPDATE,DELETE或CREATE VIEW语句的执行范围内定义的临时结果集。CTE类似于派生表,因为它不作为对象存储,并且仅在查询期间持续。与派生表不同,CTE可以是自引用的,并且可以在同一查询中多次引用。
CTE由表示CTE的表达式名称,AS关键字和SELECT语句组成。定义CTE后,可以在SELECT,INSERT,UPDATE或DELETE语句中像表或视图一样引用它。CTE也可以在CREATE VIEW语句中用作其定义SELECT语句的一部分。
小结:
getmetaData():获取源表、目标表、的元数据(主要是schema 等信息)
获取的元数据同样存储在QB/QBParseInfo 中。
①获取source table 的元数据,如果一个table 实际上是一个view,将其重写为view 的定义;
②递归的为每个子查询中的源表获得元数据;
③获取所有destination table/dir/local dir 的元数据;
至此,才把比较完整的信息传给QB
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)