Определяемые пользователем скалярные функции — 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