Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Natywny mechanizm wykonywania w usłudze Microsoft Fabric obsługuje teraz funkcje języka Python zdefiniowane przez użytkownika (UDF), funkcje języka Scala zdefiniowane przez użytkownika (UDF) oraz złożone typy danych (tablice, mapy i struktury). Te możliwości umożliwiają pisanie ekspresyjnych aplikacji Platformy Spark bez poświęcania wydajności.
Obsługa funkcji UDF języka Python
Python jest jednym z najpopularniejszych języków inżynierii danych i nauki o danych. Historycznie funkcje UDF języka Python powodowały w Sparku znaczny narzut ze względu na koszty serializacji między maszyną wirtualną Java (JVM) a procesami roboczymi Pythona. Natywny silnik wykonywania minimalizuje te kosztowne przełączenia, umożliwiając szybsze wykonywanie bez zmian w kodzie.
Jak działają funkcje UDF języka Python w natywnym silniku wykonywania
W konwencjonalnym modelu wykonywania Spark wykonywanie funkcji UDF języka Python obejmuje:
- Konwersja danych z wewnętrznego formatu platformy Spark.
- Serializacja i transfer do procesów roboczych Python.
- Wykonywanie funkcji zdefiniowanych przez użytkownika w języku Python.
- Serializacja wyników z powrotem do maszyny JVM.
- Spark wznawia działanie.
To przenoszenie między środowiskami wykonawczymi powoduje koszty serializacji/deserializacji, nieefektywne wykorzystanie procesora i zakłócenie potoków wykonywania kolumnowego. Natywny silnik wykonawczy zmniejsza ten narzut dzięki optymalizacji ścieżki transferu danych i utrzymaniu przetwarzania wektoryzowanego tam, gdzie to możliwe.
Obsługiwane typy funkcji UDF w języku Python
Natywny silnik wykonawczy obsługuje:
-
Skalarne funkcje UDF: funkcje Pythona wykonywane dla każdego wiersza, zarejestrowane za pomocą
udf(). -
Wektoryzowane funkcje UDF (Pandas): funkcje oznaczone dekoratorem
@pandas_udf, które działają na partiach danych, wykorzystując Apache Arrow do wydajnego przesyłania danych.
Wektoryzowane funkcje UDF zapewniają największy wzrost wydajności, ponieważ naturalnie wpisują się w kolumnowy model przetwarzania natywnego silnika wykonawczego.
Przykład: wektoryzowana funkcja UDF języka Python
import pandas as pd
from pyspark.sql.functions import pandas_udf
from pyspark.sql.types import DoubleType
@pandas_udf(DoubleType())
def calculate_discount(price: pd.Series, rate: pd.Series) -> pd.Series:
return price * (1 - rate)
df = spark.table("sales.transactions")
result = df.withColumn("discounted_price", calculate_discount(df.price, df.discount_rate))
result.show()
Nie jest wymagana żadna dodatkowa konfiguracja poza włączeniem natywnego silnika wykonywania. Istniejące funkcje UDF języka Python automatycznie na tym korzystają.
Obsługa funkcji UDF języka Scala
Natywny silnik wykonywania również przyspiesza funkcje UDF w języku Scala. Ponieważ funkcje UDF w Scali działają natywnie w JVM, silnik może przekazywać obsługiwane operacje do wektoryzowanej ścieżki wykonania w C++, jednocześnie zachowując wydajne wykonywanie funkcji UDF w Scali w tym samym środowisku uruchomieniowym.
Przykład: Scala UDF
import org.apache.spark.sql.functions.udf
val toUpperCase = udf((s: String) => s.toUpperCase)
val df = spark.table("catalog.customers")
val result = df.withColumn("name_upper", toUpperCase(df("name")))
result.show()
Funkcje UDF języka Scala, które operują na obsługiwanych typach danych, są przyspieszane bez zmian w kodzie po włączeniu natywnego silnika wykonywania.
Obsługa złożonych typów danych
Nowoczesne architektury typu lakehouse zależą od częściowo ustrukturyzowanych i zagnieżdżonych danych. Natywny silnik wykonywania zapewnia teraz zoptymalizowaną obsługę:
| Typ danych | Description | Przykładowy przypadek użycia |
|---|---|---|
| Tablica | Uporządkowana kolekcja elementów | Tagi zdarzeń, kategorie produktów |
| Mapa | Pary klucz-wartość | Właściwości konfiguracji, metadane |
| Struct | Pola o nazwach i różnych typach | Zagnieżdżone rekordy klienta, obiekty adresowe |
Operacje obsługiwane w przypadku typów złożonych
Natywny silnik wykonawczy przyspiesza typowe operacje na złożonych typach danych:
- Funkcje tablicowe:
explode,array_contains,size,flatten,transform - Funkcje mapy:
map_keys, ,map_valueselement_at - Dostęp do struktury: dostęp do pól notacji kropkowej,
getField - Kombinacje zagnieżdżone: tablice struktur, mapy z wartościami tablicy
Przykład: Praca z tablicami i strukturami
from pyspark.sql.functions import explode, col, size
# Read data with nested schema
df = spark.table("events.telemetry")
# Operations on arrays - accelerated by native engine
result = (df
.filter(size(col("tags")) > 0)
.select(
col("event_id"),
col("metadata.source"), # Struct field access
explode(col("tags")).alias("tag")
)
)
result.show()
Przykład: Praca z mapami
from pyspark.sql.functions import map_keys, map_values, col
df = spark.table("config.settings")
# Map operations - accelerated by native engine
result = (df
.select(
col("setting_id"),
map_keys(col("properties")).alias("keys"),
map_values(col("properties")).alias("values")
)
)
result.show()
Wyniki wydajności
Wewnętrzne benchmarki wykazują znaczną poprawę w przypadku obciążeń wykorzystujących funkcje UDF języka Python i złożone typy danych:
| Typ obciążenia | Poprawa wydajności |
|---|---|
| Wektoryzowane funkcje Python definiowane przez użytkownika | Do 5,76 razy szybciej |
| Skalarne funkcje zdefiniowane przez użytkownika w języku Python | Maksymalnie 1,08 razy szybciej |
| TPC-DS end-to-end (z typami złożonymi) | Do 2,35 razy szybciej |
Te zyski wynikają z zmniejszonego obciążenia serializacji, ulepszonej wektoryzacji i kompleksowego wykonywania kolumnowego.
Korzyści z zaawansowanych wzorców lakehouse
Przyspieszanie złożonego typu danych jest szczególnie ważne w przypadku:
- Optymalizacja Z-ORDER: kolumny zagnieżdżone uczestniczą w zoptymalizowanym układzie danych.
- Liquid Clustering: kolumny o złożonym typie zyskują na klastrowaniu bez spłaszczania.
- Analiza częściowo ustrukturyzowana: ładunki JSON i strumienie zdarzeń pozostają zagnieżdżone na potrzeby naturalnego wykonywania zapytań.
- Architektury sterowane zdarzeniami: dane telemetryczne i dane IoT zachowują strukturę hierarchiczną.
Zamiast spłaszczać dane lub restrukturyzować potoki przetwarzania pod kątem wydajności, możesz w naturalny sposób pracować ze złożonymi schematami danych, zachowując wysoką wydajność działania.
Włączanie funkcji
Funkcje UDF języka Python, funkcje UDF języka Scala oraz obsługa złożonych typów danych są dostępne, gdy natywny mechanizm wykonywania jest włączony. Nie jest wymagana żadna dodatkowa konfiguracja.
Aby włączyć silnik natywnego wykonywania, zobacz sekcję Native execution engine for Fabric Data Engineering.
Wymagania wstępne
- Środowisko uruchomieniowe 1.3 (Apache Spark 3.5) lub Środowisko uruchomieniowe 2.0 (Apache Spark 4.0).
- Natywny aparat wykonawczy włączono na poziomie środowiska, notatnika lub definicji zadania Spark.
Ograniczenia
- Nie wszystkie biblioteki Python są obsługiwane w ścieżce wektoryzowanej. Biblioteki, które wymagają serializacji dowolnych obiektów Pythona, mogą nadal powodować uruchomienie mechanizmu awaryjnego.
- Głęboko zagnieżdżone typy złożone (na przykład tablice map struktur) mogą wrócić do aparatu JVM dla niektórych operacji.
- Tryb ANSI nie jest obsługiwany przez natywny aparat wykonywania.