「ビッグデータ=Spark」と身構える前に、まず知ってほしいことがあります。小さいデータなら Lambda や pandas で十分で、Spark はむしろ過剰です。本記事は AWS Glue というサーバーレス ETL を入口に、PySpark で分散処理を触り、「いつ使うか」の判断軸まで持ち帰れる超入門です。

01なぜ分散処理か — その前に「使わない判断」

分散処理とは、ひとことで言えば「1台のマシンに載りきらない/時間がかかりすぎるデータを、複数のマシンに分けて処理する」仕組みです。その代表格が Apache Spark、そして Spark を Python から扱うのが PySpark です。

ただ、入門記事でまず最初に伝えたいのは逆のことです。データが小さいなら、分散処理は要りません。1台のメモリに載って数分で終わる程度の量なら、pandas や AWS Lambda、あるいは Athena(S3 のデータに SQL で直接集計)で十分です。Spark は起動が重く、小さいデータではむしろ遅く・高くつきます。

現場のコツ:「まず Spark を使わずに済む方法を考える」のがプロの第一歩です。数千〜数百万行の CSV 集計くらいなら、Glue を持ち出すより pandas / Lambda / Athena の方が速くて安いことは珍しくありません。

ざっくりの目安(厳密ではありません)はこうです。

本記事は素の Spark 入門ではなく、AWS Glue というサーバーレス ETL を入口に PySpark を触ることに軸足を置きます。Glue がクラウド全体のどこに位置するかは AWS・Azure・GCP・オンプレ サービス対応表 も参考にしてください。

02用語の地図 — 最初に押さえる4つ+α

PySpark を読み書きするうえで、これだけ分かっていれば迷いにくい、という言葉を先に地図にしておきます。細部は後の章のコードで自然に出てきます。

用語ざっくりの意味
DataFrame行と列の「表」。中身は複数マシンに分散して置かれている。pandas に似た操作感で書ける。
遅延評価(lazy)select / filter などの変換はその場では実行されない。設計図を組み立てるだけで、show() / write() / count() などの「アクション」で初めて計算が走る。
パーティションデータを分けた塊。処理を並列にする単位であり、S3 上の物理的な分割(例:dt=2026-07-01/…)でもある。
ドライバ司令塔。設計図を組み立て、指示を出す。collect() で全結果を集める先でもある。
エグゼキュータ実働部隊。分割されたデータを並列で処理する。数を増やすほど速くなる(が高くなる)。
遅延評価は最初の「つまづき所」です。書いた行では何も起きず、show() などを呼んだ瞬間にまとめてエラーが出るため、エラーの発生位置と原因の行がズレます。慌てず、直前のアクションまでさかのぼって確認しましょう。

もっと手前の TCP/IP・Linux・クラウドの基礎から積みたい方は、クラウドエンジニアの教科書(基礎トレーニング)もあわせてどうぞ。

03AWS での触り方 — Glue と EMR の違い

AWS で Spark を動かす代表的な選択肢が AWS GlueAmazon EMR です。ざっくり言うと、Glue はサーバーレスの ETL サービス(クラスタを自分で持たない)、EMR は自分で構築・管理する Spark クラスタです。

Glue のジョブは PySpark で書きます。しかも Glue 独自の DynamicFrame と、素の Spark DataFrame の両方が使えます。カタログ連携やスキーマ揺れに強いのが DynamicFrame、普通の集計・結合が書きやすいのが DataFrame、という住み分けです(後述)。

S3(生データ) CSV / JSON AWS Glue ジョブ PySpark で分散処理 S3(整形済み) Parquet + 分割 Crawler 自動スキャン Glue Data Catalog 表の定義(メタデータ) Athena SQL で確認 read write
S3 の生データを Glue(PySpark)で整形して Parquet で書き戻し、Crawler がカタログに登録、Athena が SQL で確認する流れ。

2026年時点のバージョンの位置づけは次の通りです。バージョンで Spark と Python が変わるので、ジョブ設定の「Glue バージョン」は必ず意識します。

Glue バージョンSpark / Python位置づけ
Glue 5.1Spark 3.5系 / Python 3.11新規ジョブの既定(Java 17)
Glue 5.0Spark 3.5系 / Python 3.11現行の主流(Java 17)
Glue 4.0Spark 3.3系 / Python 3.10互換用(Java 8)
Glue 2.0Spark 2.4系 / Python 3.7サポート終了済み。新規採用しない
版数の細部(3.5.x など)は更新されます。正確な対応は AWS 公式の「AWS Glue versions(リリースノート)」で最新を確認してください。Glue と EMR の「使い分け表」は本記事末尾の早見表にまとめました。

