Apache Spark Fundamentals
Fast, in-memory data processing at scale
The Evolution of Big Data Processing
Apache Spark is an open-source, unified analytics engine for large-scale data processing. It provides high-level APIs in Java, Scala, Python (PySpark), and R, along with an optimized engine that supports general execution graphs. Spark extends the MapReduce model to efficiently support more types of computations, including interactive queries and stream processing. Its in-memory caching makes it 100x faster than Hadoop MapReduce for iterative algorithms and interactive data mining.
Born at UC Berkeley's AMPLab in 2009, Spark addresses Hadoop's limitations by keeping data in memory across operations. It runs on Hadoop YARN, Kubernetes, Mesos, or standalone, and integrates with HDFS, S3, Cassandra, and more. In this lesson, we'll explore Spark's core components, with a focus on PySpark for practical examples.
1. Spark Core: Resilient Distributed Datasets (RDDs)
Spark Core is the foundation, providing distributed task dispatching, scheduling, and basic I/O. At its heart are RDDs: immutable, partitioned collections of objects that can be computed in parallel. RDDs support fault-tolerant, in-memory processing with lineage for recomputation on failure.
Architecture Overview
Spark follows a driver-executor model:
Main program, creates SparkContext, defines transformations/actions, manages job submission.
Worker processes on cluster nodes, run tasks, store data in memory/disk.
External service (YARN, Kubernetes) for resource allocation.
Builds directed acyclic graph of stages for optimization.
Key Features
Transformations build DAG; actions trigger computation.
Persist RDDs in memory for reuse, reducing I/O.
Lineage allows recomputation of lost partitions.
Data divided into partitions for parallel processing.
Hands-On Examples (PySpark RDDs)
from pyspark import SparkContext sc = SparkContext.getOrCreate() rdd = sc.parallelize([1, 2, 3, 4, 5]) doubled = rdd.map(lambda x: x * 2) print(doubled.collect())
rdd = sc.parallelize([1, 2, 3, 4, 5, 6]) evens = rdd.filter(lambda x: x % 2 == 0) sum_evens = evens.reduce(lambda a, b: a + b) print(sum_evens)
rdd1 = sc.parallelize([("a", 1), ("b", 2)]).cache()
rdd2 = sc.parallelize([("a", 3), ("b", 4)])
joined = rdd1.join(rdd2)
print(joined.collect())2. Spark SQL: Structured Data Processing
Spark SQL is a module for structured data processing, providing DataFrames (distributed collections with schema) and SQL querying. It integrates with Hive, supports multiple formats (Parquet, ORC, JSON), and uses Catalyst optimizer for efficient execution plans.
Architecture Overview
Built on Spark Core, with key components:
Typed, distributed datasets with schema; optimized for queries.
Rule-based and cost-based optimization for query plans.
Whole-stage code generation for CPU efficiency.
Reads Hive metastore for tables and UDFs.
Key Features
SQL, DataFrame API, and Dataset API interoperable.
Advanced analytics like ranking, aggregates over windows.
User-defined functions and aggregations.
Runtime optimizations like dynamic partitioning.
Hands-On Examples (PySpark SQL)
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
data = [("Alice", 25), ("Bob", 30)]
df = spark.createDataFrame(data, ["name", "age"])
df.show()┌───────┬─────┐ │ name │ age │ ├───────┼─────┤ │ Alice │ 25 │ │ Bob │ 30 │ └───────┴─────┘
df.createOrReplaceTempView("people")
result = spark.sql("SELECT name FROM people WHERE age > 25")
result.show()┌──────┐ │ name │ ├──────┤ │ Bob │ └──────┘
from pyspark.sql.window import Window
from pyspark.sql.functions import row_number
data = [("Alice", "Sales", 3000), ("Bob", "Sales", 4600), ("Carol", "HR", 5000)]
df = spark.createDataFrame(data, ["name", "dept", "salary"])
window = Window.partitionBy("dept").orderBy("salary")
df.withColumn("rank", row_number().over(window)).show()┌───────┬───────┬────────┬──────┐ │ name │ dept │ salary │ rank │ ├───────┼───────┼────────┼──────┤ │ Carol │ HR │ 5000 │ 1 │ │ Alice │ Sales │ 3000 │ 1 │ │ Bob │ Sales │ 4600 │ 2 │ └───────┴───────┴────────┴──────┘
3. Spark Streaming: Real-Time Data Processing
Spark Streaming enables scalable, high-throughput, fault-tolerant stream processing. Structured Streaming (introduced in Spark 2.0) treats streams as unbounded tables, allowing SQL-like queries on streaming data with exactly-once semantics.
Architecture Overview
Key elements in Structured Streaming:
Kafka, Flume, files, sockets; support rate limiting.
Incremental execution on streaming DataFrames.
HDFS, databases, console; support idempotent writes.
State recovery for fault tolerance.
Key Features
Guaranteed with idempotent sinks and offsets.
Handles late data with watermarks.
Millisecond latency for supported operations.
Same code for batch and streaming.
Hands-On Examples (PySpark Structured Streaming)
from pyspark.sql.functions import explode, split
lines = spark.readStream.format("socket").option("host", "localhost").option("port", 9999).load()
words = lines.select(explode(split(lines.value, " ")).alias("word"))
query = words.writeStream.outputMode("append").format("console").start()wordCounts = words.groupBy("word").count()
query = wordCounts.writeStream.outputMode("complete").format("console").start()from pyspark.sql.functions import window, current_timestamp
lines = lines.withColumn("timestamp", current_timestamp())
windowedCounts = lines.groupBy(
window("timestamp", "10 minutes", "5 minutes"),
"word"
).count().withWatermark("timestamp", "10 minutes")
query = windowedCounts.writeStream.outputMode("update").format("console").start()4. MLlib: Machine Learning Library
MLlib is Spark's scalable machine learning library, providing algorithms for classification, regression, clustering, and more. It leverages Spark's distributed nature for training on massive datasets, with pipelines for workflow management.
Architecture Overview
Integrated with DataFrames:
LogisticRegression, DecisionTrees, KMeans, etc.
Stages for feature extraction, transformation, modeling.
CrossValidator, TrainValidationSplit.
Save/load models for deployment.
Key Features
Distributed training on clusters.
VectorAssembler, StringIndexer, etc.
Integration with TensorFlow, PyTorch via sparkdl.
Export to PMML or use Spark ML serving.
Hands-On Examples (PySpark MLlib)
from pyspark.ml.regression import LinearRegression from pyspark.ml.linalg import Vectors data = [(Vectors.dense([1.0]), 2.0), (Vectors.dense([2.0]), 4.0)] df = spark.createDataFrame(data, ["features", "label"]) lr = LinearRegression().fit(df) print(lr.coefficients)
from pyspark.ml.clustering import KMeans data = [(Vectors.dense([0.0, 0.0]),), (Vectors.dense([1.0, 1.0]),), (Vectors.dense([9.0, 9.0]),)] df = spark.createDataFrame(data, ["features"]) kmeans = KMeans(k=2).fit(df) print(kmeans.clusterCenters())
from pyspark.ml import Pipeline from pyspark.ml.tuning import CrossValidator, ParamGridBuilder from pyspark.ml.evaluation import RegressionEvaluator lr = LinearRegression() pipeline = Pipeline(stages=[lr]) paramGrid = ParamGridBuilder().addGrid(lr.maxIter, [10, 20]).build() cv = CrossValidator(estimator=pipeline, estimatorParamMaps=paramGrid, evaluator=RegressionEvaluator(), numFolds=2) cvModel = cv.fit(df) print(cvModel.bestModel.stages[0].extractParamMap())
5. GraphX: Graph Computation
GraphX is Spark's API for graphs and graph-parallel computation, unifying graph processing with general data processing. It extends RDDs to Property Graphs with vertices and edges having properties.
Architecture Overview
Built on RDDs with:
RDD of vertices and edges with properties.
Subgraph, joinVertices, aggregateMessages.
PageRank, ConnectedComponents, TriangleCount.
Bulk-synchronous parallel message passing.
Key Features
EdgeTriplets, VertexRDD, EdgeRDD.
VertexCut, EdgePartition2D for efficiency.
Support for evolving graphs over time.
Seamless with other Spark components.
Hands-On Examples (PySpark GraphFrames - Modern Alternative)
Note: GraphX is Scala-only; in PySpark, use GraphFrames for similar functionality.
from graphframes import GraphFrame
vertices = spark.createDataFrame([("a", "Alice"), ("b", "Bob")], ["id", "name"])
edges = spark.createDataFrame([("a", "b", "friend")], ["src", "dst", "relationship"])
g = GraphFrame(vertices, edges)
g.vertices.show()┌────┬───────┐ │ id │ name │ ├────┼───────┤ │ a │ Alice │ │ b │ Bob │ └────┴───────┘
g.degrees.show()
┌────┬────────┐ │ id │ degree │ ├────┼────────┤ │ a │ 1 │ │ b │ 1 │ └────┴────────┘
results = g.pageRank(resetProbability=0.15, maxIter=10)
results.vertices.select("id", "pagerank").show()┌────┬──────────┐ │ id │ pagerank │ ├────┼──────────┤ │ a │ 0.5 │ │ b │ 0.5 │ └────┴──────────┘
6. Broader Spark Ecosystem & Integrations
Spark's ecosystem includes tools and integrations that extend its capabilities.
ACID transactions on data lakes, time travel, schema enforcement.
Native K8s scheduler for dynamic scaling.
Pandas-like API on Spark for familiarity.
Runs on YARN, reads/writes HDFS.
Structured Streaming with Kafka for reliable ingestion.
Tracking, packaging, deploying ML models.
Bonus: Real-Time Fraud Detection with PySpark Structured Streaming
Every streaming concept from this lesson: Structured Streaming, Kafka source, tumbling windows, sliding windows, watermarks, late-data handling, and exactly-once checkpointing, is demonstrated in a production-grade banking fraud detection project. Two concurrent PySpark jobs consume from Kafka, enrich each micro-batch with reference data via stream-batch broadcast joins, score transactions against weighted fraud rules, and write results to Delta Lake(local filesystem or MinIO S3-compatible). A Streamlit dashboard reads the Delta tables and auto-refreshes every few seconds.
Streaming features demonstrated:
- Job 1: fraud_detection: 100 msg/s Kafka source, 10-min watermark, stream-batch broadcast join against 10k-row customer and merchant-blacklist tables, weighted fraud scoring (6 rules, score threshold 0.35), Delta append to
enriched_transactionsandfraud_alerts, Delta upsert towindow_aggregates - Job 2: account_risk: 30-min / 5-min sliding window of failed logins, 15-min watermark, tier-weighted risk scores, Delta upsert with merge keys for idempotent restarts; uses
outputMode("update")to emit only changed windows - Late-data handling in practice: the transaction producer deliberately injects 10% of events 8 minutes late; both watermarks are tuned to process them while dropping events that arrive beyond the tolerance window
# Prerequisites: Docker + Compose, Python 3.12+, Java 21 LTS
# (Java 24+ breaks PySpark 4.x – use Java 21)
git clone https://gitlab.com/bytecode-solutions/examples/pyspark-streaming-processing
cd pyspark-streaming-processing
pip install -e ".[dev]" # pyspark, delta-spark, confluent-kafka, streamlit, plotly …
make up # Kafka, Postgres, MinIO, Spark cluster, Kafka UI
make init-data # generates 10k customers + blacklist, seeds Postgres
# Terminal A: transaction producer (100 msg/s, 5% fraud, 10% late events)
make producer-transactions
# Terminal B: account event producer (30 msg/s, 3% credential-stuffing bursts)
make producer-accounts
# Terminal C: Job 1 – fraud detection pipeline
make job-fraud
# Terminal D: Job 2 – account risk scorer (optional, runs independently)
make job-accounts
# Streamlit dashboard → http://localhost:8501
make dashboard
# Query Delta Lake output from an interactive Spark shell
make spark-shell
# >>> spark.read.format("delta").load("data/delta/fraud_alerts") \
# ... .select("transaction_id","account_id","amount","fraud_score") \
# ... .show(10, truncate=False)
# Tests (no Kafka or Docker required)
make test-unit # fast pytest, no JVM
make test-integration # local[2] Spark + file fixturesKey Takeaways
- Spark Core provides RDDs for low-level, resilient distributed processing.
- Spark SQL offers optimized structured data handling with DataFrames and Catalyst.
- Structured Streaming unifies batch and stream processing with exactly-once guarantees.
- MLlib enables scalable ML with pipelines and distributed algorithms.
- GraphX/GraphFrames handle graph computations efficiently.
- Spark's ecosystem integrates with data lakes, clusters, and tools for end-to-end analytics.
What's Next?
With Spark fundamentals mastered, explore advanced topics like data storage architectures in the next lesson.