Partition Evolution
Partition Evolution
Partition evolution là khả năng thay đổi cách một table được partition mà không bắt buộc rewrite toàn bộ data cũ.
Đây là một điểm khác biệt lớn giữa Apache Iceberg và Hive-style table.
Vấn đề với Hive-style partitioning
Trong Hive, partition thường gắn chặt với directory layout:
/table/month=2024-01/file.parquet
/table/month=2024-02/file.parquetTable/partition được hiểu rất nhiều qua folder structure. Nếu muốn đổi từ partition theo tháng sang partition theo ngày:
month(date)
→ day(date)thì thường phải rewrite/reorganize lại data theo layout mới:
/table/day=2024-01-01/...
/table/day=2024-01-02/...Ở scale lớn, việc này rất đắt.
Iceberg tách partition ra metadata
Trong Iceberg, partition không còn chỉ là folder path. Mỗi data file được manifest/metadata mô tả rõ nó dùng partition spec nào.
Ví dụ file cũ:
file-a.parquet
partition_spec_id = 1
partition_value = month(date) = 2024-01Sau này đổi partition spec:
file-b.parquet
partition_spec_id = 2
partition_value = day(date) = 2024-01-15File cũ có thể giữ nguyên. Metadata biết:
file-a dùng spec 1: month(date)
file-b dùng spec 2: day(date)Khi query, engine tạo plan/prune theo từng spec tương ứng.
Ví dụ query
Giả sử query:
WHERE date > '2008-12-14'
AND date < '2009-01-14'Nếu data cũ partition theo tháng và data mới partition theo ngày, planner có thể chia kế hoạch:
vùng data cũ:
prune theo month partition
vùng data mới:
prune theo day partitionVì vậy đổi partitioning trong Iceberg thường là đổi metadata/spec mapping từ thời điểm đó trở đi, không bắt buộc rewrite toàn bộ data file cũ để table vẫn đúng.
Manifest file đang giúp gì ở đây?
Không phải chỉ copy metadata từ bên trong data file ra ngoài là xong. Iceberg có một metadata hierarchy riêng:
metadata file
→ snapshot list
→ manifest list
→ manifest files
→ data filesManifest file là file-level index/ledger của Iceberg. Nó có thể ghi các thông tin như:
file_path
file_format
partition_spec_id
partition_values
record_count
file_size
column lower_bounds
column upper_bounds
null_value_counts
nan_value_counts
value_counts
split_offsetsNhờ vậy planner biết file nào thuộc table/snapshot, file đó dùng partition spec nào, có stats gì, và có nên scan file đó không — trước khi phải đọc data file thật.
Manifest list là tầng snapshot-level phía trên manifest file. Nó liệt kê các manifest file trong một snapshot và có summary/statistics để prune cả manifest trước, rồi mới đọc manifest chi tiết.
Nhưng không phải mọi thay đổi đều miễn rewrite
Happy case: đổi grain hoặc transform
Ví dụ:
month(date) → day(date)
bucket(16, user_id) → bucket(64, user_id)Data cũ thường không cần rewrite để table vẫn đúng. File cũ giữ spec cũ, file mới dùng spec mới.
Đổi sang column khác
Ví dụ:
month(event_time) → bucket(user_id)Table vẫn có thể đúng mà không rewrite. Nhưng query pruning sẽ không đều trên toàn table.
Nếu workload mới chủ yếu filter theo user_id, data mới prune tốt hơn, còn data cũ partition theo event_time có thể scan rộng hơn. Khi đó rewrite data cũ là optimization đáng cân nhắc, không phải yêu cầu correctness.
Đổi type/bytes thật trong data file
Ví dụ:
event_time: string → timestamp
user_id: int → stringĐây không còn chỉ là partition evolution. Parquet/ORC/Avro file cũ vẫn chứa physical schema/value cũ. Nếu muốn bytes thật trong data file đổi sang type mới, thường phải:
read old files
cast/transform data
write new files
commit snapshot mớiTức là vẫn phải rewrite hoặc migration rõ ràng.
Ghi nhớ ngắn
Iceberg partition evolution:
đổi logical partition spec trong metadata
áp dụng cho data mới từ thời điểm đó trở đi
data cũ giữ spec cũ
planner hiểu nhiều spec cùng tồn tại
Không có nghĩa là:
mọi physical data file đều tự đổi type/layout
mọi workload mới đều tối ưu ngay trên data cũCâu chốt: Iceberg đưa “sự thật của table” ra metadata/manifest/snapshot. Nó tránh rewrite cho nhiều thay đổi ở logical/table-layout level, nhưng không có phép màu biến physical bytes cũ trong Parquet/ORC thành dữ liệu kiểu mới.