天天看点

Impala学习--Impala前端代码分析Impala前端代码分析

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
  • 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