이제 Microsoft Fabric 네이티브 실행 엔진은 UDF(사용자 정의 함수), Scala UDF 및 복잡한 데이터 형식(배열, 맵 및 구조체)Python 지원합니다. 이러한 기능을 사용하면 성능을 저하시키지 않고 표현형 Spark 애플리케이션을 작성할 수 있습니다.
Python UDF 지원
Python 데이터 엔지니어링 및 데이터 과학에서 가장 인기 있는 언어 중 하나입니다. 지금까지 Python UDF는 JVM과 Python 작업자 프로세스 간의 직렬화 비용으로 인해 Spark에 상당한 오버헤드를 발생시켰습니다. 네이티브 실행 엔진은 이러한 비용이 많이 드는 전환을 최소화하여 코드 변경 없이 더 빠르게 실행할 수 있도록 합니다.
Python UDF가 네이티브 실행 엔진에서 작동하는 방법
기존 Spark 실행 모델에서 Python UDF 실행에는 다음이 포함됩니다.
- Spark의 내부 형식에서 데이터 변환
- Python 작업자 프로세스로의 직렬화 및 전송
- Python UDF 실행
- 결과를 JVM으로 다시 serialization합니다.
- Spark가 실행을 다시 시작합니다.
이 런타임 간 이동은 직렬화/역직렬화 비용, CPU 비효율성, 그리고 손상된 컬럼형 실행 파이프라인을 초래합니다. 네이티브 실행 엔진은 데이터 전송 경로를 최적화하고 가능한 경우 벡터화된 처리를 유지 관리하여 이 오버헤드를 줄입니다.
지원되는 Python UDF 형식
네이티브 실행 엔진은 다음을 지원합니다.
-
Scalar UDF:
udf()등록된 행별 Python 함수입니다. -
벡터화된(Pandas) UDF: 효율적인 전송을 위해 Apache Arrow를 사용하여 데이터 일괄 처리에서 작동하는 데코레이팅된
@pandas_udf함수입니다.
벡터화된 UDF는 네이티브 실행 엔진의 열 형식 처리 모델에 자연스럽게 맞춰지므로 가장 큰 성능 향상을 보입니다.
예: 벡터화된 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()
네이티브 실행 엔진을 사용하도록 설정하는 것 외에는 추가 구성이 필요하지 않습니다. 기존 Python UDF는 자동으로 혜택을 누릴 수 있습니다.
Scala UDF 지원
네이티브 실행 엔진은 Scala UDF도 가속화합니다. Scala UDF는 JVM에서 기본적으로 실행되므로 엔진은 지원되는 작업을 벡터화된 C++ 실행 경로로 오프로드하면서 Scala UDF 평가를 동일한 런타임 내에 효율적으로 유지할 수 있습니다.
예: 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()
지원되는 데이터 형식에서 작동하는 Scala UDF는 네이티브 실행 엔진을 사용할 때 코드 변경 없이 가속화됩니다.
복잡한 데이터 형식 지원
최신 레이크하우스 아키텍처는 반구조적 데이터와 중첩된 데이터에 따라 달라집니다. 네이티브 실행 엔진은 이제 다음에 대해 최적화된 지원을 제공합니다.
| 데이터 형식 | Description | 예제 사용 사례 |
|---|---|---|
| 배열 | 정렬된 요소 컬렉션 | 이벤트 태그, 제품 범주 |
| 지도 | 키-값 쌍 | 구성 속성, 메타데이터 |
| 구조체 | 형식이 다른 명명된 필드 | 중첩된 고객 레코드, 주소 개체 |
복합 형식에서 지원되는 연산
네이티브 실행 엔진은 복잡한 데이터 형식에 대한 일반적인 작업을 가속화합니다.
- 배열 함수:
explode,array_contains,size,flattentransform - Map 함수:
map_keys,map_valueselement_at - 구조체 액세스: 점 표기법 필드 접근,
getField - 중첩된 조합: 구조체 배열, 배열 값이 있는 맵
예: 배열 및 구조체 작업
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()
예제: 맵 작업
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()
성능 결과
내부 벤치마킹은 Python UDF 및 복잡한 데이터 형식을 사용하는 워크로드에서 크게 향상된 기능을 보여줍니다.
| 워크로드 유형 | 성능 향상 |
|---|---|
| 벡터화된 Python UDF | 최대 5.76배 더 빠름 |
| 스칼라 Python UDF들 | 최대 1.08배 더 빠릅니다. |
| TPC-DS 엔드투엔드(복합 타입 포함) | 최대 2.35배 더 빠름 |
이러한 성능 향상은 직렬화 오버헤드 감소, 벡터화 개선, 그리고 엔드 투 엔드 컬럼형 실행의 결과입니다.
고급 레이크하우스 패턴의 이점
복잡한 데이터 형식 가속은 다음 경우에 특히 중요합니다.
- Z-ORDER 최적화: 중첩 열은 최적화된 데이터 레이아웃에 참여합니다.
- 액체 클러스터링: 복합 형식 열은 평면화하지 않고 클러스터링의 이점을 누릴 수 있습니다.
- 반구조화된 분석: JSON 페이로드 및 이벤트 스트림은 자연 쿼리를 위해 중첩된 상태로 유지됩니다.
- 이벤트 기반 아키텍처: 원격 분석 및 IoT 데이터는 계층 구조를 유지합니다.
성능을 위해 데이터를 평면화하거나 파이프라인을 재구성하는 대신, 높은 실행 효율성을 유지하면서 복잡한 스키마를 자연스럽게 사용합니다.
기능을 활성화하세요.
Python UDF, Scala UDF 및 복잡한 데이터 형식 지원은 네이티브 실행 엔진을 사용하는 경우 사용할 수 있습니다. 추가 구성은 필요하지 않습니다.
네이티브 실행 엔진을 사용하도록 설정하려면 패브릭 데이터 엔지니어링에 대한 네이티브 실행 엔진을 참조하세요.
사전 요구 사항
- 런타임 1.3(Apache Spark 3.5) 또는 런타임 2.0(Apache Spark 4.0).
- 환경, Notebook 또는 Spark 작업 정의 수준에서 사용하도록 설정된 네이티브 실행 엔진입니다.
Limitations
- 모든 Python 라이브러리가 벡터화된 경로 내에서 지원되는 것은 아닙니다. 임의의 Python 객체 직렬화가 필요한 라이브러리는 여전히 폴백을 유발할 수 있습니다.
- 깊이 중첩된 복합 형식(예: 구조체 맵의 배열)은 특정 작업을 위해 JVM 엔진으로 대체될 수 있습니다.
- ANSI 모드는 네이티브 실행 엔진에서 지원되지 않습니다.