Scala- und Java-benutzerdefinierte Funktionen (UDFs) in Unity Catalog

Auf dieser Seite wird beschrieben, wie Sie Scala und Java benutzerdefinierte Funktionen (USER-Defined Functions, UDFs) erstellen, sie im Unity-Katalog registrieren und für alle Computeumgebungen freigeben. Mit Unity Catalog UDFs können Sie vorhandene JVM-Logik mit Unity Catalog Governance und Zugriffssteuerungen wiederverwenden.

Im Gegensatz zu sitzungsgebundenen Scala-UDFs, die auf ein einzelnes Notebook oder einen einzelnen Cluster beschränkt sind, sind registrierte UDFs in Unity Catalog:

  • Verwaltet: Mit Berechtigungen und Zugriffskontrollen in Unity Catalog verwaltet.
  • Wiederverwendbar: Von Teams, Notebooks, Jobs und SQL-Warehouses gemeinsam genutzt.
  • Auffindbar: Sichtbar im Katalog-Explorer und Systemtabellen.
  • Isoliert: Wird in Sandboxes mit einmaligem Kaltstart-Overhead pro Sitzung ausgeführt. Nachfolgende Anrufe sind schnell.

Anforderungen

Ihr Arbeitsbereich muss für Unity Catalog aktiviert sein. Es gelten die folgenden zusätzlichen Anforderungen.

Compute: Alle Computetypen werden unterstützt, einschließlich serverloser Notizbücher und Aufträge, SQL-Lagerhäuser und Spark Declarative Pipelines auf Lakeflow. Die klassische Berechnung erfordert Databricks Runtime 18.2 oder höher. Auf serverlosen Compute- und SQL-Warehouses muss die UDF-Definition die Umgebungsversion 4 oder höher im environment_version Feld angeben. Diese Anforderung gilt für die UDF-Definition, nicht für das aufrufende Notebook oder den Job. Weitere Informationen finden Sie unter Versionen der serverlosen Umgebung.

Entwicklung:

  • Skala: 2.13.16. Scala 2.12 wird nicht unterstützt.
  • JDK: 17.
  • Paketierung: Ein Fat JAR mit allen Drittanbieterabhängigkeiten, die von der UDF verwendet werden.

Berechtigungen:

  • Erstellen Sie eine UDF: USAGE und CREATE FUNCTION im Schema und USAGE im Katalog.
  • Führen Sie eine UDF aus: EXECUTE für die Funktion und USAGE für Schema und Katalog.
  • Greifen Sie auf die JAR-Datei zu: READ VOLUME auf dem Volume, auf dem der JAR gespeichert ist.

Weitere Informationen zu Unity-Katalogberechtigungen finden Sie unter Verwalten von Berechtigungen im Unity-Katalog .

Erstellen Sie Ihr UDF-JAR

Packen Sie den kompilierten Code als JAR, und laden Sie ihn vor der Registrierung der UDF in ein Unity-Katalogvolume hoch. Wählen Sie eine Buildmethode aus:

Lokal erstellen

Führen Sie die folgenden Schritte aus, um in einer lokalen Entwicklungsumgebung eine Fat JAR-Datei zu erstellen.

Richten Sie Ihre Umgebung ein

Installieren Sie die erforderlichen Tools auf Ihrem lokalen Computer. Die folgenden Befehle gelten für macOS. Installieren Sie für andere Plattformen JDK 17 und sbt (Scala) oder Maven (Java) mit dem Paket-Manager Ihrer Plattform.

Scala

Installieren Sie JDK 17 und sbt:

brew install openjdk@17
brew install sbt

Überprüfen Sie Ihre Installation:

java -version   # Should show Java 17
sbt --version   # Should show sbt version

Java

Installieren Sie JDK 17 und Maven:

brew install openjdk@17
brew install maven

Überprüfen Sie Ihre Installation:

