Udostępnij przez


Funkcje zdefiniowane przez użytkownika (UDF) w Unity Catalog

Ważne

Ta funkcja jest dostępna w publicznej wersji zapoznawczej.

Funkcje zdefiniowane przez użytkownika (UDF) w wykazie aparatu Unity rozszerzają możliwości języka SQL i Python w usłudze Azure Databricks. Umożliwiają one definiowanie, używanie i bezpieczne udostępnianie funkcji niestandardowych w środowiskach obliczeniowych.

Funkcje zdefiniowane przez użytkownika w języku Python, zarejestrowane jako funkcje w Unity Catalog, różnią się zakresem i obsługą od funkcji zdefiniowanych przez użytkownika PySpark, które są ograniczone do notesu lub SparkSession. Zobacz Funkcje skalarne zdefiniowane przez użytkownika — Python.

Zobacz CREATE FUNCTION (SQL i Python), aby uzyskać pełną dokumentację języka SQL.

Wymagania

Aby korzystać z funkcji zdefiniowanych przez użytkownika w wykazie aparatu Unity, należy spełnić następujące wymagania:

  • Aby użyć kodu Python w funkcjach zdefiniowanych przez użytkownika zarejestrowanych w Unity Catalog, należy użyć bezserwerowego lub pro SQL Warehouse albo klastra działającego na Databricks Runtime 13.3 LTS lub nowszym.
  • Jeśli widok zawiera funkcję UDF Python katalogu Unity, zawodzi w klasycznych hurtowniach SQL.

Tworzenie funkcji zdefiniowanych przez użytkownika w Unity Catalog

Aby utworzyć funkcję UDF w Unity Catalog, użytkownicy muszą mieć uprawnienia USAGE i CREATE dla schematu oraz uprawnienia USAGE dla katalogu. Aby uzyskać więcej informacji, zobacz Katalog Unity.

Aby uruchomić funkcję zdefiniowaną przez użytkownika (UDF), użytkownicy muszą mieć uprawnienie EXECUTE do uzyskania dostępu do tej funkcji. Użytkownicy potrzebują również uprawnień USAGE w schemacie i katalogu.

Aby utworzyć i zarejestrować funkcję zdefiniowaną przez użytkownika w schemacie wykazu aparatu Unity, nazwa funkcji powinna być zgodna z formatem catalog.schema.function_name. Alternatywnie możesz wybrać prawidłowy wykaz i schemat w edytorze SQL. W takim przypadku nazwa funkcji nie powinna być catalog.schema wstępnie przypisana:

Tworzenie funkcji zdefiniowanej przez użytkownika przy użyciu wstępnie wybranego wykazu i schematu.

Poniższy przykład rejestruje nową funkcję w my_schema schemacie w wykazie my_catalog :

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight DOUBLE, height DOUBLE)
RETURNS DOUBLE
LANGUAGE SQL
RETURN
SELECT weight / (height * height);

Funkcje języka Python zdefiniowane przez użytkownika dla Unity Catalog używają instrukcji z oznaczeniem podwójnym znakiem dolara ($$). Musisz określić mapowanie typu danych. Poniższy przykład rejestruje funkcję zdefiniowaną przez użytkownika, która oblicza indeks masy ciała:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight_kg DOUBLE, height_m DOUBLE)
RETURNS DOUBLE
LANGUAGE PYTHON
AS $$
return weight_kg / (height_m ** 2)
$$;

Teraz możesz skorzystać z funkcji Unity Catalog w zapytaniach SQL lub kodzie PySpark.

SELECT person_id, my_catalog.my_schema.calculate_bmi(weight_kg, height_m) AS bmi
FROM person_data;

Zobacz Przykłady filtrów wierszy i przykłady maski kolumn, aby uzyskać więcej przykładów funkcji UDF.

Rozszerzanie funkcji UDF przy użyciu zależności niestandardowych

Ważne

Ta funkcja jest dostępna w publicznej wersji zapoznawczej.

Rozszerz funkcjonalność Python UDFs Katalogu Unity poza środowisko Databricks Runtime, definiując niestandardowe zależności dla bibliotek zewnętrznych.

