Skip to main content

Data Quality Module

The data quality module lives at ingestion/src/metadata/data_quality/. It runs test cases against database tables (or DataFrames) and publishes results back to the OpenMetadata server. This guide walks through the architecture top-down: from how a workflow is triggered, through the execution pipeline, down to individual validators.

Directory Layout

Workflow Pipeline

Data quality follows the standard Source → Processor → Sink pattern defined in workflow/data_quality.py:

Test Execution Call Chain

This is the most important sequence to understand. When TestCaseRunner processes a test case, here is exactly what happens:

Data Model

Three entities form the core model. All are defined as JSON Schemas in openmetadata-spec/ and auto-generated into Python models:

Validator Architecture

Validators use a template method pattern with mixins for database-specific logic.

Class Hierarchy

How Validators Are Discovered

Validators are dynamically imported at runtime based on the validatorClass field from the TestDefinition:
This means adding a new test is purely additive — no registry to update, no imports to add. Just place the file in the right directory.

Dimensional Analysis

When a test case has dimensionColumns configured, the validator runs the test per group using GROUP BY:
Impact score (validations/impact_score.py) ranks which groups matter most:
  • failure_rate² — emphasizes high failure percentages
  • volume_factor — tiered by row count (0.25 for <10 rows → 1.5 for ≥100k)
  • sample_weight — credibility discount for small samples

Runtime Parameter Setters

Some tests need parameters that can only be resolved at execution time. The RuntimeParameterSetterFactory (validations/runtime_param_setter/param_setter_factory.py) maps test definition names to setter classes:

Adding a New Test

1

Create the base validator

Create validations/column/base/myNewTest.py (or table/base/ for table-level tests).Extend BaseTestValidator and implement:
  • _run_validation() — core test logic
  • _evaluate_test_condition() — return pass/fail
  • _format_result_message() — human-readable result string
2

Create the SQLAlchemy implementation

Create validations/column/sqlalchemy/myNewTest.py.Inherit from your base class and SQAValidatorMixin. The mixin gives you get_column(), run_query_results(), and _execute_dimensional_validation().
3

Create the Pandas implementation

Create validations/column/pandas/myNewTest.py.Inherit from your base class and PandasValidatorMixin.
4

Register the TestDefinition

Create a TestDefinition in OpenMetadata with:
  • validatorClass matching your file name (e.g., "myNewTestValidator")
  • entityType set to COLUMN or TABLE
  • Parameter definitions for any inputs your test needs
No imports or registries need to be updated. The ValidatorBuilder discovers your validator automatically from the file path convention.

Key Design Patterns

Key Files Quick Reference

All paths above are relative to ingestion/src/metadata/. For example, source/test_suite.py means ingestion/src/metadata/data_quality/source/test_suite.py.