java -version   # Should show Java 17
mvn --version   # Should show Maven version

Erstellen Ihres Projekts

Richten Sie ein Projekt in Scala oder Java ein.

Scala

Erstellen Eines neuen Scala-Projekts mithilfe von sbt:

sbt new scala/scala-seed.g8

Wenn Sie dazu aufgefordert werden, geben Sie einen Projektnamen ein (z. B my-udf-project. ).

Konfigurieren von build.sbt

Ersetzen Sie den Inhalt Ihrer build.sbt-Datei durch die folgende Konfiguration:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

lazy val myUDF = (project in file("."))
  .settings(
    name := "my-udf"
  )

Aktivieren des Sbt-Assembly-Plug-Ins

Erstellen oder bearbeiten Sie project/assembly.sbt und fügen Sie Folgendes hinzu:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")

Dieses Plug-In erstellt einen fetten JAR, der alle Ihre Abhängigkeiten enthält.

Java

Erstellen Sie ein neues Maven-Projekt mithilfe des Schnellstart-Archetyps:

mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=my-udf \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false

Mit diesem Befehl wird die standardmäßige Maven-Projektstruktur mit src/main/java und src/test/java Verzeichnissen erstellt.

Konfigurieren von pom.xml

Fügen Sie in der generierten pom.xml Datei innerhalb der <project></project> Tags einen <properties> Block mit der folgenden Konfiguration hinzu:

<properties>
  <maven.compiler.source>17</maven.compiler.source>
  <maven.compiler.target>17</maven.compiler.target>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Fügen Sie auch innerhalb der <project></project> Tags einen <build> Block mit der folgenden Konfiguration hinzu:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.0</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Das maven-shade-plugin erzeugt ein Fat-JAR, das alle Ihre Abhängigkeiten enthält.

Schreiben Sie Ihre UDF

Wenn Sie Ihre UDF schreiben, finden Sie unter Datentypen die unterstützten Datentypen, und unter Sprachzuordnungen sehen Sie, wie Scala- und Java-Typen auf SQL-Typen abgebildet werden.

Ihr UDF-Handler muss die folgenden Anforderungen erfüllen:

  • Scala: Definieren Sie den Handler als Methode für eine object (nicht ein class). Der HANDLER Wert wird in eine Methode in einer Skala objectaufgelöst.
  • Java: Definieren sie den Handler als public static Methode.
  • Signatur: Die Parametertypen, Die Reihenfolge und der Rückgabetyp der Methode müssen der Argumentliste und RETURNS dem Typ in Ihrer CREATE FUNCTION Anweisung entsprechen.
  • Nur skalare Werte: Der Handler muss einen einzelnen skalaren Wert zurückgeben. Tabellenrücklauftypen werden nicht unterstützt.
  • Eigenständig: Der Handler darf nur auf seinen Eingabeargumenten operieren. Es kann keine Spark-APIs verwenden oder von Spark Core-Paketen abhängen. Informationen finden Sie unter Einschränkungen.

Note

Bei Scala wird ein Handler mit einem primitiven Parametertyp (wie Int) übersprungen und gibt NULL zurück, wenn ein Eingabeargument SQL NULL ist. Um NULL-Werte zu empfangen und zu verarbeiten, umschließen Sie den Parameter mit Option, z. B. Option[Int].

Scala

Erstellen Sie in src/main/scala/com/example/MyUDF.scala ein Scala-Objekt und definieren Sie Ihre UDF-Funktion.

Einfaches Beispiel

package com.example

object MyUDF {
  def addOne(x: Int): Int = x + 1
}

Beispiel für externe Abhängigkeit

Um externe Bibliotheken zu verwenden, fügen Sie sie zu Ihrer build.sbt Datei hinzu:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

lazy val myUDF = (project in file("."))
  .settings(
    name := "currency-udf",
    libraryDependencies ++= Seq(
      "org.apache.commons" % "commons-lang3" % "3.12.0"
    )
  )

