Partage via


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

Une fonction définie par l’utilisateur permet de réutiliser une logique personnalisée dans l’environnement utilisateur. Azure Databricks prend en charge de nombreux types différents de fonctions définies par l’utilisateur afin de permettre la distribution de logique extensible. Cet article présente certaines des forces et limitations générales des fonctions définies par l’utilisateur.

Notes

Toutes les formes de fonctions définies par l’utilisateur ne sont pas disponibles dans tous les environnements d’exécution sur Azure Databricks. Si vous utilisez Unity Catalog, consultez Fonctions définies par l’utilisateur (UDF) dans Unity Catalog.

Définition d’une logique personnalisée sans pénalités de sérialisation

Azure Databricks hérite de la plupart de ses comportements UDF d’Apache Spark, y compris les limitations d’efficacité autour de nombreux types de fonctions définies par l’utilisateur. Voir Quelles sont les fonctions définies par l’utilisateur les plus efficaces ?.

Vous pouvez modulariser votre code en toute sécurité sans vous soucier des compromis potentiels en matière d’efficacité associés aux fonctions définies par l’utilisateur. Pour ce faire, vous devez définir votre logique comme une série de méthodes intégrées Spark à l’aide de DataFrames SQL ou Spark. Par exemple, les fonctions SQL et Python suivantes combinent des méthodes intégrées Spark pour définir une conversion d’unité en tant que fonction réutilisable :

SQL

CREATE FUNCTION convert_f_to_c(unit STRING, temp DOUBLE)
RETURNS DOUBLE
RETURN CASE
  WHEN unit = "F" THEN (temp - 32) * (5/9)
  ELSE temp
END;

SELECT convert_f_to_c(unit, temp) AS c_temp
FROM tv_temp;

Python

def convertFtoC(unitCol, tempCol):
  from pyspark.sql.functions import when
  return when(unitCol == "F", (tempCol - 32) * (5/9)).otherwise(tempCol)

from pyspark.sql.functions import col

df_query = df.select(convertFtoC(col("unit"), col("temp"))).toDF("c_temp")
display(df_query)

Pour exécuter les fonctions définies par l’utilisateur ci-dessus, vous pouvez créer des exemples de données.

Quelles sont les fonctions définies par l’utilisateur les plus efficaces ?

Les fonctions définies par l’utilisateur peuvent introduire des goulots d’étranglement de traitement importants dans l’exécution du code. Azure Databricks utilise automatiquement un certain nombre d’optimiseurs différents pour le code écrit avec la syntaxe Apache Spark, SQL et Delta Lake incluse. Lorsqu’une logique personnalisée est introduite par des fonctions définies par l’utilisateur, ces optimiseurs n’ont pas la capacité à planifier efficacement les tâches autour de cette logique personnalisée. En outre, la logique qui s’exécute en dehors de la machine virtuelle JVM entraîne des coûts supplémentaires liés à la sérialisation des données.

Notes

Azure Databricks optimise de nombreuses fonctions à l’aide de Photon si vous utilisez le calcul avec Photon. Seules les fonctions qui enchaînent Spark SQL de commandes DataFrame peuvent être optimisées par Photon.

Certaines fonctions définies par l’utilisateur sont plus efficaces que d’autres. En termes de performances :

  • Les fonctions intégrées seront les plus rapides grâce aux optimiseurs Azure Databricks.
  • Le code qui s’exécute dans la machine virtuelle JVM (fonctions définies par l’utilisateur Scala, Java, Hive) sera plus rapide que les fonctions définies par l’utilisateur Python.
  • Les fonctions définies par l’utilisateur Pandas utilisent Arrow pour réduire les coûts de sérialisation associés aux fonctions définies par l’utilisateur Python.
  • Les fonctions définies par l’utilisateur Python fonctionnent bien pour la logique procédurale, mais elles doivent être évitées pour les charges de travail ETL de production sur des jeux de données volumineux.

Remarque

Dans Databricks Runtime 12.2 LTS et versions ultérieures, les fonctions scalaires Python définies par l’utilisateur et les fonctions Pandas définies par l’utilisateur ne sont pas prises en charge dans Unity Catalog sur les clusters qui utilisent le mode d’accès partagé. Ces fonctions définies par l’utilisateur sont prises en charge dans Databricks Runtime 13.3 LTS et versions ultérieures pour tous les modes d’accès.

Dans Databricks Runtime 14.1 et versions antérieures, les fonctions définies par l’utilisateur scalaires Scala ne sont pas prises en charge dans Unity Catalog sur les clusters qui utilisent le mode d’accès partagé. Ces UDF sont prises en charge pour tous les modes d’accès dans Databricks Runtime 14.2 et versions ultérieures.

Dans Databricks Runtime 13.3 LTS et versions ultérieures, vous pouvez inscrire des fonctions scalaires Python définies par l’utilisateur dans Unity Catalog en utilisant la syntaxe SQL. Consultez les Fonctions définies par l’utilisateur (UDF) dans Unity Catalog.

Type Optimisée Environnement d’exécution
UDF Hive Non JVM
Fonction définie par l’utilisateur Python Non Python
Fonction définie par l’utilisateur Pandas Non Python (Arrow)
Fonction définie par l’utilisateur Scala Non JVM
Spark SQL Oui JVM (Photon)
Spark DataFrame Oui JVM (Photon)

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

Un avantage majeur des fonctions définies par l’utilisateur est qu’elles permettent aux utilisateurs d’exprimer la logique dans des langages familiers, ce qui réduit le coût humain associé à la refactorisation du code. Pour les requêtes ad hoc, le nettoyage manuel des données, l’analyse exploratoire des données et la plupart des opérations sur des jeux de données de petite ou moyenne taille, il est peu probable que les frais généraux de latence associés aux fonctions définies par l’utilisateur soient plus élevés que les coûts associés à la refactorisation du code.

Pour les travaux ETL, les opérations de streaming, les opérations sur des jeux de données très volumineux ou d’autres charges de travail exécutées régulièrement ou en continu, la refactorisation de la logique de façon à utiliser des méthodes Apache Spark natives est rapidement payante.

Exemples de données pour des exemples de fonctions définies par l’utilisateur

Les exemples de code de cet article utilisent des fonctions définies par l’utilisateur pour convertir des températures entre Celcius et Farenheit. Si vous souhaitez exécuter ces fonctions, vous pouvez créer un exemple de jeu de données avec le code Python suivant :

import numpy as np
import pandas as pd

Fdf = pd.DataFrame(np.random.normal(55, 25, 10000000), columns=["temp"])
Fdf["unit"] = "F"

Cdf = pd.DataFrame(np.random.normal(10, 10, 10000000), columns=["temp"])
Cdf["unit"] = "C"

df = spark.createDataFrame(pd.concat([Fdf, Cdf]).sample(frac=1))

df.cache().count()
df.createOrReplaceTempView("tv_temp")