Spark nedir? Pizzacı ekibi analojisi
What is Spark
Bu derste neler öğreneceksin
- Spark ın dağıtık yapısını açıklar
- RDD vs DataFrame farkını bilir
- PySpark + DuckDB karşılaştırması yapar
Spark: Büyük Verinin Dağıtık Hesaplama Motoru
Veri mühendisliğinde “büyük veri” genellikle tek bir makineye sığmayan veri demektir. Petabyte ölçeğinde günlük event log’ları, yıllık GPS izleri, IoT sensör verisi — bunları tek bir sunucuyla işlemek fiziksel olarak mümkün değil. Apache Spark, bu sorunu “veriyi böl, birçok makinede paralel işle, sonuçları birleştir” yaklaşımıyla çözen açık kaynak bir motor.
2014’te çıkan ilk sürümden bu yana sektör standardı haline geldi: Databricks, Amazon EMR, Google Dataproc, Azure Synapse — hepsi Spark etrafında dönüyor.
Mimari: Driver, Executor, Cluster
Spark’ın üç temel bileşeni var:
- Driver (master): İşi planlayan beyin.
SparkSession, kullanıcının yazdığı kodu DAG (Directed Acyclic Graph — yönlü döngüsel olmayan grafik) halinde bir iş planına çevirir. - Executor (worker): Asıl hesaplamayı yapan kol. Her executor JVM üzerinde çalışan bir süreçtir; belirli sayıda task (görev) paralel yürütür.
- Cluster Manager: Dış kaynak yöneticisi (YARN, Mesos, Kubernetes, Spark Standalone). Driver’a “şu kadar executor açabilirsin” der.
graph LR
A[Driver] -->|planla| B[Cluster Manager]
B -->|tahsis et| C[Executor 1]
B -->|tahsis et| D[Executor 2]
B -->|tahsis et| E[Executor N]
C --> F[(Partition 1)]
D --> G[(Partition 2)]
E --> H[(Partition N)]
Bir veri okunduğunda Spark onu partition’lara (parçalara) böler. Her executor kendi partition’ı üzerinde çalışır. Sonuçlar shuffle aşamasında birleştirilir — shuffle maliyetli olduğu için iyi bir Spark programcısı shuffle’ı en aza indirmeye çalışır.
RDD: Spark’ın Kökeni (Eski Usul)
İlk Spark sürümlerinde tek veri yapısı vardı: RDD (Resilient Distributed Dataset). Üç kelimenin açılımı:
- Resilient: Hata olursa lineage (soy kütüğü) üzerinden yeniden hesaplanabilir.
- Distributed: Veri birçok makineye dağıtılır.
- Dataset: Satırlık veri koleksiyonu.
RDD düşük seviyeli bir API’dir. Her şeyi lambda fonksiyonları ile yaparsın:
# RDD ile: alt seviye, fonksiyonel
rdd = sc.parallelize([
("margherita", 50), ("sucuklu", 70), ("mozzarella", 60),
("pepperoni", 75), ("veggie", 55), ("kasar", 65),
])
# Map: fiyatı 1.18 ile çarp (KDV)
kdvli = rdd.map(lambda kv: (kv[0], kv[1] * 1.18))
# Filter: pahalı pizzalar
pahali = kdvli.filter(lambda kv: kv[1] > 70)
# Reduce: ortalama fiyat
toplam = pahali.map(lambda kv: kv[1]).reduce(lambda a, b: a + b)
adet = pahali.count()
print(f"Ortalama: {toplam / adet:.2f} TL")
RDD’nin avantajı esneklik: istediğin her şeyi lambda ile yazabilirsin. Dezavantajı: Spark senin kodu optimize edemez. Çünkü Spark “bu kullanıcı ne yapıyor” diye bakamıyor — sadece sen söylediğin adımları yürütüyor.
2026’da RDD ne zaman kullanılır? Neredeyse hiç. Eski kod okurken veya çok düşük seviyeli bir kontrol gerektiğinde (ör. özel bir partitioner) karşına çıkar. Yeni proje yazıyorsan DataFrame API kullan.
DataFrame: Yüksek Seviye, Optimize Edilebilir
DataFrame API’si RDD’nin üzerine kurulu bir soyutlama. Sen tablo görürsün, Spark bir SQL/planner motoru (Catalyst) görür.
# DataFrame ile: yüksek seviye, optimize
df = spark.createDataFrame(
[("margherita", 50), ("sucuklu", 70), ("mozzarella", 60),
("pepperoni", 75), ("veggie", 55), ("kasar", 65)],
["pizza", "fiyat"],
)
from pyspark.sql.functions import col, avg
df.filter(col("fiyat") > 70).agg(avg("fiyat")).show()
Aynı sonuç — ama Spark bunu arka planda optimize eder: predicate pushdown (filtreyi erkene al), projection pruning (gereksiz sütunu atla), join reordering gibi planlamaları Catalyst otomatik yapar. RDD’de bunları sen elle yapmak zorunda kalırdın.
DataFrame API’si iki stilde yazılabilir:
# 1) Zincirleme (Pythonic)
df.filter(col("fiyat") > 70).select("pizza").show()
# 2) SQL ifadesi
df.createOrReplaceTempView("pizzalar")
spark.sql("SELECT pizza FROM pizzalar WHERE fiyat > 70").show()
İkisi de aynı plana derlenir.
PySpark vs DuckDB: Aynı Tablo, Farklı Motor
Spark dışında bir de DuckDB var. DuckDB, tek bir makinede çalışan, gömülü (in-process) bir analitik veritabanı motoru. Yani ayrı bir sunucu kurmuyorsun, Python içinden import duckdb ile çalışıyor.
| Kriter | PySpark | DuckDB |
|---|---|---|
| Ölçek | Tek makineden petabyte’a | Tek makine (genelde 10-200 GB arası rahat) |
| Kurulum | pip install pyspark (JVM indirir, 300 MB+) | pip install duckdb (50 MB) |
| Cluster | Birçok makineye dağılır | Tek makinede paralelleştirir (çok çekirdek) |
| API yüzeyi | Geniş (Spark SQL, MLlib, Structured Streaming) | Sadece SQL + DataFrame |
| Ne zaman seçilir | Veri makineye sığmıyor, üretim pipeline | Tek laptop, orta veri, hızlı analiz |
| Yerel geliştirme | Ağır (JVM başlatır) | Çok hafif |
Production kararı: Bu kursta varsayılan Polars (DuckDB benzeri, tek makine). Veri 100 GB’ı geçiyorsa Spark’a terfi et. Pratikte startup’ların çoğu verisi 50 GB altında — Spark’a hiç geçmeden ömür boyu Polars/DuckDB yeter.
PySpark ile Hızlı Demo
JVM’i yerel olarak ayağa kaldırıp 10 milyon satırlık veri üzerinde groupBy:
from pyspark.sql import SparkSession
import random
spark = SparkSession.builder \
.appName("mini-demo") \
.master("local[4]") \
.getOrCreate()
# 10M satır üret
random.seed(42)
data = [
(f"user_{i}", random.choice(["A", "B", "C"]), random.randint(1, 1000))
for i in range(10_000_000)
]
df = spark.createDataFrame(data, ["user", "segment", "amount"])
# Plan: segment başına toplam ve ortalama
df.groupBy("segment").agg(
{"amount": "sum", "amount": "avg"}
).show()
local[4] demek “yerel JVM’de 4 çekirdek kullan” demek. Production’da cluster modu açarsın.
Özet
Bugün öğrendik:
- Spark, dağıtık hesaplama motoru: driver planlar, executor’lar çalıştırır.
- Partition’lar verinin dağıtık parçaları; shuffle parçalar arası veri taşıma (maliyetli).
- RDD eski API, DataFrame yeni API; yeni kodda DataFrame.
- PySpark Python’dan Spark; DuckDB tek makinede analitik motor.
- Küçük veri için Polars/DuckDB, büyük veri için Spark; çoğu startup verisi Polars ile yaşar.
Alıştırma
pip install pysparkkur, yukarıdaki demo’yu çalıştır. Spark UI’alocalhost:4040üzerinden bak (DAG ve stage’leri göreceksin).df.groupBy("segment").count()ile sayım yap. Plan neden 2 stage gösteriyor?- Bir cümle yaz: “Kendi projemde PySpark mı DuckDB mi seçerdim, hangi koşulda?”
Sıradaki
Spark’ın temellerini gördün. Şimdi gerçek bir DataFrame batch iş yazıyoruz →