Merge (upsert) operations help you combine two datasets by updating existing records and adding new ones in one step.
Merge (upsert) operations in Apache Spark
deltaTable.alias("target") .merge( sourceData.alias("source"), "target.id = source.id" ) .whenMatchedUpdate(set = {"col": "source.col"}) .whenNotMatchedInsert(values = {"id": "source.id", "col": "source.col"}) .execute()
Use merge on a Delta table to combine data from a source DataFrame.
The whenMatchedUpdate clause updates existing rows that match the condition.
deltaTable.alias("t") .merge( updatesDF.alias("s"), "t.userId = s.userId" ) .whenMatchedUpdate(set = {"name": "s.name"}) .whenNotMatchedInsert(values = {"userId": "s.userId", "name": "s.name"}) .execute()
deltaTable.alias("target") .merge( sourceDF.alias("source"), "target.key = source.key" ) .whenMatchedUpdateAll() .whenNotMatchedInsertAll() .execute()
This program creates a Delta table with two users, then merges updates that change one name and add a new user. Finally, it shows the updated table.
from pyspark.sql import SparkSession from delta.tables import DeltaTable spark = SparkSession.builder.appName("MergeExample")\ .config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension")\ .config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog")\ .getOrCreate() # Create initial data initialData = spark.createDataFrame([ (1, "Alice"), (2, "Bob") ], ["id", "name"] ) # Write initial data as Delta table initialData.write.format("delta").mode("overwrite").save("/tmp/delta-table") deltaTable = DeltaTable.forPath(spark, "/tmp/delta-table") # New data with one update and one new record updates = spark.createDataFrame([ (2, "Robert"), # Update Bob to Robert (3, "Charlie") # New record ], ["id", "name"]) # Perform merge (upsert) deltaTable.alias("target") .merge( updates.alias("source"), "target.id = source.id" ) .whenMatchedUpdate(set = {"name": "source.name"}) .whenNotMatchedInsert(values = {"id": "source.id", "name": "source.name"}) .execute() # Show final table finalDF = spark.read.format("delta").load("/tmp/delta-table") finalDF.orderBy("id").show()
Make sure the Delta Lake library is installed and configured in Spark.
Merge operations are atomic and efficient for large datasets.
Use aliases to clearly distinguish source and target tables in the merge.
Merge (upsert) lets you update existing rows and insert new rows in one step.
It is useful for syncing and updating data efficiently.
Delta Lake provides easy syntax to perform merge operations in Spark.
Practice
merge (upsert) operation in Apache Spark with Delta Lake?Solution
Step 1: Understand the merge operation concept
Merge (upsert) combines update and insert actions to keep data synchronized.Step 2: Identify the main use case in Spark with Delta Lake
It updates existing rows and inserts new rows efficiently in one command.Final Answer:
To update existing rows and insert new rows in one step -> Option AQuick Check:
Merge = update + insert [OK]
- Confusing merge with delete operation
- Thinking merge only inserts data
- Assuming merge creates new tables
Solution
Step 1: Recall the merge syntax in Delta Lake
The merge starts withdeltaTable.merge(sourceDF, condition)followed by update and insert clauses.Step 2: Match the full correct method chain
Correct chain iswhenMatchedUpdateAll(),whenNotMatchedInsertAll(), thenexecute().Final Answer:
deltaTable.merge(sourceDF, condition).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute() -> Option DQuick Check:
Correct merge syntax = deltaTable.merge(sourceDF, condition).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute() [OK]
- Using join instead of merge
- Calling update before merge
- Missing execute() at the end
targetTable after the merge?
val sourceDF = spark.createDataFrame(Seq((1, "A"), (3, "C"))).toDF("id", "value")
val deltaTable = DeltaTable.forName("targetTable")
deltaTable.merge(sourceDF, "target.id = source.id")
.whenMatchedUpdateExpr(Map("value" -> "source.value"))
.whenNotMatchedInsertExpr(Map("id" -> "source.id", "value" -> "source.value"))
.execute()
val count = spark.table("targetTable").count()
Assuming targetTable initially has rows with ids 1 and 2.Solution
Step 1: Analyze initial data in targetTable
targetTable has ids 1 and 2 initially.Step 2: Apply merge logic with sourceDF
Source has ids 1 and 3. Id 1 matches and updates value. Id 3 does not match and inserts new row.Step 3: Calculate final row count
Rows after merge: ids 1 (updated), 2 (unchanged), 3 (inserted) -> total 3 rows.Final Answer:
3 -> Option BQuick Check:
Initial 2 + 1 inserted = 3 rows [OK]
- Counting only updated rows
- Ignoring inserted rows
- Assuming rows are deleted
deltaTable.merge(sourceDF, "target.id = source.id")
.whenMatchedUpdate(Map("value" -> "source.value"))
.whenNotMatchedInsert(Map("id" -> "source.id", "value" -> "source.value"))
.execute()Solution
Step 1: Check method names for update and insert
In Delta Lake merge, update and insert with expressions requirewhenMatchedUpdateExprandwhenNotMatchedInsertExpr.Step 2: Verify other parts of the code
Condition string and execute() are correct; sourceDF does not need temp view for merge.Final Answer:
The update and insert methods should be whenMatchedUpdateExpr and whenNotMatchedInsertExpr -> Option AQuick Check:
Use whenMatchedUpdateExpr and whenNotMatchedInsertExpr [OK]
- Using whenMatchedUpdate instead of whenMatchedUpdateExpr
- Forgetting execute()
- Miswriting condition string syntax
users with columns user_id and email. You receive a new DataFrame updatesDF with updated emails and new users. How do you write a merge operation to update emails for existing users and insert new users, ensuring no duplicates and preserving existing users without changes?Solution
Step 1: Define merge condition on user_id
Match rows whereusers.user_id = updatesDF.user_idto identify existing users.Step 2: Specify update and insert actions
Updateemailfor matched users, insert all columns for unmatched (new) users.Step 3: Preserve existing users without changes
Rows not matched remain unchanged automatically in merge.Final Answer:
Use merge with condition on user_id, update email when matched, insert all columns when not matched -> Option CQuick Check:
Merge = update matched + insert unmatched [OK]
- Overwriting entire table losing data
- Using join without update logic
- Not handling unmatched rows
Ready to prove it?
Pass the test and this pattern moves unknown
