Python UDFs, Scala UDFs und komplexe Datentypen im systemeigenen Ausführungsmodul

Das systemeigene Ausführungsmodul in Microsoft Fabric unterstützt jetzt Python benutzerdefinierte Funktionen (UDFs), Scala UDFs und komplexe Datentypen (Arrays, Karten und Strukturen). Mit diesen Funktionen können Sie ausdrucksstarke Spark-Anwendungen schreiben, ohne die Leistung zu beeinträchtigen.

Python UDF-Unterstützung

Python ist eine der beliebtesten Sprachen in Data Engineering und Data Science. In der Vergangenheit führten Python-UDFs in Spark aufgrund der Serialisierungskosten zwischen der JVM und den Python-Arbeitsprozessen zu erheblichem Overhead. Das systemeigene Ausführungsmodul minimiert diese kostspieligen Übergänge und ermöglicht eine schnellere Ausführung ohne Codeänderungen.

Wie Python-UDFs in der nativen Ausführungs-Engine funktionieren

In einem herkömmlichen Spark-Ausführungsmodell umfasst die Ausführung von Python-UDFs:

  1. Konvertierung von Daten aus Sparks internem Format.
  2. Serialisierung und Übertragung an Python-Worker-Prozesse.
  3. Python UDF-Ausführung.
  4. Serialisierung der Ergebnisse zurück in das JVM.
  5. Spark setzt die Ausführung fort.

Diese Verschiebung zwischen Laufzeitumgebungen verursacht Kosten für die Serialisierung und Deserialisierung, CPU-Ineffizienz und fehlerhafte spaltenorientierte Ausführungspipelines. Das systemeigene Ausführungsmodul reduziert diesen Aufwand, indem er den Datenübertragungspfad optimiert und die vektorisierte Verarbeitung soweit möglich verwaltet.

Unterstützte Python UDF-Typen

Das systemeigene Ausführungsmodul unterstützt Folgendes:

  • Scalar UDFs: Zeilen-nach-Zeile-Python Funktionen, die bei udf() registriert sind.
  • Vektorisierte (Pandas-)UDFs: Funktionen, die mit @pandas_udf dekoriert sind und auf Daten-Batches arbeiten, wobei Apache Arrow für eine effiziente Übertragung verwendet wird.

Vektorisierte UDFs erzielen die größten Leistungssteigerungen, weil sie naturgemäß gut zum spaltenorientierten Verarbeitungsmodell der nativen Ausführungs-Engine passen.

Beispiel: vektorisierte 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()

Es ist keine zusätzliche Konfiguration erforderlich, die über die Aktivierung des systemeigenen Ausführungsmoduls hinausgeht. Vorhandene Python UDFs profitieren automatisch.

Scala UDF-Unterstützung

Das systemeigene Ausführungsmodul beschleunigt auch Scala UDFs. Da Scala-UDFs nativ in der JVM ausgeführt werden, kann die Engine unterstützte Vorgänge in den vektorisierten C++-Ausführungspfad auslagern, wobei die Auswertung von Scala-UDFs innerhalb derselben Laufzeit effizient bleibt.

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

Skala UDFs, die auf unterstützten Datentypen arbeiten, werden ohne Codeänderungen beschleunigt, wenn das systemeigene Ausführungsmodul aktiviert ist.

Unterstützung komplexer Datentypen

Moderne Lakehouse-Architekturen sind von halbstrukturierten und geschachtelten Daten abhängig. Das systemeigene Ausführungsmodul bietet jetzt eine optimierte Unterstützung für:

Datentyp Description Exemplarischer Anwendungsfall
Array Sortierte Auflistung von Elementen Ereignis-Tags, Produktkategorien
Landkarte Schlüsselwertpaare Konfigurationseigenschaften, Metadaten
Struktur Benannte Felder mit unterschiedlichen Typen Geschachtelte Kundendatensätze, Adressobjekte

Vorgänge, die für komplexe Typen unterstützt werden

Das systemeigene Ausführungsmodul beschleunigt allgemeine Vorgänge für komplexe Datentypen:

  • Arrayfunktionen: explode, array_contains, size, flatten, transform
  • Kartenfunktionen: map_keys, map_valueselement_at
  • Strukturzugriff: Feldzugriff mit Punktnotation, getField
  • Geschachtelte Kombinationen: Arrays von Strukturen, Zuordnungen mit Arraywerten

Beispiel: Arbeiten mit Arrays und Strukturen

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

Beispiel: Arbeiten mit Karten

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

Leistungsergebnisse

Internes Benchmarking zeigt erhebliche Verbesserungen für Workloads, die Python UDFs und komplexe Datentypen verwenden:

Workload-Typ Leistungsverbesserung
Vektorisierte Python UDFs Bis zu 5,76x schneller
Skalare Python-UDFs Bis zu 1,08x schneller
TPC-DS End-to-End (mit komplexen Typen) Bis zu 2,35x schneller

Diese Gewinne ergeben sich aus reduzierter Serialisierungsaufwand, verbesserter Vektorisierung und End-to-End-Spaltenausführung.

Vorteile für fortgeschrittene Lakehouse-Muster

Komplexe Datentypbeschleunigung ist besonders wichtig für:

  • Z-ORDER-Optimierung: Geschachtelte Spalten nehmen am optimierten Datenlayout teil.
  • Liquid Clustering: Komplexe Spalten profitieren vom Clustering ohne Flattening.
  • Halbstrukturierte Analysen: JSON-Nutzlasten und Ereignisdatenströme bleiben für natürliche Abfragen geschachtelt.
  • Ereignisgesteuerte Architekturen: Telemetrie- und IoT-Daten behalten ihre hierarchische Struktur bei.

Anstatt Daten zu verflachen oder Pipelines zur Leistungsoptimierung umzustrukturieren, arbeiten Sie auf natürliche Weise mit komplexen Schemata bei gleichzeitig hoher Ausführungseffizienz.

Die Funktion aktivieren

Python UDF-, Scala-UDF- und komplexe Datentypunterstützung ist verfügbar, wenn das systemeigene Ausführungsmodul aktiviert ist. Es ist keine zusätzliche Konfiguration erforderlich.

Informationen zum Aktivieren des nativen Ausführungsmoduls finden Sie unter natives Ausführungsmodul für Fabric Data Engineering.

Voraussetzungen

Einschränkungen

  • Nicht alle Python Bibliotheken werden innerhalb des vektorisierten Pfads unterstützt. Bibliotheken, die eine beliebige Python Objekt serialisierung erfordern, lösen möglicherweise weiterhin Fallback aus.
  • Tief verschachtelte komplexe Typen (z. B. Arrays von Maps von Strukturen) können für bestimmte Vorgänge auf die JVM-Engine ausweichen.
  • Der ANSI-Modus wird mit dem systemeigenen Ausführungsmodul nicht unterstützt.