How User-Defined Functions work inside Spark—and why experienced PySpark engineers treat them carefully
You have a DataFrame.
You need to apply a custom transformation.
So you write a Python function:
def clean_name(name): return name.strip().lower()
Then you turn it into a UDF:
from pyspark.sql.functions import udfclean_name_udf = udf(clean_name)
It works.
But there is an important question:
Should you actually use a UDF?
In PySpark, the answer is often no.
Spark already provides hundreds of optimized built-in functions. When you replace those functions with Python UDFs, you can introduce Python execution and JVM ↔ Python data transfer into your execution path.
That can make a seemingly simple transformation significantly more expensive.
Understanding when UDFs are useful, when they are harmful, and what alternatives exist is an important step from writing PySpark code to writing production-grade Spark code.
📚 Complete Apache Spark Tutorial Progress
APACHE SPARK LEARNING PATH
- ✓ What is Apache Spark?
- ✓ Why Spark is Faster than Hadoop
- ✓ Spark Architecture
- ✓ Driver vs Executor
- ✓ Cluster Managers
- → RDD vs DataFrame vs Dataset
- → SparkSession
- ✓ Reading Data
- ✓ Lazy Evaluation
- ✓ DAG
- ✓ Stages and Tasks
- ✓ Shuffle
- ✓ Narrow vs Wide Transformations
- → Writing Data
- → Data Transformations
- →Window Functions
- Aggregations
- UDFs
A Small CTA Before We Start
If you’re learning PySpark for Data Engineering, Data Science, or AI Engineering, follow Geeky Codes and subscribe by email so you don’t miss the next tutorial in this Apache Spark series.
In This Article
We will cover:
- What is a UDF?
- Why do we need UDFs?
- Creating a basic PySpark UDF
- Applying UDFs to DataFrames
- UDF return types
- Registering UDFs for SQL
- Scalar Python UDFs
- Pandas UDFs
- Arrow UDFs
- UDF vs built-in Spark functions
- Why UDFs can be slow
- How Python UDF execution works
- UDFs and Catalyst
- UDFs and predicate pushdown
- Deterministic vs nondeterministic UDFs
- Null handling
- Common UDF mistakes
- Production optimization strategies
- When you should actually use a UDF
- Interview questions
1. What Is a UDF?
UDF stands for User-Defined Function.
A UDF allows you to define custom logic that Spark can apply to DataFrame columns.
For example, suppose we have:
name----------------AliceBobCharlie
We want to calculate the length of every name.
Spark already provides:
length("name")
But imagine the transformation is something that Spark does not provide natively.
We could write:
def custom_logic(value): return ...
and convert it into a Spark UDF.
Conceptually:
DataFrame │ ▼Column │ ▼Python UDF │ ▼Custom Python Logic │ ▼Result Column
PySpark currently supports several categories of Python UDFs, including scalar Python UDFs, Pandas UDFs, and Arrow UDFs.
2. Why Do We Need UDFs?
Spark’s built-in functions cover most common transformations:
from pyspark.sql.functions import ( col, lower, upper, trim, regexp_replace, when, length)
For example:
df.withColumn( "clean_name", lower(trim(col("name"))))
But sometimes your business logic is more specialized.
For example:
Customer risk classificationCustom address normalizationDomain-specific text processingSpecialized mathematical calculationLegacy Python business logicCustom feature engineering
Suppose your organization has a complicated Python function:
def calculate_customer_segment(age, income, transactions): ...
If there is no suitable native Spark expression, a UDF may be appropriate.
The important distinction is:
UDFs are an escape hatch for custom logic—not the default way to transform Spark DataFrames.
3. Creating Your First PySpark UDF
Let’s create a simple UDF.
from pyspark.sql.functions import udffrom pyspark.sql.types import IntegerTypeudf(returnType=IntegerType())def name_length(name): if name is None: return None return len(name)
Now create a DataFrame:
data = [ ("Alice",), ("Bob",), ("Charlie",), (None,)]df = spark.createDataFrame(data, ["name"])
Apply the UDF:
result = df.withColumn( "name_length", name_length("name"))result.show()
Output:
+-------+-----------+| name|name_length|+-------+-----------+| Alice| 5|| Bob| 3||Charlie| 7|| NULL| NULL|+-------+-----------+
The UDF behaves like a Spark column expression.
4. UDF Using a Normal Python Function
You don’t have to use the decorator syntax.
You can also write:
def name_length(name): if name is None: return None return len(name)name_length_udf = udf( name_length, IntegerType())
Then:
df.withColumn( "name_length", name_length_udf("name"))
Both approaches create a Spark UDF.
The returnType is important because Spark needs to know the resulting SQL data type. The current API accepts either a Spark DataType or a DDL-formatted type string.
5. Using Multiple Columns
A UDF can accept multiple columns.
Suppose we have:
age income30 10000040 150000
Create:
udf(returnType="double")def risk_score(age, income): if age is None or income is None: return None return income / age
Use it:
df.withColumn( "risk_score", risk_score( col("age"), col("income") ))
Conceptually:
age ───────┐ │income ────┼──► Python UDF ──► risk_score │
6. UDF Return Types
Spark needs to know what the UDF returns.
For example:
Integer
udf(returnType="int")def calculate_score(x): return x * 10
String
udf(returnType="string")def normalize_name(x): return x.lower()
Double
udf(returnType="double")def calculate_ratio(a, b): return a / b
Boolean
udf(returnType="boolean")def is_valid(age): return age >= 18
You can also use Spark type objects:
from pyspark.sql.types import IntegerTypeudf(returnType=IntegerType())def square(x): return x * x
7. UDFs With Complex Return Types
UDFs aren’t restricted to primitive values.
You can return structures such as arrays or structs.
For example:
from pyspark.sql.types import ArrayType, StringTypeudf(returnType=ArrayType(StringType()))def split_words(text): if text is None: return None return text.split()
Then:
df.withColumn( "words", split_words("description"))
Result:
description words------------------------------------------------"Spark is fast" ["Spark", "is", "fast"]
However, before creating a complex UDF, check whether Spark already has a native function for the operation.
8. The Most Important Rule: Prefer Built-in Functions
This is probably the most important production rule in this entire article:
If Spark already has a built-in function that solves the problem, prefer the built-in function over a Python UDF.
Suppose you want to convert names to lowercase.
You could write:
udf("string")def lower_name(name): return name.lower()
But Spark already provides:
from pyspark.sql.functions import lowerdf.withColumn( "lower_name", lower("name"))
The second version is usually preferable.
Why?
Because Spark understands native expressions.
It can reason about them as part of the query plan and apply its normal SQL/DataFrame optimizations.
9. UDF vs Built-in Function
Consider:
df.withColumn( "clean_name", lower(trim(col("name"))))
versus:
udf("string")def clean_name(name): return name.strip().lower()df.withColumn( "clean_name", clean_name("name"))
Both may produce the same result.
But they are not equivalent from Spark’s execution perspective.
Built-in function
DataFrame │ ▼Spark Expression │ ▼Catalyst Optimizer │ ▼Optimized Physical Plan │ ▼Execution
Python UDF
DataFrame │ ▼Python UDF │ ▼Python Worker │ ▼Python Logic │ ▼Spark Execution
The second path introduces an additional execution boundary.
10. Why Python UDFs Can Be Slow
Historically, one of the biggest performance concerns with Python UDFs has been data exchange between the JVM-based Spark engine and Python workers.
Conceptually:
Spark JVM
│
│ serialize
▼
Python Worker
│
│ execute Python
▼
Python Function
│
│ return result
▼
Spark JVM
That boundary can introduce overhead.
This is especially important when:
Dataset = billions of rows +UDF = expensive Python logic
Even a small per-row overhead can become significant.
11. An Important Update: Arrow-Optimized Python UDFs
Modern PySpark has improved this area.
In Spark 4.2, regular Python UDFs use Arrow for serialization/deserialization by default. However, this should not be confused with a Pandas UDF: an Arrow-optimized regular Python UDF still processes values row-by-row using normal Python objects.
Conceptually:
Traditional exchangeSpark JVM │ ▼Serialization │ ▼Python │ ▼Serialization │ ▼Spark JVM
With Arrow optimization:
Spark JVM │ ▼Apache Arrow │ ▼Python Worker │ ▼Python Logic
Arrow can make data transfer more efficient.
But:
Arrow optimization does not magically turn a Python UDF into a native Spark expression.
Your Python function is still Python logic.
12. Pandas UDFs
Another option is a Pandas UDF.
Pandas UDFs are vectorized UDFs that use Apache Arrow for data transfer and operate on batches rather than one individual Python value at a time.
Example:
import pandas as pdfrom pyspark.sql.functions import pandas_udfpandas_udf("string")def uppercase_names(names: pd.Series) -> pd.Series: return names.str.upper()
Use:
df.withColumn( "upper_name", uppercase_names("name"))
Conceptually:
Scalar Python UDFrow → Python → resultrow → Python → resultrow → Python → resultPandas UDFbatch → Python/Pandas → batch result
This can reduce Python-call overhead for workloads that benefit from vectorized processing.
13. Scalar UDF vs Pandas UDF
| Feature | Scalar Python UDF | Pandas UDF |
|---|---|---|
| Input | Individual values | Batches |
| Python execution | Row-oriented | Vectorized |
| Arrow | Supported/optimized | Core mechanism |
| Pandas required | No | Yes |
| Good for | Custom row logic | Vectorized operations |
| Typical overhead | Higher | Often lower |
| Spark-native optimization | Limited | Limited compared with native expressions |
Pandas UDFs are particularly useful when the logic naturally maps to Pandas operations.
14. Arrow UDFs
Modern PySpark also provides Arrow UDFs.
Instead of receiving normal Python values or Pandas Series, Arrow UDFs can directly work with pyarrow.Array objects.
For example:
import pyarrow as pafrom pyspark.sql.functions import arrow_udfarrow_udf("string")def to_upper(values: pa.Array) -> pa.Array: return pa.compute.ascii_upper(values)
This is another way PySpark can integrate Python logic with Arrow’s columnar representation.
So the modern UDF landscape looks roughly like:
Python UDFs│├── Scalar Python UDF│├── Pandas UDF│└── Arrow UDF
15. UDFs and Catalyst Optimizer
This is where many PySpark interviews become interesting.
Suppose you write:
df.withColumn( "x", custom_python_function("value"))
Spark knows that a UDF exists.
But it generally cannot inspect your arbitrary Python function and reason about its internal logic in the same way it understands a native Spark expression.
Compare:
upper(col("name"))
with:
my_python_udf(col("name"))
The first is a Spark expression.
The second contains arbitrary Python logic.
This creates an optimization boundary.
16. Example: Why Native Expressions Are Better
Suppose we need:
price > 100
Native Spark:
df.filter(col("price") > 100)
Spark understands the predicate.
Now imagine:
udf("boolean")def expensive_filter(price): return price > 100
Then:
df.filter(expensive_filter("price"))
Spark cannot treat the Python function as simply as the native expression.
This can affect optimization opportunities such as predicate pushdown.
17. Predicate Pushdown and UDFs
Suppose the source contains:
1 billion records
and you need:
price > 100
With a native expression:
df.filter(col("price") > 100)
Spark and the underlying data source may be able to push the filter closer to the data source, depending on the source and query.
Conceptually:
Storage │ │ filter pushed closer ▼Only relevant data │ ▼Spark
With a Python UDF:
df.filter(my_filter_udf("price"))
Spark has less ability to reason about the Python function’s semantics.
So you can potentially lose optimization opportunities.
18. UDFs and Conditional Expressions
There is another important behavior to understand.
UDFs do not provide normal SQL-style short-circuit guarantees for conditional/boolean expressions.
For example, don’t assume that writing:
df.filter( (col("value") != 0) & expensive_udf("value"))
means Spark will always evaluate value != 0 first and only invoke the UDF for safe rows.
The PySpark documentation specifically notes that UDFs do not support conditional expressions or short-circuiting in boolean expressions in the way you might expect.
If your UDF can fail on special input, make the safety condition part of the UDF itself.
For example:
udf("double")def safe_divide(x): if x is None or x == 0: return None return 100 / x
19. Handling NULL Values
Always think about NULL explicitly.
Bad:
udf("string")def normalize_name(name): return name.strip().lower()
If:
name = NULL
then:
name.strip()
fails.
Better:
udf("string")def normalize_name(name): if name is None: return None return name.strip().lower()
This is particularly important in production pipelines because NULLs are common in real-world datasets.
20. Deterministic vs Nondeterministic UDFs
Spark considers UDFs deterministic by default.
That means Spark can assume:
same input → same output
Consider:
udf("double")def calculate(x): return x * 2
This is deterministic.
But imagine:
import randomudf("double")def random_value(): return random.random()
The result isn’t deterministic.
You should mark such a UDF as nondeterministic:
random_udf = udf( lambda: random.random(), "double").asNondeterministic()
This matters because Spark’s optimizer may otherwise make assumptions about repeated evaluations. The current PySpark documentation explicitly provides asNondeterministic() for this purpose.
21. Registering a UDF for SQL
You can register a Python UDF so that it can be called from Spark SQL.
For example:
udf("string")def uppercase_name(name): if name is None: return None return name.upper()
Register it:
spark.udf.register( "uppercase_name", uppercase_name)
Now SQL can call it:
SELECT name, uppercase_name(name)FROM people
PySpark’s UDFRegistration.register() supports registering Python functions and UDFs for use as SQL functions.
22. A Real-World Example
Imagine an insurance dataset:
customer_idageannual_incomeclaim_count
We want to calculate a custom risk score.
udf("double")def risk_score(age, income, claims): if age is None or income is None or claims is None: return None score = 0 if age > 60: score += 20 if income < 50000: score += 20 if claims > 3: score += 40 return float(score)
Apply:
result = df.withColumn( "risk_score", risk_score( col("age"), col("annual_income"), col("claim_count") ))
Now:
customer_id | age | income | claims | risk_score-------------------------------------------------101 | 65 | 40000 | 4 | 80102 | 35 | 90000 | 1 | 0
This is a reasonable UDF use case if the logic genuinely cannot be expressed cleanly with Spark’s built-in functions.
23. But Could We Avoid the UDF?
Often, yes.
The same logic could potentially be expressed using:
from pyspark.sql.functions import when, litresult = df.withColumn( "risk_score", when(col("age") > 60, 20).otherwise(0) + when(col("annual_income") < 50000, 20).otherwise(0) + when(col("claim_count") > 3, 40).otherwise(0))
Now Spark sees the actual expression.
That is usually preferable.
24. A Practical Decision Tree
When you want to write a UDF, ask these questions:
Need custom logic?
│
▼
Does Spark have a built-in
function for it?
/ \
YES NO
│ │
▼ ▼
Use Spark Can the logic
function be expressed using
Spark SQL expressions?
/ \
YES NO
│ │
▼ ▼
Use native Need Python?
expression │
▼
Consider UDF
│
┌────────────┼────────────┐
▼ ▼ ▼
Scalar Pandas Arrow
UDF UDF UDF
The goal isn’t:
“Never use UDFs.”
The goal is:
Use the highest-level Spark-native abstraction that correctly solves the problem.
25. UDF Performance Hierarchy
A useful practical mental model is:
Usually easiest for Spark to optimize │ ▼ Built-in Spark functions │ ▼ Spark SQL expressions │ ▼ Native Spark operations │ ▼ Pandas / Arrow UDFs │ ▼ Python UDFs │ ▼ Expensive external Python logic
This isn’t a universal benchmark ranking.
The actual performance depends on the workload, implementation, data types, batch behavior, and Spark version.
But as an engineering principle:
Don’t cross into Python unless you have a reason to.
26. UDFs and Serialization
A distributed Spark application has multiple processes.
Conceptually:
Driver │ ▼Executors │ ├── Task │ ├── Task │ └── Task │ ▼ Python Worker
When Python UDFs are involved, Spark has to coordinate execution between the JVM-based Spark runtime and Python workers.
Modern Arrow optimization can improve serialization/deserialization, but the Python execution boundary remains important.
For cluster deployments, all required Python dependencies also need to be available on the executors. This matters particularly for Pandas/Arrow UDFs because they depend on packages such as Pandas and PyArrow.
27. Common Mistake: Using UDF for Simple String Logic
Bad:
udf("string")def upper_name(name): return name.upper()
Better:
from pyspark.sql.functions import upperdf.withColumn( "upper_name", upper("name"))
Spark already knows how to perform this operation.
28. Common Mistake: Using UDF for Date Operations
Bad:
udf("int")def get_year(date): return date.year
Instead:
from pyspark.sql.functions import yeardf.withColumn( "year", year("date"))
Use Spark’s date/time functions whenever possible.
29. Common Mistake: Calling External APIs Inside UDFs
This is one of the biggest production anti-patterns.
Avoid:
udf("string")def call_api(customer_id): response = requests.get(...) return response.text
Why?
Imagine:
100 million rows ×100 million API calls
You have now turned a distributed data-processing job into a distributed API client.
Problems can include:
- API rate limits
- retries
- network latency
- unpredictable execution time
- duplicate requests
- failed tasks
- external system overload
- difficult observability
If external enrichment is necessary, design it as a separate scalable workflow rather than blindly placing an API request inside a row-level UDF.
30. Common Mistake: Heavy Machine Learning Inside a Row UDF
Avoid repeatedly loading a model:
udf("double")def predict(features): model = load_model() return model.predict(features)
The model could be loaded repeatedly across Python worker processes/tasks.
For distributed ML inference, consider architectures designed for batch inference, vectorized UDFs, model distribution, or Spark’s ML/inference capabilities depending on the use case.
31. Common Mistake: Ignoring Python Dependencies
Suppose:
pandas_udf("double")def calculate(x): import some_library ...
Your laptop has the library.
Your executors might not.
You can therefore see:
ModuleNotFoundError
Production Spark environments need consistent Python dependencies across the worker environment.
32. How to Debug a Slow UDF
Suppose this takes:
2 minutes locally
but:
2 hours on the cluster
Don’t immediately increase cluster size.
Investigate:
Step 1 — Check the execution plan
df.explain("formatted")
Step 2 — Look for Python execution
Inspect the physical plan for Python UDF-related execution nodes.
Step 3 — Check Spark UI
Look at:
Jobs ↓Stages ↓Tasks
Check:
- task duration
- input size
- shuffle
- spill
- executor behavior
- skew
- Python execution time where available
Step 4 — Compare against a native implementation
Replace:
my_udf(...)
with an equivalent Spark expression if possible.
Step 5 — Profile the UDF
PySpark provides profiling support for Python, Pandas, and Arrow UDFs.
33. UDF Profiling
For example, Spark provides a UDF profiler configuration:
spark.conf.set( "spark.sql.pyspark.udf.profiler", "perf")
Then execute the UDF workload.
This can help identify where Python UDF time is being spent.
For production troubleshooting, combine profiling with:
Spark UI+Execution Plan+Application Logs+UDF Profiling
rather than relying on one measurement.
34. Built-in Function vs UDF: Complete Comparison
| Aspect | Built-in Function | Python UDF |
|---|---|---|
| Spark understands expression | Yes | Limited |
| Catalyst optimization | Strong | More limited |
| Python execution | No | Yes |
| Custom Python logic | No | Yes |
| Predicate pushdown opportunities | Better | Potentially reduced |
| Serialization boundary | No Python boundary | Python boundary |
| Performance | Usually preferred | Can be slower |
| Maintainability | Usually high | Depends |
| Best use | Standard transformations | Truly custom logic |
35. Scalar UDF vs Pandas UDF vs Arrow UDF
| Type | Processes | Typical use |
|---|---|---|
| Scalar Python UDF | Python values | Custom row-level logic |
| Pandas UDF | Pandas Series/DataFrame batches | Vectorized Python/Pandas logic |
| Arrow UDF | PyArrow arrays | Columnar Arrow-based Python logic |
Current PySpark documentation describes these as the three main categories of Python UDFs.
36. Production Checklist
Before deploying a UDF, ask:
Correctness
- Does it handle NULL?
- Is the return type correct?
- Is the function deterministic?
- Can it fail for special inputs?
Performance
- Is there a built-in Spark function?
- Can I express the logic using Spark SQL?
- Does the UDF process huge volumes?
- Would vectorization help?
- Have I measured the actual performance?
Distributed execution
- Are dependencies installed on executors?
- Does the function perform network calls?
- Does it load large models/files?
- Does it create unnecessary serialization overhead?
Observability
- Did I inspect
explain()? - Did I inspect Spark UI?
- Did I profile the UDF if necessary?
37. The Production Engineer’s Rule
When you see this:
udf(...)def something(...): ...
don’t immediately ask:
“Is this UDF correct?”
Also ask:
“Why is this a UDF?”
That question is much more valuable.
Maybe the logic can be written using:
when()regexp_replace()split()transform()filter()aggregate()expr()
or another native Spark expression.
If so, prefer that.
If not, then a UDF may be exactly the right tool.
38. The Mental Model
Remember this:
Spark DataFrame
│
▼
Can Spark understand it?
/ \
YES NO
│ │
▼ ▼
Native Spark Python
expression UDF
│ │
▼ ▼
Optimizer Python
friendly boundary
│ │
└────┬─────┘
▼
Execution
A UDF isn’t inherently bad.
The problem is using one when Spark already knows how to do the same thing more efficiently.
39. Common Interview Questions
1. What is a UDF in PySpark?
A UDF is a user-defined function that allows custom Python logic to be applied to Spark DataFrame columns when built-in Spark expressions aren’t sufficient.
2. Why are Python UDFs often slower than built-in functions?
Because Python UDFs introduce Python execution and a JVM-to-Python execution boundary. Built-in Spark expressions are understood directly by Spark’s query engine and provide more optimization opportunities.
3. Should you always avoid UDFs?
No.
Use them when the required logic cannot reasonably be expressed using Spark’s built-in functions or SQL expressions.
4. What is a Pandas UDF?
A Pandas UDF is a vectorized UDF that processes batches using Pandas and Apache Arrow rather than invoking Python logic independently for every individual value.
5. What is Arrow’s role in PySpark UDFs?
Apache Arrow provides an efficient columnar representation for transferring data between Spark’s JVM runtime and Python. In Spark 4.2, Arrow is also used by default for serialization/deserialization of regular Python UDFs.
6. Can a UDF accept multiple columns?
Yes.
my_udf( col("age"), col("income"))
7. Can UDFs return complex types?
Yes. UDFs can return supported Spark SQL types including arrays and structs.
8. What happens if a UDF is nondeterministic?
UDFs are deterministic by default. If the function is nondeterministic, such as one using random values, it should be marked using:
.asNondeterministic()
9. Why should you avoid API calls inside UDFs?
Because a row-level distributed UDF can generate a huge number of external requests, leading to rate limiting, network latency, retries, failures, and unpredictable execution time.
10. How do you decide whether to use a UDF?
Use this order:
Built-in Spark function ↓Spark SQL expression ↓Native DataFrame transformation ↓Pandas/Arrow UDF ↓Python UDF
Choose the simplest option that correctly solves the problem.
40. Quick Revision Cheat Sheet
UDF│├── User-defined function│├── Useful for custom logic│├── Don't use when Spark already has a native function│├── Python UDF│ └── Custom Python logic│├── Pandas UDF│ └── Vectorized batch processing│├── Arrow UDF│ └── PyArrow-based processing│├── Main concerns│ ├── Python execution│ ├── Serialization│ ├── Optimization boundaries│ └── Dependency management│└── Production rule └── Prefer Spark-native expressions
41. Key Takeaways
The most important lessons are:
- UDFs let you add custom logic to Spark.
- A UDF should not be your first choice.
- Prefer built-in Spark functions whenever possible.
- Native expressions give Spark more opportunities to optimize the query.
- Python UDFs introduce a Python execution boundary.
- Pandas UDFs process data in batches and can be useful for vectorized Python logic.
- Modern Spark also supports Arrow UDFs.
- Spark 4.2 uses Arrow by default for serialization/deserialization of regular Python UDFs.
- Arrow optimization doesn’t make arbitrary Python logic equivalent to native Spark expressions.
- Always handle NULLs explicitly.
- Mark nondeterministic UDFs appropriately.
- Never blindly put external API calls inside row-level UDFs.
- Inspect execution plans and Spark UI when UDF workloads are slow.
- Use UDFs when custom logic genuinely requires them—not simply because Python is convenient.
Continue Learning Apache Spark
You’ve now moved beyond basic DataFrame operations into an important part of production Spark engineering:
DataFrame Transformations ✓ │ ▼Actions ✓ │ ▼Aggregations ✓ │ ▼UDFs ✓ │ ▼Partitioning ← Next │ ▼Data Skew │ ▼Join Optimization │ ▼AQE & Advanced Performance
Next Article
Partitioning in Apache Spark: How Data Is Distributed Across the Cluster
We’ll move from how Spark processes data to one of the most important questions in distributed computing:
How does Spark decide where the data actually lives?
We’ll cover:
- What partitions are
- How Spark creates partitions
- Number of partitions
repartition()coalesce()- Shuffle partitions
- Partition size
- Partitioning strategies
- How bad partitioning creates slow jobs
- Practical tuning strategies
- Production examples
Further Reading
- PySpark UDF API documentation
- PySpark UDF and UDTF User Guide
- PySpark Pandas UDF documentation
- Spark SQL Performance Tuning
These official Apache Spark resources document the current UDF APIs, Arrow behavior, and performance-related features.
Further Reading
- ✓ What is Apache Spark?
- ✓ Why Spark is Faster than Hadoop
- ✓ Spark Architecture
- ✓ Driver vs Executor
- ✓ Cluster Managers
- → RDD vs DataFrame vs Dataset
- → SparkSession
- ✓ Reading Data
- ✓ Lazy Evaluation
- ✓ DAG
- ✓ Stages and Tasks
- ✓ Shuffle
- ✓ Narrow vs Wide Transformations
- → Writing Data
- → Data Transformations
- →Window Functions
- Aggregations