Это специфическая проблема с Catalyst
См. ниже мой запросExecution.optimizedPlan перед тем, как применить мое правило.
01 Project [x#9, p#10, q#11, if (isnull(q#11)) null else UDF(q#11) AS udfB_10#28, if (isnull(p#10)) null else UDF(p#10) AS udfA_99#93]
02 +- InMemoryRelation [x#9, p#10, q#11], true, 10000, StorageLevel(disk, memory, deserialized, 1 replicas)
03 : +- *SerializeFromObject [assertnotnull(input[0, eic.R0, true], top level non-flat input object).x AS x#9, unwrapoption(IntegerType, assertnotnull(input[0, eic.R0, true], top level non-flat input object).p) AS p#10, unwrapoption(IntegerType, assertnotnull(input[0, eic.R0, true], top level non-flat input object).q) AS q#11]
04 : +- *MapElements <function1>, obj#8: eic.R0
05 : +- *DeserializeToObject newInstance(class java.lang.Long), obj#7: java.lang.Long
05 : +- *Range (0, 3, step=1, splits=Some(2))
В строке 01 мне нужно поменять положение udfA и udfB следующим образом:
01 Project [x#9, p#10, q#11, if (isnull(p#10)) null else UDF(p#10) AS udfA_99#93, if (isnull(q#11)) null else UDF(q#11) AS udfB_10#28]
когда я пытаюсь изменить порядок атрибутов в операции Projection в SparkSQL с помощью оптимизации Catalyst, результат запроса изменяется на недопустимое значение. Может быть, я не делаю все, что нужно. Я просто изменяю порядок объектов NamedExpression в параметрах полей:
object ReorderColumnsOnProjectOptimizationRule extends Rule[LogicalPlan] {
def apply(plan: LogicalPlan): LogicalPlan = plan resolveOperators {
case Project(fields: Seq[NamedExpression], child) =>
if (checkCondition(fields)) Project(newFieldsObject(fields), child) else Project(fields, child)
case _ => plan
}
private def newFieldsObject(fields: Seq[NamedExpression]): Seq[NamedExpression] = {
// compare UDFs computation cost and return the new NamedExpression list
. . .
}
private def checkCondition(fields: Seq[NamedExpression]): Boolean = {
// compare UDFs computation cost and return Boolean for decision off change order on field list.
. . .
}
. . .
}
Примечание. Я добавляю свое правило в extraOptimizations
объект SparkSQL:
spark.experimental.extraOptimizations = Seq(ReorderColumnsOnProjectOptimizationRule)
Любые предложения будут очень полезны.
РЕДАКТИРОВАТЬ 1
Кстати, я создал ноутбук для Databricks для тестирования. Подробнее см. эту ссылку
Комментируя строку 60, вызывается оптимизация и возникает ошибка.
. . .
58 // Do UDF with less cost before, so I need change the fields order
59 myPriorityList.size == 2 && myPriorityList(0) > myPriorityList(1)
60 false
61 }
Что я пропустил?
РЕДАКТИРОВАТЬ 2
Рассмотрим следующий фрагмент кода из оптимизации компилятора, который почти аналогичен:
if ( really_slow_test(with,plenty,of,parameters)
&& slower_test(with,some,parameters)
&& fast_test // with no parameters
)
{
...then code...
}
Этот код сначала оценивает дорогостоящую функцию, а затем при успешном завершении оценивает оставшуюся часть выражения. Но даже если первый тест терпит неудачу и оценка короткая, это значительно снижает производительность, потому что fat really_slow_test (...) всегда оценивается. Сохраняя правильность программы, можно изменить выражение следующим образом:
if ( fast_test
&& slower_test(with,some,parameters)
&& (really_slow_test(with,plenty,of,parameters))
{
...then code...
}
Моя цель - сначала запустить самые быстрые UDF