Data Validation at Scale with Spark/Databricks
What is Data Quality?
Data quality is the measure of how well suited a data set is to serve its specific purpose. Measures of data quality are based on data quality characteristics such as accuracy, completeness, consistency, validity, uniqueness, and timeliness.
Now while you generally write unit tests for your code, but do you also test your data? Incoming data quality can make or break your application. Incorrect, missing, or malformed data can have a large impact on production systems.
Data Quality in Bigdata world
Apache Spark has become a technology by default nowadays for big data ingestion & transformation. This becomes more robust with the managed service provided by Databricks in terms of working with data at scale.
Without spending too much time on the theoretical aspects, let’s jump into few cases/scenarios (I’ll be using Databricks notebooks for demo purpose):
Here’s the result:
What’s there beyond anomaly detection?
Above we can clearly see which records got changed and specifically which are the columns that got changed. Now that we are comfortable with basic anomaly check, how do we address broader aspects like following:
- Missing values that can lead to failures in production system that require non-null values (NullPointerException)?
- How changes in the distribution of data can lead to unexpected outputs of machine learning models?
- How aggregations of incorrect data can lead to wrong business decisions?
Well there are several open source data quality frameworks viz. Apache Griffin, Great Expectations, Deequ as well as Delta Live Tables (DLT) from Databricks to facilitate this.
In our case, we will be using Deequ from AWS. It allows you to calculate data quality metrics on your dataset, define and verify data quality constraints, and be informed about changes in the data distribution. Instead of implementing checks and verification algorithms on your own, you can focus on describing how your data should look. Deequ supports you by suggesting checks for you. Deequ is implemented on top of Apache Spark and is designed to scale with large datasets (think billions of rows) that typically live in a distributed filesystem or a data warehouse.
Firstly let’s configure the required libraries deequ (pydeequ for PySpark) as shown below:
And then let’s start with sample data set below:
And then run quality checks around it as below:
Here’s the result:
Through column constraint_status = “Failure”, you can track all the records that got failed during the validation process.
Though Deequ provides an overall data quality report it doesn’t fetch the individual bad records which failed the constraints. However, we can construct methods to create dynamic queries to identify bad records. We can get ideas from few Deequ constraint implementations that we used against each dataset.
I’ll illustrate two sample implementations (e.g. “CompletenessConstraint” and “MaxLengthConstraint”) as such to give an idea.
So you can easily derive from above implementations how quickly and efficiently we can build scalable data validation framework with minimum of effort. You can view full set of constraints/checks for your use below:
- hasSize — calculates the data frame size and runs the assertion on it.
- isComplete — asserts on a column completion.
- hasCompleteness — asserts on a column completion.
- isUnique — asserts on a column uniqueness.
- isPrimaryKey — asserts on a column(s) primary key characteristics.
- hasUniqueness — asserts on uniqueness in a single or combined set of key columns.
- hasDistinctness — distinctness in a single or combined set of key columns.
- hasUniqueValueRatio — the unique value ratio in a single or combined set of key columns.
- hasNumberOfDistinctValues — asserts on the number of distinct values a column has.
- hasHistogramValues — asserts on column’s value distribution.
- hasEntropy — asserts on a column entropy.
- hasMutualInformation — asserts on a mutual information between two columns.
- hasApproxQuantile — asserts on an approximated quantile.
- hasMinLength — asserts on the minimum length of the column.
- hasMaxLength — asserts on the maximum length of the column.
- hasMin — asserts on the minimum of the column.
- hasMax — asserts on the maximum of the column.
- hasMean — asserts on the mean of the column.
- hasSum — asserts on the sum of the column.
- hasStandardDeviation — asserts on the standard deviation of the column.
- hasApproxCountDistinct — asserts on the approximate count distinct of the given column.
- hasCorrelation — asserts on the Pearson correlation between two columns.
- satisfies — runs the given condition on the data frame.
- hasPattern — checks for pattern compliance.
- containsCreditCardNumber — verifies against a Credit Card pattern.
- containsEmail — verifies against an e-mail pattern.
- containsURL — verifies against an URL pattern.
- containsSocialSecurityNumber — verifies against the Social security number pattern for the US.
- hasDataType — verifies against the fraction of rows that conform to the given data type.
- isNonNegative — asserts that a column contains no negative values.
- isPositive — asserts that a column contains no negative values.
- isLessThan — asserts that, in each row, the value of columnA < the value of columnB.
- isLessThanOrEqualTo — asserts that, in each row, the value of columnA ≤ the value of columnB.
- isGreaterThan — asserts that, in each row, the value of columnA > the value of columnB.
- isGreaterThanOrEqualTo — asserts that, in each row, the value of columnA ≥ to the value of columnB.
- isContainedIn — asserts that every non-null value in a column is contained in a set of predefined values.
For simplicity and priority perspective, I’ve discussed only the critical and commonly used scenarios in our day to day life but deequ framework also covers advanced aspects like full-fledged metrics calculation (i.e. Deequ computes data quality metrics, that is, statistics such as completeness, maximum, or correlation) and auto suggestion of constraints (i.e. automated constraint suggestion methods that profile the data to infer useful constraints).
Thanks for reading. In case you want to share your case studies or want to connect, please ping me via LinkedIn