Gab*_*yas 5 scala apache-spark apache-spark-sql
我使用 Spark Catalyst 来表示openCypher查询引擎ingraph的查询计划。在查询计划过程中,我想从某个逻辑计划(Plan1)转换为另一个逻辑计划(Plan2)。(我试图让问题保持简单,所以我在这里省略了一些细节。该项目是完全开源的,所以如果需要,我很乐意提供更多信息来说明为什么这是必要的。)
我能找到的最好的方法是递归使用transformDown。这是一个小示例,通过将每个实例替换为并将每个实例替换为 来从Plan1Nodes 转换为s 。Plan2NodeOpA1OpA2OpB1OpB2
import org.apache.spark.sql.catalyst.expressions.Attribute
import org.apache.spark.sql.catalyst.plans.logical.{LeafNode, LogicalPlan, UnaryNode}
trait Plan1Node extends LogicalPlan
case class OpA1() extends LeafNode with Plan1Node {
override def output: Seq[Attribute] = Seq()
}
case class OpB1(child: Plan1Node) extends UnaryNode with Plan1Node {
override def output: Seq[Attribute] = Seq()
}
trait Plan2Node extends LogicalPlan
case class OpA2() extends LeafNode with Plan2Node {
override def output: Seq[Attribute] = Seq()
}
case class OpB2(child: Plan2Node) extends UnaryNode with Plan2Node {
override def output: Seq[Attribute] = Seq()
}
object Plan1ToPlan2 {
def transform(plan: Plan1Node): Plan2Node = {
plan.transformDown {
case OpA1() => OpA2()
case OpB1(child) => OpB2(transform(child))
}
}.asInstanceOf[Plan2Node]
}
Run Code Online (Sandbox Code Playgroud)
这种方法可以完成工作。这段代码:
val p1 = OpB1(OpA1())
val p2 = Plan1ToPlan2.transform(p1)
Run Code Online (Sandbox Code Playgroud)
结果是:
p1: OpB1 = OpB1
+- OpA1
p2: Plan2Node = OpB2
+- OpA2
Run Code Online (Sandbox Code Playgroud)
然而,使用asInstanceOf[Plan2Node]在代码中绝对是一种不好的味道。我考虑使用策略来定义转换规则,但该类用于从物理计划转换为逻辑计划。
是否有更优雅的方式来定义逻辑计划之间的转换?或者使用多个逻辑计划是否被视为反模式?
(回答我自己的问题。)
更改transformDown为简单的模式匹配 ( match) 和递归调用解决了类型问题:
object Plan1ToPlan2 {
def transform(plan: Plan1Node): Plan2Node = {
plan match {
case OpA1() => OpA2()
case OpB1(child) => OpB2(transform(child))
}
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎是一个类型安全且(基于我对 Catalyst 的有限理解)惯用的解决方案。