題幹與適用場景
請為 Iceberg 表設計向量檢索擴充。資料檔案繼續存放列資料,查詢引擎按快照讀取;向量索引放在 Puffin sidecar 檔案中,索引元資料透過快照關聯。目標是支援近似最近鄰查詢,同時不破壞 Iceberg 的快照隔離、時間旅行與資料檔案維護。
可以先假設每天有批次追加和小批次更新,查詢允許近似結果但必須標示索引版本。讀者要區分 Apache Puffin 的檔案格式能力與研究論文提出的具體 ANN 組織方式,不能把實驗設計描述成 Iceberg 標準行為。
面試官考察點
快照與索引的一致性
高品質回答會說明資料快照、Puffin blob 與索引元資料必須透過一次可見的提交繫結;只上傳索引檔案不代表查詢引擎可以使用它。
近似搜尋與檔案裁剪
候選人應解釋向量索引負責候選召回,最終距離計算仍要讀取可見資料列,並處理索引缺失、過期和召回不足。
增量維護與刪除語意
需要涵蓋追加、更新、刪除、合併與 compaction 後如何重建或合併索引,而不只是討論一次離線建索引。
計算儲存解耦的營運性
要說清楚索引放在物件儲存、協調器如何選擇分片、如何限制 Puffin 垃圾,以及如何監測 freshness 與回退率。
回答前需要釐清的問題
- embedding 維度、距離函數、查詢延遲與可接受召回率是多少?
- 查詢必須讀取最新快照,還是允許固定時間視窗內的索引落後?
- 更新與刪除是追加式 CDC、Iceberg equality delete,還是會重寫資料檔案?
- 近似索引可由一個引擎生成,還是要讓 Spark、Flink、Trino 等共用?
- 索引是否包含敏感向量,存取控制與加密由誰負責?
- 時間旅行查詢需要重用歷史索引,還是只保證目前快照有索引?
30 秒回答框架
「我把 Iceberg 資料檔案、Puffin 索引 blob 與快照元資料分開,但只在一次提交中發布同一 snapshot_id 的繫結。查詢先選擇可見快照,讀取其索引參照,再做 ANN 候選召回,最後回表驗證列版本與距離;索引缺失或落後時回退到分割區/檔案掃描並標示品質。追加可以產生增量索引,更新刪除先用 tombstone 或 delta 層過濾,背景在 compaction 後重建基線。所有索引任務使用快照樂觀並行提交,監測索引 freshness、召回抽樣、回退率與 Puffin 垃圾回收。」
分步驟深入解答
第一步:估算資料與索引邊界
以 10 億筆向量、768 維 float32 為例,原始向量約為 10 億乘 768 乘 4 位元組,約 3 TB,尚未計算欄式壓縮與索引開銷。這個估算說明索引不能塞入單一 manifest 或協調器記憶體,必須分片、放物件儲存,並按查詢分割區載入。
第二步:定義 Puffin 與快照繫結
Puffin 檔案保存表 manifest 無法直接承載的索引或統計 blob,每個 blob 帶類型、欄位、分割區或資料檔案參照等元資料。索引建置器產生 Puffin 檔案後,提交一個新的 Iceberg snapshot,在 snapshot summary 寫入索引位置、版本與涵蓋範圍。查詢器只接受與目前 snapshot 可見性同時成立的參照。
snapshot S42
data files: D100, D101
summary:
vector.index.version = v7
vector.index.puffin = s3://table/metadata/puffin-v7
vector.index.covers = D100,D101第三步:設計查詢路徑
查詢先解析時間旅行或目前分支得到 snapshot S,再按涵蓋範圍選擇 Puffin blob。ANN 圖或分片索引回傳候選列識別與近似距離;引擎回讀對應資料檔案,檢查列是否仍在 S、過濾權限與業務條件,並用真實向量重算最終距離。回傳結果必須帶 snapshotid 與 indexversion,避免呼叫方誤解資料新鮮度。
第四步:處理追加、更新與刪除
追加資料可以先寫增量 Puffin 索引,並在同一 snapshot 提交中宣告涵蓋檔案。更新或刪除在索引重建前透過 equality delete、position delete 或 delta tombstone 過濾舊候選;查詢不能回傳已刪除列。背景把多個增量索引合併成新基線,完成後再提交新的 snapshot 繫結,失敗時保留舊索引與回退路徑。
第五步:並行提交與 compaction
索引任務讀取基線 snapshot S42,產生 v7;若資料提交已把表推進到 S43,索引提交必須用樂觀並行檢查決定重試、合併增量或放棄。compaction 改變資料檔案路徑時,舊索引不能繼續聲稱涵蓋新檔案;新 Puffin blob 要繫結重寫後的檔案集合,舊 blob 進入參照追蹤與寬限期回收。
第六步:營運、隔離與回退
物件儲存保存 Puffin,協調器按分割區或檔案集合調度建置,查詢節點按熱度快取小型路由或質心結構。索引缺失、版本不相容、權限失敗或召回抽樣低於門檻時,回退到檔案掃描或只回傳已驗證候選,並記錄原因。指標包括索引 freshness、建置落後、查詢 p95、召回抽樣、Puffin 位元組數、回退率與未參照 blob 數。
高品質示範回答
「我會把向量欄位留在 Iceberg 資料檔案,把 ANN 結構寫入 Puffin,並把參照作為 snapshot 的一部分發布。以 10 億筆、768 維 float32 向量為假設,原始向量約 3 TB,所以索引必須分片儲存,不能讓協調器持有全量資料。
建置器讀取 S42,產生涵蓋 D100、D101 的 Puffin v7,然後用樂觀並行提交新的 snapshot。查詢根據時間旅行選擇快照,只讀取該快照宣告涵蓋範圍的索引,取得候選列後回表驗證可見性、權限與真實距離。索引落後時,追加資料走增量索引,更新刪除由 delete 檔案或 tombstone 過濾,背景 compaction 後重建基線。
如果提交已推進到 S43,v7 不能直接標記為最新,任務要重試或明確標記 stale。索引缺失、格式不相容或召回低於門檻時回退掃描,並把 snapshotid、indexversion、回退原因寫入查詢指標。舊 Puffin 檔案只在所有歷史快照和分支都不再參照後回收。」
常見錯誤
- 把 Puffin 當作新的主表格式 → 查詢無法證明索引對應哪一版資料 → 用 snapshot 綁定索引涵蓋範圍。
- 上傳索引後立即可讀 → 資料檔案與索引可能不屬於同一快照 → 透過一次樂觀並行提交發布參照。
- 只回傳 ANN 候選 → 刪除、權限或距離誤差會洩露錯誤結果 → 回表驗證可見性並重算最終距離。
- 更新後繼續使用舊圖 → 已刪除列可能被召回 → 用 delete 層過濾,背景合併增量並重建基線。
- compaction 後沿用舊檔案路徑 → 索引聲稱涵蓋不存在的資料檔案 → 新檔案集合生成新 blob 與新 snapshot。
- 把研究論文的圖結構當成 Puffin 標準 → 跨引擎互通失敗 → 讓 Puffin 負責承載與元資料,圖演算法作為可替換實作。
- 索引缺失就讓查詢失敗 → 新分割區上線期間服務不可用 → 回退掃描並記錄 freshness 與回退原因。
- 沒有參照計數就刪除 Puffin → 時間旅行或分支讀取損壞 → 等待所有快照、分支與寬限期解除參照。
追問及應對
追問一:如何保證時間旅行查詢拿到正確索引?
索引參照必須寫在對應 snapshot 的 summary,並宣告涵蓋檔案與版本。查詢先固定 snapshot,再拒絕只涵蓋後續或不同檔案集合的 blob;缺失時回退掃描,不偷偷使用目前索引。
追問二:更新量很大,增量索引會不會無限增長?
為每個分割區或檔案集合設定增量層上限,超過門檻就安排合併重建。合併完成後以新 snapshot 原子切換,舊增量保留到歷史快照不再參照。
追問三:兩個引擎產生的 ANN 索引可以互換嗎?
只有當 blob 類型、距離函數、向量編碼、列識別與版本協定都相容才可以。Puffin 提供承載與元資料邊界,具體圖結構需要能力宣告;否則查詢器應忽略該 blob 並回退。
追問四:如何驗證召回率而不掃描全表?
從線上查詢抽樣一小批,在離線視窗用精確暴力或高品質基線計算近似真值,按分割區、向量版本與距離函數比較 recall@k。抽樣低於門檻時把索引標為 stale,而不是只看 p95 延遲。
追問五:Puffin 檔案損壞或物件儲存暫時不可用怎麼辦?
校驗 blob 校驗和與元資料,失敗時從副本重試;超時後回退到檔案掃描或拒絕近似查詢並回傳明確狀態。建置任務不應把損壞 blob 發布到新的 snapshot。
來源一:Apache Puffin 規範
Puffin 規範定義用於保存 Iceberg manifest 無法直接承載的索引與統計資訊的檔案格式,以及 blob 元資料和資料檔案參照。本文據此區分 sidecar 承載、涵蓋範圍與主表快照。
來源二:Puffin 向量索引研究論文
2026 年論文提出把近似最近鄰結構附加到 Iceberg snapshot,並討論計算與儲存解耦、快照級索引管理與大規模向量場景。本文將它作為可替換研究實作,補充刪除、回退與並行提交邊界。
來源三:資料工程面試準備指南
公開資料工程面試指南強調 SQL、資料建模、管道、批流處理與可靠性。本文把這些評估面映射到快照一致性、索引維護、儲存分片、驗證與故障回退。