home
diamond Go Premium
Data Engineering Path  ·  PySpark

Spark Tuning - Advanced Partitioning: Hands-on Bucketing Workbook

This workbook walks you through writing and validating bucketed tables to avoid shuffles.


1. Bucketing Operations

  • Task: Write a PySpark DataFrame to a hive catalog as bucketed tables and inspect the physical join plan.

2. Tasks

Task 1: Write Bucketed Tables

Write the PySpark code to bucket two DataFrames (users and orders) by user_id into 16 buckets, write them to disk, join them, and verify that the join execution runs without a shuffle.

Task 2: Implement Salting Transformations

Assume users table has a highly skewed key "GUEST_USER". Write the PySpark code to append random salts (0 to 3) to "GUEST_USER" records and join it safely with the salted orders table.


3. Step-by-Step Solutions

Solution 1: Bucketed Join Implementation

  • PySpark Code:
# 1. Write users table bucketed
users_df.write.format("parquet") \
        .bucketBy(16, "user_id") \
        .sortBy("user_id") \
        .saveAsTable("bucketed_users")

# 2. Write orders table bucketed
orders_df.write.format("parquet") \
        .bucketBy(16, "user_id") \
        .sortBy("user_id") \
        .saveAsTable("bucketed_orders")

# 3. Read tables back from Catalog
b_users = spark.read.table("bucketed_users")
b_orders = spark.read.table("bucketed_orders")

# 4. Join bucketed tables (must share exact number of buckets and sorting key)
joined_df = b_users.join(b_orders, "user_id")

# 5. Explain Physical Plan to confirm absence of 'Exchange' (Shuffle)
joined_df.explain()
  • Physical Plan Verification: The resulting plan shows a SortMergeJoin with direct file scans, and no Exchange (shuffle) operators in the execution path, proving bucketing worked perfectly!

Solution 2: Salting Code

import pyspark.sql.functions as F

# Add random salt (0 to 3) to skewed keys
salted_users = users_df.withColumn(
    "salted_key", 
    F.when(F.col("user_id") == "GUEST_USER", 
           F.concat(F.col("user_id"), F.lit("_"), F.randint(0, 3)))
     .otherwise(F.col("user_id"))
)

# Explode lookup order records
exploded_orders = orders_df.withColumn("salt_array", F.array([F.lit(i) for i in range(4)])) \
                            .withColumn("salt_val", F.explode("salt_array")) \
                            .withColumn("salted_order_key", 
                                        F.when(F.col("user_id") == "GUEST_USER", 
                                               F.concat(F.col("user_id"), F.lit("_"), F.col("salt_val")))
                                         .otherwise(F.col("user_id")))

# Join on salted keys
joined_df = salted_users.join(exploded_orders, salted_users.salted_key == exploded_orders.salted_order_key)
Find this content helpful? ☕ Buy me a coffee

Entity Details

Create New Item

celebration
Enjoying the free content?

Create a free account to track your progress and save your place.

Create Free Account
help

Submit Technical Query

Have a question or run into an issue? Describe it below, upload an optional screenshot, and our engineering team will answer it!

image Attach image (optional)

Submit Feedback

build Free Developer Utility Free Tool
gavel

Privacy & Legal Disclaimer

1. Client-Side Browser Processing

All utility tools on DeepEngineerHub (including Image to PDF, Text Formatters, JSON Converters, and Encryptors) execute 100% locally within your client browser using WebAssembly and JavaScript. No uploaded images, text, or documents are transmitted, collected, or stored on remote servers.

2. Limitation of Liability ("As-Is" Provision)

Tools and services are provided free of charge for convenience and educational purposes "as-is" without warranties of any kind. DeepEngineerHub shall not be held liable for any data loss, formatting inconsistencies, or indirect damages resulting from tool usage.

3. Open Source & Third-Party Software

Certain utilities utilize open-source client libraries (such as jsPDF, Mermaid.js, Pyodide) licensed under MIT, Apache, or BSD open licenses. All intellectual property remains with their respective copyright holders.