Hive 源码解读 Driver 语义分析器 SemanticAnalyzer

Posted @SmartSi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive 源码解读 Driver 语义分析器 SemanticAnalyzer相关的知识,希望对你有一定的参考价值。

Hive 版本:2.3.4

通过上一篇文章 Hive 源码解读 Driver 将 HQL 语句转换为 AST 中,我们可以看到 AST 抽象语法树还是很抽象,不够结构化,并且也不携带表、字段相关的信息。为了方便翻译为 MapReduce 程序,AST 需要进一步的抽象和结构化转化为 QueryBlock,在这个过程中语义分析器 SemanticAnalyzer 起到了重要的作用

1. 如何获取语义分析器

通过 QueryState 和语法树 ASTNode 以工厂设计模式获取处理不同语义的语义分析器:

BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(queryState, tree);

获取具体语义分析器的工作实际是交由 getInternal 方法处理,获取到语义分析器之后需要判断语法树 Token 对应的操作类型是否是 Hive 支持的:

public static BaseSemanticAnalyzer get(QueryState queryState, ASTNode tree) throws SemanticException 
  BaseSemanticAnalyzer sem = getInternal(queryState, tree);
  if(queryState.getHiveOperation() == null) 
    String query = queryState.getQueryString();
    if(query != null && query.length() > 30) 
      query = query.substring(0, 30);
    
    String msg = "Unknown HiveOperation for query='" + query + "' queryId=" + queryState.getQueryId();
  
  return sem;

2. 不同的语义分析器

获取具体语义分析器的工作实际是交由 getInternal 方法处理,获取过程如下所示:

private static BaseSemanticAnalyzer getInternal(QueryState queryState, ASTNode tree) throws SemanticException 
  if (tree.getToken() == null) 
    throw new RuntimeException("Empty Syntax Tree");
   else 
    // 通过词法符号获取对应的 Hive 操作
    HiveOperation opType = commandType.get(tree.getType());
    queryState.setCommandType(opType);
    // 通过词法符号获取对应的语义分析器
    switch (tree.getType()) 
      ...
    
  

核心是通过词法符号获取对应的语义分析器。不同的词法符号对应的语义分析器不同,例如 explain 命令解析后的抽象语法树的 Token 为 TOK_EXPLAIN,需要通过 ExplainSemanticAnalyzer 语义分析器进行分析:

switch (tree.getType()) 
    case HiveParser.TOK_EXPLAIN:
      return new ExplainSemanticAnalyzer(queryState);
    case HiveParser.TOK_EXPLAIN_SQ_REWRITE:
      return new ExplainSQRewriteSemanticAnalyzer(queryState);
    case HiveParser.TOK_LOAD:
      return new LoadSemanticAnalyzer(queryState);
    ...
    case HiveParser.TOK_CREATEDATABASE:
    case HiveParser.TOK_DROPDATABASE:
    case HiveParser.TOK_DROPTABLE:
    case HiveParser.TOK_SHOWDATABASES:
    case HiveParser.TOK_SHOWTABLES:
    case HiveParser.TOK_SHOWCOLUMNS:
    ...
    case HiveParser.TOK_SHOW_CREATEDATABASE:
    case HiveParser.TOK_SHOW_CREATETABLE:
    case HiveParser.TOK_SHOWFUNCTIONS:
    case HiveParser.TOK_SHOWPARTITIONS:
      return new DDLSemanticAnalyzer(queryState);
    ...
    case HiveParser.TOK_START_TRANSACTION:
    case HiveParser.TOK_COMMIT:
    case HiveParser.TOK_ROLLBACK:
    case HiveParser.TOK_SET_AUTOCOMMIT:
    default: 
      SemanticAnalyzer semAnalyzer = HiveConf.getBoolVar(
            queryState.getConf(), HiveConf.ConfVars.HIVE_CBO_ENABLED
      ) ? new CalcitePlanner(queryState) : new SemanticAnalyzer(queryState);
      return semAnalyzer;
    

