Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
As UDFs (funções definidas pelo usuário) permitem que você reutilize e compartilhe código que estende a funcionalidade interna no Azure Databricks. Use UDFs para executar tarefas específicas, como cálculos complexos, transformações ou manipulações de dados personalizadas.
Quando usar uma função UDF vs. Apache Spark?
Use UDFs para lógica difícil de expressar com funções internas do Apache Spark. As funções internas do Apache Spark são otimizadas para processamento distribuído e oferecem melhor desempenho em escala. Para obter mais informações, consulte Funções.
A Databricks recomenda UDFs para consultas ad hoc, limpeza manual de dados, análise exploratória de dados e operações em conjuntos de dados de pequeno a médio porte. Os casos de uso comuns para UDFs incluem criptografia de dados, descriptografia, hash, análise JSON e validação.
Use métodos do Apache Spark para operações em conjuntos de dados muito grandes e todas as cargas de trabalho são executadas regularmente ou continuamente, incluindo trabalhos ETL e operações de streaming.
Entender os tipos de UDF
Selecione um tipo UDF nas guias a seguir para ver uma descrição, um exemplo e um link para saber mais.
UDF escalar
UDFs escalares operam em uma única linha e retornam um único valor de resultado para cada linha. Elas podem ser controladas pelo Catálogo do Unity ou terem escopo de sessão.
O exemplo a seguir usa uma UDF escalar para calcular o comprimento de cada nome em uma name
coluna e adicionar o valor em uma nova coluna name_length
.
+-------+-------+
| name | score |
+-------+-------+
| alice | 10.0 |
| bob | 20.0 |
| carol | 30.0 |
| dave | 40.0 |
| eve | 50.0 |
+-------+-------+
-- Create a SQL UDF for name length
CREATE OR REPLACE FUNCTION main.test.get_name_length(name STRING)
RETURNS INT
RETURN LENGTH(name);
-- Use the UDF in a SQL query
SELECT name, main.test.get_name_length(name) AS name_length
FROM your_table;
+-------+-------+-------------+
| name | score | name_length |
+-------+-------+-------------+
| alice | 10.0 | 5 |
| bob | 20.0 | 3 |
| carol | 30.0 | 5 |
| dave | 40.0 | 4 |
| eve | 50.0 | 3 |
+-------+-------+-------------+
Para implementar isso em um notebook do Databricks usando o PySpark:
from pyspark.sql.functions import udf
from pyspark.sql.types import IntegerType
@udf(returnType=IntegerType())
def get_name_length(name):
return len(name)
df = df.withColumn("name_length", get_name_length(df.name))
# Show the result
display(df)
Consulte UDFs (funções definidas pelo usuário) no Catálogo do Unity e funções escalares definidas pelo usuário – Python.
UDFs escalares em lote
Processe dados em lotes mantendo a paridade de linha de entrada/saída 1:1. Isso reduz a sobrecarga de operações linha por linha para processamento de dados em grande escala. UDFs em lote também mantêm o estado entre execuções para funcionar de forma mais eficiente, reutilizar recursos e lidar com cálculos complexos que requerem contexto entre conjuntos de dados.
Elas podem ser controladas pelo Catálogo do Unity ou terem escopo de sessão.
A seguinte UDF em lote do Python do Catálogo do Unity calcula o IMC durante o processamento de lotes de linhas:
+-------------+-------------+
| weight_kg | height_m |
+-------------+-------------+
| 90 | 1.8 |
| 77 | 1.6 |
| 50 | 1.5 |
+-------------+-------------+
%sql
CREATE OR REPLACE FUNCTION main.test.calculate_bmi_pandas(weight_kg DOUBLE, height_m DOUBLE)
RETURNS DOUBLE
LANGUAGE PYTHON
PARAMETER STYLE PANDAS
HANDLER 'handler_function'
AS $$
import pandas as pd
from typing import Iterator, Tuple
def handler_function(batch_iter: Iterator[Tuple[pd.Series, pd.Series]]) -> Iterator[pd.Series]:
for weight_series, height_series in batch_iter:
yield weight_series / (height_series ** 2)
$$;
select main.test.calculate_bmi_pandas(cast(70 as double), cast(1.8 as double));
+--------+
| BMI |
+--------+
| 27.8 |
| 30.1 |
| 22.2 |
+--------+
Veja UDFs (funções definidas pelo usuário) no Catálogo do Unity e UDFs (funções definidas pelo usuário) em lote do Python no Catálogo do Unity.
UDFs não escalares
As UDFs não escalares operam em conjuntos de dados/colunas inteiros com taxas flexíveis de entrada/saída (1:N ou muitos:muitos).
As UDFs do Pandas do lote com escopo de sessão podem ser dos seguintes tipos:
- Série para série
- Iterador de série para iterador da série
- Iterador de várias séries para iterador de série
- Série para escalar
Veja a seguir um exemplo de uma UDF de série para série do Pandas.
from pyspark.sql.functions import pandas_udf
import pandas as pd
df = spark.createDataFrame([(70, 1.75), (80, 1.80), (60, 1.65)], ["Weight", "Height"])
@pandas_udf("double")
def calculate_bmi_pandas(weight: pd.Series, height: pd.Series) -> pd.Series:
return weight / (height ** 2)
df.withColumn("BMI", calculate_bmi_pandas(df["Weight"], df["Height"])).display()
Consulte as funções definidas pelo usuário do Pandas.
UDAF
Os UDAFs operam em várias linhas e retornam um único resultado agregado. As UDAFs são somente com escopo de sessão.
O exemplo UDAF a seguir agrega pontuações por comprimento do nome.
from pyspark.sql.functions import pandas_udf
from pyspark.sql import SparkSession
import pandas as pd
# Define a pandas UDF for aggregating scores
@pandas_udf("int")
def total_score_udf(scores: pd.Series) -> int:
return scores.sum()
# Group by name length and aggregate
result_df = (df.groupBy("name_length")
.agg(total_score_udf(df["score"]).alias("total_score")))
display(result_df)
+-------------+-------------+
| name_length | total_score |
+-------------+-------------+
| 3 | 70.0 |
| 4 | 40.0 |
| 5 | 40.0 |
+-------------+-------------+
Consulte funções definidas pelo usuário do pandas para Python e funções agregadas definidas pelo usuário - Scala.
UDTFs
Um UDTF usa um ou mais argumentos de entrada e retorna várias linhas (e possivelmente várias colunas) para cada linha de entrada. As UDTFs são somente com escopo de sessão.
No exemplo a seguir, cada valor na coluna de pontuação corresponde a uma lista de categorias. O UDTF divide a lista separada por vírgulas em várias linhas.
+-------+-------+-----------------+
| name | score | categories |
+-------+-------+-----------------+
| alice | 10.0 | math,science |
| bob | 20.0 | history,math |
| carol | 30.0 | science,history |
| dave | 40.0 | math,art |
| eve | 50.0 | science,art |
+-------+-------+-----------------+
from pyspark.sql.functions import udtf
@udtf(returnType="name: string, score: int, category: string")
class ScoreCategoriesUDTF:
def eval(self, name: str, score: int, categories: str):
category_list = categories.split(',')
for category in category_list:
yield (name, score, category)
ScoreCategoriesUDTF(lit("Alice"), lit(85), lit("Math,Science,English")).display()
+-------+-------+----------+
| name | score | category |
+-------+-------+----------+
| alice | 10.0 | math |
| alice | 10.0 | science |
| bob | 20.0 | history |
| bob | 20.0 | math |
| carol | 30.0 | science |
| carol | 30.0 | history |
| dave | 40.0 | math |
| dave | 40.0 | art |
| eve | 50.0 | science |
| eve | 50.0 | art |
+-------+-------+----------+
Consulte UDTFs (funções de tabela definidas pelo usuário) do Python.
Comparação entre UDFs controladas pelo Catálogo do Unity e UDFs com escopo de sessão
UDFs do Python do Catálogo do Unity e UDFs em lote do Python do Catálogo do Unity são persistentes no Catálogo do Unity para melhor governança, reutilização e descoberta. Todos os outros UDFs são baseados em sessão, o que significa que eles são definidos em um notebook ou trabalho e têm como escopo o SparkSession atual. Você pode definir e acessar UDFs com escopo de sessão usando Scala ou Python.
Folha de referências de UDFs controladas pelo Catálogo do Unity
As UDFs governadas do Catálogo do Unity permitem que funções personalizadas sejam definidas, usadas, compartilhadas com segurança e governadas em ambientes de computação. Consulte UDFs (funções definidas pelo usuário) no Catálogo do Unity.
Tipo de UDF | Computação suportada | Descrição |
---|---|---|
UDF do Python do Catálogo do Unity |
|
Defina uma UDF no Python e registre-a no Catálogo do Unity para governança. UDFs escalares operam em uma única linha e retornam um único valor de resultado para cada linha. |
UDF em lote do Python do Catálogo do Unity |
|
Defina uma UDF no Python e registre-a no Catálogo do Unity para governança. Realiza operações em lote em vários valores e retorna vários valores. Reduz a sobrecarga de operações linha por linha para processamento de dados em grande escala. |
Folha de referências de UDFs com escopo de sessão para a computação isolada pelo usuário
UDFs com escopo de sessão são definidos em um notebook ou trabalho e têm como escopo o SparkSession atual. Você pode definir e acessar UDFs com escopo de sessão usando Scala ou Python.
Tipo de UDF | Computação suportada | Descrição |
---|---|---|
Escalar do Python |
|
UDFs escalares operam em uma única linha e retornam um único valor de resultado para cada linha. |
Não escalar do Python |
|
UDFs não escalares incluem pandas_udf , mapInPandas , mapInArrow , applyInPandas . As UDFs do Pandas usam o Apache Arrow para transferir dados e o Pandas para trabalhar com os dados. As UDFs do Pandas dão suporte a operações vetorizadas que podem aumentar consideravelmente o desempenho em UDFs escalares linha por linha. |
UDTFs do Python |
|
Um UDTF usa um ou mais argumentos de entrada e retorna várias linhas (e possivelmente várias colunas) para cada linha de entrada. |
UDFs escalares do Scala |
|
UDFs escalares operam em uma única linha e retornam um único valor de resultado para cada linha. |
UDAFs Scala |
|
Os UDAFs operam em várias linhas e retornam um único resultado agregado. |
Considerações sobre desempenho
Funções internas e UDFs do SQL são as opções mais eficientes.
As UDFs do Scala geralmente são mais rápidas do que as UDFs do Python.
- Os UDFs Scala não isolados são executados na máquina virtual Java (JVM), evitando assim a sobrecarga causada pela movimentação de dados para dentro e fora da JVM.
- UDFs do Scala isolados precisam mover dados para dentro e para fora da JVM, mas ainda podem ser mais rápidos do que UDFs do Python porque lidam com a memória com mais eficiência.
UDFs do Python e UDFs pandas tendem a ser mais lentos do que UDFs scala porque precisam serializar dados e transferi-los da JVM para o interpretador do Python.
- As UDFs do Pandas são até 100x mais rápidas que as UDFs do Python porque usam o Apache Arrow para reduzir os custos de serialização.