Episode ini membahas DataFrame dan Spark SQL: membuat DataFrame dari CSV, JSON, dan Parquet, query SQL dengan temporary views, schema inference dan explicit schema, serta peran Catalyst optimizer dalam eksekusi plan yang efisien.

DataFrame dan Spark SQL adalah jantung dari sebagian besar pekerjaan Spark modern. Keduanya memakai abstraksi yang sama — data berkolom dengan schema — sehingga kalian bisa menulis logika sekali dan mengeksekusinya lewat API Python, Scala, maupun SQL murni.
Episode 5 ini membahas: membuat DataFrame dari berbagai format file, menjalankan query SQL dengan temporary views, memahami schema inference versus explicit schema, dan bagaimana Catalyst optimizer menghasilkan eksekusi yang efisien. Ini adalah keterampilan yang paling sering dipakai sehari-hari di dunia data engineering.
CSV adalah format paling umum untuk data tabular. PySpark menyediakan API spark.read yang ringkas:
df = spark.read.format("csv") \
.option("header", True) \
.option("inferSchema", True) \
.load("data/penjualan.csv")
df.printSchema()df.printSchema() menampilkan struktur kolom. Opsi header dan inferSchema adalah pasangan yang hampir selalu kalian set — tanpa inferSchema, semua kolom akan dibaca sebagai string.
JSON cocok untuk data semi-terstruktur, sementara Parquet adalah format kolom terkompresi yang paling direkomendasikan untuk data lake:
json_df = spark.read.format("json").load("data/event.json")
parquet_df = spark.read.format("parquet").load("data/tabel.parquet")
parquet_df.show(5)Karena Parquet menyimpan schema di dalam file-nya, tidak perlu konfigurasi tambahan — spark.read.format("parquet") langsung memahami strukturnya. Ini alasan mengapa Parquet menjadi standar de facto untuk penyimpanan data lake.
Untuk memakai SQL, daftarkan DataFrame sebagai view:
df.createOrReplaceTempView("penjualan")
hasil = spark.sql("""
SELECT kategori, SUM(jumlah) AS total
FROM penjualan
GROUP BY kategori
ORDER BY total DESC
""")
hasil.show()df.createOrReplaceTempView("penjualan") membuat view yang hanya hidup selama session berlangsung. Kalian bisa menulis query SQL yang sama persis dengan yang kalian tulis di database — kalian bahkan bisa menggabungkan view dengan table lain di join.
Spark SQL bukan sekadar ekstensi — seluruh DataFrame API diterjemahkan ke rencana logis yang sama. Artinya kalian bisa memilih antara menulis df.filter(df.jumlah > 100) atau spark.sql("SELECT * FROM penjualan WHERE jumlah > 100"). Keduanya menghasilkan rencana eksekusi yang identik.
df.filter(df.jumlah > 100) ← API
spark.sql("SELECT ... WHERE ...") ← SQLinferSchema memang praktis, tapi ada risiko: Spark menebak tipe dari data yang dibaca. Kolom angka dengan satu nilai yang terbaca salah bisa berubah menjadi string, atau nilai kosong mengubah tipe kolom. Untuk pipeline produksi, tebakan otomatis adalah sumber bug yang halus.
Untuk kontrol penuh, definisikan schema dengan tipe eksplisit:
from pyspark.sql.types import StructType, StructField, StringType, IntegerType
schema = StructType([
StructField("produk", StringType(), True),
StructField("stok", IntegerType(), True),
])
df = spark.read.format("csv") \
.option("header", True) \
.schema(schema) \
.load("data/stok.csv")Argumen ketiga StructField adalah nullable — untuk kolom yang wajib ada, set False agar Spark memvalidasi data masuk. Schema eksplisit juga mempercepat loading karena Spark tidak perlu membaca seluruh data hanya untuk menebak tipe.
Catalyst adalah optimizer berbasis aturan yang mengubah query menjadi rencana eksekusi efisien. Ia bekerja dalam beberapa tahap: analysis, logical optimization, physical planning, dan code generation.
SQL/API → logical plan → optimized plan → physical plan → RDD → hasilBeberapa optimasi Catalyst yang paling berdampak:
Cara terbaik merasakan kerja Catalyst adalah melihat rencana eksekusi:
df.explain("extended")df.explain("extended") menampilkan logical plan dan physical plan. Membiasakan diri membaca output ini adalah keterampilan kunci untuk episode 9 tentang performance tuning.
Tip
Setiap kali query terasa lambat, jangan langsung menebak. Jalankan df.explain("extended") dan periksa apakah predicate pushdown bekerja, apakah terjadi full scan, dan di mana shuffle terjadi. Diagnosis selalu dimulai dari rencana eksekusi.
Vokabulari DataFrame mirip SQL namun dalam bentuk metode:
hasil = df \
.select("produk", "harga") \
.filter(df.harga > 50000) \
.withColumn("harga_ppn", df.harga * 1.11) \
.groupBy("produk") \
.agg({"harga_ppn": "avg"})withColumn menambah atau mengganti kolom, agg menerima kamus agregasi. Rantai ini lazy — eksekusi baru terjadi saat show(), collect(), atau action lain dipanggil.
Spark menyediakan fungsi-fungsi bawaan di modul functions:
from pyspark.sql import functions as F
df2 = df.withColumn("bulan", F.month(df.tanggal)) \
.withColumn("label", F.when(df.stok == 0, "habis").otherwise("tersedia"))F.when(...).otherwise(...) adalah if-else untuk kolom. Ratusan fungsi lain seperti F.coalesce, F.window, F.row_number akan muncul berulang kali di episode 7 dan 10.
Episode 5 membekali kalian keterampilan utama Spark: membuat DataFrame dari CSV, JSON, dan Parquet, mengquery dengan SQL melalui temporary views, mengendalikan tipe data dengan explicit schema, memahami Catalyst optimizer, dan merangkai transformation dengan expression API.
Inti yang harus dibawa pulang:
spark.read.format(...) membaca CSV, JSON, Parquet, dan lainnya.df.explain("extended") adalah alat diagnosis utama.Di episode 6 selanjutnya kita akan membahas Dataset API dan strong typing — typed Dataset di Scala dan Java, peran encoders dan compile-time type safety, perbedaan struktur Dataset versus DataFrame, serta konversi dua arah antara keduanya.