Определяемые пользователем скалярные функции — Scala
В этой статье приведены примеры определяемых пользователем функций Scala. Здесь показано, как регистрировать и вызывать такие функции, а также даны рекомендации, касающиеся порядка вычислений частей выражений в Spark SQL. Дополнительные сведения см. в статье о внешних скалярных функциях (ОПРЕДЕЛяемых пользователем) функциях.
Примечание.
Для вычислительных ресурсов с поддержкой каталога Unity scala UDFs с режимом общего доступа требуется Databricks Runtime 14.2 и более поздних версий.
Регистрация определяемой пользователем функции
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
В SQL Spark (включая SQL, а также API кадров и наборов данных) не гарантируется определенный порядок вычисления частей выражения. В частности, входные данные оператора или функции не обязательно вычисляются слева направо или в любом другом фиксированном порядке. Например, логические выражения AND
и OR
не имеют привычной семантики слева направо.
Таким образом, не следует полагаться на побочные эффекты или порядок вычисления логических выражений, а также порядок предложений WHERE
и HAVING
, так как этот порядок и правила применения предложений могут изменяться в результате оптимизации или планирования запросов. В частности, если определяемая пользователем функция использует привычную семантику в SQL для проверки значений 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 и выполняйте проверку этих значений внутри самой функции.
- Используйте выражения
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
API типизированного набора данных
Примечание.
Эта функция поддерживается в кластерах с поддержкой каталога Unity с режимом общего доступа в Databricks Runtime 15.4 и выше.
API типизированного набора данных позволяют выполнять преобразования, такие как сопоставление, фильтрация и агрегаты для результирующего набора данных с определяемой пользователем функцией.
Например, следующее приложение Scala использует map()
API для изменения числа в столбце результатов на префиксированную строку.
spark.range(3).map(f => s"row-$f").show()
Хотя в этом примере используется map()
API, это также относится к другим типизированным API набора данных, таким как filter()
, , foreach()
mapPartitions()
, reduce()
foreachPartition()
и flatMap()
.