Uživatelsky definované funkce v jazyce Python, uživatelsky definované funkce v jazyce Scala a komplexní datové typy v nativním modulu pro vykonávání

Nativní prováděcí modul v Microsoft Fabric teď podporuje Python uživatelem definované funkce (UDF), UDF scala a komplexní datové typy (pole, mapy a struktury). Tyto funkce umožňují psát expressivní aplikace Spark bez obětování výkonu.

Podpora funkcí UDF v Pythonu

Python je jedním z nejoblíbenějších jazyků v oblasti přípravy dat a datových věd. V minulosti Python UDF zavedly ve Sparku významné režijní náklady z důvodu nákladů na serializaci mezi prostředím JVM a Python pracovními procesy. Nativní prováděcí modul minimalizuje tyto nákladné přechody a umožňuje rychlejší spouštění bez změn kódu.

Jak fungují Python UDF v nativním modulu pro provádění

V konvenčním prováděcím modelu Sparku Python provádění UDF zahrnuje:

  1. Převod dat z interního formátu Sparku
  2. Serializace a přenos do Python pracovních procesů.
  3. Spuštění funkce UDF v Pythonu.
  4. Serializace výsledků zpět do prostředí JVM.
  5. Spark obnoví provádění.

Tento přesun mezi běhovými prostředími způsobuje náklady na serializaci/deserializaci, neefektivní využití CPU a narušení pipeline sloupcového zpracování. Nativní prováděcí modul tuto režii snižuje optimalizací cesty přenosu dat a údržbou vektorizovaného zpracování, pokud je to možné.

Podporované typy uživatelsky definovaných funkcí v Pythonu

Nativní prováděcí modul podporuje:

  • Skalární UDF: Python funkce zpracovávané po jednotlivých řádcích, registrované pomocí udf().
  • Vektorizované UDF (Pandas): Funkce dekorované pomocí @pandas_udf, které pracují nad dávkami dat a využívají Apache Arrow k efektivnímu přenosu.

Uživatelsky definované vektorizované funkce přinášejí největší nárůst výkonu, protože přirozeně odpovídají sloupcovému modelu zpracování nativního spouštěcího modulu.

Příklad: Vektorizovaná Python UDF

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

Kromě povolení nativního prováděcího modulu se nevyžaduje žádná další konfigurace. Stávající funkce UDF v jazyce Python z toho automaticky těží.

Podpora uživatelsky definovaných funkcí Scala

Modul pro nativní spouštění také urychluje uživatelsky definované funkce (UDF) ve Scale. Protože UDF ve Scale běží nativně v prostředí JVM, může engine přenést podporované operace na vektorizovanou cestu vykonávání v jazyce C++ a zároveň zachovat efektivní vyhodnocování UDF ve Scale v rámci stejného runtime prostředí.

Příklad: UDF scala

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

Uživatelsky definované funkce ve Scale, které pracují s podporovanými datovými typy, se bez změn kódu zrychlí, když je povolen nativní spouštěcí modul.

Podpora komplexních datových typů

Moderní architektury lakehouse jsou založeny na semistrukturovaných a vnořených datech. Nativní prováděcí modul teď poskytuje optimalizovanou podporu pro:

Datový typ Description Příklad případu použití
Pole Uspořádaná kolekce prvků Značky událostí, kategorie produktů
Map Páry klíč-hodnota Vlastnosti konfigurace, metadata
Struct Pojmenovaná pole s různými typy Vnořené záznamy zákazníků, adresní objekty

Operace podporované pro komplexní typy

Nativní prováděcí modul zrychluje běžné operace u složitých datových typů:

  • Maticové funkce: explode, array_contains, size, flatten, transform
  • Mapové funkce: map_keys, map_valueselement_at
  • Přístup ke struktuře: Přístup k poli pomocí tečkové notace, getField
  • Vnořené kombinace: Matice struktur, mapy s hodnotami pole

Příklad: Práce s poli a 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()

Příklad: Práce s 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()

Výsledky výkonu

Interní srovnávací testy ukazují významná vylepšení napříč úlohami, které používají Python UDF a komplexní datové typy:

Typ úlohy Zlepšení výkonu
Vektorizované funkce UDF v Pythonu Až 5,76krát rychlejší
Skalární funkce UDF v jazyce Python Až 1,08x rychlejší
TPC-DS kompletní (se složitými typy) Až 2,35x rychlejší

Tato zlepšení vyplývají ze snížení režie spojené se serializací, lepší vektorizace a plně sloupcového zpracování.

Výhody pokročilých architektur lakehouse

Akcelerace komplexního datového typu je obzvláště důležitá pro:

  • Optimalizace Z-ORDER: Vnořené sloupce se účastní optimalizovaného rozložení dat.
  • Liquid clustering: Sloupce komplexních typů těží ze shlukování bez zploštění.
  • Částečně strukturovaná analýza: Datové části JSON a streamy událostí zůstávají vnořené pro přirozené dotazování.
  • Architektury řízené událostmi: Telemetrie a data IoT uchovávají svou hierarchickou strukturu.

Místo zplošťování dat nebo restrukturalizace pipeline kvůli výkonu pracujte přirozeně se složitými schématy při zachování vysoké efektivity vykonávání.

Povolení funkce

Python UDF, Scala UDF a komplexní podpora datových typů je dostupná, když je povolený nativní prováděcí modul. Není potřeba žádná další konfigurace.

Pokud chcete povolit nativní výpočetní stroj, přečtěte si téma Nativní výpočetní stroj pro Fabric Data Engineering.

Předpoklady

Omezení

  • V rámci vektorizované cesty nejsou podporovány všechny knihovny Python. Knihovny, které vyžadují serializaci libovolných objektů Pythonu, mohou stále spustit záložní mechanismus.
  • Hluboce vnořené komplexní typy (například pole map struktur) se můžou vrátit do modulu JVM pro určité operace.
  • Režim ANSI není u nativního prováděcího modulu podporovaný.