Free Interactive Course · Spark + Scala

Spark with Scala — The Functions Handbook

Learn every Spark DataFrame function by running it. Each function gets a plain-English definition, its full signature, and the N ways to actually use it — with editable, runnable examples. Pick a module on the left, or start at Foundations.

The dataset

Every example in this course runs against the same two small DataFrames. Learn them once; you'll see them everywhere.

peopleid, name, country, age, signup_date
ordersid, user_id, product, category, amount, qty, status, ordered_at
0.1

SparkSession — your entry point

Everything in the DataFrame API starts from a SparkSession. In a notebook (Databricks) or spark-shell it already exists as spark. In an sbt/IntelliJ app you build it yourself:

Scala
import org.apache.spark.sql.SparkSession

val spark = SparkSession.builder
  .appName("functions-handbook")
  .master("local[*]")   // remove in production; the cluster sets this
  .getOrCreate()

import spark.implicits._   // enables $"col" and .toDF(...)
That last line — import spark.implicits._ — is what makes $"name" and Seq(...).toDF(...) compile. Forget it and you'll get "value $ is not a member of StringContext". It's the #1 beginner error.
0.2

What a DataFrame is

A DataFrame is a distributed table: named, typed columns and lazily-evaluated rows spread across the cluster. It's an alias for Dataset[Row]. Nothing runs until an action (like show() or collect()) forces it — transformations just build a plan.

The SQL you run in the cells on this page is that same plan, executed in a tiny SQLite engine inside your browser so you can see real output instantly. The Scala on top is the exact DataFrame API you'd write against Spark.

0.3

Creating DataFrames — every way

You'll create DataFrames four common ways. First, spark.range(n) — a one-column DataFrame of id from 0 to n-1, perfect for quick experiments:

Signature
def range(end: Long): Dataset[Row]
def range(start: Long, end: Long): Dataset[Row]
def range(start: Long, end: Long, step: Long): Dataset[Row]
Scala
spark.range(5).show()
spark.range(5) → ids 0..4
id
0
1
2
3
4
baked output — Spark-only type, not runnable in the browser engine

Second, from a Scala Seq of tuples with toDF — the fastest way to hand-build test data:

Scala
val people = Seq(
  (1, "Aisha", "India",  29, "2025-02-11"),
  (2, "Rohan", "India",  34, "2024-11-03"),
  (3, "Mia",   "USA",    41, "2025-06-20"),
  (4, "Liam",  "UK",     23, "2025-01-08"),
  (5, "Noah",  "Canada", 37, "2024-08-15")
).toDF("id", "name", "country", "age", "signup_date")

people.show()
Run the equivalent Spark SQL — edit it and press Run
SQL
⌘/Ctrl + Enter

Third, with an explicit StructType schema when you need exact types (and control over nullability) instead of letting Spark infer them:

Scala
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row

val schema = StructType(Seq(
  StructField("id",      IntegerType, nullable = false),
  StructField("name",    StringType,  nullable = true),
  StructField("country", StringType,  nullable = true),
  StructField("age",     IntegerType, nullable = true)
))

val rows = Seq(Row(1, "Aisha", "India", 29), Row(2, "Rohan", "India", 34))
val df = spark.createDataFrame(spark.sparkContext.parallelize(rows), schema)
df.printSchema()
printSchema() output
schema
root
|-- id: integer (nullable = false)
|-- name: string (nullable = true)
|-- country: string (nullable = true)
|-- age: integer (nullable = true)
baked output — Spark-only type, not runnable in the browser engine

Fourth — how you'll actually load data in production — from files: spark.read.csv / json / parquet. Give it a schema or ask it to infer one:

Scala
val orders = spark.read
  .option("header", "true")
  .option("inferSchema", "true")
  .csv("s3://bucket/orders/")

// or, columnar + schema baked in:
val o2 = spark.read.parquet("s3://bucket/orders_parquet/")
inferSchema makes Spark read the file twice and it often guesses wrong (dates become strings, ints become doubles). For anything real, pass an explicit schema(...) or use a self-describing format like Parquet. We go deep on this in the Parquet vs ORC vs Avro guide.
0.4

Inspecting a DataFrame

Four things you'll reach for constantly: show() to print rows, printSchema() for column types, .schema / .dtypes to inspect programmatically, and .columns for the names.

Scala
orders.show(3, truncate = false)
orders.printSchema()
orders.columns          // Array[String]
orders.dtypes           // Array[(String, String)]
Run the equivalent Spark SQL — edit it and press Run
SQL
⌘/Ctrl + Enter
show() defaults to 20 rows and truncates cells to 20 chars — pass show(50, truncate = false) when a column gets cut off. It's an action: it triggers a real job, so don't sprinkle it through production code.

Ready for the full data stack?

These Spark functions are one piece. When you want pipelines, Kafka, lakehouse table formats, and a full end-to-end project, the Data Engineering course is free too.

Explore Data Engineering →

Comments

0

Join the conversation. Sign in to leave a comment — questions and feedback welcome.