Zainstaluj zależności z następujących źródeł:

  • Pakiety PyPI
  • Pliki przechowywane w woluminach Unity Catalogu Użytkownik wywołujący funkcję UDF musi mieć uprawnienia do woluminu źródłowego.
  • Pliki dostępne na publicznych adresach URL Reguły zabezpieczeń sieci obszaru roboczego muszą zezwalać na dostęp do publicznych adresów URL.

Uwaga

Aby skonfigurować reguły zabezpieczeń sieci, aby zezwolić na dostęp do publicznych adresów URL z bezserwerowego magazynu SQL, zobacz Weryfikowanie przy użyciu usługi Databricks SQL.

  • Bezserwerowe magazyny SQL wymagają włączenia funkcji Publiczna wersja zapoznawcza Włączanie sieci dla funkcji zdefiniowanych przez użytkownika w bezserwerowych magazynach SQL Warehouse na stronie Podglądy obszaru roboczego w celu uzyskania dostępu do Internetu dla niestandardowych zależności.

Niestandardowe zależności dla funkcji zdefiniowanych przez użytkownika w katalogu Unity Catalog są obsługiwane na następujących typach obliczeń:

  • Notesy i zadania bezserwerowe
  • Obliczenia ogólnego przeznaczenia przy użyciu środowiska Databricks Runtime w wersji 16.2 lub nowszej
  • Pro lub bezserwerowa usługa SQL Warehouse

Użyj sekcji ENVIRONMENT definicji UDF, aby określić zależności.

CREATE OR REPLACE FUNCTION my_catalog.my_schema.mixed_process(data STRING)
RETURNS STRING
LANGUAGE PYTHON
ENVIRONMENT (
  dependencies = '["simplejson==3.19.3", "/Volumes/my_catalog/my_schema/my_volume/packages/custom_package-1.0.0.whl", "https://my-bucket.s3.amazonaws.com/packages/special_package-2.0.0.whl?Expires=2043167927&Signature=abcd"]',
  environment_version = 'None'
)
AS $$
import simplejson as json
import custom_package
return json.dumps(custom_package.process(data))
$$;

Sekcja ENVIRONMENT zawiera następujące pola:

(No changes needed) Opis Typ Przykładowe użycie
dependencies Lista zależności rozdzielonych przecinkami do zainstalowania. Każdy wpis jest ciągiem znaków zgodnym z formatem pliku wymagań pip. STRING dependencies = '["simplejson==3.19.3", "/Volumes/catalog/schema/volume/packages/my_package-1.0.0.whl"]'
dependencies = '["https://my-bucket.s3.amazonaws.com/packages/my_package-2.0.0.whl?Expires=2043167927&Signature=abcd"]'
environment_version Określa bezserwerową wersję środowiska, w której ma być uruchamiana funkcja UDF.
Obecnie obsługiwana jest tylko wartość None.
STRING environment_version = 'None'

Korzystanie z Unity Catalog UDFs w narzędziu PySpark

from pyspark.sql.functions import expr

result = df.withColumn("bmi", expr("my_catalog.my_schema.calculate_bmi(weight_kg, height_m)"))
display(result)

Uaktualnianie funkcji zdefiniowanej przez użytkownika w zakresie sesji

Uwaga

Składnia i semantyka funkcji Python UDFs w Unity Catalog różnią się od Python UDFs zarejestrowanych w ramach SparkSession. Zobacz funkcje skalarne zdefiniowane przez użytkownika — Python.

Biorąc pod uwagę następującą funkcję zdefiniowaną przez użytkownika opartą na sesji w notesie usługi Azure Databricks:

from pyspark.sql.functions import udf
from pyspark.sql.types import StringType

@udf(StringType())
def greet(name):
    return f"Hello, {name}!"

# Using the session-based UDF
result = df.withColumn("greeting", greet("name"))
result.show()

Aby zarejestrować to jako funkcję Katalogu Unity, użyj instrukcji SQL CREATE FUNCTION, jak pokazano w poniższym przykładzie:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.greet(name STRING)
RETURNS STRING
LANGUAGE PYTHON
AS $$
return f"Hello, {name}!"
$$

Udostępnianie UDF w katalogu Unity

