plan创建的方法入口是SparkSession的sql方法中的parsePlan方法调用
parse方法将sql转换成语法树(使用的antlr),使用SqlBaseLexer、SqlBaseParser进行词法解析和语法解析。调用toResult函数从语法树生成plan。
生成plan的入口是astBuilder.visitSingleStatement(parser.singleStatement())
parse生成的语法树如下(sql:SELECT name
FROM student
WHERE age
>10 ):
生成未解析计划
parser.singleStatement()返回SingleStatementContext,对应语法树的顶点singleStatement
astBuilder.visitSingleStatement方法中是获取SingleStatementContext的statement,返回LogicalPlan
一般语法树上的节点对应的类是后面加Context,比如singleStatement对应类是SingleStatementContext。还有就是这种statement:statementDefault,是statement有多个实现,冒号后面就是对应的实现,statement对应的类是StatementDefaultContext.
visit(ctx.statement)
这里使用了观察者模式。
先看ctx.statement是获取的StatementContext,对应的实现类是StatementDefaultContext
再看visit方法,是调用对应tree的accept方法,这里就是StatementDefaultContext的accept
StatementDefaultContext的accept是调用对应visitor的visitStatementDefault方法。
visitStatementDefault方法是调用visitChildren
visitChildren方式是遍历子节点,调用对应的accept方法,最后聚合结果返回。
statement节点下面只有一个query节点,所以是调用query节点的accept方法。
QueryContext的accept方法是调用visitor的visitQuery方法
visitQuery方法调用plan方法创建了LogicalPlan。这里分别处理了queryTerm、queryOrganization、ctes。
queryTerm是单个查询的基本单元
queryOrganization是SQL查询中组织查询项的方式,例如排序、分组等
ctes是SQL中一种特殊的查询结构,用于定义临时的结果集
这里query节点只有queryTerm、queryOrganization
plan方法就是调用了typedVisit方法。就是调用对应的节点的accept方法将放回结果转换成LogicalPlan
queryTerm节点的accept方法对应就是QueryTermDefaultContext的accept方法,就是visitor的visitQueryTermDefault方法。
visitQueryTermDefault跟上面类似也是调用visitChildren方法
visitQueryTermDefault的子节点是queryPrimary,所以是调用对应实现类QueryPrimaryDefaultContext的accept方法。
QueryPrimaryDefaultContext的accept方法是调用visitor的visitQueryPrimaryDefault方法。
visitQueryPrimaryDefault同样是调用visitChildren,它的子节点是querySpecification。
调用的是RegularQuerySpecificationContext的accept方法,即visitor的visitRegularQuerySpecification
visitRegularQuerySpecification这个方法的返回值是LogicalPlan。
这个方法处理了全部子节点
selectClause、lateralView、whereClause、aggregationClause、havingClause、windowClause、fromClause,最后生成plan。
这个例子是只有selectClause、fromClause、whereClause三个节点。
fromClause下面的relation节点下面的relationPrimary节点调用plan方法,上面也说到plan方法,是调用visit的对应的方法。这里是调用visitTableName方法。
visitTableName处理了multipartIdentifier子节点。
multipartIdentifier用于明确指定数据库对象的完整路径,包括库名、表名和列名。
visitMultipartIdentifier方法中是获取parts节点的内容。parts是ErrorCapturingIdentifierContext集合。
只有一个ErrorCapturingIdentifierContext子节点,调用它的getText方法。
getText方法就不断向下遍历子节点并调用对应的getText,合并到一起。这里不就在往下track了。
ErrorCapturingIdentifierContext在这里结果就是 student
所以visitTableName中tableId就是 student
。生成UnresolvedRelation对象。UnresolvedRelation的含义是没有和catalog关联的表,它是LogicalPlan的子类。
到这里,visitRegularQuerySpecification中from节点处理完成了。
然后调用withSelectQuerySpecification处理剩下的select和where
withSelectQuerySpecification是中withWhereClause处理where、visitNamedExpressionSeq处理select。
流程基本和处理from一样。
最后生成了一个Project对象(LogicalPlan子类)。
UnresolvedPlan生成流程如下图
SparkSQL——UnresolvedPlan生成
最新推荐文章于 2024-08-10 16:43:15 发布