Skip to main content
๐Ÿ“˜ Complete PDF

PySpark Certification Practice Test 03

Data Engineer Review Notes

Question 1 of 20
๐Ÿ“‹ Multiple Choice
Question 41
A newly joined Data Engineer reviews the following requirement: "We have customer data and customer address data. Only customers existing in both datasets should appear in the output." Which join type should be recommended?
โœ“
A. Inner Join
B. Left Outer Join
C. Full Outer Join
D. Left Anti Join
Answer
โœ… A. Inner Join
Explanation

1. Core Concept An **Inner Join** evaluates two DataFrames against a join condition (equality predicate) and outputs only rows where matching keys exist in **both** the left and right DataFrames. Any row from either side whose key has no corresponding counterpart in the other DataFrame is excluded from the result set.

2. Detailed Breakdown In PySpark Catalyst optimization and physical execution: - The default join type when executing `df1.join(df2, on="key")` without specifying the `how` parameter is `how="inner"`. - Under the hood, Catalyst analyzes table statistics. If one side is smaller than `spark.sql.autoBroadcastJoinThreshold` (default 10 MB), Spark plans a **BroadcastHashJoinExec (BHJ)**. The small DataFrame is collected to the driver, hashed, and broadcast to all worker executors, eliminating shuffle. - If both tables exceed the threshold and Adaptive Query Execution (AQE) does not dynamically convert it, Spark executes a **SortMergeJoinExec (SMJ)** (or `ShuffledHashJoinExec` if enabled). Both DataFrames are shuffled across cluster nodes partitioned by `hash(join_key) % spark.sql.shuffle.partitions`, sorted locally by join key within each partition, and merged. - Rows with NULL join keys are automatically dropped from the output in an inner join because `NULL = NULL` evaluates to `UNKNOWN` (false in boolean join predicates).

3. Why the Correct Answer is Correct The business requirement explicitly dictates: *"Only customers existing in both datasets should appear in the output."* - An **Inner Join** strictly retains rows with matching keys in both datasets. - Customers present in the customer table but missing from address data are discarded. - Address records without a matching customer record are discarded. - Therefore, option A is precisely the join type required.

4. Why Each Distractor is Incorrect - **B (Left Outer Join):** A left outer join preserves *all* records from the left DataFrame regardless of whether a match exists on the right side. If a customer lacks an address, the customer row is still emitted with `NULL` address fields, violating the requirement that records must exist in both. - **C (Full Outer Join):** A full outer join preserves all records from *both* DataFrames. Unmatched customer records and unmatched address records would appear with NULLs, directly violating the exclusion requirement. - **D (Left Anti Join):** A left anti join returns only rows from the left DataFrame that have **no** match in the right DataFrame. It would return only customers *without* addresses, which is the exact opposite of what was requested.

5. Code Example

from pyspark.sql import SparkSession
from pyspark.sql.functions import col

spark = SparkSession.builder.appName("InnerJoinDemo").getOrCreate()

# Customer demographics
customers = spark.createDataFrame([
    (101, "Alice"),
    (102, "Bob"),
    (103, "Charlie")
], ["customer_id", "name"])

# Customer addresses (Bob has no address record, 104 is orphan address)
addresses = spark.createDataFrame([
    (101, "123 Maple St, Seattle"),
    (103, "456 Oak Ave, Denver"),
    (104, "789 Pine Rd, Austin")
], ["customer_id", "address"])

# Perform Inner Join
inner_joined_df = customers.join(addresses, on="customer_id", how="inner")
inner_joined_df.show(truncate=False)
# Result:
# +-----------+-------+---------------------+
# |customer_id|name   |address              |
# +-----------+-------+---------------------+
# |101        |Alice  |123 Maple St, Seattle|
# |103        |Charlie|456 Oak Ave, Denver  |
# +-----------+-------+---------------------+

6. Key Takeaway An Inner Join retains only intersecting records matching keys in both DataFrames, automatically filtering out non-matching rows and NULL keys on either side.

7. Production Best Practice When joining large datasets on nullable columns, pre-filter NULLs before joining (`df.filter(col("id").isNotNull())`) or ensure join keys are cleanly typed. In skewed joins where certain keys (e.g. guest customer IDs) appear millions of times, use AQE skew join optimization (`spark.sql.adaptive.skewJoin.enabled=true`) or broadcast the dimensional lookup table.

8. Real-World Engineering Scenario In a financial KYC (Know Your Customer) reporting pipeline, analysts need verified profiles where both core CRM customer identity and authenticated government ID documents are confirmed. An inner join ensures that unverified users without documentation and orphan document scans without registered users are excluded from the regulatory filing.

9. Common Pitfall / Anti-Pattern Specifying `df1.join(df2, df1["id"] == df2["id"])` creates duplicate column names in the resulting DataFrame, which breaks downstream references when calling `df["id"]`. Prefer joining with a string key `df1.join(df2, on="id")` or aliasing DataFrames and dropping the duplicate column explicitly.

10. Tutorial Reference Explore join mechanics and physical execution strategies in [PySpark DataFrame Joins](/tutorials/pyspark/df-joins).

Answered: 0 / 20
Question Navigator (Test 03)0% Answered