Funções escalares definidas pelo usuário - Scala
Este artigo contém exemplos de função definida pelo usuário (UDF) do Scala. Ele mostra como registrar UDFs, como invocar UDFs e advertências sobre a ordem de avaliação de subexpressões no Spark SQL. Consulte Funções escalares definidas pelo usuário externo (UDFs) para obter mais detalhes.
Nota
UDFs Scala em recursos de computação habilitados para Unity Catalog com modo de acesso compartilhado requer o Databricks Runtime 14.2 e superior.
Registrar uma função como UDF
val squared = (s: Long) => {
s * s
}
spark.udf.register("square", squared)
Chamar o UDF no Spark SQL
spark.range(1, 20).createOrReplaceTempView("test")
%sql select id, square(id) as id_squared from test
Usar UDF com DataFrames
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"))
Ordem de avaliação e verificação nula
O Spark SQL (incluindo SQL e as APIs DataFrame e Dataset) não garante a ordem de avaliação das subexpressões. Em particular, as entradas de um operador ou função não são necessariamente avaliadas da esquerda para a direita ou em qualquer outra ordem fixa. Por exemplo, a lógica AND
e OR
as expressões não têm semântica de "curto-circuito" da esquerda para a direita.
Portanto, é perigoso confiar nos efeitos colaterais ou na ordem de avaliação das expressões booleanas, e na ordem das e HAVING
cláusulas, uma vez que tais expressões e cláusulas podem ser reordenadas durante a otimização e o planejamento da WHERE
consulta. Especificamente, se um UDF depende de semântica de curto-circuito no SQL para verificação nula, não há garantia de que a verificação nula acontecerá antes de invocar o UDF. Por exemplo,
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
Esta WHERE
cláusula não garante que o strlen
UDF seja invocado após filtrar nulos.
Para executar a verificação nula adequada, recomendamos que você siga um destes procedimentos:
- Tornar a própria UDF nula e fazer verificação nula dentro da própria UDF
- Use
IF
ouCASE WHEN
expressões para fazer a verificação nula e invocar a UDF em uma ramificação condicional
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
APIs de conjunto de dados tipadas
Nota
Esse recurso é suportado em clusters habilitados para Unity Catalog com modo de acesso compartilhado no Databricks Runtime 15.4 e superior.
As APIs de conjunto de dados tipadas permitem executar transformações como mapa, filtro e agregações em conjuntos de dados resultantes com uma função definida pelo usuário.
Por exemplo, o seguinte aplicativo Scala usa a map()
API para modificar um número em uma coluna de resultados para uma cadeia de caracteres prefixada.
spark.range(3).map(f => s"row-$f").show()
Embora este exemplo use a map()
API, isso também se aplica a outras APIs de conjunto de dados tipadas, como filter()
, mapPartitions()
, foreach()
, foreachPartition()
, reduce()
e flatMap()
.