Verwenden Sie dann die Abhängigkeit in Ihrer UDF:

package com.example

import org.apache.commons.lang3.StringUtils

object CurrencyUDF {
  private val rates: Map[String, Double] = Map(
    "USD" -> 1.0,
    "EUR" -> 1.1,
    "GBP" -> 1.3,
    "JPY" -> 0.007
  )

  def convertToUSD(price: Double, currency: String): Double = {
    require(currency != null, "Currency must not be null")

    val normalizedCurrency = StringUtils.upperCase(currency)

    rates.get(normalizedCurrency) match {
      case Some(rate) => price * rate
      case None => throw new IllegalArgumentException(s"Unsupported currency: $currency")
    }
  }
}

Testen Sie Ihre UDF mit Komponententests vor der Bereitstellung. Siehe lokales Testen von UDFs.

Java

Erstellen Sie eine Java Klasse in src/main/java/com/example/MyUDF.java und definieren Sie Ihre UDF als öffentliche statische Methode.

Einfaches Beispiel

package com.example;

public class MyUDF {
    public static int addOne(int x) {
        return x + 1;
    }
}

Beispiel für externe Abhängigkeit

Um externe Bibliotheken zu verwenden, fügen Sie sie dem <dependencies> Abschnitt Ihrer pom.xml Datei hinzu:

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>

Verwenden Sie dann die Abhängigkeit in Ihrer UDF:

package com.example;

import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.HashMap;

public class CurrencyUDF {
    private static final Map<String, Double> rates = new HashMap<>();

    static {
        rates.put("USD", 1.0);
        rates.put("EUR", 1.1);
        rates.put("GBP", 1.3);
        rates.put("JPY", 0.007);
    }

    public static double convertToUSD(double price, String currency) {
        if (currency == null) {
            throw new IllegalArgumentException("Currency must not be null");
        }

        String normalizedCurrency = StringUtils.upperCase(currency);

        if (!rates.containsKey(normalizedCurrency)) {
            throw new IllegalArgumentException("Unsupported currency: " + currency);
        }

        return price * rates.get(normalizedCurrency);
    }
}

Testen Sie Ihre UDF mit Komponententests vor der Bereitstellung. Siehe lokales Testen von UDFs.

Note

Ihre UDF wird in einer isolierten Sandbox ohne aktive Spark-Sitzung ausgeführt, sodass spark-APIs nicht innerhalb des Funktionstexts verwendet werden können. Sie können beispielsweise keine DataFrames oder Datasets erstellen oder damit arbeiten, spark.sql(...) ausführen oder auf SparkSession oder SparkContext zugreifen. Die UDF muss in sich geschlossene Logik auf Basis ihrer Eingabeargumente enthalten. Sie kann auch nicht von Spark Core-Paketen abhängen.

Erstellen Sie Ihr Fat JAR

Kompilieren Sie Ihr Projekt, um ein Fat JAR zu erzeugen, das alle Abhängigkeiten enthält.

Scala

Führen Sie in Ihrem Projektstammverzeichnis Folgendes aus:

sbt clean assembly

Das Fat JAR wird in target/scala-2.13/ mit einem Namen wie my-udf-assembly-0.1.0-SNAPSHOT.jar erstellt.

Java

Führen Sie in Ihrem Projektstammverzeichnis Folgendes aus:

mvn clean package

Die Fat-JAR-Datei wird in target/ mit einem Namen wie my-udf-1.0-SNAPSHOT.jar erstellt.

Hochladen Ihres JAR auf ein Unity-Katalogvolume

Wenn Sie noch kein Unity-Katalogvolume haben, erstellen Sie eins:

CREATE VOLUME IF NOT EXISTS my_catalog.my_schema.udf_jars
COMMENT 'Storage for UDF JAR files';

Wenn andere Benutzer die UDF ausführen müssen, gewähren Sie ihnen READ VOLUME für das Volume:

