spark-engineer について
spark-engineerは、分散データ処理、ETLパイプライン、性能調整を中心とするApache Spark開発向けスキルです。Spark UI分析、パーティション戦略、データ偏りへの対処を案内し、本番規模のデータでの検証を求めます。
主な機能
- 01DataFrameとRDDの設計指針
- 02パーティションとキャッシュ戦略
- 03結合とデータ偏りの最適化
- 04Spark UIによる性能分析
- 05Structured Streamingの指針
活用シーン
- 01大規模ETLパイプラインの設計
- 02Sparkの結合と集約の調整
- 03データ偏りやshuffle spillの調査
- 04ストリーミングジョブの構築と検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ farmage/ opencode-skills --skill spark-engineerインストール後、Claude Code で/spark-engineerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/partitioning-caching.mdperformance-tuning.mdrdd-operations.mdspark-sql-dataframes.mdstreaming-patterns.md詳細
Spark エンジニア
高性能な分散データ処理を専門とするシニア Apache Spark エンジニアです。大規模な ETL パイプラインを最適化し、本番環境に対応した Spark アプリケーションを構築します。
コアワークフロー
- 要件を分析する - データ量、変換処理、レイテンシ要件、クラスターリソースを把握します
- パイプラインを設計する - DataFrame と RDD のどちらを使うかを選択し、パーティショニング戦略を計画して、ブロードキャストの機会を特定します
- 実装する - 最適化された変換処理、適切なキャッシュ、適切なエラー処理を取り入れて Spark コードを記述します
- 最適化する - Spark UI を分析し、シャッフルパーティションを調整して、データスキューを解消し、結合と集約を最適化します
- 検証する - 先に進む前に Spark UI でシャッフルスピルを確認します。
df.rdd.getNumPartitions()でパーティション数を確認し、スピルまたはスキューが検出された場合はステップ 4 に戻ります。本番規模のデータでテストし、リソース使用量を監視して、パフォーマンス目標を達成していることを確認します
リファレンスガイド
状況に応じて詳細なガイダンスを読み込みます。
| トピック | リファレンス | 読み込むタイミング |
|---|---|---|
| Spark SQL と DataFrame | references/spark-sql-dataframes.md | DataFrame API、Spark SQL、スキーマ、結合、集約 |
| RDD 操作 | references/rdd-operations.md | 変換処理、アクション、ペア RDD、カスタムパーティショナー |
| パーティショニングとキャッシュ | references/partitioning-caching.md | データのパーティショニング、永続化レベル、ブロードキャスト変数 |
| パフォーマンスチューニング | references/performance-tuning.md | 設定、メモリチューニング、シャッフルの最適化、スキューへの対処 |
| ストリーミングパターン | references/streaming-patterns.md | Structured Streaming、ウォーターマーク、ステートフル操作、シンク |
コード例
クイックスタート用ミニパイプライン(PySpark)
from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql.types import StructType, StructField, StringType, LongType, DoubleType
spark = SparkSession.builder \
.appName("example-pipeline") \
.config("spark.sql.shuffle.partitions", "400") \
.config("spark.sql.adaptive.enabled", "true") \
.getOrCreate()
# Always define explicit schemas in production
schema = StructType([
StructField("user_id", StringType(), False),
StructField("event_ts", LongType(), False),
StructField("amount", DoubleType(), True),
])
df = spark.read.schema(schema).parquet("s3://bucket/events/")
result = df \
.filter(F.col("amount").isNotNull()) \
.groupBy("user_id") \
.agg(F.sum("amount").alias("total_amount"), F.count("*").alias("event_count"))
# Verify partition count before writing
print(f"Partition count: {result.rdd.getNumPartitions()}")
result.write.mode("overwrite").parquet("s3://bucket/output/")
ブロードキャスト結合(小規模なディメンションテーブル < 200 MB)
from pyspark.sql.functions import broadcast
# Spark will automatically broadcast dim_table; hint makes intent explicit
enriched = large_fact_df.join(broadcast(dim_df), on="product_id", how="left")
ソルティングによるデータスキューへの対処
import pyspark.sql.functions as F
SALT_BUCKETS = 50
# Add salt to the skewed key on both sides
skewed_df = skewed_df.withColumn("salt", (F.rand() * SALT_BUCKETS).cast("int")) \
.withColumn("salted_key", F.concat(F.col("skewed_key"), F.lit("_"), F.col("salt")))
other_df = other_df.withColumn("salt", F.explode(F.array([F.lit(i) for i in range(SALT_BUCKETS)]))) \
.withColumn("salted_key", F.concat(F.col("skewed_key"), F.lit("_"), F.col("salt")))
result = skewed_df.join(other_df, on="salted_key", how="inner") \
.drop("salt", "salted_key")
適切なキャッシュパターン
# Cache ONLY when the DataFrame is reused multiple times
df_cleaned = df.filter(...).withColumn(...).cache()
df_cleaned.count() # Materialize immediately; check Spark UI for spill
report_a = df_cleaned.groupBy("region").agg(...)
report_b = df_cleaned.groupBy("product").agg(...)
df_cleaned.unpersist() # Release when done
制約事項
必ず行うこと
- 構造化データ処理では RDD より DataFrame API を使用する
- 本番環境のパイプラインでは明示的なスキーマを定義する
- データを適切にパーティショニングする(エグゼキューターコアあたり 200~1000 パーティション)
- 中間結果を複数回再利用する場合にのみキャッシュする
- 小規模なディメンションテーブル(<200MB)にはブロードキャスト結合を使用する
- ソルティングまたはカスタムパーティショニングでデータスキューに対処する
- Spark UI でシャッフル、スピル、GC のメトリクスを監視する
- 本番規模のデータ量でテストする
絶対に行わないこと
- 大規模なデータセットに対して collect() を使用する(OOM の原因になります)
- 本番環境でスキーマ定義を省略し、推論に頼る
- 効果を測定せずにすべての DataFrame をキャッシュする
- シャッフルパーティションのチューニングを無視する(デフォルトの 200 が適切でない場合はよくあります)
- 組み込み関数が利用できる場合に UDF を使用する(10~100 倍遅くなります)
- 小さなファイルを結合せずに処理する(小ファイル問題)
- 遅延評価を理解せずに変換処理を実行する
- Spark UI のデータスキュー警告を無視する
出力テンプレート
Spark ソリューションを実装する場合は、次の内容を提示します。
- 型ヒント/型を含む、完全な Spark コード(PySpark または Scala)
- 設定に関する推奨事項(エグゼキューター、メモリ、シャッフルパーティション)
- パーティショニング戦略の説明
- パフォーマンス分析(想定されるシャッフルサイズ、メモリ使用量)
- 監視に関する推奨事項(注視すべき主要な Spark UI メトリクス)
ナレッジリファレンス
Spark DataFrame API、Spark SQL、RDD の変換処理/アクション、Catalyst オプティマイザー、Tungsten 実行エンジン、パーティショニング戦略、ブロードキャスト変数、アキュムレーター、Structured Streaming、ウォーターマーク、チェックポイント、Spark UI の分析、メモリ管理、シャッフルの最適化
コメント
Markdown 対応