
Image by Author | Canva
Joining various datasets into one dataset is something you’ll often have to do in data analysis and engineering workflows. In PySpark, this joining takes the form of joining DataFrames.
In the following 1,000 words or so, I will cover all the information you need to join DataFrames efficiently in PySpark. This will include explanations of what PySpark and DataFrames are before I explain all the possible join types, their syntax, and examples.
What is PySpark?
PySpark is the Python API for Apache Spark. Apache Spark is, thanks for asking, a big data analytics engine for both batch data processing and live data streaming.
With PySpark, you can perform big data processing, (real-time) analytics, machine learning tasks, and data integration.
This is very useful if you’re a data engineer or a data scientist working with big data.
What are DataFrames in PySpark?
As per the official Apache Spark documentation definition, DataFrames are datasets “organized into named columns…conceptually equivalent to a table in a relational database or a data frame in R/Python”. Compared to relational databases and R/Python/pandas, DataFrames in PySpark have much more powerful optimization capabilities using the Catalyst optimizer.
They are designed for handling large-scale datasets, so there’s a high level of abstraction for structured data, thus benefiting from the capabilities of Spark’s distributed execution engine. In layperson’s terms, they’re damn fast!
Joins in PySpark
Joining means you’re combining data from two or more DataFrames based on a related column or index.
In PySpark, you can use these joins.

Before showing examples of each join type, let’s first set up PySpark and create sample DataFrames that we’ll join.
Initializing a PySpark Session And Creating a Sample Dataset
I won’t talk about installing PySpark here. If you don’t have PySpark installed already, follow one of the installation instructions from the official PySpark documentation.
Before joining DataFrames, you first need to initialize a PySpark session. Do it using this code.
from pyspark.sql import SparkSession
# Initialize Spark session
spark = SparkSession.builder \
.appName("Custom DataFrame Creation") \
.getOrCreate()
Next, we’ll create sample DataFrames that we’ll join in the following sections. The DataFrames we’ll use are recreated data from IBM’s Interaction Summary interview question.
# Data for 'customer_interactions'
customer_interactions_data = [
(1, 7, "click", "2024-02-13"),
(2, 4, "view", "2024-01-25"),
(3, 8, "like", "2024-02-18"),
(4, 5, "like", "2024-01-27"),
(5, 7, "view", "2024-02-28"),
(6, 10, "view", "2024-02-11"),
(7, 3, "view", "2024-01-28"),
(8, 7, "like", "2024-02-29"),
(9, 8, "like", "2024-01-16"),
(10, 5, "click", "2024-01-15"),
(11, 4, "click", "2024-02-16"),
(12, 8, "like", "2024-02-20"),
(13, 8, "view", "2024-02-13"),
(14, 3, "view", "2024-02-24"),
(15, 6, "click", "2024-02-21")
]
customer_interactions_columns = ["interaction_id", "customer_id", "interaction_type", "interaction_date"]
customer_interactions_df = spark.createDataFrame(data=customer_interactions_data, schema=customer_interactions_columns)
# Data for 'user_content'
user_content_data = [
(1, 2, "comment", "hello world! this is a TEST."),
(2, 8, "comment", "what a great day"),
(3, 4, "comment", "WELCOME to the event."),
(4, 2, "comment", "e-commerce is booming."),
(5, 6, "comment", "Python is fun!!"),
(6, 6, "review", "123 numbers in text."),
(7, 10, "review", "special chars: @#$$%^&*()"),
(8, 4, "comment", "multiple CAPITALS here."),
(9, 6, "review", "sentence. and ANOTHER sentence!"),
(10, 2, "post", "goodBYE!")
]
user_content_columns = ["content_id", "customer_id", "content_type", "content_text"]
user_content_df = spark.createDataFrame(data=user_content_data, schema=user_content_columns)
# Show the DataFrames
customer_interactions_df.show()
user_content_df.show()
The above code returns the customer_interactions_df:

and user_content_df in the output:

Now that we have DataFrames ready, I can show you how to join them.
Joining DataFrames
In this section, I will show you codes for different join types and explain the outputs.
Inner Join
The DataFrames are inner-joined like this. The syntax is relatively simple. Create a DataFrame (inner_join_df) that will contain the joined data. Next, use the .join() operation to join the customer_interactions_df DataFrame with another DataFrame. We do it by defining parameters in .join(): first, we name the second DataFrame to be joined (user_content_df), then we define the column on which the DataFrames will be joined (on=”customer_id”), and, finally, we define the join type (how=”inner”).
inner_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="inner") inner_join_df.show(truncate=False)
The second code line just displays the joined data (in the non-truncated format, which is important to fully see data in the content_text column). The output shows only the matching rows from both DataFrames.

Left Outer Join
The syntax for left outer join (and all other joins, except cross join, for that matter) is the same as in the previous example: the only thing you change is the join type parameter in the .join() operation.
left_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="left") left_join_df.show(truncate=False)
Where you see NULLs in the output, those are non-matching values from user_content_df.