04UC:S3 の CSV/JSON を Parquet に変換する

もっとも基本のユースケースです。生の CSV/JSON を、集計に向いた列指向フォーマット Parquet に変換し、日付でパーティション分割して書き戻します。Glue ジョブの PySpark はこの「読む→変換→書く」が土台になります。

まず Glue ジョブ内で Spark を使うための定型(ボイラープレート)です。glueContext.spark_session から、素の Spark DataFrame API がそのまま使えます。

import sys
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from pyspark.sql import functions as F

sc = SparkContext.getOrCreate()
glueContext = GlueContext(sc)
spark = glueContext.spark_session   # ← 素の Spark DataFrame はこれ経由で使う

# 1) 読む:S3 の CSV(ヘッダあり・型は自動推論)
df = (spark.read
        .option("header", "true")
        .option("inferSchema", "true")
        .csv("s3://YOUR-BUCKET/raw/access/"))

# 2) 変換:列を絞る・型を直す・日付列(dt)を足す
out = (df.select("user_id", "path", "status", "ts")
         .withColumn("status", F.col("status").cast("int"))
         .withColumn("dt", F.to_date("ts")))

# 3) 書く:Parquet で出力。dt でパーティション分割
(out.write
    .mode("overwrite")
    .partitionBy("dt")
    .parquet("s3://YOUR-BUCKET/curated/access/"))

JSON を読むなら spark.read.json("s3://.../")、区切りが違う CSV は .option("sep", "\t") のように指定します。partitionBy("dt") で S3 上が dt=2026-07-15/ のように分割され、後述の Athena で「特定日だけ読む」ことができて速く・安くなります。

現場のコツ:CSV の inferSchema は便利ですが、全行を一度スキャンするので大きいデータでは遅く、型の推論も外すことがあります。本番では列の型を明示(スキーマ指定)する方が安全で速いです。

05UC:集計と結合(groupBy / agg / join)

次に使う頻度が高いのが、絞り込み・列の追加・集計・結合です。pandas に近い感覚で書けますが、裏では分散実行されます。

from pyspark.sql import functions as F

# filter → withColumn → groupBy().agg()(ユーザー×日次のアクセス数)
daily = (df.filter(F.col("status") < 400)
           .withColumn("dt", F.to_date("ts"))
           .groupBy("user_id", "dt")
           .agg(F.count("*").alias("hits")))

# join:ユーザー属性マスタと左結合(user_id で紐づけ)
users = spark.read.parquet("s3://YOUR-BUCKET/master/users/")   # user_id, plan など
report = daily.join(users, on="user_id", how="left")

# 確認:先頭5行だけドライバに集める(全件 collect はしない)
report.show(5)
report.printSchema()
joingroupBydistinct は「シャッフル」(マシン間でのデータ再配置)を伴い、重い処理になりがちです。むやみに繰り返さない・結合前に不要な行と列を減らす、が基本の勘どころです。

06UC:カタログ連携(Crawler → Data Catalog → Athena)

Parquet に変換しただけでは「S3 にファイルがある」状態です。これを SQL で扱える「テーブル」に見せるのが Glue Data Catalog です。カタログは、どの S3 パスに・どんな列とパーティションの表があるか、というメタデータの置き場所です。

カタログにテーブルを登録する簡単な方法が Crawler です。Crawler は指定した S3 パスを自動でスキャンし、列やパーティションを推定してカタログにテーブル定義を作成・更新します。作成後は CLI からも起動できます。

# Crawler を起動(テーブル定義を最新化)
aws glue start-crawler --name access-curated-crawler

CLI の基本操作は AWS CLI 実践リファレンスにまとめています。Crawler がテーブル(例:mydb.access)を作ったら、Athena から標準 SQL で中身を確認できます。Athena はメタデータの参照先として Glue Data Catalog を使うため、Glue で作った表がそのまま見えます。

-- Athena:Glue Data Catalog のテーブルを SQL で確認
SELECT dt, count(*) AS rows
FROM   mydb.access
WHERE  dt >= DATE '2026-07-01'
GROUP  BY dt
ORDER  BY dt;

カタログは Glue のジョブからも直接使えます。ここで DynamicFrame の出番です。スキーマが揺れる生データの取り込みに強く、素の DataFrame と相互変換できます。

from awsglue.dynamicframe import DynamicFrame