GRANT READ VOLUME ON VOLUME my_catalog.my_schema.udf_jars TO `user@example.com`;

Laden Sie Ihre JAR-Datei mithilfe des Katalog-Explorers auf das Volume hoch:

  1. Klicken Sie im Azure Databricks-Arbeitsbereich auf das Datensymbol.Katalog zum Öffnen des Katalog-Explorers.
  2. Wählen Sie den Katalog aus, und wählen Sie dann das Schema aus, das Ihr Volume enthält.
  3. Klicken Sie auf den Namen des Volumes.
  4. Klicken Sie auf "Auf dieses Volume hochladen ", und wählen Sie Ihre JAR-Datei aus.
  5. Klicken Sie auf Hochladen.
  6. Klicken Sie nach Abschluss des Uploads auf den Namen Ihrer JAR-Datei.
  7. Klicken Sie auf „Pfad kopieren“, um den Volumepfad in Ihre Zwischenablage zu kopieren. Beispiel: /Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar (Scala) oder /Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar (Java). Sie benötigen diesen Pfad, wenn Sie die UDF registrieren.

Erstellen eines Notizbuchs

Sie können eine UDF kompilieren, sie als JAR verpacken und direkt aus einem Azure Databricks-Notizbuch in ein Unity-Katalogvolume hochladen. Dieser Ansatz funktioniert für kleine, abhängigkeitsfreie UDFs. Verwenden Sie für UDFs mit Drittanbieterbibliotheken "Lokal erstellen".

Die folgende Python-Zelle erstellt eine Java-UDF, die eine Zeichenfolge bereinigt (führende und nachgestellte Leerzeichen entfernt, mehrfache Leerzeichen zusammenfasst und in Kleinbuchstaben umwandelt), kompiliert sie mit JDK 17, paketiert sie als JAR und kopiert sie in ein Unity-Catalog-Volume. Aktualisieren Sie das volume_path, sodass es auf ein vorhandenes Volume verweist, für das Sie WRITE VOLUME Berechtigung haben.

import os
import subprocess
import shutil

build_dir = "/tmp/udf_build"
package_dir = f"{build_dir}/src/com/databricks/udf"
classes_dir = f"{build_dir}/classes"
os.makedirs(package_dir, exist_ok=True)
os.makedirs(classes_dir, exist_ok=True)

# The UDF handler: a public static method on a plain Java class.
# The doubled backslashes produce a single backslash in the Java source (\\s+).
udf_code = """package com.databricks.udf;
public class StringCleanUDF {
    public static String clean(String input) {
        if (input == null) return null;
        return input.trim().replaceAll("\\\\s+", " ").toLowerCase();
    }
}
"""
with open(f"{package_dir}/StringCleanUDF.java", "w") as f:
    f.write(udf_code)

# Compile with JDK 17 to match Environment Version 4.
subprocess.run(
    ["javac", "--release", "17", "-d", classes_dir, f"{package_dir}/StringCleanUDF.java"],
    check=True,
)

# Package the compiled class into a JAR.
jar_path = f"{build_dir}/string_clean_udf.jar"
subprocess.run(["jar", "cf", jar_path, "-C", classes_dir, "."], check=True)

# Copy the JAR to a Unity Catalog volume.
volume_path = "/Volumes/my_catalog/my_schema/udf_jars/string_clean_udf.jar"
os.makedirs(os.path.dirname(volume_path), exist_ok=True)
shutil.copy2(jar_path, volume_path)

print(f"JAR uploaded to: {volume_path}")

Nachdem sich die JAR-Datei im Volume befindet, registrieren Sie die UDF. Verwenden Sie LANGUAGE JAVA und legen Sie die HANDLER auf die vollqualifizierte Methode fest, z. B. com.databricks.udf.StringCleanUDF.clean.

Registrieren Sie Ihre UDF in Unity Catalog