Right Outer Join
Here’s the code for right-joining the DataFrames.
right_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="right") right_join_df.show(truncate=False)
As the right join is the mirror image of the left join, the NULLs in the output below are the non-matching rows from the left (customer_interactions_df) DataFrame.

Full Outer Join
Use this code to perform a full outer join on DataFrames in PySpark.
full_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="outer") full_join_df.show(truncate=False)
NULLs appear in the output where there are non-matching rows in either DataFrames.

Cross Join
Use the following code to cross-join DataFrames. Here, the syntax is a bit different. Since cross join results in a Cartesian product (all combinations of all data rows), there’s no need to specify the column on which DataFrames will be joined.
Instead of .join(), we use .crossJoin() to join the DataFrames, with the second DataFrame written in parentheses.
cross_join_df = customer_interactions_df.crossJoin(user_content_df) cross_join_df.show(truncate=False)
Here’s the output.

Semi Join
We’re now back to the syntax we’re used to; we again use the .join() operation. To create a semi join, use left_semi in the how argument.
semi_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="left_semi") semi_join_df.show(truncate=False)
The output shows the rows from customer_interactions_df where there are matching rows in user_content_df.

Anti Join
To anti join DataFrames, simply use the left_anti keyword.
anti_join_df = customer_interactions_df.join(user_content_df, on="customer_id", how="left_anti") anti_join_df.show(truncate=False)
The output shows the rows from customer_interactions_df where no matches exist in user_content_df.

Resources for Practicing PySpark
As with any coding, practicing is crucial for all the concepts to really sink in and become second nature. As for PySpark, here are several resources for practicing:
- Databricks Community Edition
- pyspark_exercises repository on GitHub
- Analytical questions with a PySpark code editor on StrataScratch
- PySpark projects and tutorials on Kaggle
- DataCamp’s interactive PySpark Courses
Conclusion
There it is: seven different ways of joining DataFrames in PySpark. Understanding these joins and their use cases is crucial for building efficient data pipelines or performing almost any operation on large data sets.

Hi Nate,
I’m beginner on PySpark and I’m trying to execute PySpak with python’s package pyspark but I’m getting message errors about Java. Can you explain mee why do I need Java to execute PySpark??
In you opinion, PySpark is as efficiently/powerful in data analytics as Scala?? Maybe more??which is more complicated to learn??
Thanks Nate,
Great questions! Let’s unpack them one at a time to help you get a clear understanding of what’s going on with PySpark and how it compares to Scala.
—
### 🔧 Why Do You Need Java to Run PySpark?
PySpark is a **Python API for Apache Spark**, and **Apache Spark is written in Scala**, which runs on the **Java Virtual Machine (JVM)**. Here’s what happens behind the scenes:
* When you write PySpark code, it communicates with the **Spark engine** (written in Scala/Java) through **Py4J**, a bridge between Python and JVM.
* So, even though you’re writing Python, the core computations are done by Spark on the JVM.
✅ **Conclusion:** You need **Java** (and **Java Runtime Environment** installed and correctly configured) because Spark is fundamentally a JVM-based engine.
—
### ⚖️ PySpark vs Scala Spark for Data Analytics
| Feature | **PySpark (Python)** | **Scala Spark** |
| ———————– | ——————————————————— | ——————————————————— |
| **Ease of Learning** | Easier, especially for those already familiar with Python | Harder, especially if new to Scala/functional programming |
| **Community Support** | Larger due to Python’s popularity in data science | Smaller, more focused on big data engineering |
| **Performance** | Slightly slower due to Python-JVM communication overhead | Faster and more direct since it runs natively on JVM |
| **API Coverage** | Good, covers most features | Full, always first to get new Spark features |
| **Integration with ML** | Excellent (pandas, scikit-learn, etc.) | Strong but more technical (MLlib, Breeze) |
🧠 **Efficiency & Power:** For **data analysis and prototyping**, PySpark is usually more than sufficient and much easier to work with. For **production-level pipelines**, **custom Spark optimizations**, or **performance-critical jobs**, Scala might be better.
—
### 🧠 Which Is Harder to Learn?
* **PySpark** is easier if you:
* Already know Python
* Come from a data science background
* Want quick prototyping
* **Scala Spark** is harder because:
* Scala is a statically typed, functional language
* It has a steeper learning curve for beginners
—
### ✅ Recommendation for Beginners
Stick with **PySpark** while learning Spark concepts. It’s fully capable for real-world data analytics and much more beginner-friendly. Only consider Scala if:
* You’re working in an environment where performance is critical
* Your team/codebase is already in Scala
* You’re comfortable diving deeper into JVM-level optimization
—
Thanks for your detailed reply @james, it was very useful and clear 🙂
You are very welcome ppinedo! We appreciate your feedback!