Skip to main content
Articles/Python/rdds-vs-dataframes-spark-api-evolution
Series: Data Engineering & Spark Masteryβ€’Part 7 of 19
Scenario Article

RDDs vs DataFrames vs Datasets: Understanding the Evolution of Spark APIs

Concept: The Evolution of Apache Spark APIs

Abstract Algorithmsβ€’Jun 18, 2026
XLinkedInReddit
πŸ’‘ Executive Summary

Apache Spark has evolved from low-level RDDs (Resilient Distributed Datasets) to highly optimized DataFrames and Datasets.

🎯 System Scenario & Requirements

System Goal

Apache Spark has evolved from low-level RDDs (Resilient Distributed Datasets) to highly optimized DataFrames and Datasets.

Actors & Components

  • Application or API tier
  • Core service under design
  • Operator or SRE observer

Functional Requirements

  • TLDR: Apache Spark has evolved from low-level RDDs (Resilient Distributed Datasets) to highly optimized DataFrames and Datasets.
  • RDDs offer functional control but miss engine-level optimization.
  • DataFrames use Spark's Catalyst Optimizer to compile declarative queries into high-performance JVM bytecode.

Constraints & Assumptions

  • Constraints are derived from the rebuilt scenario stages.

⚑ Execution Stages & Decision Trace

1

Stage 1 β€” Basics: RDDs, DataFrames, and Datasets

Action / Decision:

Choosing the correct API requires understanding their compile-time characteristics and memory representations: 1.

Component Behavior:

Resilient Distributed Dataset (RDD) The low-level API of Spark.

Observable Output: RDDs represent collections of JVM objects.
Read Full Stage in Deep Dive ↓
πŸ“–

Deep Dive

Detailed Architectural Analysis

Scenario context

Apache Spark has evolved from low-level RDDs (Resilient Distributed Datasets) to highly optimized DataFrames and Datasets. RDDs offer functional control but miss engine-level optimization. DataFrames use Spark's Catalyst Optimizer to compile declarative queries into high-performance JVM bytecode. This guide traces their differences and compares their execution paths with runnable PySpark examples.


To truly und…

This walkthrough focuses on Concept: The Evolution of Apache Spark APIs.

Before making a design choice, clarify:

  • To truly understand why Apache Spark has evolved through several iterations of APIs, we must first look back at the limitations of the classic Hadoop MapReduce programming model.
  • In the early days of big data engineering, MapReduce was the primary tool for distributed computations.
  • It split work into rigid map and reduce tasks.

Concepts in play: spark-data-engineering, jvm-internals-and-garbage-collection, tree-data-structures, circuit-breaker

Stage 1 β€” Basics: RDDs, DataFrames, and Datasets

  • Choosing the correct API requires understanding their compile-time characteristics and memory representations: 1.
  • Resilient Distributed Dataset (RDD) The low-level API of Spark.
  • RDDs represent collections of JVM objects.
  • They are strongly typed (e.g., RDD[User] in Scala), meaning they catch type errors at compile time.

Observable outcome: They are strongly typed (e.g., RDD[User] in Scala), meaning they catch type errors at compile time.

Stage 2 β€” Mechanics: Under the Hood of the Catalyst Optimizer

  • The primary reason to choose DataFrames and Datasets over raw RDDs is the query optimization pipeline managed by the Catalyst Optimizer .
  • The Catalyst Optimizer is an extensible query planning framework that automatically optimizes relational execution paths.
  • When you write a declarative DataFrame expression, Spark does not execute it immediately.
  • Instead, the query passes through the following optimization pipeline: 1.

Observable outcome: Instead, the query passes through the following optimization pipeline: 1.

Stage 3 β€” Flow: Spark Query Optimization Pipeline

  • The flowchart below visualizes the transition steps of a query through the Catalyst Optimizer and Tungsten code generation: To illustrate, suppose we execute the following query: df.filter(df("age") 21).select("name") T…
graph TD
    Query[User DataFrame/SQL Query] -->|Parse| ULP[Unresolved Logical Plan]
    ULP -->|Analysis & Catalog Lookup| RLP[Resolved Logical Plan]
    RLP -->|Catalyst Optimization Rules| OLP[Optimized Logical Plan]
    OLP -->|Physical Planning Cost Model| Phys[Physical Execution Plan]
    Phys -->|Code Generation Janino| Byte[Optimized JVM Bytecode]

Observable outcome: The flowchart below visualizes the transition steps of a query through the Catalyst Optimizer and Tungsten code generation: To illustrate, suppose we execute the following query: df.filter(df("age") 21).select("name") T…

End-to-end outcome

After working through the stages, you should be able to explain:

  • Incorrect Object Serialization in Python RDDs: Python RDD transformations require serializing Python objects (using Pickle) and passing them back and forth between the Python process and the JVM executor process via a P…
  • This serialization bridge is extremely slow.
  • RDDs (Resilient Distributed Datasets): Immutable, partitioned, low-level functional API.
  • DataFrames: Schema-aware, tabular abstraction.

Alternatives considered

Applications: When to Use RDDs vs. DataFrames

Unstructured Data Processing: Use RDDs when processing raw, unstructured binary data (like raw video files, image streams, or raw network socket text) where schemas are impossible to define.

Practical Implementation: Side-by-Side Code Comparison

Here is a complete, runnable PySpark script showing a side-by-side processing flow: performing a group-by aggregation using RDD functional APIs vs.

Failure and degraded modes

The source does not isolate a separate failure mode. Limits that matter for the scenario are called out in the stage decisions above.

Share this case study

Discuss architecture trade-offs and lessons with your team.

Share:XLinkedInReddit