Funkcje zdefiniowane przez użytkownika (UDF) w językach Scala i Java w Unity Catalog

Na tej stronie opisano, jak tworzyć funkcje definiowane przez użytkownika (UDF) w językach Scala i Java, rejestrować je w Unity Catalog oraz udostępniać je w różnych środowiskach obliczeniowych. Funkcje definiowane przez użytkownika (UDF) w Unity Catalog umożliwiają ponowne wykorzystanie istniejącej logiki JVM z użyciem mechanizmów zarządzania i kontroli dostępu Unity Catalog.

W przeciwieństwie do funkcji Scala UDF o zakresie sesji, które są ograniczone do pojedynczego notatnika lub klastra, funkcje UDF zarejestrowane w Unity Catalog to:

  • Zarządzane: Zarządzane przy użyciu uprawnień i mechanizmów kontroli dostępu w Unity Catalog.
  • Wielokrotne użycie: współużytkowany między zespołami, notesami, zadaniami i magazynami SQL.
  • Wykrywalne: widoczne w Eksploratorze katalogu i tabelach systemowych.
  • Izolowane: Uruchamiane w piaskownicach z jednorazowym kosztem zimnego startu na każdą sesję. Kolejne wywołania są szybkie.

Requirements

Obszar roboczy musi być włączony dla Unity Catalog. Obowiązują następujące dodatkowe wymagania.

Obliczenia: obsługiwane są wszystkie typy obliczeń, w tym notesy i zadania bezserwerowe, magazyny SQL i potoki deklaratywne platformy Spark w usłudze Lakeflow. Obliczenia klasyczne wymagają środowiska Databricks Runtime w wersji 18.2 lub nowszej. W przypadku bezserwerowych zasobów obliczeniowych i hurtowni SQL definicja UDF musi określać w polu environment_version wersję środowiska 4 lub nowszą. To wymaganie dotyczy definicji UDF, a nie wywołującego notatnika ani zadania. Zobacz wersje środowiska bezserwerowego.

Programowanie:

  • Scala: 2.13.16. Scala 2.12 nie jest obsługiwana.
  • JDK: 17.
  • Pakowanie: plik JAR zawierający wszystkie zależności zewnętrzne używane przez funkcję zdefiniowaną przez użytkownika (UDF).

Uprawnienia:

  • Utwórz UDF: USAGE i CREATE FUNCTION w schemacie oraz USAGE w katalogu.
  • Uruchom funkcję UDF: EXECUTE dla funkcji oraz USAGE dla schematu i katalogu.
  • Uzyskaj dostęp do pliku JAR: READ VOLUME na woluminie, w którym jest przechowywany plik JAR.

Więcej informacji o uprawnieniach w Unity Catalog można znaleźć w sekcji Zarządzanie uprawnieniami w Unity Catalog.

Zbuduj swój plik JAR UDF

Spakuj skompilowany kod w pliku JAR i prześlij go do woluminu Unity Catalog przed zarejestrowaniem funkcji UDF. Wybierz metodę kompilacji:

Zbuduj lokalnie

Wykonaj następujące kroki, aby zbudować gruby plik JAR przy użyciu lokalnego środowiska programistycznego.

Konfigurowanie środowiska

Zainstaluj wymagane narzędzia na komputerze lokalnym. Następujące polecenia są przeznaczone dla systemu macOS. W przypadku innych platform zainstaluj zestaw JDK 17 i sbt (Scala) lub Maven (Java) przy użyciu menedżera pakietów platformy.

Scala

Zainstaluj zestaw JDK 17 i sbt:

brew install openjdk@17
brew install sbt

Sprawdź instalację:

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

Java

Zainstaluj zestaw JDK 17 i narzędzie Maven:

brew install openjdk@17
brew install maven

Sprawdź instalację:

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

Tworzenie projektu

Skonfiguruj projekt w języku Scala lub Java.

Scala

Utwórz nowy projekt Scala przy użyciu polecenia sbt:

sbt new scala/scala-seed.g8

Po wyświetleniu monitu wprowadź nazwę projektu (na przykład my-udf-project).

Konfigurowanie pliku build.sbt

Zastąp zawartość build.sbt pliku następującą konfiguracją:

scalaVersion := "2.13.16"

ThisBuild / organization := "com.example"

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

Włączanie wtyczki sbt-assembly

Utwórz lub edytuj project/assembly.sbt i dodaj:

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

Ta wtyczka tworzy gruby plik JAR zawierający wszystkie zależności.

Java

Utwórz nowy projekt Maven przy użyciu archetypu szybkiego startu:

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

To polecenie tworzy standardową strukturę projektu Maven z katalogami src/main/java i .src/test/java

Konfigurowanie pom.xml

W wygenerowanym pliku pom.xml, wewnątrz znaczników <project></project> dodaj blok <properties> z następującą konfiguracją:

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