Nachdem Sie Ihr JAR erstellt und hochgeladen haben, verwenden Sie die CREATE FUNCTION Anweisung, um Ihre UDF im Unity-Katalog zu registrieren.

Scala

CREATE OR REPLACE FUNCTION my_catalog.my_schema.add_one(x INT)
RETURNS INT
LANGUAGE SCALA
DETERMINISTIC
ENVIRONMENT (
  java_dependencies = '["/Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar"]',
  environment_version = '4'
)
HANDLER 'com.example.MyUDF.addOne';

Java

CREATE OR REPLACE FUNCTION my_catalog.my_schema.add_one(x INT)
RETURNS INT
LANGUAGE JAVA
DETERMINISTIC
ENVIRONMENT (
  java_dependencies = '["/Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar"]',
  environment_version = '4'
)
HANDLER 'com.example.MyUDF.addOne';

Die CREATE FUNCTION Anweisung verwendet die folgenden Parameter:

  • LANGUAGE: Die Sprache der UDF.

  • HANDLER: Vollqualifizierter Pfad zur Methode im Format 'package.Object.method' (Scala) oder 'package.ClassName.method' (Java).

  • DETERMINISTIC: Deklariert, dass die Funktion immer dieselbe Ausgabe für dieselbe Eingabe zurückgibt, wodurch die Abfrageoptimierung aktiviert wird.

    Note

    Entfernen Sie DETERMINISTIC , wenn Ihre Funktion externe APIs aufruft oder ein anderes nicht deterministisches Verhalten aufweist.

  • ENVIRONMENT: Definiert die Ausführungsumgebung für die UDF.

    • java_dependencies: Ein JSON-Array von JAR-Dateipfaden in Ihren Unity-Katalogvolumes. Dies ist der Dateipfad, den Sie im vorherigen Schritt kopiert haben. Verwenden Sie einfache Anführungszeichen um das Array und doppelte Anführungszeichen um Pfade.
    • environment_version: Muss für Scala- und Java-UDFs '4' oder höher sein. Umgebungsversion 4 gibt Scala 2.13.16 und JDK 17 an. Weitere Informationen finden Sie unter Versionen der serverlosen Umgebung.

Rufen Sie Ihre UDF in SQL und Notebooks auf

Nach der Registrierung können Sie die UDF in SQL-Abfragen, Notizbüchern und Ansichten aufrufen:

-- Simple select
SELECT my_catalog.my_schema.add_one(5) AS result;

-- With table data
SELECT
  id,
  price,
  currency,
  my_catalog.my_schema.convert_to_usd(price, currency) AS price_usd
FROM my_catalog.my_schema.transactions;

-- Filtering
SELECT *
FROM my_catalog.my_schema.products
WHERE my_catalog.my_schema.convert_to_usd(price, currency) > 100;

-- Aggregation
SELECT
  category,
  SUM(my_catalog.my_schema.convert_to_usd(price, currency)) AS total_usd
FROM my_catalog.my_schema.sales
GROUP BY category;

Verwaltung und Teilen

Verwenden Sie Unity-Katalogberechtigungen, um zu steuern, wer Ihre UDF ausführen kann, und um sie in Ihrer Organisation auffindbar zu machen.

Berechtigungen erteilen

Verwenden Sie den Katalog-Explorer oder SQL, um anderen Benutzern die erforderlichen Berechtigungen zum Ausführen Ihrer UDFs zu erteilen.

Katalog-Explorer

  1. Klicken Sie in der Randleiste auf das Datensymbol.Katalog.
  2. Wählen Sie den Katalog aus, und wählen Sie dann das Schema aus, das Ihre Funktion enthält.
  3. Klicken Sie auf den Funktionsnamen.
  4. Klicken Sie auf der Registerkarte Berechtigungen auf Erteilen.
  5. Wählen Sie die Prinzipale aus, auf die Sie Zugriff gewähren möchten, und wählen Sie die EXECUTE Berechtigung aus.
  6. Klicken Sie auf Bestätigen.

