Iceberg 테이블 스펙은 다음과 같은 목적과 기본 특징을 갖습니다:
대규모, 느리게 변하는 파일들의 모음을 분산 파일 시스템 또는 키-값 저장소에 테이블 형태로 관리하기 위해 설계됨. oai_citation:0‡Iceberg
포맷 버전(format version) 관리:
각 버전의 주요 추가 기능:
주요 목표 (Goals) 요약:
아래는 Iceberg Spec에서 자주 쓰이는 용어들 및 정의입니다:
Table
데이터 파일(data files) + 메타데이터(metadata files) + 스냅샷(snapshot) 등을 포함하는 단위. 테이블을 통해 분석 엔진이 일관된 뷰(view)를 가질 수 있도록 함. oai_citation:15‡Iceberg
Snapshot
테이블의 특정 시점 시 상태. 테이블의 모든 데이터 파일이 어떤 상태인지, 어떤 manifest가 포함되는지 등을 정의함. 읽기 시점(read) 조회, 변경 추적, 타임 트래블(time travel) 지원. oai_citation:16‡Iceberg
Manifest
스냅샷이 참조하는 데이터 파일들의 메타정보(파일 경로, 파티션 값, 통계 등)를 담은 파일. 여러 manifest 파일이 하나의 스냅샷을 구성함. oai_citation:17‡Iceberg
Manifest List
특정 스냅샷이 포함하는 모든 manifest 파일을 모아 놓은 목록(metadata 파일). 스냅샷 하나의 “목차(table of contents)” 역할. oai_citation:18‡Iceberg
Partition Spec
테이블 데이터를 어떻게 파티셔닝(partitioning)할지 정의하는 규격. 소스 컬럼(source column) + 변환(transform) 조합. 예: date(ts) 같은 변환. oai_citation:19‡Iceberg
Partition Tuple
각 데이터 파일(data file)의 파티션(patition tuple) 값들의 구조체(struct). 파티션 사양대로 변환된 값들을 저장. 동일 파일 내 모든 행(row)은 동일한 partition tuple 값을 가짐. oai_citation:20‡Iceberg
Snapshot Log (history table)
테이블의 현재 snapshot이 시간에 따라 어떻게 바뀌었는지 기록한 로그. 시간(timestamp)과 snapshot ID의 쌍(pair)들로 구성됨. 메타데이터(metadata)의 snapshot-log 필드에 저장됨. oai_citation:21‡Iceberg
스냅샷(snapshot)은 여러 개의 매니페스트 파일을 포함할 수 있고, 이 매니페스트들을 manifest list 라는 별도의 파일에서 관리한다.
| v1 | v2 | v3 | 필드명 (ID, Name) | 타입 | 설명 |
|---|---|---|---|---|---|
| required | required | required | 500 manifest_path | string | 매니페스트 파일 경로 |
| required | required | required | 501 manifest_length | long | 매니페스트 파일의 크기 (바이트 단위) |
| required | required | required | 502 partition_spec_id | int | 매니페스트가 참조하는 파티션 스펙 ID |
| required | required | required | 503 added_snapshot_id | long | 매니페스트가 추가된 스냅샷 ID |
| required | required | 515 sequence_number | long | 매니페스트가 테이블에 추가된 시점의 시퀀스 번호 | |
| required | required | 516 min_sequence_number | long | 매니페스트에 포함된 모든 라이브 데이터/삭제 파일의 최소 시퀀스 번호 | |
| required | required | required | 517 content | int | 매니페스트 유형: 0 = 데이터 파일, 1 = 삭제 파일 |
| optional | required | required | 504 added_files_count | int | ADDED 상태인 파일 개수 |
| optional | required | required | 505 existing_files_count | int | EXISTING 상태인 파일 개수 |
| optional | required | required | 506 deleted_files_count | int | DELETED 상태인 파일 개수 |
| optional | required | required | 512 added_rows_count | long | 추가된 파일들의 행 수 총합 |
| optional | required | required | 513 existing_rows_count | long | 기존 파일들의 행 수 총합 |
| optional | required | required | 514 deleted_rows_count | long | 삭제된 파일들의 행 수 총합 |
| optional | optional | optional | 507 partitions | list<field_summary> | 파티션 필드별 요약 정보 |
| optional | optional | optional | 519 key_metadata | binary | 암호화 키 메타데이터 |
| optional | 520 first_row_id | long | ADDED된 행들의 첫 _row_id 값 |
| v1 | v2 | 필드명 (ID, Name) | 타입 | 설명 |
|---|---|---|---|---|
| required | required | 509 contains_null | boolean | null 값을 가진 파티션 포함 여부 |
| optional | optional | 518 contains_nan | boolean | NaN 값을 가진 파티션 포함 여부 |
| optional | optional | 510 lower_bound | bytes | 파티션 필드의 최소(non-null, non-NaN) 값 |
| optional | optional | 511 upper_bound | bytes | 파티션 필드의 최대(non-null, non-NaN) 값 |
주의사항
- Lower/Upper bound는 Iceberg 직렬화 포맷(Appendix D) 규칙에 따라
bytes로 저장됨.- 부동소수점 값에서
-0.0과+0.0구분 필수.
Scan Planning은 쿼리할 때 어떤 데이터 파일(data file), 삭제(delete) 파일, 매니페스트(manifest) 등을 읽을지 결정하는 과정이에요.
DELETED인 데이터/삭제 항목(entry)은 실제 스캔에는 포함 안 됨. 쿼리가 들어왔을 때 Scan Planning은 다음 단계를 거쳐요:
Partition Predicate 변환
ts_day = day(ts) 파티션이 있고 쿼리가 ts > X라면, partition predicate은 ts_day >= day(X) 같은 식으로.Manifest List 단계 필터링
이 manifest 안에 파일 중에서 쿼리 조건에 맞을 가능성이 있는 파일 여부 판단Manifest 단계 필터링
Delete 파일 / Deletion Vector 적용 여부 결정
삭제 파일이나 deletion vector를 데이터 파일에 적용해야 할 경우 다음 조건들을 봐요:
Deletion Vector:
file_path == deletion vector의 referenced_data_file Position Delete 파일:
referenced_data_file (있다면) 및 file_path가 동일 Equality Delete 파일:
Iceberg v2부터는 row-level deletes(행 단위 삭제)가 지원돼요.
v3에서는 Deletion Vector(DV)가 추가되고, Position Delete는 deprecated 되었어요.
deletion-vector-v1)로 저장file_path: 데이터 파일의 경로content_offset: DV blob 시작 위치content_size_in_bytes: DV blob 전체 길이2147483546 file_path string # 삭제 대상 데이터 파일 경로
2147483545 pos long # 삭제된 행의 위치
2147483544 row struct<> # 삭제된 행 값 (선택)file_path → pos 순으로 정렬 (스캔 시 최적화)equality_ids: 삭제 조건으로 쓰이는 컬럼 ID들col IS NULL 조건처럼 동작id | category | name
---|-----------|------
1 | marsupial | Koala
2 | toy | Teddy
3 | NULL | Grizzly
4 | NULL | Polarcol=value)file+pos) → v3에서 deprecatedIceberg의 테이블 메타데이터는 JSON 파일로 저장되며,
각 변경(commit) 시마다 새로운 메타데이터 파일이 생성돼 원자적(atomic)으로 교체됨.
이 과정을 통해 테이블의 선형적 버전 히스토리를 보장하고, 동시에 커밋 충돌도 방지함.
| 버전 | 필드 | 설명 |
|---|---|---|
| v1/v2/v3 | format-version | 테이블 포맷 버전 (1 또는 2, 3). 지원 불가능한 버전일 경우 예외 발생 |
| v2/v3 | table-uuid | 테이블 UUID. 생성 시 부여되며, 변경 불가 |
| v1/v2/v3 | location | 테이블 기본 경로. 데이터 파일, manifest, 메타데이터 파일 저장 위치 |
| v2/v3 | last-sequence-number | 테이블 내 가장 큰 시퀀스 번호 (스냅샷 순서 추적용) |
| v1/v2/v3 | last-updated-ms | 마지막 업데이트 시각 (epoch ms) |
| v1/v2/v3 | last-column-id | 마지막으로 할당된 컬럼 ID |
| v1 (deprecated) | schema | 현재 스키마 (단일 값, v2부터는 schemas 사용) |
| v2/v3 | schemas | 모든 스키마 목록 (schema-id 포함) |
| v2/v3 | current-schema-id | 현재 사용 중인 스키마 ID |
| v1 (deprecated) | partition-spec | 현재 파티션 스펙 (단일 값) |
| v2/v3 | partition-specs | 모든 파티션 스펙 목록 |
| v2/v3 | default-spec-id | 기본 사용 파티션 스펙 ID |
| v2/v3 | last-partition-id | 마지막으로 할당된 파티션 필드 ID |
| v1/v2/v3 | properties | 테이블 속성 (예: commit.retry.num-retries) |
| v2/v3 | current-snapshot-id | 현재 스냅샷 ID (main branch의 최신) |
| v2/v3 | snapshots | 유효한 스냅샷 리스트 |
| v2/v3 | snapshot-log | 스냅샷 변경 이력 (timestamp + snapshot-id) |
| v2/v3 | metadata-log | 메타데이터 파일 변경 이력 |
| v2/v3 | sort-orders | 정렬 순서 목록 |
| v2/v3 | default-sort-order-id | 기본 정렬 순서 ID |
| v2/v3 | refs | 스냅샷 참조 (branches, tags) |
| v3 | statistics | 테이블 통계 파일 목록 (선택적) |
| v3 | partition-statistics | 파티션 통계 파일 목록 (선택적) |
| v3 | next-row-id | 다음에 할당될 row ID (Row Lineage용) |
| v3 | encryption-keys | 암호화 키 정보 |
snapshot-id: 스냅샷 IDstatistics-path: 통계 파일 경로file-size-in-bytes: 통계 파일 크기file-footer-size-in-bytes: Footer 크기blob-metadata: 통계 블롭 정보type: Blob 타입snapshot-id, sequence-number: 생성된 시점fields: 통계 계산에 사용된 필드 IDproperties: 추가 메타데이터partition: 파티션 값 튜플spec_id: 파티션 스펙 IDdata_record_count: 데이터 행 수data_file_count: 데이터 파일 개수total_data_file_size_in_bytes: 데이터 파일 총 크기position_delete_record_count: position delete 기록 수equality_delete_record_count: equality delete 기록 수dv_count: deletion vector 개수total_record_count: 삭제 적용 후 전체 레코드 수last_updated_at: 마지막 업데이트 시각last_updated_snapshot_id: 업데이트한 스냅샷 ID주의:
total_record_count는 equality delete나 v2 position delete가 있으면 정확히 알 수 없어서 NULL일 수 있음.
deletion vector만 있는 경우에는 계산 가능.
key-id: 키 식별자encrypted-key-metadata: 암호화된 키 메타데이터 (base64)encrypted-by-id: (선택) 키를 암호화한 상위 키 IDproperties: 추가 메타데이터next-row-id는 반드시 현재 테이블에서 사용된 모든 row-id보다 커야 함added_rows_count + existing_rows_count 합산해 next-row-id 갱신Iceberg는 원자적 커밋(atomic commit) 모델을 사용하기 때문에
동시에 두 개의 커밋이 발생하면 충돌(conflict)이 생길 수 있음.
이 경우, 하나의 커밋만 성공하고 나머지는 실패 → 실패한 커밋은 새로운 메타데이터 버전으로 재시도(retry) 가능.
Append 연산
Replace 연산
Delete 연산
WHERE timestamp < X)는 항상 재적용 가능Schema 업데이트 & Partition spec 변경
⚠️ v4에서 제거 예정.
객체 스토리지나 로컬 파일 시스템에서는 안전하지 않음.
<table-location>/metadata/v<V>.metadata.json<random-uuid>.metadata.json 파일로 저장v<V+1>.metadata.json으로 rename<V+1>-<random-uuid>.metadata.json 파일로 저장Iceberg는 row-level delete를 지원 (v2 이상).
Deletion vectors (DV) (v3)
deletion-vector-v1) 사용Position delete files (v2, deprecated in v3)
(file_path, pos)로 삭제된 행 지정file_path → pos 순으로 정렬Equality delete files
id = 3, category IS NULLcol IS NULL)Iceberg는 테이블의 스키마(schema)를 쉽고 안전하게 진화(evolution)시킬 수 있도록 설계되어 있어요.
스키마 변경은 대부분 메타데이터(metadata) 수준에서 이루어지고, 데이터 파일을 다시 쓰지 않아도 되는 경우가 많습니다. oai_citation:0‡Iceberg
Iceberg가 지원하는 스키마 변경 유형은 다음과 같고, nested 구조 (struct 내부)도 가능해요. oai_citation:1‡Iceberg
| 변경 타입 | 설명 |
|---|---|
| Add | 새 컬럼 추가 (또는 nested struct 안에 새 필드) oai_citation:2‡Iceberg |
| Drop | 기존 컬럼 또는 struct 안의 필드 제거 oai_citation:3‡Iceberg |
| Rename | 기존 컬럼/필드 이름 변경 (nested struct 포함) oai_citation:4‡Iceberg |
| Reorder | 컬럼/필드의 순서 변경 (예: struct 내, 또는 전체) oai_citation:5‡Iceberg |
| Type promotion / Update | 컬럼 타입 넓히기(widening) 등, struct 내부, map key/value, list element 등에서도 지원됨. 예: int → long, float → double, decimal 정밀도 늘리기 등. oai_citation:6‡AWS Documentation |
스키마 진화를 통해도 기존 데이터가 영향을 받지 않고, 예기치 않은 side-effect가 없도록 다음을 보장함: oai_citation:7‡Iceberg
day(ts), 나중엔 hour(ts) 같은 변경. 기존 데이터를 가진 매니페스트들은 기존 파티션 스펙으로 계속 유지됨. 새 쓰는 데이터(new writes)만 새 스펙 적용됨. oai_citation:12‡Iceberg 예: Amazon Athena에서는 아래와 같은 DDL 문으로 진화 가능함: oai_citation:14‡AWS Documentation
ALTER TABLE my_table ADD COLUMN new_col STRING;
ALTER TABLE my_table DROP COLUMN old_col;
ALTER TABLE my_table RENAME COLUMN colA TO colB;
ALTER TABLE my_table CHANGE COLUMN colX TYPE BIGINT; -- 타입 넓히기