Ponadto w tagach <project></project> dodaj blok z następującą konfiguracją <build> :

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

maven-shade-plugin tworzy gruby plik JAR zawierający wszystkie zależności.

Napisz swój UDF

Podczas pisania UDF zapoznaj się z sekcją Typy danych, aby sprawdzić obsługiwane typy danych, oraz z sekcją Mapowania języków, aby zobaczyć, jak typy Scala i Java są mapowane na typy SQL.

Twój moduł obsługi UDF musi spełniać następujące wymagania:

  • Scala: Zdefiniuj procedurę obsługi jako metodę w obiekcie object (a nie class). Wartość HANDLER odnosi się do metody w obiekcie Scala object.
  • Java: Zdefiniuj procedurę obsługi jako metodępublic static.
  • Sygnatura: typy parametrów metody, ich kolejność oraz typ zwracany muszą odpowiadać liście argumentów i typowi RETURNS w instrukcji CREATE FUNCTION.
  • Tylko wartość skalarna: moduł obsługi musi zwrócić pojedynczą wartość skalarną. Typy zwracanych tabel nie są obsługiwane.
  • Samowystarczalny: moduł obsługi musi działać wyłącznie na podstawie swoich argumentów wejściowych. Nie może używać interfejsów API platformy Spark ani zależeć od pakietów podstawowych platformy Spark. Zobacz Ograniczenia.

Note

W przypadku języka Scala procedura obsługi z prymitywnym typem parametru (na przykład Int) jest pomijana i zwraca NULL, gdy dowolny argument wejściowy ma wartość SQL NULL. Aby odbierać i obsługiwać wartości NULL, owiń parametr w Option, na przykład Option[Int].

Scala

Utwórz obiekt w Scali w pliku src/main/scala/com/example/MyUDF.scala i zdefiniuj funkcję UDF.

Przykład podstawowy

package com.example

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

Przykład z zależnością zewnętrzną

Aby użyć bibliotek zewnętrznych, dodaj je do pliku build.sbt :

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"
    )
  )

Następnie użyj tej zależności w swojej funkcji 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")
    }
  }
}

Przetestuj funkcję UDF przy użyciu testów jednostkowych przed wdrożeniem. Zobacz Lokalne testowanie UDF-ów.

Java

Utwórz klasę Java w src/main/java/com/example/MyUDF.java pliku i zdefiniuj funkcję UDF jako publiczną metodę statyczną.

Przykład podstawowy

package com.example;

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

Przykład z zależnością zewnętrzną

Aby użyć bibliotek zewnętrznych, dodaj je do <dependencies> sekcji pom.xml pliku:

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

Następnie użyj tej zależności w swojej funkcji zdefiniowanej przez użytkownika:

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);
    }
}

Przetestuj funkcję UDF przy użyciu testów jednostkowych przed wdrożeniem. Zobacz Lokalne testowanie funkcji UDF.

Note

Funkcja UDF działa w izolowanym środowisku typu sandbox bez aktywnej sesji Spark, więc nie może używać interfejsów API Spark wewnątrz ciała funkcji. Na przykład nie można tworzyć ani działać na ramkach danych lub zestawach danych, uruchomić spark.sql(...)lub uzyskać dostęp SparkSession lub SparkContext. Funkcja UDF musi być autonomiczną logiką dla argumentów wejściowych. Nie może również zależeć od pakietów podstawowych platformy Spark.

Zbuduj swój fat JAR

Skompiluj projekt, aby utworzyć gruby plik JAR zawierający wszystkie zależności.

Scala

W katalogu głównym projektu uruchom polecenie:

sbt clean assembly

Plik fat JAR jest tworzony w target/scala-2.13/ pod nazwą taką jak my-udf-assembly-0.1.0-SNAPSHOT.jar.

Java

W katalogu głównym projektu uruchom polecenie:

mvn clean package

Gruby plik JAR jest tworzony w target/ pliku o nazwie takiej jak my-udf-1.0-SNAPSHOT.jar.

Prześlij plik JAR do woluminu Unity Catalog

Jeśli nie masz jeszcze woluminu Unity Catalog, utwórz go:

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

Jeśli inni użytkownicy muszą uruchomić funkcję zdefiniowaną przez użytkownika, przyznaj im READ VOLUME do woluminu:

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