# カタログのテーブルから DynamicFrame で読む(スキーマ揺れに強い)
dyf = glueContext.create_dynamic_frame.from_catalog(
        database="mydb", table_name="access")

df = dyf.toDF()                                    # → 素の Spark DataFrame に変換して集計
# ...(04・05 のように変換)...
dyf2 = DynamicFrame.fromDF(df, glueContext, "dyf2")  # → 書き戻すとき DynamicFrame に戻す
現場のコツ:Crawler は便利ですが「自動で走らせっぱなし」にすると、意図しないスキーマ変更を拾って表がずれることがあります。列や型が固まったら、Crawler を止めて Athena の DDL(CREATE TABLE)で明示管理に切り替えるのも堅実な運用です。

07つまづき所 — 事故らないための勘どころ

現場のコツ:迷ったら「このデータ、本当に分散が要る?」と自問するのが一番の事故防止です。1台に載るなら Glue より Athena/pandas。分散が要るほど大きいなら、パーティションとシャッフルを意識して設計する — この切り分けが入口の肝です。

08早見表 — 1画面チートシート

PySpark DataFrame ミニ早見Ffrom pyspark.sql import functions as F)。

やりたいこと書き方
CSV を読むspark.read.option("header","true").csv("s3://.../")
Parquet を書く(分割)df.write.partitionBy("dt").parquet("s3://.../")
列を選ぶdf.select("a", "b")
絞り込みdf.filter(F.col("status") < 400)
列を追加・変換df.withColumn("dt", F.to_date("ts"))
集計df.groupBy("dt").agg(F.count("*"))
結合a.join(b, on="user_id", how="left")
少量だけ確認df.show(5) / df.printSchema()
DynamicFrame ⇄ DataFramedyf.toDF() / DynamicFrame.fromDF(df, glueContext, "n")

Glue / EMR / Athena の使い分け

観点GlueEMRAthena
形態サーバーレス ETL管理型 Spark クラスタサーバーレス SQL
得意定期的な変換・加工大規模・重い分散処理保存済みデータの集計・確認
書くものPySpark(DynamicFrame 可)Spark / Hive / Presto 等標準 SQL
サーバー管理不要必要不要
小さいデータ過剰なことも過剰向く(手軽)
シリーズ内の関連記事:AWS CLI 実践リファレンス(Crawler やジョブの起動を CLI で)/Python×Lambda 実践ユースケース(小さいデータはこちらで十分)。土台づくりに興味がある方へ — EMW は札幌で AWS のデータ基盤・ETL を支援しています。採用情報・カジュアル面談はこちら

09よくある質問(FAQ)

Q. Python しかできませんが、Glue で分散処理を触れますか?

はい。Glue のジョブは基本的に PySpark(Python)で書けます。pandas に似た DataFrame 操作が中心で、SQL(Athena)とも併用できます。まずは小さな CSV を Parquet に変換するところから始めると感覚がつかめます。ただし「何でも Glue」ではなく、小さいデータは Lambda や pandas で十分、という判断も同じくらい大切です。

Q. Glue と EMR、どちらを選べばよいですか?

定期的な ETL でサーバー管理をしたくないならサーバーレスの Glue が第一候補です。超大規模なデータや、Spark 以外(Hive・Presto など)も回す、クラスタを細かくチューニングしたい、といった要件があるなら EMR が向きます。迷ったら、まずは Glue で足りることが多いです。

Q. Glue のバージョンはどれを使えばよいですか?

2026年時点、新規ジョブの既定は Glue 5.x(Spark 3.5系 / Python 3.11 / Java 17)です。古いライブラリの都合で Java 8 が必要なら Glue 4.0(Spark 3.3系)を選びます。バージョンによって Spark と Python が変わるため、ジョブ設定の Glue バージョンは必ず意識してください。細かい版数は変わるので、最新は AWS 公式ドキュメントで確認するのが安全です。

Q. DynamicFrame と DataFrame、どちらで書くべきですか?

どちらも同じジョブ内で使え、dyf.toDF() と DynamicFrame.fromDF() で相互に変換できます。スキーマが揺れる生データの取り込みやカタログ連携は Glue の DynamicFrame が便利で、集計・結合など普通の加工は素の Spark DataFrame が書きやすいです。実務では両方を混ぜて使うのが自然です。

EMW は札幌で AWS のデータ基盤・ETL 設計を支援しています。「この処理、Glue に載せるべき? それとも Lambda / pandas で十分?」という切り分けの相談だけでも歓迎です。基礎から積み上げたい方の採用も行っています。

相談する
← ブログ一覧へ戻る