大数据 - hive执行SQL语句基本流程- 源码01

hive简介

什么是Hive?

  • 数据仓库:存储、查询、分析大规模数据
  • SQL语言:简单易用的类SQL查询语言
  • 编程模型:允许开发者自定义UDF、Transform、Mapper、Reducer,来更简单地完成复杂MapReduce无法完成的工作
  • 数据格式:处理Hadoop上任意数据格式的数据,或者使用优化的格式存储Hadoop上的数据,RCFile,ORCFile,Parquest
  • 数据服务:HiveServer2,多种API访问Hadoop上的数据,JDBC,ODBC
  • 元数据服务:数据什么样,数据在哪里,Hadoop上的唯一标准
hive架构图

hive cli架构图

hive源码结构

在这里插入图片描述

hive三大核心模块
  • Query Processor:查询处理工具,源码ql包
  • SerDe:序列化与反序列化器,源码serde包
  • MetaStore:元数据存储及服务,源码metastore包

hive执行命令入口

入口为:/bin/cli.sh
一个查询(假设通过CLI入口)直到获取最终结果,Hive内部的执行流程主要包括:

  1. CLI 获取用户查询,解析用户输入的命令,提交给Driver;
  2. Driver 结合编译器(COMPILER)和元数据库(METASTORE),对用户查询进行编译解析;
  3. 根据解析结果(查询计划)生成MR任务提交给Hadoop执行;
  4. 获取最终结果;
接收命令的入口函数

CliDriver类的执行入口,cli.CliDriver.main()函数,创建CliDriver实例,接受用户输入参数,开始运行。

  public static void main(String[] args) throws Exception {
    int ret = new CliDriver().run(args);
    System.exit(ret);
  }
调用cli.CliDriver.run()方法

方法返回return executeDriver(ss, conf, oproc);调用executeDriver,在executeDriver中对应上边提到的三种情况:

  • 一种是hive -e执行sql,此时ss.execString非空,执行完进程退出;
  • 一种是hive -f执行sql文件,此时ss.fileName非空,执行完进程退出;
  • 一种是hive交互式执行sql,此时会不断读取reader.readLine,然后执行失去了并输出结果;
executeDriver调用 cli.processLine()或者cli.processFile()
 if (ss.execString != null) {
      int cmdProcessStatus = cli.processLine(ss.execString);
      return cmdProcessStatus;
    }
    try {
      if (ss.fileName != null) {
        return cli.processFile(ss.fileName);
    } catch (FileNotFoundException e) {
      System.err.println("Could not open input file for reading. (" + e.getMessage() + ")");
      return 3;
    }
cli.processLine()后面会调用cli.processFile()方法
调用CliDriver.processCmd()方法

CliDriver.processCmd()方法根据指令不同进行对应的操作,指令分为四种:

  • quit or exit系统正常退出
  • !开头的命令行执行操作系统命令
  • source开头的,读取外部文件并执行文件中的命令list列出jar file archive
  • 其他命令提交给Commandprocess,进行命令的预处理
调用processLocalCmd()方法
        //CommandProcessorFactory 根据用户指令生成的tokens和配置文件,返回CommandProcessor的一个具体实现
        CommandProcessor proc = CommandProcessorFactory.get(tokens, (HiveConf) conf);
        //提交用户的cmd到指定的CommandProcessor,并获取结果。
        ret = processLocalCmd(cmd, proc, ss);

很核心的一个方法,提交用户的cmd到指定的CommandProcessor,并获取结果.

调用Driver.run()方法

在processLocalCmd()中调用Driver.run()方法去执行sql

 qp.setTryCount(tryCount);
            //driver实例运行用户指令,获取运行结果响应码
            ret = qp.run(cmd).getResponseCode();
            if (ret != 0) {
              qp.close();
              return ret;
            }

            // 统计指令的运行时间
            long end = System.currentTimeMillis();
            double timeTaken = (end - start) / 1000.0;

            ArrayList<String> res = new ArrayList<String>();
             //打印查询结果的列名称
            printHeader(qp, out);

            // 打印查询结果
            int counter = 0;
            try {
              if (out instanceof FetchConverter) {
                ((FetchConverter)out).fetchStarted();
              }
              while (qp.getResults(res)) {
                for (String r : res) {
                  out.println(r);
                }
                
                counter += res.size();
                res.clear();
                if (out.checkError()) {
                  break;
                }
              }
            } catch (IOException e) {
              console.printError("Failed with exception " + e.getClass().getName() + ":"
                  + e.getMessage(), "\n"
                  + org.apache.hadoop.util.StringUtils.stringifyException(e));
              ret = 1;
            }
            //关闭结果
            int cret = qp.close();
            if (ret == 0) {
              ret = cret;
            }

            if (out instanceof FetchConverter) {
              ((FetchConverter)out).fetchFinished();
            }

            console.printInfo("Time taken: " + timeTaken + " seconds" +
                (counter == 0 ? "" : ", Fetched: " + counter + " row(s)"));
          } else {
            //如果proc不是Driver,也就是用户执行的是非SQL查询操作,直接执行语句,不自信FetchResult的操作
            String firstToken = tokenizeCmd(cmd.trim())[0];
            String cmd_1 = getFirstCmd(cmd.trim(), firstToken.length());

            if (ss.getIsVerbose()) {
              ss.out.println(firstToken + " " + cmd_1);
            }
            CommandProcessorResponse res = proc.run(cmd_1);
            if (res.getResponseCode() != 0) {
              ss.out.println("Query returned non-zero code: " + res.getResponseCode() +
                  ", cause: " + res.getErrorMessage());
            }
            ret = res.getResponseCode();
          }
        }
      } catch (CommandNeedRetryException e) {
        //如果执行过程中出现异常,修改needRetry标志,下次循环是retry。
        console.printInfo("Retry query with a different approach...");
        tryCount++;
        needRetry = true;
      }
    } while (needRetry);

之后进入Driver类对sql进行处理,包括编译、解析、优化、执行。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值