Catalyst 타입 시스템: untyped DataFrame vs typed Dataset
Spark: The Definitive Guide (Excerpts, Databricks Preview, 2017) — Chapters 2-6 — Bill Chambers & Matei Zaharia Chapter 4: Overview of Structured Spark Types - Catalyst, DataFrame/Dataset 타입 차이, Columns, Rows 절 (PDF pp.45-47)
이 모듈을 다 읽으면
- Spark가 자체 Catalyst 타입 시스템을 유지하는 이유와 그 이점을 설명할 수 있다
- untyped DataFrame과 typed Dataset의 차이(런타임 검사 vs 컴파일타임 검사)를 구분해 설명할 수 있다
- Row 타입이 왜 필요한지, DataFrame과 Row의 관계를 설명할 수 있다
Spark는 Catalyst라는 내부 엔진을 통해 언어와 무관한 자체 타입 시스템을 유지하며, 이 덕분에 다양한 실행 최적화가 가능해진다. DataFrame(untyped)은 런타임에만 스키마 타입을 검사하는 반면 Dataset(typed)은 컴파일 타임에 검사하며 JVM 언어에서만 쓸 수 있다. Scala의 DataFrame은 사실 Dataset[Row]이고, Row는 GC·객체 생성 비용을 피하기 위한 Spark의 내부 최적화 포맷이다.
Catalyst 엔진과 Spark 자체 타입 시스템
Spark는 사실상 하나의 독립된 프로그래밍 언어처럼 동작한다. 내부적으로는 Catalyst라는 엔진이 쿼리를 계획하고 처리하는 전 과정에서 자체 타입 정보를 유지하는데, 얼핏 과해 보일 수 있는 이 설계 덕분에 다양한 실행 최적화가 가능해진다.
Spark 타입은 Scala, Java, Python, SQL, R 등 각 언어 API에 대응되는 별도의 타입 대응표를 갖는다. 즉 Python이나 R에서 Structured API를 쓰더라도 실제 연산 대부분은 Python/R 타입이 아니라 Spark 타입에서 이뤄진다. 예를 들어 `df.select(df["number"] + 10)` 같은 코드는 겉보기엔 Python/Scala의 덧셈 같지만, 실제로는 사용자 언어의 표현식이 Spark 내부(Catalyst) 표현으로 변환되어 순수하게 Spark 타입 위에서 연산이 수행되는 것이다.
핵심 포인트
- Catalyst 엔진이 쿼리 계획·처리 전 과정에서 Spark 자체 타입 정보를 유지해 다양한 실행 최적화를 가능하게 한다
- DataFrame 연산은 사용자 언어(Python/Scala 등)의 연산이 아니라 Catalyst 내부 표현으로 변환되어 수행된다
untyped DataFrame vs typed Dataset
Structured API 안에는 다시 "untyped"인 DataFrame과 "typed"인 Dataset이라는 두 갈래가 있다. DataFrame을 untyped라고 부르는 것은 다소 오해의 소지가 있는 표현이다 - DataFrame도 타입 정보를 갖고 있지만, Spark가 그 타입을 전적으로 관리하며 스키마와의 일치 여부를 런타임에만 검사한다는 뜻이다.
반면 Dataset은 타입이 명세와 맞는지를 컴파일 타임에 검사한다. Dataset은 JVM 기반 언어인 Scala와 Java에서만 사용할 수 있으며, 타입은 Scala의 case class나 Java의 bean으로 지정한다.
핵심 포인트
- DataFrame(untyped)은 스키마 타입 일치 여부를 런타임에만 검사한다
- Dataset(typed)은 컴파일 타임에 타입을 검사하며 Scala/Java 등 JVM 언어에서만 사용 가능하고, case class나 Java bean으로 타입을 지정한다
Row 타입과 언어별 차이
Scala 관점에서 DataFrame은 사실 Row 타입의 Dataset, 즉 Dataset[Row]이다. Row는 Spark가 계산을 위해 최적화해 둔 인메모리 포맷을 나타내는 내부 표현이다. 이 포맷 덕분에 JVM 객체를 직접 다룰 때 발생하는 높은 가비지 컬렉션·객체 생성 비용을 치르지 않고도 효율적인 연산이 가능해진다.
Python에는 Dataset이라는 개념 자체가 존재하지 않고, 구조화된 데이터는 전부 DataFrame으로 다뤄진다. 한편 컬럼(Column)은 정수·문자열 같은 단순 타입뿐 아니라 배열·맵 같은 복합 타입, 또는 null 값도 나타낼 수 있으며 Spark가 이 타입 정보를 전부 추적한다.
핵심 포인트
- Scala에서 DataFrame은 Dataset[Row]이며, Row는 GC·객체 생성 비용을 피하는 Spark 내부 최적화 포맷이다
- Python에는 Dataset이 없고 모든 구조화 데이터는 DataFrame으로 다뤄진다
- 컬럼은 단순 타입·복합 타입(array, map)·null 값을 모두 표현할 수 있다