PySpark Interview Questions with Examples
PySpark interview questions test the API details that decide whether a job is correct and fast. Seven are answered on a real two-million-row electricity file that fights back: a placeholder that turns numbers into strings, dates without leading zeros that Spark 3 will not parse, and a UDF that drags rows into Python.
GloryTecks Team
Training & Placement Faculty
Last updated: 9 October 2026
PySpark interview questions move quickly from "what is a DataFrame?" to details that decide whether a job is correct: how it reads a file, what it does with missing values and dates, and when your code leaves the JVM for Python. Clean sample data hides most of these. The answers below come from a real file that does not cooperate: the UCI household power data, two million one-minute readings, separated by semicolons, with "?" for missing values and dates written without leading zeros (UCI: household power consumption).
import re
from pyspark.sql import SparkSession, Window, functions as F, types as T
spark = (SparkSession.builder.master("local[4]").config("spark.ui.showConsoleProgress", "false")
.config("spark.driver.memory", "2g").getOrCreate())
spark.sparkContext.setLogLevel("ERROR")
tracker = spark.sparkContext.statusTracker()
PATH = "household_power_consumption.txt" # UCI household power: ';'-separated, '?' = missing
def jobs(group, action):
spark.sparkContext.setJobGroup(group, group)
out = action()
return out, len(tracker.getJobIdsForGroup(group))
print("P1 schema inference and a placeholder for missing values")
inferred, n_inferred = jobs("infer", lambda: spark.read.csv(PATH, sep=";", header=True, inferSchema=True))
print(f" inferSchema=True: Global_active_power is {dict(inferred.dtypes)['Global_active_power']} (jobs to read the schema: {n_inferred})")
with_null, _ = jobs("infer-null", lambda: spark.read.csv(PATH, sep=";", header=True, inferSchema=True, nullValue="?"))
print(f" with nullValue='?': Global_active_power is {dict(with_null.dtypes)['Global_active_power']}")
print("\nP2 an explicit schema skips the inference pass")
schema = T.StructType([T.StructField("Date", T.StringType()), T.StructField("Time", T.StringType())]
+ [T.StructField(c, T.DoubleType()) for c in ["Global_active_power", "Global_reactive_power", "Voltage",
"Global_intensity", "Sub_metering_1", "Sub_metering_2", "Sub_metering_3"]])
power, n_explicit = jobs("explicit", lambda: spark.read.csv(PATH, sep=";", header=True, schema=schema, nullValue="?"))
print(f" jobs to read with an explicit schema: {n_explicit}")
print("\nP3 nulls")
total, missing = power.count(), power.filter(F.col("Global_active_power").isNull()).count()
avg_all = power.agg(F.avg("Global_active_power")).first()[0]
avg_zero = power.fillna(0, ["Global_active_power"]).agg(F.avg("Global_active_power")).first()[0]
print(f" {total:,} rows, {missing:,} with no reading | avg ignoring nulls {avg_all:.4f} kW | avg after fillna(0) {avg_zero:.4f} kW")
print("\nP4 parsing dates: the pattern must match the data")
sample = power.select("Date").distinct().orderBy("Date")
print(f" example raw values: {[r.Date for r in sample.limit(3).collect()]}")
try:
power.select(F.to_date("Date", "dd/MM/yyyy").alias("d")).filter(F.col("d").isNull()).count()
except Exception as error: # Spark 3 refuses rather than silently returning nulls
name = type(error).__name__
reason = next(line for line in str(error).splitlines() if "could not be parsed" in line or "Fail to parse" in line)
message = re.sub(r"'[^']*'", "'<first bad value>'", reason.split("You can set")[0].strip()) # which row fails first varies
print(f" 'dd/MM/yyyy' -> {name}: {message}")
loose = power.select(F.to_date("Date", "d/M/yyyy").alias("d")).filter(F.col("d").isNull()).count()
print(f" 'd/M/yyyy' -> rows that fail to parse: {loose:,}")
daily = (power.withColumn("day", F.to_date("Date", "d/M/yyyy")).groupBy("day")
.agg(F.avg("Global_active_power").alias("kw")).filter(F.col("kw").isNotNull()))
w = Window.orderBy("day").rowsBetween(-6, 0)
rolled = daily.withColumn("kw_7d", F.avg("kw").over(w)).orderBy(F.desc("kw")).first()
print(f"\nP5 window: highest daily average {rolled.kw:.3f} kW on {rolled.day}, 7-day rolling average then {rolled.kw_7d:.3f} kW")
print("\nP6 a Python UDF vs a built-in function")
watts_udf = F.udf(lambda kw: None if kw is None else kw * 1000.0, T.DoubleType())
by_udf = power.select(watts_udf("Global_active_power").alias("w"))
by_builtin = power.select((F.col("Global_active_power") * 1000).alias("w"))
same = by_udf.agg(F.sum("w")).first()[0] == by_builtin.agg(F.sum("w")).first()[0]
print(f" same total: {same} | UDF plan runs Python (BatchEvalPython): {'BatchEvalPython' in by_udf._jdf.queryExecution().executedPlan().toString()}"
f" | built-in plan does: {'BatchEvalPython' in by_builtin._jdf.queryExecution().executedPlan().toString()}")
print("\nP7 take() vs collect()")
print(f" take(5) returned {len(power.take(5))} rows; collect() would pull all {total:,} rows into the driver")
spark.stop()P1 schema inference and a placeholder for missing values
inferSchema=True: Global_active_power is string (jobs to read the schema: 2)
with nullValue='?': Global_active_power is double
P2 an explicit schema skips the inference pass
jobs to read with an explicit schema: 0
P3 nulls
2,075,259 rows, 25,979 with no reading | avg ignoring nulls 1.0916 kW | avg after fillna(0) 1.0779 kW
P4 parsing dates: the pattern must match the data
example raw values: ['1/1/2007', '1/1/2008', '1/1/2009']
'dd/MM/yyyy' -> Py4JJavaError: Fail to parse '<first bad value>' in the new parser.
'd/M/yyyy' -> rows that fail to parse: 0
P5 window: highest daily average 3.315 kW on 2006-12-23, 7-day rolling average then 1.817 kW
P6 a Python UDF vs a built-in function
same total: True | UDF plan runs Python (BatchEvalPython): True | built-in plan does: False
P7 take() vs collect()
take(5) returned 5 rows; collect() would pull all 2,075,259 rows into the driverP1. What does inferSchema do with a placeholder value?
It sees text. With inferSchema=True, the power column came back as a string, because "?" is not a number, and every later sum or average would have needed a cast or would have failed. Declaring the placeholder with nullValue="?" turned those cells into nulls, and inference then chose double (Spark: CSV options). Ask what "missing" looks like in the source before trusting inferred types.
P2. Why pass an explicit schema?
Inference reads the data to guess types, an extra pass over the file. Reading with inference launched 2 jobs before any query ran; reading with an explicit schema launched none. On large files, that pass costs real time. An explicit schema also documents what you expect, and a type that does not match becomes visible immediately instead of quietly turning a column into strings.
P3. How do aggregates treat nulls?
They skip them. 25,979 of 2,075,259 rows had no reading. The average ignoring nulls was 1.0916 kW; after fillna(0) it fell to 1.0779 kW, because 25,979 invented zeros were averaged in. Filling with zero is only right when zero is the true value, not when the value is unknown. Count nulls before and after every fill, and say which you chose and why.
P4. Why did a date pattern fail?
Because the data has no leading zeros: dates such as "1/1/2007". In Spark 3, a numeric pattern letter repeated twice, as in dd, expects exactly two digits when parsing (Spark: datetime patterns). Spark did not quietly return nulls; it raised an error: "Fail to parse ... in the new parser", naming the first value it met. The pattern d/M/yyyy parsed every row. The error mentions the change of parser in Spark 3.0 and the spark.sql.legacy.timeParserPolicy setting (Spark: migration guide). Fixing the pattern is better than switching to the legacy parser.
P5. How do you calculate a rolling average in PySpark?
With a window and a row frame: Window.orderBy("day").rowsBetween(-6, 0) averages each day with the six before it. The highest daily average was 3.315 kW on 23 December 2006, while the 7-day rolling average that day was 1.817 kW, smoothing a single cold, busy day. A window with orderBy and no partitionBy moves all rows to one partition, which is fine for 1,442 daily rows and a problem for billions; partition by a key when the data is large.
P6. Why avoid Python UDFs?
Because each row leaves the JVM, is converted, processed in Python and sent back. A UDF converting kilowatts to watts gave exactly the same total as the built-in expression col * 1000, but its physical plan contained BatchEvalPython, the step that ships rows to Python workers; the built-in plan did not. Use built-in functions first, and if Python is unavoidable, pandas UDFs, which move data in Arrow batches and work on whole columns (PySpark: Arrow and pandas UDFs).
P7. What is wrong with collect()?
It brings every row to the driver. take(5) returned 5 rows; collect() would have pulled all 2,075,259 into one Python process. On real data that is how drivers run out of memory. Use take, limit or show to inspect, and write large results to storage instead of collecting them.
P8. repartition() or coalesce()?
Both change the number of partitions. repartition(n) shuffles all rows into n roughly equal partitions, and can also partition by a column; coalesce(n) only merges existing partitions without a full shuffle, so it is cheaper but can leave partitions uneven. Use coalesce to reduce the number of output files before writing, and repartition when you need more parallelism or rows grouped by a key.
How to answer PySpark questions
- Read deliberately: separator, header, null marker and schema.
- Count nulls before and after every transformation that touches them.
- Prefer built-in functions to UDFs, and check the plan.
- Keep data on the executors; bring only small results to the driver.
Spark's internals are covered in Apache Spark interview questions and tuning in Spark performance interview questions. The same file is used with shell tools in Linux interview questions for data engineers. For when Spark is overkill, see PySpark vs pandas; for the full round, data engineering interview questions and answers.
What are common PySpark interview questions?
Should I use inferSchema in PySpark?
Why are Python UDFs slow in PySpark?
How do I handle dates without leading zeros in Spark 3?
PySpark is part of the Data Engineering course.
Sources
- CSV Files (Apache Spark 3.5 documentation) — The Apache Software Foundation
- Datetime Patterns for Formatting and Parsing (Apache Spark 3.5 documentation) — The Apache Software Foundation
- Migration Guide: SQL, Datasets and DataFrame (Apache Spark 3.5 documentation) — The Apache Software Foundation
- Apache Arrow in PySpark (PySpark 3.5 documentation) — The Apache Software Foundation
- Individual Household Electric Power Consumption (UCI Machine Learning Repository) — UCI Machine Learning Repository
GloryTecks Team
Training & Placement Faculty
The GloryTecks faculty team mentors learners across Data Science, AI and Data Engineering, with a focus on real-time projects and placement readiness in Hyderabad.
Want to master Interview Questions?
Join GloryTecks’ expert-led Data Engineering training in Hyderabad with real-time projects and 100% placement support.
Related articles
SQL Interview Questions: Top 50 with Answers
Fifty SQL interview questions with answers checked on PostgreSQL, DuckDB and SQLite against one small practice schema: evaluation order, NULL logic, joins and fan-out, window functions, dates, and performance, including where the three engines disagree.
Python Interview Questions for Data Roles
The plain-Python coding tasks data-analyst and data-engineer interviews use, without pandas: counting, deduplicating, grouping, streaming large files, flattening JSON, joining, and the bugs interviewers plant. Each has a worked solution and the follow-up questions to expect.
Data Science Interview Questions and Answers 2026
A data science interview is several interviews in one: statistics, machine learning, coding, product sense and a take-home. This guide maps each round with model answers, then works a churn take-home on real telecom data, including the checks that separate a strong submission from a high score.