Hive 源码解读 CLI 入口 CliDriver
Posted @SmartSi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive 源码解读 CLI 入口 CliDriver相关的知识,希望对你有一定的参考价值。
Hive 版本:2.3.4
1. 主入口 main
在上篇文章介绍 cli.sh 脚本时,我们了解到 CLI 的主入口类为 org.apache.hadoop.hive.cli.CliDriver
,其中入口即是 main 方法:
public static void main(String[] args) throws Exception
int ret = new CliDriver().run(args);
System.exit(ret);
在 main 方法中创建了 CliDriver 对象并进行一些初始化:
public CliDriver()
// 创建一个 SessionState 内部保存大量配置信息
SessionState ss = SessionState.get();
// 配置对象
conf = (ss != null) ? ss.getConf() : new Configuration();
// 初始化 Logger
Logger LOG = LoggerFactory.getLogger("CliDriver");
if (LOG.isDebugEnabled())
LOG.debug("CliDriver inited with classpath ", System.getProperty("java.class.path"));
console = new LogHelper(LOG);
2. 执行入口 run
在 main 方法调用了 CliDriver 的 run 方法。首先构造了一个参数解析器,来解析用户命令行 CLI 选项,Hive CLI 选项具体用法可查阅 Hive CLI 命令解读。在第一阶段 CLI 选项解析 process_stage1 中主要解析 hiveconf、define 以及 hivevar 选项定义的自定义变量和属性:
// 参数解析器
OptionsProcessor oproc = new OptionsProcessor();
if (!oproc.process_stage1(args))
return 1;
public boolean process_stage1(String[] argv)
try
// 调用解析器的 parse 方法解析参数
commandLine = new GnuParser().parse(options, argv);
// --hiveconf 属性选项
Properties confProps = commandLine.getOptionProperties("hiveconf");
for (String propKey : confProps.stringPropertyNames())
if (propKey.equalsIgnoreCase("hive.root.logger"))
CommonCliOptions.splitAndSetLogger(propKey, confProps);
else
System.setProperty(propKey, confProps.getProperty(propKey));
// --define 自定义变量选项
Properties hiveVars = commandLine.getOptionProperties("define");
for (String propKey : hiveVars.stringPropertyNames())
hiveVariables.put(propKey, hiveVars.getProperty(propKey));
// --hivevar 自定义变量选项
Properties hiveVars2 = commandLine.getOptionProperties("hivevar");
for (String propKey : hiveVars2.stringPropertyNames())
hiveVariables.put(propKey, hiveVars2.getProperty(propKey));
catch (ParseException e)
System.err.println(e.getMessage());
printUsage();
return false;
return true;
OptionsProcessor 如何解析 Hive CLI 选项可查阅 Apache Common CLI 如何实现命令行解析
然后定义标准化输入输出和错误输出流保存在 CliSessionState 会话对象中:
CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class));
ss.in = System.in;
try
ss.out = new PrintStream(System.out, true, "UTF-8");
ss.info = new PrintStream(System.err, true, "UTF-8");
ss.err = new CachingPrintStream(System.err, true, "UTF-8");
catch (UnsupportedEncodingException e)
return 3;
CliSessionState 使用 HiveConf 进行实例化,继承了 SessionState 类,是专门为 Hive CLI 创建的一个会话对象。用来记录 -database
、-e
、-f
、-hiveconf
以及 -i
选项指定的值。
在第二阶段 CLI 选项解析 process_stage2 中主要解析 -H
、-S
、--database
、-e
、-f
、-v
以及-i
选项:
if (!oproc.process_stage2(ss))
return 2;
public boolean process_stage2(CliSessionState ss)
ss.getConf();
// -H 帮助选项
if (commandLine.hasOption('H'))
printUsage();
return false;
// -S 静默选项
ss.setIsSilent(commandLine.hasOption('S'));
// --database 数据库选项
ss.database = commandLine.getOptionValue("database");
// -e 单 HQL 命令执行选项
ss.execString = commandLine.getOptionValue('e');
// -f HQL 文件执行选项
ss.fileName = commandLine.getOptionValue('f');
// -v 详细选项
ss.setIsVerbose(commandLine.hasOption('v'));
// -i 初始化选项
String[] initFiles = commandLine.getOptionValues('i');
if (null != initFiles)
ss.initFiles = Arrays.asList(initFiles);
// -e 和 -f 不能同时指定
if (ss.execString != null && ss.fileName != null)
System.err.println("The '-e' and '-f' options cannot be specified simultaneously");
printUsage();
return false;
//
if (commandLine.hasOption("hiveconf"))
Properties confProps = commandLine.getOptionProperties("hiveconf");
for (String propKey : confProps.stringPropertyNames())
ss.cmdProperties.setProperty(propKey, confProps.getProperty(propKey));
return true;
将解析出的选项内容填充 CliSessionState 会话对象。例如,用户输入了 -e
,就把 -e
对应的字符串赋值给 CliSessionState 的 execString 成员。
然后将用户命令行输入的配置信息和变量等覆盖 HiveConf 的默认值:
HiveConf conf = ss.getConf();
for (Map.Entry<Object, Object> item : ss.cmdProperties.entrySet())
conf.set((String) item.getKey(), (String) item.getValue());
ss.getOverriddenConfigurations().put((String) item.getKey(), (String) item.getValue());
读取配置提示和替换变量。用户可以在查询中引用变量,Hive 会先使用变量值替换掉查询中的变量引用,然后才会将查询语句提交给查询处理器:
// 提示符
prompt = conf.getVar(HiveConf.ConfVars.CLIPROMPT);
// 变量替换
prompt = new VariableSubstitution(new HiveVariableSource()
@Override
public Map<String, String> getHiveVariable()
return SessionState.get().getHiveVariables();
).substitute(conf, prompt);
prompt2 = spacesForString(prompt);
开启会话状态:
if (HiveConf.getBoolVar(conf, ConfVars.HIVE_CLI_TEZ_SESSION_ASYNC))
SessionState.beginStart(ss, console);
else
SessionState.start(ss);
最重要的的一步就是执行 CLI 驱动程序:
try
return executeDriver(ss, conf, oproc);
finally
ss.resetThreadName();
ss.close();
3. 执行 CLI 驱动
在上面说到最重要的的一步就是执行 CLI 驱动程序方法 executeDriver。下面具体看一下如何执行的。首先从 OptionsProcessor 解析器中获取解析到的 Hive 变量并存储到 SessionState 的 hiveVariables 变量中:
// oproc 为 OptionsProcessor
cli.setHiveVariables(oproc.getHiveVariables());
// 存储到 SessionState 的 hiveVariables 变量中
public void setHiveVariables(Map<String, String> hiveVariables)
SessionState.get().setHiveVariables(hiveVariables);
如果 Hive CLI 命令行中指定了 --database
选项,需要使用指定的数据库,即执行 use <database>;
HQL 语句:
cli.processSelectDatabase(ss);
// 执行切换数据库HQL语句
public void processSelectDatabase(CliSessionState ss) throws IOException
String database = ss.database;
if (database != null)
int rc = processLine("use " + database + ";");
if (rc != 0)
System.exit(rc);
如果 Hive CLI 命令行中指定了 -e '<quoted-query-string>'
选项,需要调用 processLine 来执行 HQL 语句:
if (ss.execString != null)
int cmdProcessStatus = cli.processLine(ss.execString);
return cmdProcessStatus;
processLine 如何处理 HQL 语句后续会详细介绍
如果 Hive CLI 命令行中指定了 -f <query-file>
选项,需要调用 processFile 来执行文件中的一个或者多个 HQL 语句:
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;
processFile 如何处理文件中的一个或者多个 HQL 语句后续会详细介绍
如果 Hive 的执行引擎选择的是 mr 会打印警告信息 Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases.
,提示你要切换到 Spark 或者 Tez 执行引擎上:
if ("mr".equals(HiveConf.getVar(conf, ConfVars.HIVE_EXECUTION_ENGINE)))
console.printInfo(HiveConf.generateMrDeprecationWarning());
最后最重要的是从标准化输入中解析出一个个完整 HQL 语句交由 processLine 来执行:
String line;
int ret = 0;
String prefix = "";
String curDB = getFormattedDb(conf, ss);
String curPrompt = prompt + curDB;
String dbSpaces = spacesForString(curDB);
while ((line = reader.readLine(curPrompt + "> ")) != null)
// 换行
if (!prefix.equals(""))
prefix += '\\n';
// 遇到注释跳过
if (line.trim().startsWith("--"))
continue;
// 直到遇到分号结尾 表示一个完整 HQL 语句
if (line.trim().endsWith(";") && !line.trim().endsWith("\\\\;"))
line = prefix + line;
// HQL 语句的执行实际上交由 processLine 处理
ret = cli.processLine(line, true);
prefix = "";
curDB = getFormattedDb(conf, ss);
curPrompt = prompt + curDB;
dbSpaces = dbSpaces.length() == curDB.length() ? dbSpaces : spacesForString(curDB);
else
prefix = prefix + line;
curPrompt = prompt2 + dbSpaces;
continue;
以上是关于Hive 源码解读 CLI 入口 CliDriver的主要内容,如果未能解决你的问题,请参考以下文章