Uprawnienia dla funkcji zdefiniowanych przez użytkownika są zarządzane na podstawie kontroli dostępu stosowanej do katalogu, schematu lub bazy danych, w której funkcja zdefiniowana przez użytkownika jest zarejestrowana. Aby uzyskać więcej informacji, zobacz Zarządzanie uprawnieniami w wykazie aparatu Unity .

Użyj usługi Azure Databricks SQL lub interfejsu użytkownika obszaru roboczego usługi Azure Databricks, aby udzielić uprawnień użytkownikowi lub grupie (zalecane).

Uprawnienia w interfejsie użytkownika obszaru roboczego

  1. Znajdź katalog i schemat, w którym są przechowywane funkcje zdefiniowane przez użytkownika, i wybierz funkcję zdefiniowanej przez użytkownika.
  2. Poszukaj opcji Uprawnienia w ustawieniach UDF. Dodaj użytkowników lub grupy i określ typ dostępu, który powinni mieć, na przykład EXECUTE lub MANAGE.

Uprawnienia w interfejsie użytkownika obszaru roboczego

Uprawnienia przy użyciu usługi Azure Databricks SQL

Poniższy przykład przyznaje użytkownikowi uprawnienie EXECUTE dla funkcji:

GRANT EXECUTE ON FUNCTION my_catalog.my_schema.calculate_bmi TO `user@example.com`;

Aby usunąć uprawnienia, użyj polecenia REVOKE, jak w poniższym przykładzie:

REVOKE EXECUTE ON FUNCTION my_catalog.my_schema.calculate_bmi FROM `user@example.com`;

Izolacja środowiskowa

Uwaga

Środowiska izolacji współużytkowanej wymagają oprogramowania Databricks Runtime w wersji 18.0 lub nowszej. We wcześniejszych wersjach wszystkie funkcje Pythona zdefiniowane przez użytkownika w katalogu Unity działają w trybie ścisłej izolacji.

Funkcje Python UDFs w katalogu Unity z tym samym właścicielem i sesją mogą domyślnie współużytkować środowisko izolacyjne. Zwiększa to wydajność i zmniejsza użycie pamięci przez zmniejszenie liczby oddzielnych środowisk, które należy uruchomić.

Ścisła izolacja

Aby zapewnić, że funkcja UDF zawsze działa we własnym, w pełni izolowanym środowisku, dodaj klauzulę charakterystyczną STRICT ISOLATION .

Większość funkcji zdefiniowanych przez użytkownika nie wymaga ścisłej izolacji. Standardowe funkcje zdefiniowane przez użytkownika przetwarzania danych korzystają z domyślnego środowiska izolacji współużytkowanej i działają szybciej dzięki mniejszej ilości pamięci.

Dodaj klauzulę charakterystyczną do funkcji zdefiniowanych STRICT ISOLATION przez użytkownika, które:

  • Uruchom dane wejściowe jako kod przy użyciu eval()funkcji , exec()lub podobnych.
  • Zapisywanie plików w lokalnym systemie plików.
  • Modyfikowanie zmiennych globalnych lub stanu systemu.
  • Uzyskaj dostęp do zmiennych środowiskowych lub zmodyfikuj je.

Poniższy kod przedstawia przykład funkcji zdefiniowanej przez użytkownika, która powinna być uruchamiana za pomocą polecenia STRICT ISOLATION. Ta funkcja UDF wykonuje dowolny kod języka Python, więc może zmienić stan systemu, uzyskać dostęp do zmiennych środowiskowych lub zapisać w lokalnym systemie plików. Użycie klauzuli STRICT ISOLATION pomaga zapobiegać ingerencji lub wyciekom danych między UDF-ami.

CREATE OR REPLACE TEMPORARY FUNCTION run_python_snippet(python_code STRING)
RETURNS STRING
LANGUAGE PYTHON
STRICT ISOLATION
AS $$
import sys
from io import StringIO

# Capture standard output and error streams
captured_output = StringIO()
captured_errors = StringIO()
sys.stdout = captured_output
sys.stderr = captured_errors

try:
    # Execute the user-provided Python code in an empty namespace
    exec(python_code, {})
