Hive源码阅读–查询分析器–SemanticAnalyzer
程序员文章站
2022-07-08 10:26:04
SemanticAnalyzer可以说是对查询所有的优化都在其中。代码量有13514行,我们主要关注他对analyzeInternal的实现。 void analyzeInternal(ASTNode ast, PlannerContext plannerCtx) throws SemanticException { // 1.从语法树生成解析树 LOG.info("Starting Semantic Analysis"); processPositionAlias(ast);...
SemanticAnalyzer
可以说是对查询所有的优化都在其中。代码量有13514行,我们主要关注他对analyzeInternal的实现。
void analyzeInternal(ASTNode ast, PlannerContext plannerCtx) throws SemanticException {
// 1.从语法树生成解析树
LOG.info("Starting Semantic Analysis");
processPositionAlias(ast);
// 语义解析
if (!genResolvedParseTree(ast, plannerCtx)) {
return;
}
// 2. 从解析树生成逻辑执行计划
// 解析QB生成一个Operator Tree,其实是生成一个DAG
Operator sinkOp = genOPTree(ast, plannerCtx);
if (!unparseTranslator.isEnabled() && tableMask.isEnabled()) {
// 重写表列的遮蔽
ASTNode tree = rewriteASTWithMaskAndFilter(tableMask, ast, ctx.getTokenRewriteStream(),
ctx, db, tabNameToTabObject, ignoredTokens);
if (tree != ast) {
ctx.setSkipTableMasking(true);
init(true);
// change the location of position alias process here
processPositionAlias(tree);
genResolvedParseTree(tree, plannerCtx);
if (this instanceof CalcitePlanner) {
((CalcitePlanner) this).resetCalciteConfiguration();
}
sinkOp = genOPTree(tree, plannerCtx);
}
}
// 3. 从逻辑执行计划推导结果集模式
if (createVwDesc != null && !this.ctx.isCboSucceeded()) {
resultSchema = convertRowSchemaToViewSchema(opParseCtx.get(sinkOp).getRowResolver());
} else {
// 在hive1.1.0之后,feature是默认开启的,他可以自动优化多join的顺序,并选择适合的join算法。
// 如果满足以下条件,则resultSchema将为null
// (1) cbo已禁用;
// (2) cbo已通过AST返回路径启用 (无论成功与否,resultSchema将被重新初始化)
// 只有使用新的返回路径启用cbo并且它会不为null最后才会成功
if (resultSchema == null) {
resultSchema = convertRowSchemaToResultSetSchema(opParseCtx.get(sinkOp).getRowResolver(),
HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_RESULTSET_USE_UNIQUE_COLUMN_NAMES));
}
}
// 4.为优化器和物理编译器生成解析上下文
copyInfoToQueryProperties(queryProperties);
ParseContext pCtx = new ParseContext(queryState, opToPartPruner, opToPartList, topOps,
new HashSet<JoinOperator>(joinContext.keySet()),
new HashSet<SMBMapJoinOperator>(smbMapJoinContext.keySet()),
loadTableWork, loadFileWork, columnStatsAutoGatherContexts, ctx, idToTableNameMap, destTableId, uCtx,
listMapJoinOpsNoReducer, prunedPartitions, tabNameToTabObject, opToSamplePruner,
globalLimitCtx, nameToSplitSample, inputs, rootTasks, opToPartToSkewedPruner,
viewAliasToInput, reduceSinkOperatorsAddedByEnforceBucketingSorting,
analyzeRewrite, tableDesc, createVwDesc, queryProperties, viewProjectToTableSchema, acidFileSinks);
// 5. 创建视图
if (createVwDesc != null) {
if (ctx.getExplainAnalyze() == AnalyzeState.RUNNING) {
return;
}
if (!ctx.isCboSucceeded()) {
saveViewDefinition();
}
// 此时验证create view语句,createVwDesc将获取所有信息以进行语义检查
validateCreateView();
if (!createVwDesc.isMaterialized()) {
// 由于我们仅创建视图(不执行视图),因此不需要优化或转换计划(实际上,这些过程会干扰视图的创建)。
// 因此,跳过此方法的其余部分。
ctx.setResDir(null);
ctx.setResFile(null);
try {
PlanUtils.addInputsForView(pCtx);
} catch (HiveException e) {
throw new SemanticException(e);
}
// 生成创建视图的语句如果配置LineageLogger hook ,
// 添加计算血缘信息
Set<String> postExecHooks = Sets.newHashSet(Splitter.on(",").trimResults()
.omitEmptyStrings()
.split(Strings.nullToEmpty(HiveConf.getVar(conf, HiveConf.ConfVars.POSTEXECHOOKS))));
if (postExecHooks.contains("org.apache.hadoop.hive.ql.hooks.PostExecutePrinter")
|| postExecHooks.contains("org.apache.hadoop.hive.ql.hooks.LineageLogger")
|| postExecHooks.contains("org.apache.atlas.hive.hook.HiveHook")) {
ArrayList<Transform> transformations = new ArrayList<Transform>();
transformations.add(new HiveOpConverterPostProc());
transformations.add(new Generator());
for (Transform t : transformations) {
pCtx = t.transform(pCtx);
}
// 使用视图名称
SessionState.get().getLineageState()
.mapDirToOp(new Path(createVwDesc.getViewName()), sinkOp);
}
return;
}
}
// 6. 生成表访问统计信息
if (HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_TABLEKEYS)) {
TableAccessAnalyzer tableAccessAnalyzer = new TableAccessAnalyzer(pCtx);
setTableAccessInfo(tableAccessAnalyzer.analyzeTableAccess());
}
// 7.执行逻辑优化
if (LOG.isDebugEnabled()) {
LOG.debug("Before logical optimization\n" + Operator.toString(pCtx.getTopOps().values()));
}
Optimizer optm = new Optimizer();
optm.setPctx(pCtx);
// 初始化的时候,加入很多优化器
optm.initialize(conf);
// 优化逻辑执行计划
pCtx = optm.optimize();
if (pCtx.getColumnAccessInfo() != null) {
// 为视图列授权设置ColumnAccessInfo
setColumnAccessInfo(pCtx.getColumnAccessInfo());
}
FetchTask origFetchTask = pCtx.getFetchTask();
if (LOG.isDebugEnabled()) {
LOG.debug("After logical optimization\n" + Operator.toString(pCtx.getTopOps().values()));
}
// 8. 可能的话,进行列裁剪
boolean isColumnInfoNeedForAuth = SessionState.get().isAuthorizationModeV2()
&& HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED);
if (isColumnInfoNeedForAuth
|| HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS)) {
ColumnAccessAnalyzer columnAccessAnalyzer = new ColumnAccessAnalyzer(pCtx);
// 查看列访问信息
setColumnAccessInfo(columnAccessAnalyzer.analyzeColumnAccess(this.getColumnAccessInfo()));
}
// 9. 优化物理操作树并转换为目标执行引擎
if (!ctx.getExplainLogical()) {
TaskCompiler compiler = TaskCompilerFactory.getCompiler(conf, pCtx);
compiler.init(queryState, console, db);
compiler.compile(pCtx, rootTasks, inputs, outputs);
fetchTask = pCtx.getFetchTask();
}
LOG.info("Completed plan generation");
// 10. 将访问的列放入readEntity
if (HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS)) {
putAccessedColumnsToReadEntity(inputs, columnAccessInfo);
}
// 11. 如果需要检查,只会在limit范围内进行
if (!ctx.isExplainSkipExecution()) {
enforceScanLimits(pCtx, origFetchTask);
}
return;
}
里面涵盖了 语法树–》解析树–》逻辑执行计划–》结果结果集模式–》构建上下文–》查询视图–》获取表信息–》逻辑优化–》获取列信息–》查询所需数据–》检查。
全套的流程,从查询SQL到最后的结果,流程全部都在这里。
然后看一下重中之重的语义解析,
boolean genResolvedParseTree(ASTNode ast, PlannerContext plannerCtx) throws SemanticException {
ASTNode child = ast;
this.ast = ast;
viewsExpanded = new ArrayList<String>();
ctesExpanded = new ArrayList<String>();
// 1. 分析处理别名
// 2. 分析创建表命令
if (ast.getToken().getType() == HiveParser.TOK_CREATETABLE) {
// 如果不是CTAS(create table ... as select ...)语法,直接返回即可,
// 如果是,执行setCommandType
if ((child = analyzeCreateTable(ast, qb, plannerCtx)) == null) {
return false;
}
} else {
queryState.setCommandType(HiveOperation.QUERY);
}
// 3. 分析创建视图命令
if (ast.getToken().getType() == HiveParser.TOK_CREATEVIEW ||
ast.getToken().getType() == HiveParser.TOK_CREATE_MATERIALIZED_VIEW ||
(ast.getToken().getType() == HiveParser.TOK_ALTERVIEW &&
ast.getChild(1).getType() == HiveParser.TOK_QUERY)) {
child = analyzeCreateView(ast, qb, plannerCtx);
if (child == null) {
return false;
}
viewSelect = child;
// 视图不可引用自身
viewsExpanded.add(createVwDesc.getViewName());
}
switch(ast.getToken().getType()) {
case HiveParser.TOK_SET_AUTOCOMMIT:
assert ast.getChildCount() == 1;
if(ast.getChild(0).getType() == HiveParser.TOK_TRUE) {
setAutoCommitValue(true);
}
else if(ast.getChild(0).getType() == HiveParser.TOK_FALSE) {
setAutoCommitValue(false);
}
else {
assert false : "Unexpected child of TOK_SET_AUTOCOMMIT: " + ast.getChild(0).getType();
}
// 计划落空
case HiveParser.TOK_START_TRANSACTION:
case HiveParser.TOK_COMMIT:
case HiveParser.TOK_ROLLBACK:
if(!(conf.getBoolVar(ConfVars.HIVE_IN_TEST) || conf.getBoolVar(ConfVars.HIVE_IN_TEZ_TEST))) {
throw new IllegalStateException(SemanticAnalyzerFactory.getOperation(ast.getToken().getType()) +
" is not supported yet.");
}
queryState.setCommandType(SemanticAnalyzerFactory.getOperation(ast.getToken().getType()));
return false;
}
// 掩蔽与过滤解析
tableMask = new TableMask(this, conf, ctx.isSkipTableMasking());
// 4. AST node ==》 QB
Phase1Ctx ctx_1 = initPhase1Ctx();
preProcessForInsert(child, qb);
// doPhase1 负责把 ASTTree 分解存入对应的QB
if (!doPhase1(child, qb, ctx_1, plannerCtx)) {
// 如果 phase1Result 错误返回false
return false;
}
LOG.info("Completed phase 1 of Semantic Analysis");
// 5. 处理元数据相关
// getMetaData 负责把表、字段等元数据信息存入QB
getMetaData(qb, createVwDesc == null);
LOG.info("Completed getting MetaData in Semantic Analysis");
plannerCtx.setParseTreeAttr(child, ctx_1);
return true;
}
本文地址:https://blog.csdn.net/qq_41106844/article/details/108195151