home
diamond Go Premium
Data Engineering Path  ·  PySpark

DataFrame Complex & Nested Type Operations

Parsing JSON structures, querying arrays, and manipulating complex struct elements in PySpark using struct, explode, from_json, and to_json.


What are Complex & Nested Type Operations?

Real-world enterprise data pipelines often ingest complex hierarchical formats like JSON or Avro. Instead of simple flat rows, columns contain nested structures:

  • Structs: Nested objects containing their own sub-columns.
  • Arrays: Lists containing multiple elements.
  • JSON Strings: Raw text fields containing serialized JSON payloads.

PySpark provides native functions (like explode(), from_json(), to_json(), and dot-notation) to parse and query these complex data structures without any custom serialization code.


Core Complex Type Functions

1. Extracting Struct Sub-fields (Dot Notation)

Access nested fields directly using standard dot-notation:

# Access 'street' sub-field nested inside 'address' struct
df.select("address.street", "address.city")

2. Flattening Lists with explode()

Flattens an array column, splitting each array element into its own separate row:

from pyspark.sql import functions as F
# Generates a separate row for each tag inside the 'tags' array column
df.select("post_id", F.explode("tags").alias("tag"))

3. Parsing JSON Strings with from_json()

Parses serialized JSON string columns directly into fully-typed Structs by applying an explicit schema:

from pyspark.sql.types import StructType, StructField, StringType, IntegerType
from pyspark.sql import functions as F

# Define target JSON schema structure
json_schema = StructType([
    StructField("city", StringType()),
    StructField("zip", IntegerType())
])

# Parse column
parsed_df = df.withColumn("location", F.from_json("raw_json_str", json_schema))

Example Usage Pipeline

Below is a complete, copy-paste-ready PySpark script demonstrating nested type operations:

from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql.types import StructType, StructField, StringType, ArrayType

# 1. Setup local Spark session
spark = SparkSession.builder \
    .appName("DataFrame Complex Types Demo") \
    .master("local[*]") \
    .getOrCreate()

# 2. Dummy dataset with nested array and raw JSON string columns
data = [
    ("usr_101", ["Python", "Spark"], '{"city": "Mumbai", "country": "India"}'),
    ("usr_102", ["SQL", "Snowflake"], '{"city": "Bangalore", "country": "India"}'),
]
columns = ["user_id", "skills_array", "raw_location_json"]
df = spark.createDataFrame(data, columns)

# 3. Define schema for parsing the raw JSON string
location_schema = StructType([
    StructField("city", StringType(), True),
    StructField("country", StringType(), True)
])

# 4. Perform Complex Transformations:
# - Parse raw JSON column into a structured struct
# - Extract 'city' sub-field from parsed struct
# - Explode 'skills array' so each skill gets its own row
transformed_df = df \
    .withColumn("location_struct", F.from_json(F.col("raw_location_json"), location_schema)) \
    .select(
        "user_id",
        F.col("location_struct.city").alias("city"),
        F.explode("skills_array").alias("skill")
    )

# 5. Show results
print("=== Original Nested DataFrame ===")
df.show(truncate=False)
df.printSchema()

print("=== Flattened & Parsed DataFrame ===")
transformed_df.show(truncate=False)
transformed_df.printSchema()

Rendered Output:

=== Original Nested DataFrame ===
+-------+------------------+-----------------------------------------+
|user_id|skills_array      |raw_location_json                        |
+-------+------------------+-----------------------------------------+
|usr_101|[Python, Spark]    |{"city": "Mumbai", "country": "India"}   |
|usr_102|[SQL, Snowflake]  |{"city": "Bangalore", "country": "India"}|
+-------+------------------+-----------------------------------------+

root
 |-- user_id: string (nullable = true)
 |-- skills_array: array (nullable = true)
 |    |-- element: string (containsNull = true)
 |-- raw_location_json: string (nullable = true)

=== Flattened & Parsed DataFrame ===
+-------+---------+---------+
|user_id|city     |skill    |
+-------+---------+---------+
|usr_101|Mumbai   |Python   |
|usr_101|Mumbai   |Spark    |
|usr_102|Bangalore|SQL      |
|usr_102|Bangalore|Snowflake|
+-------+---------+---------+

root
 |-- user_id: string (nullable = true)
 |-- city: string (nullable = true)
 |-- skill: string (nullable = true)
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.