
Before you start
Before trying this example, make sure you have:- The Astro CLI.
Clone the project
Clone the example project from the Astronomer GitHub. To keep your credentials secure when you deploy this project to your own git repository, create a file called.env with the contents of the .env_example file in the project root directory.
The repository is configured to create and use a local Postgres instance, accessible on port 5433. You do not need to define connections or access external tools.
Run the project
To run the example project, open your project directory and run:- The Airflow webserver, which runs the Airflow UI and can be accessed at
https://localhost:8080/. - The Airflow scheduler, which is responsible for monitoring and triggering tasks.
- The Airflow triggerer, which is an Airflow component used to run deferrable operators.
- The Airflow metadata database, which is a Postgres database that runs on port
5432. - A local Postgres instance, that runs on port
5433. This is the database that the DAGs in this project use to store the rose data.
create_rose_table DAG will start its first run automatically. The rose_classification DAG is scheduled on a dataset and will start as soon as the last task in the create_rose_table DAG finishes successfully.
Congratulations! You ran an end to end pipeline from creating a table in a best practice pattern including two sets of efficient data quality checks to model training and plotting! Use this project as a blueprint to build your own data-driven pipelines.
Project contents
Data source
The data in this example is generated using thegenerate_rose_data script. The script creates a CSV file in include that contains synthetic data about three cultivars of roses: Damask Rose (Rosa damascena), Tea Rose (Rosa odorata), and Moss Rose (Rosa centifolia).
You can use a classification model with the generated data to predict the cultivar of a rose with an accuracy of around 70-80%. Adjust the parameters in the script and rerun it to generate different data.
Project overview
This project consists of two DAGs,create_rose_table and rose_classification which is scheduled on a task in the first DAG completing successfully using an Airflow dataset.

create_rose_table DAG contains a task group with a table creation pattern that includes two types of data quality checks:
- Checks that stop the pipeline if data doesn’t pass the checks.
- Checks that log a warning but don’t stop the pipeline.

rose_classification DAG engineers machine learning features based on the table created by the create_rose_table DAG and then trains a classification model to predict the rose_type column based on these features. The last task plots model results.

Project code
This use case showcases setup/ teardown tasks in a data quality use case, as well as how to use Airflow datasets and the Astro Python SDK, an open-source package created by Astronomer to simplify DAG writing with Python functions. The result is a complete ELT and ML pipeline example.Create table DAG
Thecreate_rose_table DAG is organized using nested task groups. This pattern has two advantages: It makes it easier to navigate the DAG graph, and it gives you the ability to template the task group pattern and turn it into a reusable module.
The create table pattern shown in this example starts with creating and populating a temporary table. This is especially helpful in production when the target table is already in use, for example when serving a dashboard or machine learning model. Both creating the table (create_tmp) and loading data into the table (load_data_into_tmp) are defined as setup tasks. The task which drops the temporary table (drop_tmp) is the corresponding teardown task.
The full setup/ teardown workflow includes all tasks shown in the following DAG graph:

.as_teardown method on a regular Airflow task object and supplying all associated setup tasks to the setups parameter. The test_tmp task group and the swap task are automatically determined to be in scope of the setup/ teardown workflow because they lie in between the setup and teardown tasks in the dependency structure.
SQLColumnCheckOperator and SQLTableCheckOperator.
The test_cols task runs checks on individual columns of the temporary table, in this case to check that the petal_size_cm, stem_length_cm and leaf_size_cm columns contain values in a reasonable range for the rose cultivars. To see more examples of defining data quality check statements in the SQLColumnCheckOperator and SQLTableCheckOperator, see the Run data quality checks using SQL check operators.
test_table task runs checks on the table to make sure that there’s enough rows for the downstream model to be trained, and that the rose_type column only contains three cultivars.
DO block that checks if the target table already exists and creates a backup table if it does.
swap task creates the backup table, which is why it’s defined as a setup task. The associated teardown task is drop_backup, the task that drops the backup table. Defining this second setup/ teardown workflow ensures that the backup table is dropped even if the dropping of the temporary table isn’t successful, ensuring idempotency of the DAG.
validate task group runs non-halting data quality checks on the target table. These checks are defined using the same two SQL check operators as the halting checks on the temporary table. If the data fails the checks in this second task group, the pipeline won’t be stopped, but the check failures are printed to the logs. It is common to set up notifications to alert relevant data stakeholders of these check failures.

test_cols task and ensured the blooming_month information matches our expectations.
validate task group, the pipeline will continue because the sql_check_done task uses the trigger rule all_done to be successful always.
table_ready_for_the_model task produces to the Airflow dataset postgres://public/roses to trigger the downstream rose_classification DAG.
ML DAG
Airflow datasets let you schedule DAGs based on when a specific file or database is updated in a separate DAG. In this example, the ML DAGrose_classification is scheduled to run as soon as the roses table is updated by the upstream DAG.
aql.dataframe decorator, the roses table is ingested directly as a pandas DataFrame.
The feature_engineering task creates a train-test split, scales the numeric features, and one-hot encodes the categorical feature blooming_month using functions from scikit-learn. The resulting sets of train and test data are returned as a dictionary of pandas DataFrames.
train_model task ingests the dictionary and trains a RandomForestClassifier on the training data. The fitted model is then used to predict the rose_type of the test data.
The train_model task prints the accuracy, f1-score, and a classification report to the logs and returns a dictionary of model results for the downstream plotting task.
plot_results task. The plot is saved in the include directory of the local Astro project. If you are running this pipeline in production, make sure to save this file to persistent storage.
aql.cleanup task is run in parallel to the rest of the DAG and cleans up any temporary tables after they’re no longer needed.
See also
- Documentation: Astro Python SDK.
- Guide: Setup/ teardown.
- Tutorial: SQL check operators.