我们日常打交道更多的是用户查询 Query,因此会走 default 选项,根据是否开启了 CBO 优化 选择的语义分析器也不一样:如果开启了则使用 CalcitePlanner 语义分析器,否则走 SemanticAnalyzer 语义分析器。

CBO,全称是 Cost Based Optimization,即基于代价的优化器。其优化目标是:在编译阶段,根据查询语句中涉及到的表和查询条件,计算出产生中间结果少的高效 JOIN 顺序,从而减少查询时间和资源消耗。Hive 使用开源组件 Apache Calcite 实现 CBO 优化。

下面简单罗列了词法符号与语义分析器的对应关系:

语义分析器词法符号
ExplainSemanticAnalyzerTOK_EXPLAIN
ExplainSQRewriteSemanticAnalyzerTOK_EXPLAIN_SQ_REWRITE
LoadSemanticAnalyzerTOK_LOAD
ExportSemanticAnalyzerTOK_EXPORT
ImportSemanticAnalyzerTOK_IMPORT
ReplicationSemanticAnalyzerTOK_REPL_DUMP、TOK_REPL_LOAD、TOK_REPL_STATUS
DDLSemanticAnalyzerTOK_ALTERTABLE、TOK_CREATEDATABASE、TOK_DROPDATABASE、TOK_DROPTABLE 等
FunctionSemanticAnalyzerTOK_CREATEFUNCTION、TOK_DROPFUNCTION、TOK_RELOADFUNCTION
ColumnStatsSemanticAnalyzerTOK_ANALYZE、TOK_ALTERVIEW
MacroSemanticAnalyzerTOK_CREATEMACRO、TOK_DROPMACRO
UpdateDeleteSemanticAnalyzerTOK_EXPORT、TOK_UPDATE_TABLE、TOK_DELETE_FROM、TOK_MERGE
CalcitePlanner在上与语义分析器满足不了的场景下使用,兜底语义分析器。开启 CBO 优化的情况下
SemanticAnalyzer在上与语义分析器满足不了的场景下使用,兜底语义分析器。不开启 CBO 优化的情况下

3. 示例

通过上一篇文章 Hive 源码解读 Driver 将 HQL 语句转换为 AST 中,我们了解到如下 SQL:

SELECT COUNT(*) AS num FROM behavior WHERE uid LIKE 'a%';

经过词法分析器、语义解析器分析之后得到的语法树 ASTNode 打印之后树形形式如下所示:

nil
   TOK_QUERY
      TOK_FROM
         TOK_TABREF
            TOK_TABNAME
               behavior
      TOK_INSERT
         TOK_DESTINATION
            TOK_DIR
               TOK_TMP_FILE
         TOK_SELECT
            TOK_SELEXPR
               TOK_FUNCTIONSTAR
                  COUNT
               num
         TOK_WHERE
            LIKE
               TOK_TABLE_OR_COL
                  uid
               'a%'
   <EOF>

上述语法树得到的节点类型为 HiveParser.TOK_QUERY,在默认开启 CBO 优化的情况下得到的语义分析器为 CalcitePlanner

default: 
  SemanticAnalyzer semAnalyzer = HiveConf
      .getBoolVar(queryState.getConf(), HiveConf.ConfVars.HIVE_CBO_ENABLED) ?
          new CalcitePlanner(queryState) : new SemanticAnalyzer(queryState);
  return semAnalyzer;

以上是关于Hive 源码解读 Driver 语义分析器 SemanticAnalyzer的主要内容,如果未能解决你的问题,请参考以下文章

Hive 源码解读 Driver 语义分析器 SemanticAnalyzer

Hive 源码解读 Driver 将 HQL 语句转换为 AST

Hive 源码解读 Driver 将 HQL 语句转换为 AST

Hive 源码解读 Driver 将 HQL 语句转换为 AST

第13课:Spark Streaming源码解读之Driver容错安全性

Spark Streaming源码解读之Driver容错安全性