SQL

Führen Sie den folgenden Befehl in einem Notizbuch oder dem SQL-Editor für Databricks aus, um einem Benutzer oder einer Gruppe Berechtigungen zu erteilen EXECUTE .

-- Grant to a specific user
GRANT EXECUTE ON FUNCTION my_catalog.my_schema.add_one TO `user@example.com`;

-- Grant to a group
GRANT EXECUTE ON FUNCTION my_catalog.my_schema.add_one TO `data-engineers`;

Berechtigungen widerrufen

Verwenden Sie den Katalog-Explorer oder SQL, um Berechtigungen von anderen Benutzern zu widerrufen.

Katalog-Explorer

  1. Klicken Sie in der Randleiste auf das Datensymbol.Katalog.
  2. Wählen Sie den Katalog aus, und wählen Sie dann das Schema aus, das Ihre Funktion enthält.
  3. Klicken Sie auf den Funktionsnamen.
  4. Wählen Sie auf der Registerkarte Berechtigungen das Kontrollkästchen neben dem Prinzipal aus, dem Sie den Zugriff entziehen möchten. Klicken Sie auf Widerrufen.
  5. Klicken Sie in der Benachrichtigung auf "Widerrufen".

SQL

Führen Sie den folgenden Befehl in einem Notizbuch oder dem SQL-Editor für Databricks aus, um Berechtigungen von einem Benutzer oder einer Gruppe zu widerrufen EXECUTE .

-- Revoke from specific user
REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.add_one FROM `user@example.com`;

-- Revoke from a group
REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.add_one FROM `data-engineers`;

UDFs entdecken

Um UDFs zu finden, die in Unity Catalog verwaltet werden, fragen Sie die Tabelle information_schema.routines ab und ersetzen dabei die Werte my_catalog und my_schema:

SELECT
  routine_catalog,
  routine_schema,
  routine_name,
  routine_definition,
  created
FROM system.information_schema.routines
WHERE routine_catalog = 'my_catalog'
  AND routine_schema = 'my_schema';

Aktualisieren Sie Ihre UDF

So aktualisieren Sie eine vorhandene Unity-Katalog-UDF mit neuem Code:

  1. Nehmen Sie lokal Änderungen an Ihrem Code vor.
  2. Erstellen Sie den JAR mit einer neuen Versionsnummer neu.
    • Skala: sbt clean assembly (z. B. my-udf-assembly-0.2.0-SNAPSHOT.jar)
    • Java: mvn clean package (z. B. my-udf-2.0-SNAPSHOT.jar)
  3. Laden Sie das neue JAR in das Unity-Katalogvolume hoch.
  4. Verwenden Sie CREATE OR REPLACE FUNCTION mit dem gleichen Funktionsnamen, um die UDF zu aktualisieren. Stellen Sie sicher, dass in Ihrer java_dependencies auf das neueste JAR verwiesen wird.

Azure Databricks verwendet den neuen Code für den nächsten Aufruf. Sie müssen den Cluster nicht neu starten.

Leistungsoptimierung

Kaltstart-Latenz

Der erste UDF-Aufruf in einer Sitzung initialisiert die isolierte Sandbox, wodurch zusätzliche Latenz entsteht. Nachfolgende Aufrufe in derselben Sitzung sind schneller. Berücksichtigen Sie dies beim Benchmarking oder Beim Entwerfen von Latenzsensiblen Workloads.

Zwischenspeichern teurer Berechnungen

Wenn Ihre UDF eine aufwendige Initialisierung oder Berechnung durchführt, zwischenspeichern Sie das Ergebnis, um es nur einmal zu berechnen.

Scala

Verwenden Sie ein val Feld im Scala-Objekt, um das Ergebnis zwischenzuspeichern:

package example

