spark-engineer について
Apache Spark エンジニア向けに、分散データパイプラインの設計、実装、性能検証を案内するスキルです。
主な機能
- 01DataFrame と RDD の設計指針
- 02パーティションとキャッシュ戦略
- 03結合とデータスキューの最適化
- 04Spark UI による性能確認
- 05Structured Streaming の参照ガイド
活用シーン
- 01大規模 ETL パイプラインの設計
- 02shuffle の多い Spark ジョブの調整
- 03本番規模のデータパイプラインの検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jeffallan/ claude-skills --skill spark-engineerインストール後、Claude Code で/spark-engineerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/partitioning-caching.mdperformance-tuning.mdrdd-operations.mdspark-sql-dataframes.mdstreaming-patterns.md詳細
Spark Engineer
大規模な分散データ処理の高性能化、大規模 ETL パイプラインの最適化、本番環境向けの高品質な Spark アプリケーションの構築を専門とする、シニア Apache 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 実行エンジン、パーティショニング戦略、ブロードキャスト変数、アキュムレーター、構造化ストリーミング、ウォーターマーク、チェックポイント、Spark UI の分析、メモリ管理、シャッフルの最適化
@jeffallan(Synergetic Solutions のプリンシパルコンサルタント)がメンテナンスしています。
コメント
Markdown 対応