Partager via


Que sont les fonctions définies par l’utilisateur (UDF) ?

Les fonctions définies par l’utilisateur vous permettent de réutiliser et de partager du code qui étend les fonctionnalités intégrées sur Azure Databricks. Utilisez des fonctions définies par l’utilisateur pour effectuer des tâches spécifiques, telles que des calculs complexes, des transformations ou des manipulations de données personnalisées.

Remarque

Sur les clusters avec mode d’accès partagé, les fonctions définies par l’utilisateur scalaire Python sont prises en charge dans Databricks Runtime 13.3 LTS et versions ultérieures, tandis que les fonctions définies par l’utilisateur Scala sont prises en charge dans Databricks Runtime 14.2 et versions ultérieures.

Les fonctions définies par l’utilisateur scalaire Python peuvent être inscrites dans le catalogue Unity à l’aide de la syntaxe SQL dans Databricks Runtime 13.3 LTS et versions ultérieures. Consultez les Fonctions définies par l’utilisateur (UDF) dans Unity Catalog.

Quand faut-il utiliser une fonction définie par l’utilisateur ?

Utilisez des fonctions définies par l’utilisateur pour la logique qui est difficile à exprimer avec les fonctions Apache Spark intégrées. Les fonctions Apache Spark intégrées sont optimisées pour le traitement distribué et offrent généralement de meilleures performances à grande échelle. Pour plus d’informations, consultez Fonctions.

Databricks recommande des fonctions définies par l’utilisateur pour les requêtes ad hoc, le nettoyage manuel des données, l’analyse exploratoire des données et les opérations sur des jeux de données de petite à moyenne taille. Les cas d’usage courants pour les fonctions définies par l’utilisateur incluent le chiffrement et le déchiffrement des données, le hachage, l’analyse JSON et la validation.

Utilisez des méthodes Apache Spark pour les opérations sur des jeux de données très volumineux et toutes les charges de travail qui s’exécutent régulièrement ou en continu, y compris les travaux ETL et les opérations de streaming.

Fonctions définies par l’utilisateur et les fonctions définies par l’étendue de session

Les fonctions définies par l’utilisateur créées à l’aide de SQL sont inscrites dans le catalogue Unity et disposent d’autorisations associées, tandis que les fonctions définies par l’utilisateur créées dans votre bloc-notes sont basées sur une session et sont limitées à la session SparkSession actuelle.

Vous pouvez définir et accéder aux fonctions définies par l’utilisateur basées sur une session à l’aide de n’importe quel langage pris en charge par Azure Databricks. Les fonctions définies par l’utilisateur peuvent être scalaires ou non scalaires.

Remarque

Actuellement, seules les fonctions définies par l’utilisateur scalaire SQL et Python inscrites dans le catalogue Unity sont disponibles dans DBSQL.

Fonctions UDF scalaires

Les fonctions définies par l’utilisateur scalaires fonctionnent sur une seule ligne et retournent une valeur unique pour chaque ligne. L’exemple suivant utilise une fonction UDF scalaire pour calculer la longueur de chaque nom dans une name colonne et ajouter la valeur dans une nouvelle colonne 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 get_name_length(name STRING)
RETURNS INT
RETURN LENGTH(name);

-- Use the UDF in a SQL query
SELECT name, 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      |
+-------+-------+-------------+

Pour implémenter ceci dans un notebook Databricks à l’aide de 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)

Pour plus d’informations, consultez fonctions définies par l’utilisateur dans le catalogue Unity et les fonctions scalaires définies par l’utilisateur - Python.

Fonctions définies par l’utilisateur d’agrégation (UDAF)

Les fonctions d’agrégation définies par l’utilisateur fonctionnent sur plusieurs lignes et retournent un résultat agrégé unique. Dans l’exemple suivant, un UDAF est défini pour agréger les scores.

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    |
+-------------+-------------+

Consultez les fonctions pandas définies par l’utilisateur pour les fonctions d’agrégation Python et définies par l’utilisateur - Scala.

Fonctions de table définies par l’utilisateur (UDTF) Python

Important

Cette fonctionnalité est disponible en préversion publique.

Remarque

Les fonctions définies par l’utilisateur Python sont disponibles dans Databricks Runtime 14.3 LTS et versions ultérieures.

Les fonctions de table définies par l’utilisateur Python peuvent retourner plusieurs lignes et colonnes pour chaque ligne d’entrée. Dans l’exemple suivant, chaque valeur de la colonne de score correspond à une liste de catégories. Un UDTF est défini pour fractionner la liste séparée par des virgules en plusieurs lignes. Consultez les fonctions de table définies par l’utilisateur Python (UDF)

+-------+-------+-----------------+
| 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="score: int, categories: string, name: string")
class ScoreCategoriesUDTF:
    def eval(self, name: str, score: float, categories: str):
        category_list = categories.split(',')
        for category in category_list:
            yield (name, score, category)

# Apply the UDTF
result_df = df.select(ScoreCategoriesUDTF(df.score, df.categories, df.name))
display(result_df)
+-------+-------+----------+
| 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    |
+-------+-------+----------+

Considérations relatives aux performances

  • Les fonctions intégrées et les fonctions définies par l’utilisateur SQL sont l’option la plus efficace disponible.
  • Les fonctions définies par l’utilisateur Scala sont généralement plus rapides à mesure qu’elles s’exécutent dans la machine virtuelle Java (JVM) et évitent la surcharge liée au déplacement de données dans et hors de la machine virtuelle JVM.
  • Les fonctions définies par l’utilisateur Python et les fonctions définies par l’utilisateur Pandas ont tendance à être plus lentes que les fonctions définies par l’utilisateur Scala, car elles nécessitent la sérialisation et le déplacement des données hors de la machine virtuelle JVM vers l’interpréteur Python. Les fonctions définies par l’utilisateur Pandas jusqu’à 100x sont plus rapides que les fonctions définies par l’utilisateur Python, car elles utilisent Apache Arrow pour réduire les coûts de sérialisation.