except SyntaxError:
    # Retry with escaped characters decoded (for cases like "\n")
    def decode_code(raw_code):
        return raw_code.encode('utf-8').decode('unicode_escape')
    python_code = decode_code(python_code)
    exec(python_code, {})

# Return everything printed to stdout and stderr
return captured_output.getvalue() + captured_errors.getvalue()
$$

Ustaw DETERMINISTIC , czy funkcja generuje spójne wyniki

Dodaj DETERMINISTIC do definicji funkcji, jeśli generuje te same dane wyjściowe dla tych samych danych wejściowych. Dzięki temu optymalizacje zapytań mogą zwiększyć wydajność.

Domyślnie przyjmuje się, że funkcje zdefiniowane przez użytkownika języka Python wykazu aparatu Unity w usłudze Batch są niedeterministyczne, chyba że jawnie zadeklarowano. Przykłady funkcji niedeterministycznych obejmują generowanie wartości losowych, uzyskiwanie dostępu do bieżących godzin lub dat lub wykonywanie zewnętrznych wywołań interfejsu API.

Zobacz CREATE FUNCTION (SQL i Python)

Funkcje zdefiniowane przez użytkownika dla narzędzi agenta sztucznej inteligencji

Agenty generatywnej AI mogą używać funkcji zdefiniowanych przez użytkownika katalogu Unity jako narzędzi do realizowania zadań i wykonywania niestandardowej logiki.

Zobacz Utwórz narzędzia agenta sztucznej inteligencji, korzystając z funkcji katalogu Unity.

Funkcje zdefiniowane przez użytkownika na potrzeby uzyskiwania dostępu do zewnętrznych interfejsów API

Za pomocą funkcji zdefiniowanych przez użytkownika można uzyskiwać dostęp do zewnętrznych interfejsów API z poziomu SQL. W poniższym przykładzie użyto biblioteki języka Python requests do utworzenia żądania HTTP.

Uwaga

UDF Python umożliwiają ruch sieciowy TCP/UDP przez porty 80, 443 i 53 podczas korzystania z architektury bezserwerowej lub obliczeń skonfigurowanych w standardowym trybie dostępu.

CREATE FUNCTION my_catalog.my_schema.get_food_calories(food_name STRING)
RETURNS DOUBLE
LANGUAGE PYTHON
AS $$
import requests

api_url = f"https://example-food-api.com/nutrition?food={food_name}"
response = requests.get(api_url)

if response.status_code == 200:
   data = response.json()
   # Assume the API returns a JSON object with a 'calories' field
   calories = data.get('calories', 0)
   return calories
else:
   return None  # API request failed

$$;

Funkcje użytkownika (UDFs) dla zabezpieczeń i zgodności

Użyj funkcji zdefiniowanych przez użytkownika (UDF) języka Python, aby zaimplementować niestandardową tokenizację, maskowanie danych, redagowanie danych lub mechanizmy szyfrowania.

Poniższy przykład maskuje tożsamość adresu e-mail przy zachowaniu długości i domeny:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.mask_email(email STRING)
RETURNS STRING
LANGUAGE PYTHON
DETERMINISTIC
AS $$
parts = email.split('@', 1)
if len(parts) == 2:
  username, domain = parts
else:
  return None
masked_username = username[0] + '*' * (len(username) - 2) + username[-1]
return f"{masked_username}@{domain}"
$$

Następujący przykład stosuje tę UDF w definicji widoku dynamicznego.

-- First, create the view
CREATE OR REPLACE VIEW my_catalog.my_schema.masked_customer_view AS
SELECT
  id,
  name,
  my_catalog.my_schema.mask_email(email) AS masked_email
FROM my_catalog.my_schema.customer_data;

-- Now you can query the view
SELECT * FROM my_catalog.my_schema.masked_customer_view;
+---+------------+------------------------+------------------------+
| id|        name|                   email|           masked_email |
+---+------------+------------------------+------------------------+
|  1|    John Doe|   john.doe@example.com |  j*******e@example.com |
|  2| Alice Smith|alice.smith@company.com |a**********h@company.com|
|  3|   Bob Jones|    bob.jones@email.org |   b********s@email.org |
+---+------------+------------------------+------------------------+

