729 words
4 minutes
[DE Design Pattern]05-3. Dynamic Joiner
3. Data Decoration: Wrapper
01. Pattern Overview
- Wrapper는 원본 레코드에 computed attributes
- 원본 값과 계산된 값을 분리하는 패턴.
- 디버깅을 위해 원본을 보존하면서도 다운스트림 소비자에게 가공된 값을 제공
소프트웨어 엔지니어링의 Decorator/Wrapper 패턴과 같은 아이디어입니다. 원본 객체를 감싸는 envelope을 추가하는 것입니다.
02. 4가지 Wrapper 구현 방식
- 구현 1: 원본은 flat, 계산값은 nested struct →
{col1, col2, ..., computed: {a, b}} - 구현 2: 원본은 nested struct, 계산값은 flat →
{a, b, raw_data: {col1, col2}} - 구현 3: 모두 같은 레벨에 flat →
{col1, col2, a, b} - 구현 4: 원본 테이블과 계산값 테이블을 분리 → 키로 JOIN
언제 어떤 구현을 고려하는가
- 구현 1, 2는 비정규화(읽기 빠름),
- 구현 4는 정규화(논리적 격리 가능, 원본 구조 변경 불필요).
03. 원본 flat + 계산값 nested
from pyspark.sql import functions as F
# 메타데이터 컨텍스트를 struct로 추가visits_wrapped = ( visits .withColumn("processing_context", F.struct( F.lit(job_version).alias("job_version"), F.lit(str(processing_time)).alias("processing_time") )) .withColumn("output", F.struct( F.col("value").cast("string").alias("raw_data"), F.col("processing_context") )))04. 계산값 flat + 원본 nested (SQL)
-- 계산값을 1급 컬럼으로, 원본은 struct로 보관SELECT CASE WHEN context.user.connected_since IS NULL THEN false ELSE true END AS is_connected, CONCAT_WS('-', page, context.referral) AS page_referral_key, STRUCT(visit_id, event_time, user_id, page, context) AS raw_dataFROM input_visits05. 구현 1의 SQL 변형: NAMED_STRUCT
-- 원본 컬럼 유지 + decorated struct 추가SELECT *, NAMED_STRUCT( 'is_connected', CASE WHEN context.user.connected_since IS NULL THEN false ELSE true END, 'page_referral_key', CONCAT_WS('-', page, context.referral)) AS decoratedFROM input_visitsNAMED_STRUCT는 key, value 쌍으로 struct를 생성하는 편의 함수입니다.
주요 트레이드오프
- Domain Split: 하나의 도메인(예: user) 속성이 raw와 computed 두 곳에 분산됨. 소비자가 두 위치를 알아야 함 → Silver 레이어까지만 적용하고, 최종 사용자 노출 레이어에서는 통합하는 것을 권장
- Size 영향: 계산값이 레코드의 일부가 되므로 전체 크기와 네트워크 트래픽 증가 → columnar 포맷의 projection pushdown으로 완화 (필요한 컬럼만 물리적으로 읽기)
Concept
- Wrapper 패턴 : 원본 레코드에 계산된 속성을 추가하면서 원본과 계산값을 명확히 분리하는 데코레이션 패턴
- Envelope : 원본 값과 계산된 값을 감싸는 상위 추상화 구조
- Denormalized Wrapper (구현 1, 2) : 원본과 계산값을 같은 레코드에 nested struct로 포함. 읽기 성능 유리
- Normalized Wrapper (구현 4) : 원본과 계산값을 별도 테이블로 분리. 논리적 격리와 원본 구조 보존에 유리
- NAMED_STRUCT : SQL에서 key-value 쌍으로 struct를 생성하는 함수
- Projection Pushdown : columnar 포맷에서 필요한 컬럼만 물리적으로 읽어 I/O를 최적화하는 기법
- Domain Split : Wrapper 적용 시 하나의 도메인 속성이 raw/computed 두 곳에 분산되는 문제
[DE Design Pattern]05-3. Dynamic Joiner
https://yjinheon.netlify.app/posts/02de/de-design-pattern/05_data_value/05-03-data-decoration-wrapper/