PySpark 面試問題
作者 Aaron Cao · 更新於

PySpark 面試的重點集中在執行模型和效能上。你需要能解釋轉換(transformation)與動作(action)的差異、判斷哪些操作會觸發 shuffle、知道何時該選擇廣播 join、診斷資料傾斜、說明快取的取捨,並描述如何調校一個記憶體用盡的作業。
面試官會怎麼問執行模型?
就算你能寫出跑得動的 PySpark 程式碼,這類問題還是可能讓你卡住,因為它們問的是引擎在做什麼,而不是你的程式碼寫了什麼。面試官喜歡用這類問題開場,正是因為它能區分出真正調校過作業的人,和只是跑過一次的人。這一節整理執行模型相關的問題,以及一個完整答案該包含哪些重點。
- 轉換(transformation)和動作(action)有什麼差別? 轉換操作會建立執行計畫並惰性回傳一個新的 DataFrame;而
count、collect這類動作,或是一次寫入操作,才會觸發真正的執行。在動作要求結果之前,什麼都不會被計算。 - 惰性求值有什麼用? 最佳化器能在真正執行之前看到完整的操作鏈,因此可以重新排列篩選條件、裁掉不需要的欄位,並合併多個步驟。
- 窄依賴轉換還是寬依賴轉換? 像
filter、select這樣的窄依賴操作,每個輸出分區只依賴一個輸入分區。而groupBy、join、distinct這類寬依賴操作會在分區之間重新分配資料,也就是 shuffle。 - 什麼是 shuffle,為什麼它很重要? 資料會跨網路傳輸並落到磁碟,形成一個 stage 邊界。這通常是一個作業裡開銷最大的環節。
- 解釋一下 job、stage 和 task。 一個動作會啟動一個 job,shuffle 邊界會把它拆成多個 stage,每個 stage 會為每個分區執行一個 task。
- RDD、DataFrame 還是 Dataset? 優先使用 DataFrame,因為它能享有 Catalyst 最佳化器和欄式執行的優化。RDD 仍保留用於底層控制。有型別的 Dataset 是 JVM 層面的概念,所以在 Python 裡,誠實的答案是它並不適用。
該用 shuffle 和 stage 這些字眼的時候就要用出來。面試官會把它們當成一個捷徑,用來判斷你有沒有真的看過 Spark UI。
效能相關的問題該怎麼回答?
大多數資深 PySpark 面試本質上都是效能面試。這些問題通常以情境的形式出現,而不是要你背定義。
- 一個 join 很慢,你會先檢查什麼? 先看兩邊資料的大小。如果有一側能放進 executor 記憶體,就把它廣播出去,完全跳過 shuffle。否則要先看分區和資料傾斜的狀況,再考慮叢集規模。
- 什麼是資料傾斜,該怎麼解決? 少數幾個 key 佔了大部分資料列,導致一個 task 在其他任務都結束後還在跑。解法包括為熱門 key 加鹽、把較小的一側廣播出去,或是過濾掉那些會被雜湊到同一分區的空值。診斷訊號是 Spark UI 裡 task 執行時間的分布差異。
- 什麼時候該用 cache 或 persist? 當一個 DataFrame 會被多個動作重複使用、且重新計算成本較高時。對只用一次的資料做快取是在浪費記憶體,而在長時間執行的作業裡,適時 unpersist 也很重要。
- 用 repartition 還是 coalesce? repartition 會觸發 shuffle,可以把分區數平均增加或減少;coalesce 則不需要完整的 shuffle 就能合併分區,是減少輸出檔案數量較便宜的方式。
- 為什麼要盡量避免 Python UDF? 資料列需要在 JVM 和 Python 行程之間序列化,而且最佳化器看不到函式內部的邏輯。應優先使用內建函式,只有在沒有對應內建函式時才考慮向量化 UDF。
- 為什麼
collect很危險? 它會把完整結果拉到 driver 端,可能耗盡 driver 的記憶體。 - 一個作業因記憶體不足而失敗,你的排查順序是什麼? 先確認是 driver 還是 executor 記憶體不足,接著看資料傾斜,再看分區大小設定,最後才是記憶體配置本身。一開始就直接調大記憶體,是經驗不足的訊號。
有一位面試平台團隊的資料工程師被問到,一個已經穩定跑了一年的夜間作業為什麼突然要花四個小時才能跑完。真正說到重點的答案不是調整設定,而是某個上游合作夥伴開始在 join key 裡傳空值,導致所有空值列都被雜湊到了同一個分區。面試官看重的正是這種排查順序:先看資料,再看叢集。
依職務分類的相關題庫請見 依職務分類的面試問題。
還會遇到哪些實作與資料處理相關的問題?
剩下這些問題是在檢驗你是不是真的上線過一條資料管線,而不只是跟著教學走了一遍。
- 如何有效率地讀取資料? 使用 Parquet 這類欄式格式、對篩選欄位做分區裁剪,以及述詞下推。要能說清楚為什麼少讀位元組比事後優化更划算。
- 為什麼要明確定義 schema,而不是讓系統推斷? 推斷 schema 需要額外掃描一次資料,而且不同次執行猜出來的型別還可能不一致。
- 如何處理空值和重複資料? 說明相關函式的用法,並指出大量空值的 join key 會造成資料傾斜這一點。
- 視窗函式都用在哪些場景? 排名、累計加總,以及按 key 去重保留最新一筆記錄,這是資料管線裡非常常見的任務。
- 寫出結果時要怎麼避免產生成千上萬個小檔案? 寫出之前先做 coalesce 或 repartition,並依一個基數合理的欄位對輸出做分區。
- 如何測試 PySpark 程式碼? 用帶有固定測試資料的小型本地 session,並把商業邏輯拆成接收和回傳 DataFrame 的函式。
- 如何提交和設定一個作業? 涉及 executor 數量、核心數和記憶體的設定,以及為什麼太多小 executor 和太少的大 executor 都會浪費資源這一點。
面試前該怎麼練習?
PySpark 的答案說出口時,失敗的方式很有辨識度:考生知道 shuffle 開銷大,卻說不清到底是哪些操作會觸發它,於是答案就變成一堆形容詞的堆砌。刷題庫能帶來一種「看起來眼熟」的感覺,但那和在別人等待作答時把解釋清楚講出來,完全是兩回事。
找一條你親手搭建過的資料管線,從頭到尾完整講一遍:讀取資料、每一步轉換、stage 邊界落在哪裡,以及如果變慢了你會先檢查什麼。大聲講出來,直到不再頻繁重講為止。用會追問的 AI 面試官來練習這些問題,比反覆翻看筆記更接近真實的面試現場,這正是 模擬面試 模式存在的意義。
SubcueAI 的創辦人 Aaron Cao 把練習的重點放在了這個「說出來」的落差上,而不是一味堆更多題目。在真實面試中,桌面應用程式和瀏覽器擴充功能的側邊欄能在面試官說話的同時把重點結構呈現出來,這對你已經練習過的內容幫助最大。設定過程只需要幾分鐘,詳細步驟請見 教學 頁面。