Impala前端代码分析
Table of Contents
- 1 概述
- 2 语法分析和ParseNode
- 3 Analyzer
- 4 生成执行计划和Planner
- 5 Catalog
1 概述
前端代码使用java。感觉使用java的原因是,本身语法分析不会占用太多时间,毫秒级可以完成,不是性能瓶颈。而且语法分析的代码通常比较复杂,逻辑较多,如果再自己管理内存的话,会影响开发效率。
Impala通过jni调用前端java代码,前后端数据传递采用thrift格式。
前端的代码主要包括以下几个功能:
- 将用户提交的query转换成语法树,这个通过jflex和cup完成(hive使用的是antlr)
- 语法分析
- 生成执行计划
- 在编译中访问元数据
2 语法分析和ParseNode
ParseNode定义了一个接口。jflex和cup分析完的语法树中,每一个节点都实现了这个接口。语法分析就是在这个ParseNode组成的树中进行的。
ParseNode的实现和继承关系如下:
- Expr (表达式)
- Predicate (谓词,出现在where语句中)
- BetweenPredicate
- BinaryPredicate (=, !=, <=, >=, <, >)
- CompoundPredicate (&&, ||, !)
- InPredicate
- IsNullPredicate
- LikePredicate
- LiteralPredicate
- BoolLiteral
- DateLiteral
- FloatLiteral
- IntLiteral
- NullLiteral
- StringLiteral
- AggregateExpr (count, min, max, distince, sum, avg)
- ArithmeticExpr (*, /, %, DIV, +, -, &, |, ^, ~)
- CaseExpr
- CastExpr
- FunctionCallExpr
- LiteralExpr
- TimestampArithmeticExpr
- Predicate (谓词,出现在where语句中)
- QueryStmt
- SelectStmt
- UnionStmt
- InsertStmt
- ShowDbStmt
- ShowTablesStmt
- DescribeStmt
- UseStmt
- TableRef
- BaseTableRef
- InlineViewTableRef (alias)
其中,Expr继承了TreeNode类,可以组成一个求值树。而其他ParseNode虽然没有继承TreeNode,但也都有类似的数据结构。可以访问孩子节点。这样ParseNode就组成了一颗语法树。
语法分析阶段主要进行了一些基本的语法检查,类型检查,并抽取一些信息,放到Analyzer类中,例如alias映射表等等。
3 Analyzer
Analyzer是语法分析的一个产出。Analyzer用于收集某一个QureyBlock内的信息。类似Hive中的QB类。
其主要成员变量包括:
- DescriptorTable descTbl;
- Catalog catalog;
- String defaultDb;
- IdGenerator<ExprId> conjunctIdGenerator;
- Analyzer parentAnalyzer;
- Map<String, TupleDescriptor> aliasMap;
- Map<String, SlotDescriptor> slotRefMap;
- Map<ExprId, Predicate> conjuncts;
- Map<TupleId, List<ExprId> > tuplePredicates;
- Map<SlotId, List<ExprId> > slotPredicates;
- Map<TupleId, List<ExprId> > eqJoinConjuncts;
- Set<ExprId> assignedConjuncts;
- Map<TupleId, TableRef> outerJoinedTupleIds;
- Map<TableRef, List<ExprId> > conjunctsByOjClouse;
- Map<ExprId, TableRef> ojClouseByConjunct;
- Set<ExprId> whereClauseConjuncts;
4 生成执行计划和Planner
Planner负责将分析后的语法树转换成执行计划,即PlanFragments。
Planner的入口函数是Planner::createPlanFragments()。其主要流程如下:
-
createSinglePlan:
根据语法分析的结果,遍历并生成一个逻辑执行计划树。树中的节点是PlanNode。树的根节点是最后被执行的节点。
-
createPlanFragments:
将生成的执行计划切割成多个PlanFragment。这个过程类似Hive中将执行计划分割成多个MapRed阶段。目前Impala划分阶段的规则是:如果遇到ScanNode, HashJoinNode, MergeNode, AggregationNode, SortNode,则产生一个新的PlanFragment。每一个PlanFragment之间通过ExchangeNode相连。ExchangeNode在运行时中会负责跨Impalad的数据传输。
-
computeMemLayout:
对于输入表,计算在内存中的layout。主要目的是为了计算一条记录在内存中会占用多少字节(由TupleDescriptor描述),以及每一个字段在内存中如何分布(由SlotDescriptor描述)。
最后PlanFragments就会成为物理执行计划,转成thrift后返回给前端。
5 Catalog
Impala直接使用了Hive的HiveMeteStoreClient类,用于访问元数据。这就意味着,必须还要启动一个HiveMetaStore进程,用于提供元数据服务。目前Catalog默认采用lazy模式,只在需要时加载database和table对象。
Catalog主要在语法分析阶段使用,用于获取Hive元数据,目前在Planner中没有使用Catalog。
Author: <[email protected]>
Date: 2013-02-20 19:43:07 CST
HTML generated by org-mode 6.21b in emacs 23