Pipeline orchestration with Airflow in Apache Spark - Time & Space Complexity
We want to understand how the time to run a data pipeline changes as the amount of data or tasks grows.
How does adding more steps or data affect the total execution time?
Analyze the time complexity of the following Airflow DAG that runs Spark jobs sequentially.
from airflow import DAG
from airflow.operators.bash import BashOperator
from datetime import datetime
def spark_job(task_id, script):
return BashOperator(
task_id=task_id,
bash_command=f"spark-submit {script}",
dag=dag
)
dag = DAG('spark_pipeline', start_date=datetime(2024,1,1))
job1 = spark_job('job1', 'job1.py')
job2 = spark_job('job2', 'job2.py')
job3 = spark_job('job3', 'job3.py')
job1 >> job2 >> job3
This code defines three Spark jobs run one after another using Airflow orchestration.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Running each Spark job one after another.
- How many times: Once per job, here 3 times, but can grow with more jobs.
As you add more Spark jobs to the pipeline, the total time grows roughly by adding each job's time.
| Input Size (number of jobs) | Approx. Operations (job runs) |
|---|---|
| 3 | 3 Spark job runs |
| 10 | 10 Spark job runs |
| 100 | 100 Spark job runs |
Pattern observation: The total execution time grows linearly as you add more jobs.
Time Complexity: O(n)
This means the total time grows directly in proportion to the number of jobs in the pipeline.
[X] Wrong: "Adding more jobs won't increase total time because they run in parallel automatically."
[OK] Correct: In this setup, jobs run one after another, so each job adds to total time. Parallelism must be explicitly set.
Understanding how pipeline steps add up in time helps you design efficient workflows and explain your reasoning clearly in interviews.
"What if we changed the pipeline to run some jobs in parallel? How would the time complexity change?"
Practice
Solution
Step 1: Understand Airflow's role
Airflow is designed to schedule and orchestrate workflows, ensuring tasks run in the correct order.Step 2: Compare with other options
Writing Spark SQL, storing data, and visualizing data are not Airflow's main functions.Final Answer:
To schedule and manage the order of Spark jobs -> Option DQuick Check:
Airflow schedules pipelines = C [OK]
- Confusing Airflow with Spark SQL or storage tools
- Thinking Airflow processes data directly
- Assuming Airflow is for data visualization
spark-submit?Solution
Step 1: Identify operator for shell commands
BashOperator runs shell commands, perfect forspark-submit.Step 2: Exclude other operators
PythonOperator runs Python code, SparkOperator is not a default Airflow operator, EmailOperator sends emails.Final Answer:
BashOperator -> Option AQuick Check:
Run shell commands with BashOperator [OK]
- Choosing PythonOperator for shell commands
- Assuming SparkOperator exists by default
- Confusing EmailOperator with job execution
task1 = BashOperator(task_id='task1', bash_command='spark-submit job1.py', dag=dag) task2 = BashOperator(task_id='task2', bash_command='spark-submit job2.py', dag=dag) task3 = BashOperator(task_id='task3', bash_command='spark-submit job3.py', dag=dag) task1 >> task2 >> task3
Solution
Step 1: Understand the dependency operator
The operator>>means 'runs before', so task1 runs before task2, and task2 before task3.Step 2: Determine execution order
Tasks run sequentially: task1, then task2, then task3.Final Answer:
task1 -> task2 -> task3 -> Option BQuick Check:
Dependencies define order = D [OK]
- Reading >> as reverse order
- Assuming tasks run in parallel without dependencies
- Mixing up task names and order
task1 = BashOperator(task_id='task1', bash_command='spark-submit job1.py', dag=dag) task2 = BashOperator(task_id='task1', bash_command='spark-submit job2.py', dag=dag) task1 >> task2
Solution
Step 1: Check task_id uniqueness
Both tasks have the same task_id 'task1', which is not allowed in Airflow.Step 2: Verify other parts
dag parameter is present, >> operator is correctly used, bash_command syntax is valid.Final Answer:
Duplicate task_id 'task1' causes conflict -> Option CQuick Check:
Unique task_id needed = A [OK]
- Reusing task_id for different tasks
- Ignoring error messages about task_id
- Thinking >> operator causes error here
Solution
Step 1: Understand dependency direction
job1 must run before job2, and job2 before job3, so job1 is upstream of job2, job2 upstream of job3.Step 2: Check each option's dependency setup
job1 = BashOperator(task_id='job1', bash_command='spark-submit job1.py', dag=dag) job2 = BashOperator(task_id='job2', bash_command='spark-submit job2.py', dag=dag) job3 = BashOperator(task_id='job3', bash_command='spark-submit job3.py', dag=dag) job1.set_downstream(job2) job2.set_downstream(job3)
uses set_downstream correctly: job1 -> job2 -> job3. The other snippets reverse or mix the order incorrectly.Final Answer:
job1.set_downstream(job2); job2.set_downstream(job3) -> Option AQuick Check:
Use set_downstream for correct order = A [OK]
- Reversing dependency direction
- Mixing task order in >> chains
- Confusing set_downstream with set_upstream
Ready to prove it?
Pass the test and this pattern moves unknown