Przekaż plik JAR do woluminu przy użyciu Eksploratora wykazu:

  1. W obszarze roboczym Azure Databricks kliknij pozycję Ikona Danych.Katalog aby otworzyć Eksplorator Katalogu.
  2. Wybierz katalog, a następnie wybierz schemat zawierający wolumin.
  3. Kliknij nazwę woluminu.
  4. Kliknij pozycję Prześlij do tego wolumenu i wybierz plik JAR.
  5. Kliknij Przekaż.
  6. Po zakończeniu przesyłania kliknij nazwę swojego pliku JAR.
  7. Kliknij opcję Kopiuj ścieżkę, aby skopiować ścieżkę woluminu do schowka. Na przykład /Volumes/my_catalog/my_schema/udf_jars/my-udf-assembly-0.1.0-SNAPSHOT.jar (Scala) lub /Volumes/my_catalog/my_schema/udf_jars/my-udf-1.0-SNAPSHOT.jar (Java). Ta ścieżka będzie potrzebna podczas rejestrowania UDF.

Kompilowanie w notatniku

Można skompilować funkcję UDF, spakować ją jako plik JAR i przesłać ją bezpośrednio z notatnika Azure Databricks do woluminu katalogu Unity Catalog. To podejście sprawdza się w przypadku małych UDF-ów niewymagających zależności. W przypadku UDF z bibliotekami zewnętrznymi użyj opcji Build locally.

Poniższa komórka w Pythonie zapisuje funkcję UDF w języku Java, która czyści ciąg znaków (usuwa białe znaki z początku i końca, scala wielokrotne spacje i zamienia tekst na małe litery), kompiluje ją przy użyciu JDK 17, pakuje ją do pliku JAR i kopiuje do woluminu usługi Unity Catalog. Zaktualizuj volume_path, aby wskazywał na istniejący wolumin, do którego masz uprawnienie WRITE VOLUME.

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}")

Gdy plik JAR znajdzie się w wolumenie, zarejestruj UDF. Użyj LANGUAGE JAVA i ustaw parametr HANDLER na w pełni kwalifikowaną nazwę metody, na przykład com.databricks.udf.StringCleanUDF.clean.

Zarejestruj swój UDF w Unity Catalog

Po skompilowaniu i przesłaniu pliku JAR użyj instrukcji CREATE FUNCTION, aby zarejestrować funkcję UDF w Unity Catalog.

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';

Instrukcja CREATE FUNCTION używa następujących parametrów:

  • LANGUAGE: Język UDF.

  • HANDLER: W pełni kwalifikowana ścieżka do metody w formacie 'package.Object.method' (Scala) lub 'package.ClassName.method' (Java).

  • DETERMINISTIC: deklaruje, że funkcja zawsze zwraca te same dane wyjściowe dla tych samych danych wejściowych, włączając optymalizację zapytań.

    Note

    Usuń DETERMINISTIC , jeśli funkcja wywołuje zewnętrzne interfejsy API lub ma inne niedeterministyczne zachowanie.

  • ENVIRONMENT: definiuje środowisko wykonywania dla UDF.

    • java_dependencies: tablica JSON zawierająca ścieżki do plików JAR w woluminach Unity Catalog. Jest to ścieżka pliku skopiowana w poprzednim kroku. Użyj pojedynczych cudzysłowów wokół tablicy i podwójnych cudzysłowów wokół ścieżek.
    • environment_version: Musi mieć wartość '4' lub wyższą dla UDF języków Scala i Java. Środowisko w wersji 4 określa użycie Scala 2.13.16 i JDK 17. Zobacz wersje środowiska bezserwerowego.

Wywołaj swój UDF w SQL i notatnikach

Po rejestracji można wywołać funkcję UDF w zapytaniach SQL, notesach i widokach:

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

Nadzór i udostępnianie

Użyj uprawnień Unity Catalog, aby zarządzać tym, kto może uruchamiać Twoją funkcję UDF, i udostępnić ją do odnajdywania w całej organizacji.

Udzielanie uprawnień

Użyj Catalog Explorer lub SQL, aby nadać innym użytkownikom niezbędne uprawnienia do uruchamiania swoich funkcji UDF.

Eksplorator wykazu

  1. Na pasku bocznym kliknij ikonę Dane.Wykaz.
  2. Wybierz wykaz, a następnie wybierz schemat zawierający funkcję.
  3. Kliknij nazwę funkcji.
  4. Na karcie Uprawnienia kliknij Przyznaj.
  5. Wybierz podmioty, którym chcesz przyznać dostęp, i wybierz uprawnienie EXECUTE.
  6. Kliknij przycisk Potwierdź.

SQL

Uruchom następujące polecenie w notesie lub edytorze SQL usługi Databricks, aby udzielić EXECUTE uprawnień użytkownikowi lub grupie.

