PySparkの面接でよく聞かれる質問
文責 Aaron Cao · 更新

PySparkの面接は実行モデルとパフォーマンスに重点が置かれます。transformationとactionの違いを説明し、どの操作がシャッフルを引き起こすかを見極め、ブロードキャストjoinを選ぶ判断ができ、データスキューを診断し、キャッシュの是非を説明し、メモリ不足になったジョブをどうチューニングするかを述べられることが求められます。
実行モデルについて面接官は何を聞くのか?
動くPySparkのコードを書けても、この手の質問ではつまずくことがあります。これらの質問が問うのは、あなたのコードが何を書いているかではなく、エンジンが実際に何をしているかだからです。面接官がこの種の質問から始めたがるのは、ジョブをチューニングした経験がある人と、ただ一度実行しただけの人を見分けられるからです。このセクションでは実行モデルに関する質問と、完全な回答に含めるべき要素を扱います。
- transformationとactionの違いは何ですか? transformationは実行計画を組み立て、新しいDataFrameを遅延的に返します。一方、
countやcollect、あるいは書き込みといったactionが実行をトリガーします。actionが結果を要求するまで、何も計算は行われません。 - 遅延評価はなぜ有用なのですか? オプティマイザは実行前に処理の連鎖全体を把握できるため、フィルタの並べ替えや不要な列の削減、複数ステップの結合ができます。
- 狭い変換と広い変換の違いは?
filterやselectのような狭い操作では、各出力パーティションは一つの入力パーティションにのみ依存します。groupBy、join、distinctのような広い操作はパーティション間でデータを再分配し、これがシャッフルです。 - シャッフルとは何で、なぜ重要なのですか? データはネットワークを越えて移動し、ディスクにも書き込まれ、ステージの境界を形成します。多くの場合、ジョブの中で最もコストの高い処理です。
- job、stage、taskについて説明してください。 actionがjobを開始し、シャッフルの境界がそれをstageに分割し、各stageはパーティションごとに一つのtaskを実行します。
- RDD、DataFrame、それともDataset? 基本的にはDataFrameを使うべきです。Catalystオプティマイザと列指向実行の恩恵を受けられるためです。RDDは低レベルの制御が必要な場合に残されています。型付きのDatasetはJVM上の概念であり、Pythonでは正直なところ該当しません。
回答の中でシャッフルやステージという言葉を使うべき場面では、きちんと使いましょう。面接官はそれを、あなたがSpark UIを実際に見たことがあるかどうかを判断する近道として使っています。
パフォーマンスに関する質問にはどう答えるべきか?
シニア向けのPySparkの面接の多くは、実質的にパフォーマンスの面接です。質問は定義ではなくシナリオの形で出されます。
- joinが遅いとき、まず何を確認しますか? まず双方のデータサイズです。片方がexecutorのメモリに収まるならブロードキャストし、シャッフルを完全に回避します。そうでなければ、クラスタサイズに手をつける前にパーティショニングとスキューを確認します。
- データスキューとは何で、どう修正しますか? 一部のキーに大半の行が集中し、一つのtaskだけが他が終わった後も長く動き続けます。対処法としては、ホットキーへのソルト付加、小さい側のブロードキャスト、同じハッシュ値に集中するnullのフィルタリングなどがあります。診断のシグナルはSpark UIに表示されるtaskの実行時間のばらつきです。
- cacheやpersistはいつ使いますか? DataFrameが複数のactionで再利用され、再計算のコストが高い場合です。一度しか使わないデータをキャッシュするのはメモリの無駄で、長時間実行されるジョブではunpersistのタイミングも重要になります。
- repartitionとcoalesce、どちらを使いますか? repartitionはシャッフルを伴い、パーティション数を均等に増減できます。coalesceは完全なシャッフルなしにマージするため、出力ファイル数を減らす際はより低コストな方法です。
- なぜPython UDFは避けるべきなのですか? 各行はJVMとPythonプロセスの間でシリアライズされ、オプティマイザは関数の中身を見ることができません。組み込み関数を優先し、対応する組み込み関数が存在しない場合に限りベクトル化UDFを検討します。
- なぜ
collectは危険なのですか? 結果全体をdriverに引き寄せるため、driverのメモリを使い果たす可能性があります。 - ジョブがメモリ不足で失敗しました。どの順番で調査しますか? まずdriverかexecutorかを確認し、次にスキュー、次にパーティションのサイズ設定、最後にメモリ設定を見ます。最初にメモリを増やそうとするのは、経験不足を示す回答です。
あるプラットフォームチームの面接を受けたデータエンジニアは、一年間安定して動いていた夜間ジョブが突然四時間もかかるようになった理由を尋ねられました。評価された答えは設定変更ではなく、あるアップストリームのパートナーがjoinキーにnullを送り始め、null行がすべて同じパーティションにハッシュされていたというものでした。面接官はこの順序を評価します。クラスタより先にデータを見ることです。
職種別の関連する質問集は職種別の面接質問にまとまっています。
実務やデータ処理に関するどんな質問が出るのか?
残りの質問は、チュートリアルをこなしただけなのか、実際にパイプラインをリリースした経験があるのかを見極めるものです。
- データを効率よく読み込むにはどうしますか? Parquetのような列指向フォーマット、フィルタ列でのパーティションプルーニング、述語のプッシュダウンです。読み込むバイト数を減らすことが、後段の処理を最適化するより効果的である理由を説明します。
- なぜスキーマを推論に任せず明示的に定義するのですか? 推論にはデータへの追加のパスが必要で、実行のたびに型の推測結果が一致しないこともあります。
- nullや重複データはどう扱いますか? 関連する関数の使い方に加え、nullの多いjoinキーがスキューを生む点も押さえます。
- ウィンドウ関数は何に使われますか? ランキング、累積集計、キーごとに最新のレコードへ重複排除する処理などで、パイプラインでは非常によくあるタスクです。
- 何千もの小さなファイルを作らずに出力するにはどうしますか? 書き込み前にcoalesceかrepartitionを行い、カーディナリティが適切な列で出力をパーティション分割します。
- PySparkのコードはどうテストしますか? フィクスチャのDataFrameを使った小さなローカルセッションと、DataFrameを受け取り返す関数にビジネスロジックを切り出すことです。
- ジョブの投入や設定はどう行いますか? executorの数、コア数、メモリの設定に加え、小さすぎるexecutorが多すぎても、大きすぎるexecutorが少なすぎても容量が無駄になるという理屈です。
面接前にどう練習すべきか?
PySparkの回答は、声に出したときに特徴的な失敗の仕方をします。候補者はシャッフルにコストがかかることは知っていても、どの操作がそれを引き起こすのかを言えず、答えが形容詞の羅列になってしまうのです。問題集を読むと「見覚えがある」という感覚は得られますが、それは相手が待っている中で説明を組み立てることとは別物です。
自分が実際に構築したパイプラインを一つ選び、読み込みからすべての変換、stageの境界がどこにあるか、遅くなった場合にまず何を確認するかまで、最初から最後まで語ってみましょう。言い直さずに話せるようになるまで、声に出して練習します。フォローアップまでしてくるAI面接官相手にこうした質問を練習するほうが、ノートを読み返すより本番に近い体験になります。それこそが模擬面接モードの目的です。
SubcueAIの創業者であるAaron Caoは、問題数を増やすことよりも、この「話す」というギャップを埋めることを中心に練習の仕組みを作りました。実際の面接では、デスクトップアプリとブラウザ拡張機能のサイドパネルが、面接官が話している間に構造を提示してくれます。これはすでに練習済みの内容に対して最も効果を発揮します。セットアップは数分で完了し、詳細はチュートリアルページに記載しています。