題幹與適用場景
你負責廣告點擊預測的特徵平台。訓練樣本包含 entityid、labelts 與標籤,特徵值會隨事件更新;線上請求還要求低延遲讀取最新特徵。請說明離線訓練集如何做 point-in-time join,以及回填、延遲事件和線上服務如何處理。假設同一實體可能有多個特徵版本,特徵紀錄帶有計算時間,訓練標籤時間是事件發生時間。
面試官考察點
面試官要看你是否先定義「可取得時間」,再選擇儲存與連接方式。普通回答只會說離線倉庫加 Redis;強回答會明確寫出 featurets <= labelts 的不變量、同一實體取不晚於標籤時間的最新版本、沒有歷史值時回傳 null,並區分訓練時的歷史視圖與線上最新值。也要說明延遲資料會觸發哪些樣本重算,以及如何偵測訓練與服務的特徵偏移。
回答前需要澄清的問題
- 標籤時間代表業務事件發生時間還是標籤寫入時間?兩者不同會改變連接邊界。
- 預測允許使用事件發生後多久才到達的特徵?若只能使用嚴格即時可見資料,必須以計算完成或可取得時間建模。
- 訓練集要重現歷史版本,還是只需要最近窗口?前者要保留完整歷史,後者可以增加 lookback 限制。
- 線上讀取要的是請求時刻最新值,還是某個事件時間的值?後者需要時間戳查詢介面,不能只讀單一快取值。
30 秒回答框架
「我會先把每筆特徵紀錄保存實體鍵、特徵版本和可取得時間。建立訓練集時,對每個樣本按實體鍵做 as-of join,只取 featurets <= labelts 的最新紀錄;沒有符合條件的紀錄就保留 null。離線層保存歷史,線上層提供低延遲最新值,兩者由同一份特徵定義和物化流程連接。延遲事件進入重算佇列,重算受影響時間窗並版本化訓練集。最後監控 join 後 null 率、特徵新鮮度、線上線下分布和模型效果。」
分步驟深入解答
1. 先寫出時間不變量
對樣本 s=(e, tlabel) 與特徵歷史 He,選擇集合 C={h∈He | h.featurets ≤ tlabel},結果是 arg max featurets(C)。這條規則直接阻止未來特徵進入訓練。若業務語意要求「資料到達並可用」而不是「事件發生」,就要把 available_ts 納入條件。
2. 設計歷史表與連接
歷史表至少保存實體鍵、特徵名稱或版本、特徵值、featurets、availablets、來源批次和品質狀態。訓練樣本帶 label_ts。執行按實體鍵分割、按時間排序的 as-of join;同一時間有多筆紀錄時使用來源序號或寫入批次作為確定性 tie-breaker。精確時間等值連接會漏掉多數樣本,直接取最新值則會產生標籤洩漏。
3. 分離離線與線上路徑
離線儲存適合保留完整歷史並批次產生訓練集;線上鍵值儲存適合依實體快速讀取目前值。物化工作從統一特徵定義產生兩條路徑,記錄定義版本、輸入快照和物化水位。線上讀取允許短暫陳舊時可回傳最近值並附帶 feature_ts,由呼叫方決定是否降級;不能假設快取值與訓練時刻相同。
4. 處理延遲事件、回填與版本
延遲事件先寫入不可變原始層,再依受影響實體和時間窗排入重算。重算只替換對應訓練快照版本,不覆蓋已發佈模型使用的快照。回填工作要具備冪等性:輸入批次和定義版本組成工作鍵,重複執行不會產生重複歷史。若特徵定義改變,建立新版本並保留舊版本。
5. 驗證與監控
離線檢查抽樣樣本是否滿足 featurets <= labelts,並統計沒有歷史值的 null 率。線上監控讀取延遲、特徵年齡、物化延遲和錯誤率;對齊訓練與服務的特徵分布,找出缺失值處理或窗口長度不同造成的 skew。把樣本快照、定義版本和輸入水位寫入模型中繼資料,才能重現訓練。
6. 選擇替代方案的邊界
規模小且只有批次訓練時,可直接在倉庫中使用窗口排序和 as-of join,避免引入完整 feature store。需要毫秒級線上讀取、多人共用特徵和持續回填時,再採用離線歷史層、線上鍵值層、註冊表和物化管道。把所有特徵都即時計算會增加狀態、成本和一致性風險;只保留最新值又無法重建歷史訓練集。
高品質示範回答
我會把「當時可見」定義成硬性約束。每個實體的特徵歷史都帶 featurets;如果資料到達時間可能晚於事件時間,我還會保存 availablets。產生樣本 (entityid, labelts) 時做 as-of join,取同一實體中時間不晚於 labelts 的最新版本;若產品語意要求資料真正可用,就同時要求 availablets <= label_ts。這比直接 join 最新值安全,因為後者會把未來資訊洩漏進訓練集。
架構上,離線層保存完整歷史供訓練,線上層保存目前值供低延遲推論,兩層都由同一份定義和版本驅動。延遲事件先落原始層,再觸發受影響時間窗的冪等重算;已發佈模型使用的訓練快照不被覆蓋,重算結果建立新版本。驗證包括時間不變量抽樣、null 率、新鮮度、線上線下分布和模型效果。只有在沒有線上低延遲需求時,我才會省略線上層,保持批次方案簡單。
常見錯誤
- 錯誤表現:訓練集直接 join 特徵表最新一列 → 未來更新值進入歷史樣本,離線指標虛高 → 使用依實體和標籤時間的 as-of join。
- 錯誤表現:只保存事件時間,不保存可取得時間 → 事件雖早發生但當時尚未到達,訓練仍使用不可見資料 → 有延遲或批次延遲時記錄
available_ts。 - 錯誤表現:回填直接覆蓋既有特徵歷史 → 已訓練模型無法重現,稽核失去依據 → 以輸入批次和定義版本建立不可變快照。
- 錯誤表現:線上和離線各寫一套轉換程式 → null 處理或窗口邊界漂移,產生 training-serving skew → 共用定義或用同一組黃金樣本做一致性測試。
追問及應對
如果特徵事件在標籤之後到達,但事件時間早於標籤時間,可以使用嗎?
不能只看事件時間。若線上在標籤時刻看不到該事件,就要求 availablets <= labelts;否則訓練集會模擬線上不可能擁有的資訊。可以同時保存事件時間和可取得時間,依業務承諾選擇嚴格或寬鬆規則。
線上需要查詢過去某一時刻的特徵,目前值快取還足夠嗎?
不夠。目前值快取只能回答「現在最新值」,無法回答歷史時刻。應提供帶時間戳的歷史查詢或從離線層產生時間點快照;若延遲預算不允許線上歷史查詢,就在請求鏈路提前物化所需版本。
延遲事件持續到達,如何避免重算成本失控?
依實體、時間窗和特徵版本合併重算請求,設定最大回看窗口和優先級。超過窗口的事件進入人工或離線批次,並記錄哪些模型版本未重算。用受影響樣本數、重算耗時和佇列年齡監控成本,不要無限追趕所有歷史。