Najlepsze rozwiązania

Aby funkcje zdefiniowane przez użytkownika były dostępne dla wszystkich użytkowników, zalecamy utworzenie dedykowanego wykazu i schematu z odpowiednimi mechanizmami kontroli dostępu.

W przypadku funkcji zdefiniowanych przez zespół należy użyć dedykowanego schematu w katalogu zespołów na potrzeby magazynowania i zarządzania.

Usługa Databricks zaleca dołączenie następujących informacji do dokumentu usługi UDF:

  • Bieżący numer wersji
  • Dziennik zmian do śledzenia modyfikacji w różnych wersjach
  • Cel, parametry i wartość zwracana przez użytkownika
  • Przykład użycia funkcji zdefiniowanej przez użytkownika

Oto przykład funkcji zdefiniowanej przez użytkownika zgodnej z najlepszymi praktykami:

CREATE OR REPLACE FUNCTION my_catalog.my_schema.calculate_bmi(weight_kg DOUBLE, height_m DOUBLE)
RETURNS DOUBLE
COMMENT "Calculates Body Mass Index (BMI) from weight and height."
LANGUAGE PYTHON
DETERMINISTIC
AS $$
 """
Parameters:
calculate_bmi (version 1.2):
- weight_kg (float): Weight of the individual in kilograms.
- height_m (float): Height of the individual in meters.

Returns:
- float: The calculated BMI.

Example Usage:

SELECT calculate_bmi(weight, height) AS bmi FROM person_data;

Change Log:
- 1.0: Initial version.
- 1.1: Improved error handling for zero or negative height values.
- 1.2: Optimized calculation for performance.

 Note: BMI is calculated as weight in kilograms divided by the square of height in meters.
 """
if height_m <= 0:
 return None  # Avoid division by zero and ensure height is positive
return weight_kg / (height_m ** 2)
$$;

Zachowanie strefy czasowej znacznika czasu dla danych wejściowych

W środowisku Databricks Runtime 18.0 lub nowszym, gdy wartości TIMESTAMP są przekazywane do funkcji UDF w Pythonie, pozostają one w UTC, ale atrybut metadanych strefy czasowej tzinfo nie jest uwzględniany w obiekcie datetime.

Ta zmiana dopasowuje funkcje zdefiniowane przez użytkownika (UDF) w języku Python katalogu Unity do zoptymalizowanych za pomocą Arrow funkcji UDF w Apache Spark.

Na przykład następujące zapytanie:

CREATE FUNCTION timezone_udf(date TIMESTAMP)
RETURNS STRING
LANGUAGE PYTHON
AS $$
return f"{type(date)} {date} {date.tzinfo}"
$$;

SELECT timezone_udf(TIMESTAMP '2024-10-23 10:30:00');

Wcześniej utworzono te dane wyjściowe w wersjach środowiska Databricks Runtime przed 18.0:

<class 'datetime.datetime'> 2024-10-23 10:30:00+00:00 Etc/UTC

W środowisku Databricks Runtime w wersji 18.0 lub nowszej są teraz generowane następujące dane wyjściowe:

<class 'datetime.datetime'> 2024-10-23 10:30:00+00:00 None

Jeśli funkcja zdefiniowana przez użytkownika korzysta z informacji o strefie czasowej, musisz ją jawnie przywrócić:

from datetime import timezone

date = date.replace(tzinfo=timezone.utc)

Ograniczenia

  • Można zdefiniować dowolną liczbę funkcji języka Python w Python UDF, ale wszystkie muszą zwracać wartość skalarną.
  • Funkcje języka Python muszą obsługiwać wartości NULL niezależnie, a wszystkie mapowania typów muszą być zgodne z mapowaniami języka SQL usługi Azure Databricks.
  • Jeśli nie określono wykazu lub schematu, funkcje UDF języka Python są rejestrowane w bieżącym aktywnym schemacie.
  • Funkcje użytkownika w Pythonie są wykonywane w bezpiecznym, izolowanym środowisku i nie mają dostępu do systemów plików ani usług wewnętrznych.
  • Nie można wywołać więcej niż pięciu funkcji zdefiniowanych przez użytkownika w zapytaniu.