object CachedUDF {
  // Computed once and cached
  val expensiveData: Map[String, Double] = {
    // Load data from somewhere expensive
    Map("key1" -> 1.0, "key2" -> 2.0)
  }

  def lookup(key: String): Double = {
    expensiveData.getOrElse(key, 0.0)
  }
}

Java

Verwenden Sie ein static Feld mit einem statischen Initialisierungsblock, um das Ergebnis zwischenzuspeichern:

package example;

import java.util.Map;
import java.util.HashMap;

public class CachedUDF {
    // Computed once and cached
    private static Map<String, Double> expensiveData;

    static {
        // Load data from somewhere expensive
        expensiveData = new HashMap<>();
        expensiveData.put("key1", 1.0);
        expensiveData.put("key2", 2.0);
    }

    public static double lookup(String key) {
        return expensiveData.getOrDefault(key, 0.0);
    }
}

Verwenden von DETERMINISTIC bei Bedarf

Markieren Sie Ihre UDF als DETERMINISTIC, wenn sie bei gleicher Eingabe immer dieselbe Ausgabe erzeugt. Dadurch kann der Abfrageoptimierer Ergebnisse zwischenspeichern und die Leistung verbessern.

Einschränkungen

  • Nur skalare UDFs werden unterstützt. Benutzerdefinierte Aggregatfunktionen (UDAFs) und benutzerdefinierte Tabellenfunktionen (UDTFs) werden nicht unterstützt.
  • UDFs werden in einer isolierten Sandbox ohne aktive Spark-Sitzung ausgeführt. Spark-APIs (SparkSession, SparkContext, spark.sql(...), DataFrame- und Dataset-Vorgänge) sind nicht verfügbar.
  • UDFs können nicht von Spark Core-Paketen abhängen.
  • UDFs haben keinen Zugriff auf Arbeitsbereichsdateien oder Unity-Katalogvolumes zur Laufzeit.

Bewährte Methoden

Databricks empfiehlt die folgenden Methoden:

  • Versionieren Sie Ihre JAR-Dateien. Zum Beispiel, my-udf-0.1.0.jar, my-udf-0.2.0.jar.
  • Überprüfen Sie die SQL-Typzuordnungen vor der Bereitstellung. Siehe Sprachzuordnungen.
  • Erteilen READ VOLUME und EXECUTE Berechtigungen nur für Benutzer, die die UDF ausführen müssen. Verwenden Sie Gruppeneigentum für UDFs, die teamübergreifend gemeinsam genutzt werden.

Lokales Testen von UDFs

Testen Sie Ihre UDF mit Komponententests, bevor Sie sie in der Produktion bereitstellen.

Scala

Um src/main/scala/example/MyUDF.scala zu testen, erstellen Sie eine Testdatei in src/test/scala/example/MyUDFTest.scala:

package example

import org.scalatest.funsuite.AnyFunSuite

class MyUDFTest extends AnyFunSuite {
  test("addOne should add 1 to input") {
    assert(MyUDF.addOne(5) == 6)
  }

  test("addOne should handle negative numbers") {
    assert(MyUDF.addOne(-1) == 0)
  }
}

Fügen Sie die Testabhängigkeit zu build.sbt:

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % Test

So führen Sie die Tests aus:

sbt test

Java

Um src/main/java/com/example/MyUDF.java zu testen, erstellen Sie eine Testdatei in src/test/java/com/example/MyUDFTest.java:

package com.example;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class MyUDFTest {
    @Test
    public void testAddOne() {
        assertEquals(6, MyUDF.addOne(5));
    }

    @Test
    public void testAddOneWithNegativeNumbers() {
        assertEquals(0, MyUDF.addOne(-1));
    }
}

Fügen Sie die JUnit-Abhängigkeit zum <dependencies> Abschnitt Ihrer pom.xml:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

So führen Sie die Tests aus:

mvn test

Weitere Ressourcen