Apache Spark 4 in 2026: Nieuwe Functies, Structured Streaming en Sollicitatievragen
Uitgebreide gids over Apache Spark 4 met ANSI SQL, VARIANT datatype, Real-Time Mode streaming, Spark Connect en declaratieve pipelines. Inclusief veelgestelde sollicitatievragen voor data engineering.

Apache Spark 4 vertegenwoordigt de meest ingrijpende herziening van het framework sinds de overgang van Spark 2 naar 3. Met de release van versie 4.0.0 in mei 2025, gevolgd door 4.1.0 in december 2025 en de eerste preview van 4.2 in februari 2026, beschikken data engineers over een fundamenteel vernieuwd platform voor grootschalige dataverwerking. De wijzigingen raken vrijwel elk onderdeel van het ecosysteem: van SQL-semantiek en semi-gestructureerde datatypes tot streaming-architectuur en client-server connectiviteit.
Dit artikel analyseert de belangrijkste vernieuwingen in Spark 4, demonstreert de praktische toepassing aan de hand van productiecode en behandelt de meest voorkomende sollicitatievragen die data engineering kandidaten over deze technologie kunnen verwachten.
Apache Spark 4.0.0 verscheen in mei 2025 met ANSI SQL standaard aan, VARIANT datatype en Spark Connect GA. Versie 4.1.0 (december 2025) introduceerde Real-Time Mode streaming en Spark Declarative Pipelines. De preview van Spark 4.2 (februari 2026) voegt verbeterde Python-ondersteuning en uitgebreidere VARIANT-functies toe.
ANSI SQL-modus standaard ingeschakeld
Een van de meest impactvolle wijzigingen in Spark 4 is de activering van ANSI SQL-modus als standaardinstelling. In voorgaande versies retourneerde een ongeldige cast stilzwijgend NULL, wat leidde tot moeilijk traceerbare datakwaliteitsproblemen in productieomgevingen. Spark 4 gooit nu een ArithmeticException of SparkException bij ongeldige type-conversies, deling door nul en vergelijkbare operaties.
Deze verandering heeft directe gevolgen voor bestaande codebases. Queries die eerder foutieve data stilzwijgend accepteerden, genereren nu runtime-fouten. De aanbevolen migratiestrategie maakt gebruik van TRY_CAST en gerelateerde TRY_*-functies die het oude NULL-gedrag behouden waar dat gewenst is.
# ansi_mode_migration.py
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, try_cast
spark = SparkSession.builder.appName("ANSIMigration").getOrCreate()
# This now throws ArithmeticException in Spark 4 ANSI mode
# SELECT CAST('abc' AS INT) -- runtime error
# Safe migration: use TRY_CAST to preserve NULL behavior
df = spark.sql("""
SELECT
TRY_CAST(raw_value AS INT) AS parsed_value,
TRY_CAST(amount AS DECIMAL(10,2)) AS safe_amount
FROM raw_events
WHERE TRY_CAST(raw_value AS INT) IS NOT NULL
""")
# Alternatively, wrap arithmetic in try_divide / try_add
result = df.withColumn(
"ratio",
col("safe_amount") / col("parsed_value") # throws on zero
)Voor teams die een grootschalige migratie moeten uitvoeren, is het raadzaam om eerst de configuratie spark.sql.ansi.enabled tijdelijk op false te zetten, vervolgens de codebase systematisch te doorlopen met TRY_CAST-vervanging, en daarna de ANSI-modus definitief te activeren. Deze gefaseerde aanpak minimaliseert het risico op productiestoringen.
VARIANT Datatype voor semi-gestructureerde data
Het nieuwe VARIANT datatype lost een langdurig knelpunt op in het Spark-ecosysteem: de efficiënte opslag en bevraging van semi-gestructureerde data zoals JSON, Avro en Protobuf. In tegenstelling tot de traditionele aanpak met string-kolommen en from_json(), slaat VARIANT de data op in een geoptimaliseerd binair formaat met automatische shredding van veelgebruikte velden.
De prestatieverbetering is aanzienlijk. Waar het parsen van JSON-strings bij elke query opnieuw plaatsvond, maakt VARIANT gebruik van kolomgebaseerde extractie die vergelijkbaar is met het lezen van native Parquet-kolommen. Benchmarks tonen snelheidsverbeteringen van 3x tot 10x voor typische analytische queries op geneste JSON-structuren.
import org.apache.spark.sql.SparkSession
val spark = SparkSession.builder.appName("VariantDemo").getOrCreate()
import spark.implicits._
// Create a table with VARIANT column
spark.sql("""
CREATE TABLE events (
event_id BIGINT,
timestamp TIMESTAMP,
payload VARIANT
) USING PARQUET
""")
// Insert JSON data — automatically converted to VARIANT
spark.sql("""
INSERT INTO events VALUES
(1, current_timestamp(),
PARSE_JSON('{"user_id": 42, "action": "click", "metadata": {"page": "/home", "duration_ms": 320}}')),
(2, current_timestamp(),
PARSE_JSON('{"user_id": 87, "action": "purchase", "metadata": {"item_id": "SKU-9001", "amount": 49.99}}'))
""")
// Query nested fields with dot notation — uses shredding for fast access
val clicks = spark.sql("""
SELECT
event_id,
payload:user_id::INT AS user_id,
payload:action::STRING AS action,
payload:metadata.page::STRING AS page
FROM events
WHERE payload:action::STRING = 'click'
""")
clicks.show()De dot-notatie (payload:metadata.page::STRING) biedt een intuïtieve syntax voor het navigeren door geneste structuren. Het schema hoeft niet vooraf gedefinieerd te worden, wat VARIANT bijzonder geschikt maakt voor event-driven architecturen waar het payload-formaat regelmatig evolueert.
Real-Time Mode Streaming in Spark 4.1
Spark Structured Streaming was traditioneel geoptimaliseerd voor micro-batch verwerking met latenties van seconden tot minuten. Spark 4.1 introduceert Real-Time Mode (RTM), een nieuwe verwerkingsmodus die sub-seconde end-to-end latentie bereikt zonder de schaalbaarheidsvoordelen van Spark op te offeren.
RTM wijzigt de interne scheduling-architectuur door de batchplanningsoverhead te elimineren. In plaats van het groeperen van records in micro-batches, verwerkt RTM individuele records zodra deze beschikbaar komen uit de bron. De Kafka-connector profiteert het meest van deze optimalisatie, met gemeten latenties van 50-200 milliseconden voor typische verwerkingspipelines.
# real_time_streaming.py
from pyspark.sql import SparkSession
from pyspark.sql.functions import from_json, col, window
from pyspark.sql.types import StructType, StructField, StringType, DoubleType, TimestampType
spark = SparkSession.builder \
.appName("RTMDemo") \
.config("spark.sql.streaming.mode", "realtime") \
.getOrCreate()
schema = StructType([
StructField("sensor_id", StringType()),
StructField("temperature", DoubleType()),
StructField("event_time", TimestampType())
])
# Read from Kafka with Real-Time Mode enabled
raw_stream = spark.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "broker:9092") \
.option("subscribe", "sensor-readings") \
.option("startingOffsets", "latest") \
.load()
parsed = raw_stream \
.select(from_json(col("value").cast("string"), schema).alias("data")) \
.select("data.*")
# Write to Kafka sink — sub-second end-to-end
query = parsed \
.filter(col("temperature") > 80.0) \
.writeStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "broker:9092") \
.option("topic", "alerts") \
.option("checkpointLocation", "/tmp/checkpoints/alerts") \
.start()
query.awaitTermination()Belangrijk om op te merken is dat RTM niet elke workload vervangt. Voor aggregaties over grote tijdvensters en schrijfbewerkingen naar bestandssystemen zoals Delta Lake blijft de klassieke micro-batch modus efficienter. RTM is primair ontworpen voor event-driven toepassingen zoals alertering, fraud detection en real-time personalisatie.
Spark Connect en de lichtgewicht PySpark-client
Spark Connect, geintroduceerd als experimentele functie in Spark 3.4, bereikt met Spark 4 de status van General Availability. Deze architectuurwijziging scheidt de Spark-client van de server door middel van een gRPC-protocol, waardoor PySpark-applicaties kunnen draaien zonder lokale JVM-installatie.
De praktische implicaties zijn aanzienlijk. Data scientists kunnen vanuit een lichtgewicht Python-omgeving verbinding maken met een Spark-cluster zonder de complexiteit van een volledige Spark-installatie. De client-bibliotheek is minder dan 10 MB groot en installeerbaar via een simpele pip install pyspark[connect].
# spark_connect_client.py
from pyspark.sql import SparkSession
# Connect to remote Spark cluster — no local JVM needed
spark = SparkSession.builder \
.remote("sc://spark-cluster.internal:15002") \
.getOrCreate()
# Full DataFrame API available through thin client
df = spark.read.parquet("s3a://data-lake/events/2026/")
aggregated = df.groupBy("country", "event_type") \
.count() \
.orderBy("count", ascending=False)
aggregated.show(20)Spark Connect verbetert tevens de multi-tenancy van Spark-clusters. Meerdere gebruikers kunnen geisoleerde sessies draaien op dezelfde server, elk met eigen resource-limieten en autorisatieregels. Voor organisaties die hun data platform centraliseren, biedt dit een schaalbaar model voor het ontsluiten van Spark-capaciteit naar diverse teams.
Klaar om je Data Engineering gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
transformWithState API voor complexe streaminglogica
De bestaande mapGroupsWithState en flatMapGroupsWithState API's kenden beperkingen op het gebied van state management: handmatig beheer van TTL (time-to-live), complexe serialisatie en beperkte ondersteuning voor meerdere state-variabelen per sleutel. De nieuwe transformWithState API in Spark 4 lost deze problemen op met een declaratief state-model.
De StatefulProcessor interface biedt ValueState, ListState en MapState primitieven met ingebouwde TTL-configuratie. Wanneer een state-entry de geconfigureerde TTL overschrijdt, wordt deze automatisch opgeruimd zonder dat de ontwikkelaar hiervoor timer-logica hoeft te implementeren.
import org.apache.spark.sql.streaming._
import org.apache.spark.sql.streaming.StatefulProcessor
import java.time.Duration
case class UserEvent(userId: String, action: String, timestamp: Long)
case class SessionSummary(userId: String, actionCount: Int, durationMs: Long)
class SessionProcessor extends StatefulProcessor[String, UserEvent, SessionSummary] {
// ValueState with 30-minute TTL — auto-cleanup of idle sessions
@transient private var sessionStart: ValueState[Long] = _
@transient private var actionCount: ValueState[Int] = _
override def init(outputMode: OutputMode, timeMode: TimeMode): Unit = {
sessionStart = getHandle.getValueState[Long]("start", TTLConfig(Duration.ofMinutes(30)))
actionCount = getHandle.getValueState[Int]("count", TTLConfig(Duration.ofMinutes(30)))
}
override def handleInputRows(
key: String,
rows: Iterator[UserEvent],
timerValues: TimerValues
): Iterator[SessionSummary] = {
rows.flatMap { event =>
if (!sessionStart.exists()) {
sessionStart.update(event.timestamp)
actionCount.update(1)
Iterator.empty
} else {
val count = actionCount.get() + 1
actionCount.update(count)
// Emit summary every 10 actions
if (count % 10 == 0) {
val duration = event.timestamp - sessionStart.get()
Iterator(SessionSummary(key, count, duration))
} else Iterator.empty
}
}
}
}Het bovenstaande voorbeeld demonstreert sessietracking met automatische opruiming na 30 minuten inactiviteit. De ValueState met TTL-configuratie elimineert de noodzaak voor aangepaste timer-logica die in eerdere Spark-versies handmatig beheerd moest worden. Dit patroon is bijzonder relevant voor fraud detection, gebruikersanalyse en IoT-dataverwerking.
Spark Declarative Pipelines (SDP) in Spark 4.1
Spark 4.1 introduceert Spark Declarative Pipelines (SDP), een framework voor het definieren van data-transformaties als declaratieve grafiekstructuren in plaats van imperatieve scripts. Het concept is vergelijkbaar met dbt-modellen of Delta Live Tables, maar dan native geintegreerd in het Spark-framework zelf.
Bij SDP definieert de ontwikkelaar datasets als functies met de @spark.declarative.table decorator. Spark analyseert de afhankelijkheden tussen deze functies automatisch, construeert een optimale uitvoerings-DAG en beheert retries en foutherstel. Dit elimineert de noodzaak voor externe orchestratietools bij eenvoudige tot middelgrote pipelines.
# declarative_pipeline.py
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, sum as _sum, current_date
spark = SparkSession.builder.appName("SDP-Demo").getOrCreate()
# Define datasets declaratively — Spark resolves dependencies
@spark.declarative.table("clean_orders")
def clean_orders():
return spark.read.table("raw_orders") \
.filter(col("status") != "cancelled") \
.filter(col("amount") > 0)
@spark.declarative.table("daily_revenue")
def daily_revenue():
return spark.read.table("clean_orders") \
.groupBy("order_date", "region") \
.agg(_sum("amount").alias("total_revenue"))
@spark.declarative.table("revenue_summary")
def revenue_summary():
return spark.read.table("daily_revenue") \
.groupBy("region") \
.agg(_sum("total_revenue").alias("grand_total")) \
.orderBy("grand_total", ascending=False)
# Execute — Spark builds the DAG, parallelizes, handles retries
spark.declarative.run()SDP brengt het medallion-architectuurpatroon (bronze-silver-gold) naar het hart van Spark. Elke laag wordt als een onafhankelijke declaratieve tabel gedefinieerd, waarbij Spark de uitvoeringsvolgorde en parallellisatie automatisch optimaliseert. Voor teams die momenteel Airflow of Prefect gebruiken voor eenvoudige lineaire pipelines, biedt SDP een lichtgewicht alternatief dat de operationele complexiteit reduceert.
Sollicitatievragen over Apache Spark 4
De volgende vragen verschijnen frequent in technische interviews voor data engineering posities. Elk antwoord behandelt zowel de technische details als de achterliggende ontwerpbeslissingen die interviewers verwachten.
Vraag 1: Wat is de impact van ANSI SQL-modus op bestaande Spark-applicaties?
ANSI SQL-modus, standaard ingeschakeld in Spark 4, wijzigt het foutafhandelingsgedrag van type-conversies en rekenkundige operaties. Waar CAST('abc' AS INT) voorheen NULL retourneerde, gooit Spark 4 een runtime-exception. Migratie vereist het vervangen van CAST door TRY_CAST op plaatsen waar NULL-gedrag gewenst is, en het toevoegen van expliciete foutafhandeling voor rekenkundige operaties met try_divide en try_add.
Vraag 2: Hoe verschilt het VARIANT datatype van het opslaan van JSON als string?
VARIANT slaat semi-gestructureerde data op in een geoptimaliseerd binair formaat met automatische shredding van veelgebruikte velden. Dit elimineert het herhaaldelijk parsen van JSON bij elke query. Veelgeraadpleegde velden worden automatisch als native kolommen opgeslagen (shredding), waardoor leesoperaties vergelijkbaar presteren met native Parquet-kolommen. STRING-gebaseerde JSON vereist deserialisatie bij elke query, wat 3x tot 10x langzamer is voor analytische workloads.
Vraag 3: Wanneer kiest een team voor Real-Time Mode versus micro-batch streaming?
Real-Time Mode is geschikt voor toepassingen met sub-seconde latentie-eisen: alertering, fraud detection en real-time personalisatie. Micro-batch blijft de voorkeur voor aggregaties over grote tijdvensters, schrijfbewerkingen naar bestandsformaten (Delta Lake, Iceberg) en workloads waar doorvoer belangrijker is dan latentie. RTM verbruikt meer resources per record vanwege de afwezigheid van batch-amortisatie.
Vraag 4: Wat zijn de voordelen van Spark Connect voor de architectuur van een data platform?
Spark Connect introduceert een client-server scheiding via gRPC, waardoor PySpark-clients draaien zonder lokale JVM. Dit verbetert multi-tenancy (geisoleerde sessies met eigen resource-limieten), vereenvoudigt het onboarden van data scientists (lichtgewicht pip-installatie), en maakt taalkundige decoupling mogelijk: de server kan upgraden zonder dat clients wijzigingen nodig hebben.
Vraag 5: Hoe verbetert transformWithState ten opzichte van flatMapGroupsWithState?
transformWithState biedt getypeerde state-primitieven (ValueState, ListState, MapState) met ingebouwde TTL. De oude API vereiste handmatige state-serialisatie, custom timer-management voor opruiming en was beperkt tot een enkele state-structuur per sleutel. De nieuwe API ondersteunt meerdere onafhankelijke state-variabelen per sleutel, automatische TTL-gebaseerde opruiming en verbeterde schema-evolutie van state-data.
Bij vragen over Spark 4 verwachten interviewers niet alleen kennis van de nieuwe functies, maar ook inzicht in de migratiestrategie. Bereid concrete voorbeelden voor van hoe bestaande code aangepast moet worden, met name rond ANSI SQL-modus en de overgang van flatMapGroupsWithState naar transformWithState.
Kandidaten verwarren regelmatig Real-Time Mode met Continuous Processing (geintroduceerd in Spark 2.3). Continuous Processing is deprecated in Spark 4 en wordt vervangen door RTM. Het verschil: RTM behoudt compatibiliteit met het volledige Structured Streaming API-oppervlak, terwijl Continuous Processing beperkte operator-ondersteuning had.
Een complete Spark 4 ETL-pipeline bouwen
Het volgende voorbeeld combineert meerdere Spark 4-functies in een productieklare ETL-pipeline die het medallion-patroon (bronze-silver-gold) implementeert. De pipeline leest ruwe events uit Kafka, parseert VARIANT-payloads naar getypeerde kolommen en schrijft de resultaten naar Delta Lake.
Deze architectuur demonstreert hoe ANSI SQL-modus, VARIANT en streaming samenwerken in een realistisch scenario. De bronzelaag behoudt de ruwe data in VARIANT-formaat voor maximale flexibiliteit. De zilverlaag extraheert en typeert specifieke velden met expliciete NULL-controles die door ANSI-modus worden afgedwongen. De goudlaag schrijft het eindresultaat weg in Delta Lake met schema-evolutie.
# spark4_etl_pipeline.py
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, from_json, current_timestamp, parse_json
spark = SparkSession.builder \
.appName("Spark4ETL") \
.config("spark.sql.ansi.enabled", "true") \
.getOrCreate()
# Bronze: raw ingestion from Kafka
bronze = spark.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "broker:9092") \
.option("subscribe", "user-events") \
.load() \
.select(
col("key").cast("string").alias("event_key"),
parse_json(col("value").cast("string")).alias("payload"),
col("timestamp").alias("kafka_ts")
)
# Silver: extract typed fields from VARIANT
silver = bronze.select(
col("event_key"),
col("payload:user_id").cast("int").alias("user_id"),
col("payload:action").cast("string").alias("action"),
col("payload:metadata.session_id").cast("string").alias("session_id"),
col("kafka_ts"),
current_timestamp().alias("processed_at")
).filter(
col("user_id").isNotNull() # ANSI mode makes this explicit
)
# Gold: write to Delta Lake with schema enforcement
query = silver.writeStream \
.format("delta") \
.outputMode("append") \
.option("checkpointLocation", "s3a://checkpoints/user-events/") \
.option("mergeSchema", "true") \
.toTable("gold.user_events")
query.awaitTermination()Dit patroon is direct toepasbaar in productieomgevingen en vormt een uitstekend startpunt voor het opzetten van een modern data platform met Spark 4. De combinatie van streaming-ingestie, VARIANT-verwerking en Delta Lake-opslag biedt een robuuste basis die meeschaalt met groeiende datavolumes.
Conclusie
Apache Spark 4 markeert een keerpunt in het data engineering landschap. De combinatie van verbeterde SQL-semantiek, native ondersteuning voor semi-gestructureerde data en fundamenteel vernieuwde streaming-architectuur biedt data engineers een krachtiger en consistenter platform.
De belangrijkste ontwikkelingen samengevat:
- ANSI SQL standaard aan: Strengere type-controles voorkomen stilzwijgende datafouten en verbeteren de datakwaliteit in productieomgevingen
- VARIANT datatype: Efficiënte opslag en bevraging van semi-gestructureerde data met automatische shredding en 3-10x prestatieverbetering
- Real-Time Mode: Sub-seconde streaming-latentie voor event-driven toepassingen zonder concessies aan schaalbaarheid
- Spark Connect GA: Client-server scheiding via gRPC voor lichtgewicht PySpark-clients en verbeterde multi-tenancy
- transformWithState: Declaratief state management met ingebouwde TTL en ondersteuning voor meerdere state-variabelen
- Declarative Pipelines: Native DAG-gebaseerde pipeline-definitie die de operationele complexiteit van externe orchestratietools reduceert
Voor data engineering professionals is grondige kennis van deze vernieuwingen essentieel, zowel voor dagelijkse werkzaamheden als voor technische interviews. De verschuiving naar strengere SQL-semantiek, efficiëntere dataverwerking en vereenvoudigde architectuurpatronen weerspiegelt de volwassenwording van het Spark-ecosysteem als industriestandaard voor grootschalige dataverwerking.
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Tags
Delen
Gerelateerde artikelen

Apache Spark met Python: datapijplijnen stap voor stap bouwen
Een praktische PySpark-tutorial over DataFrame-operaties, de opbouw van ETL-pijplijnen en de functies van Spark 4.0. Met productie-klare codevoorbeelden voor data engineers die zich voorbereiden op technische interviews.

Apache Kafka voor Data Engineers: Streaming, Partities en Interviewvragen
Apache Kafka voor data engineers: streaming-architectuur, partities, consumer groups, KRaft, CDC met Debezium, exactly-once semantics en interviewvragen met Kafka 4.x voorbeelden.

De 25 belangrijkste Data Engineering sollicitatievragen in 2026
Een praktische gids met de 25 meest gestelde sollicitatievragen voor data engineers in 2026. Van SQL-optimalisatie en pipeline-architectuur tot system design en datakwaliteit, met codevoorbeelden en uitgebreide antwoorden.