Parquet 內容定義分塊以提升資料去重效率

Parquet 內容定義分塊(CDC)現已在 PyArrow 與 Pandas 中提供,使得在類似 Hugging Face 的 Xet 儲存層等內容可尋址儲存系統上,能有效去除 Parquet 檔案的重複資料。僅上傳或下載變更的資料分塊,CDC 可大幅降低大規模資料集的傳輸與儲存成本。

使用 Xet 與 CDC 優化 Parquet 儲存

Hugging Face 目前托管超過 4 PB 的 Parquet 檔案。為了優化這些儲存,Hugging Face 推出了 Xet 儲存層,該層使用內容定義分塊來去除資料分塊的重複,並提升傳輸速度。

雖然 Xet 與格式無關,但標準的 Apache Parquet 版面配置與欄位分塊壓縮,即使在資料僅有微小變動時,也常會產生完全不同的位元組層級表示。這會導致去重效果不佳。Parquet CDC 透過在序列化或壓縮之前,根據欄位的邏輯內容將其切分為資料頁(data pages),從而減少相似資料集之間的位元組差異,解決了此問題。

實作與使用方式

使用者只要在 PyArrow 或 Pandas 中傳入 use_content_defined_chunking=True 參數,即可啟用 Parquet CDC:

PyArrow:

import pyarrow.parquet as pq
pq.write_table(table, "hf://datasets/{user}/{repo}/path.parquet", use_content_defined_chunking=True)

Pandas:

import pandas as pd
df.to_parquet("hf://datasets/{user}/{repo}/path.parquet", use_content_defined_chunking=True)

常見資料工作流程的效能表現

在結合 Xet 儲存層使用時,Parquet CDC 在多種常見資料工程情境下提供顯著的去重效益:

完全相同的副本與欄位修改

  • 完全相同的副本: 將相同檔案上傳至不同的倉庫會即時完成,因系統已辨識出內容已存在。
  • 新增/移除欄位: 僅傳輸新欄位與更新的 footer 中繼資料。例如,為資料集新增欄位時,對於一個 96.6MB 的檔案,只上傳了 575kB 的新資料。
  • 變更欄位類型: 將欄位轉型(例如 int64 轉為 int32)只需上傳被修改的欄位與更新的中繼資料。

行級操作

  • 追加行: 將新行串接至表格時,只傳輸新資料,因原始行在儲存層中保持不變。
  • 插入與刪除行: 在原始 Parquet 中,插入或刪除一行會導致所有後續行位移,改變所有後續資料頁的位元組表示,必須完整重新上傳。Parquet CDC 透過基於內容的分塊避免此問題,使系統僅辨識並傳輸特定變更。在測試中,向資料集插入行時,傳輸量從近 90MB(原始)降至 6MB(CDC)。

結構與分片變更

  • Row-Group 大小: 調整 row-group 大小(例如從 1M 行改為 128k 或 256k)通常會在資料頁之間移動值。即使有此類結構變更,Parquet CDC 仍能保持去重效率。
  • 檔案層級切分: 當資料集被切分為不同數量的分片(例如 5、10 或 20 個分片)時,結合 Xet 的 Parquet CDC 可確保整體上傳大小僅比原始資料集稍大,與分片邊界無關。

限制與考量

由於 Parquet CDC 在資料頁(欄位分塊)層級運作,其效能取決於變更的選擇性。若過濾或修改影響到資料集中大多數的資料頁,則會有更多分塊被視為唯一,導致去重比例下降。

Sources