例如,我有一个 SQL 查询
SELECT id, "delta.`/example/table/path`" FROM delta.`/example/table/path` WHERE str LIKE "%delta.`/example/table/path`"
我怎样才能只替换出现的
FROM delta.`/example/table/path`
到
FROM new_table_name
沿着逻辑计划树
lp
生成
val plan = spark.sessionState.sqlParser.parsePlan(query)
var lp = spark.sessionState.analyzer
.executeAndCheck(plan, new QueryPlanningTracker)
我知道所有表格都由
LogicalRelation
节点表示,从那里,我失去了方向。
Project [ID#1619]
+- Join Inner, (fk#1620 = ID#1643)
:- SubqueryAlias T1
: +- SubqueryAlias spark_catalog.delta.`T1`
: +- Relation [ID#1619,fk#1620] parquet
+- SubqueryAlias T2
+- SubqueryAlias spark_catalog.delta.`T2`
+- Relation [ID#1643,amount#1644,cost#1645] parquet
有人对我如何只替换表名有建议吗? 预先感谢您!
我尝试通过沿着树走来检索所有表名
def getTableNamesOnlyWrapper(root: LogicalPlan): Set[String] = {
var nameSet: Set[String] = Set()
def getTableNamesOnly(root: LogicalPlan, prevAlias: String): Unit = {
root match {
case a: SubqueryAlias => {
getTableNamesOnly(a.child, a.alias)
}
case r: LogicalRelation => {
val name = r.catalogTable.map(_.identifier.unquotedString).getOrElse(prevAlias)
nameSet += name
}
case p: LogicalPlan =>
for (c <- p.children) {
getTableNamesOnly(c, prevAlias)
}
}
}
getTableNamesOnly(root, "")
println("kebing name set is: " + nameSet)
nameSet
}
然后匹配原SQL中的表,替换为
new_table_name
。但是,这不能处理相同表名显示为字符串文字的情况。
SELECT id, "delta.`/example/table/path`" FROM delta.`/example/table/path` WHERE str LIKE "%delta.`/example/table/path`"
字符串文字显示为 Literal 表达式的实例。
在模式匹配中,您可以使用 StringLiteral 来简化。
Spark 计划中有许多结构组合,这些组合不容易预测,并且在每个版本中可能会发生变化。 要导航/更改内容,您应该更喜欢 QueryPlan/TreeNode 上的内置操作(对于文字而言,transformAllExpressionsWithSubqueries 似乎合适,而 transformWithSubqueries 则可以换行)。
通常最好查看源代码以获取转换示例,查询优化非常适合这种洞察力,CTESubstitution对于处理 cte、子查询、别名等看起来非常完整。