-- 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`;

Odwoływanie uprawnień

Użyj Eksploratora wykazu lub programu SQL, aby odwołać uprawnienia od innych użytkowników.

Eksplorator wykazu

  1. Na pasku bocznym kliknij ikonę Dane.Wykaz.
  2. Wybierz wykaz, a następnie wybierz schemat zawierający funkcję.
  3. Kliknij nazwę funkcji.
  4. Na karcie Uprawnienia zaznacz pole wyboru obok podmiotu, któremu chcesz cofnąć dostęp. Kliknij pozycję Odwołaj.
  5. W powiadomieniu kliknij pozycję Odwołaj.

SQL

Uruchom następujące polecenie w notesie lub edytorze SQL usługi Databricks, aby odwołać EXECUTE uprawnienia użytkownika lub grupy.

-- 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`;

Odnajdywanie funkcji zdefiniowanych przez użytkownika

Aby znaleźć funkcje UDF zarządzane w Unity Catalog, wykonaj zapytanie względem tabeli information_schema.routines, zastępując wartości my_catalog i 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';

Zaktualizuj swój UDF

Aby zaktualizować istniejącą funkcję UDF w usłudze Unity Catalog za pomocą nowego kodu:

  1. Wprowadź zmiany w kodzie lokalnie.
  2. Ponownie skompiluj plik JAR przy użyciu nowego numeru wersji.
    • Scala: sbt clean assembly (na przykład my-udf-assembly-0.2.0-SNAPSHOT.jar)
    • Java: mvn clean package (na przykład my-udf-2.0-SNAPSHOT.jar)
  3. Prześlij nowy plik JAR do woluminu Unity Catalog.
  4. Użyj CREATE OR REPLACE FUNCTION z tą samą nazwą funkcji, aby zaktualizować funkcję zdefiniowaną przez użytkownika. Sprawdź, czy odwołujesz się do najnowszego pliku JAR w pliku java_dependencies.

Azure Databricks używa nowego kodu podczas następnego wywołania. Nie musisz ponownie uruchamiać klastra.

Optymalizacja wydajności

Opóźnienie zimnego startu

Pierwsze wywołanie UDF w sesji inicjuje izolowane środowisko piaskownicy, co powoduje dodatkowe opóźnienie. Kolejne wywołania w tej samej sesji są szybsze. Należy to uwzględnić podczas testów porównawczych lub projektowania obciążeń wrażliwych na opóźnienia.

Buforowanie kosztownych obliczeń

Jeśli funkcja zdefiniowana przez użytkownika wykonuje kosztowną inicjalizację lub obliczenia, zapisz wynik w pamięci podręcznej, aby był obliczany tylko raz.

Scala

val Użyj pola w obiekcie Scala, aby buforować wynik:

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

static Użyj pola ze statycznym blokiem inicjatora, aby buforować wynik:

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);
    }
}

Użyj DETERMINISTIC, gdy jest to właściwe

Oznacz swój UDF jako DETERMINISTIC, jeśli zawsze zwraca te same dane wyjściowe dla tych samych danych wejściowych. Dzięki temu optymalizator zapytań może buforować wyniki i poprawiać wydajność.

Ograniczenia

  • Obsługiwane są tylko skalarne funkcje zdefiniowane przez użytkownika. Funkcje agregujące zdefiniowane przez użytkownika (UDAFs) i funkcje tabeli zdefiniowane przez użytkownika (UDTFs) nie są obsługiwane.
  • Funkcje zdefiniowane przez użytkownika działają w izolowanym środowisku bez aktywnej sesji Spark. Interfejsy API Spark (SparkSession, SparkContext, spark.sql(...), operacje na ramkach danych i zbiorach danych) nie są dostępne.
  • Funkcje definiowane przez użytkownika nie mogą być zależne od pakietów rdzenia Spark.
  • UDF-y nie mają dostępu do plików w obszarze roboczym ani woluminów Unity Catalog w czasie działania.

Najlepsze rozwiązania

Usługa Databricks zaleca następujące rozwiązania:

  • Wersjonuj pliki JAR. Na przykład , my-udf-0.1.0.jar. my-udf-0.2.0.jar
  • Przed wdrożeniem zweryfikuj mapowania typów SQL. Zobacz Mapowania języka.
  • Przyznawaj uprawnienia READ VOLUME i EXECUTE tylko użytkownikom, którzy muszą uruchamiać UDF. Użyj własności grupowej dla funkcji zdefiniowanych przez użytkownika współdzielonych między zespołami.

Lokalne testowanie funkcji zdefiniowanych przez użytkownika

Przetestuj funkcję UDF przy użyciu testów jednostkowych przed wdrożeniem w środowisku produkcyjnym.

Scala

Aby przetestować src/main/scala/example/MyUDF.scala, utwórz plik testowy w 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)
  }
}

Dodaj zależność testową do build.sbt:

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

Aby uruchomić testy:

sbt test

Java

Aby przetestować src/main/java/com/example/MyUDF.java, utwórz plik testowy w 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));
    }
}

Dodaj zależność JUnit do sekcji <dependencies> w pliku pom.xml:

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

Aby uruchomić testy:

mvn test

Dodatkowe zasoby