Определяемые пользователем скалярные функции — Scala

В этой статье приведены примеры определяемых пользователем функций Scala . В ней показано, как регистрировать пользовательские функции, вызывать пользовательские функции и предостережения относительно порядка вычислений вложенных выражений в Spark SQL. Дополнительные сведения см. в статье Внешние определяемые пользователем скалярные функции (UDF).

Регистрация функции в качестве определяемой пользователем функции

val squared = (s: Long) => {
  s * s
}
spark.udf.register("square", squared)

Вызов определяемой пользователем функции в Spark SQL

spark.range(1, 20).createOrReplaceTempView("test")
%sql select id, square(id) as id_squared from test

Использование определяемой пользователем функции с кадрами данных

import org.apache.spark.sql.functions.{col, udf}
val squared = udf((s: Long) => s * s)
display(spark.range(1, 20).select(squared(col("id")) as "id_squared"))

Порядок оценки и проверка значений NULL

Spark SQL (включая SQL и API кадра данных и наборов данных) не гарантирует порядок вычисления вложенных выражений. В частности, входные данные оператора или функции не обязательно вычисляются слева направо или в любом другом фиксированном порядке. Например, логические AND выражения и OR не имеют семантики короткого замыкания слева направо.

Поэтому опасно полагаться на побочные эффекты или порядок вычисления логических выражений WHERE , а также порядок предложений и HAVING , так как такие выражения и предложения могут быть переупорядочены во время оптимизации и планирования запросов. В частности, если определяемая пользователем функция использует семантику короткого замыкания в SQL для проверки значения NULL, нет никакой гарантии, что проверка null произойдет перед вызовом определяемой пользователем функции. Например

spark.udf.register("strlen", (s: String) => s.length)
spark.sql("select s from test1 where s is not null and strlen(s) > 1") // no guarantee

Это WHERE предложение не гарантирует strlen , что определяемая пользователем функция будет вызвана после фильтрации значений NULL.

Для правильной проверки значений NULL рекомендуется выполнить одно из следующих действий:

  • Сделайте саму определяемую пользователем функцию с учетом значений NULL и выполните проверку null внутри самой определяемой пользователем функции.
  • Использование IF выражений или CASE WHEN для выполнения проверка null и вызова определяемой пользователем функции в условной ветви
spark.udf.register("strlen_nullsafe", (s: String) => if (s != null) s.length else -1)
spark.sql("select s from test1 where s is not null and strlen_nullsafe(s) > 1") // ok
spark.sql("select s from test1 where if(s is not null, strlen(s), null) > 1")   // ok