Я определил UDF, который увеличивает входное значение на единицу, названный "в c", это код моего udf
spark.udf.register("inc", (x: Long) => x + 1)
, это мой тест sql
val df = spark.sql("select sum(inc(vals)) from data")
df.explain(true)
df.show()
это оптимизированный план для этого sql
== Optimized Logical Plan ==
Aggregate [sum(inc(vals#4L)) AS sum(inc(vals))#7L]
+- LocalRelation [vals#4L]
Я хочу переписать план и извлечь "in c" из "суммы", как python udf делает. Итак, это оптимизированный план, который я хотел.
Aggregate [sum(inc_val#6L) AS sum(inc(vals))#7L]
+- Project [inc(vals#4L) AS inc_val#6L]
+- LocalRelation [vals#4L]
Я обнаружил, что файл исходного кода "ExtractPythonUDFs. scala" предоставляет аналогичную функцию, которая работает на PythonUDF, но он вставляет новый узел с именем " ArrowEval Python ", это логический план pythonudf.
== Optimized Logical Plan ==
Aggregate [sum(pythonUDF0#7L) AS sum(inc(vals))#4L]
+- Project [pythonUDF0#7L]
+- ArrowEvalPython [inc(vals#0L)], [pythonUDF0#7L], 200
+- Repartition 10, true
+- RelationV2[vals#0L] parquet file:/tmp/vals.parquet
То, что я хочу вставить, это просто" узел проекта ", я не хочу определять новый узел.
это тестовый код моего проекта
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.catalyst.expressions.{Expression, NamedExpression, ScalaUDF}
import org.apache.spark.sql.catalyst.plans.logical.{Aggregate, LogicalPlan}
import org.apache.spark.sql.catalyst.rules.Rule
object RewritePlanTest {
case class UdfRule(spark: SparkSession) extends Rule[LogicalPlan] {
def collectUDFs(e: Expression): Seq[Expression] = e match {
case udf: ScalaUDF => Seq(udf)
case _ => e.children.flatMap(collectUDFs)
}
override def apply(plan: LogicalPlan): LogicalPlan = plan match {
case agg@Aggregate(g, a, _) if (g.isEmpty && a.length == 1) =>
val udfs = agg.expressions.flatMap(collectUDFs)
println("================")
udfs.foreach(println)
val test = udfs(0).isInstanceOf[NamedExpression]
println(s"cast ScalaUDF to NamedExpression = ${test}")
println("================")
agg
case _ => plan
}
}
def main(args: Array[String]): Unit = {
Logger.getLogger("org").setLevel(Level.WARN)
val spark = SparkSession
.builder()
.master("local[*]")
.appName("Rewrite plan test")
.withExtensions(e => e.injectOptimizerRule(UdfRule))
.getOrCreate()
val input = Seq(100L, 200L, 300L)
import spark.implicits._
input.toDF("vals").createOrReplaceTempView("data")
spark.udf.register("inc", (x: Long) => x + 1)
val df = spark.sql("select sum(inc(vals)) from data")
df.explain(true)
df.show()
spark.stop()
}
}
У меня есть извлечение ScalaUDF
из узла Aggregate
,
, поскольку аргументы необходимы для Project
Узел Seq[NamedExpression]
case class Project(projectList: Seq[NamedExpression], child: LogicalPlan)
, но ему не удалось привести ScalaUDF
к NamedExpression
,
, поэтому я понятия не имею, как построить узел Project
.
Может кто-нибудь дать мне несколько советов?
Спасибо.