-
Notifications
You must be signed in to change notification settings - Fork 128
Extend summary metrics with per-check-name breakdowns #1097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mwojtyczka
merged 29 commits into
main
from
ghanse/issue-943-extend-summary-metrics-check-name
Apr 21, 2026
Merged
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
91309bc
Extend summary metrics with per-check-name breakdowns
ghanse 78cd9e3
Add unit tests for per-check summary metrics
ghanse d99bf2d
add track_extended_metrics flag to DQMetricsObserver, use DQXError
ghanse 09ac7c6
add integration tests for extended metrics, update unit tests
ghanse 4022ec0
add duplicate alias collision detection in per-check metrics
ghanse 1167903
cleanup: improve naming and fix misleading docstring
ghanse 7bf8468
Merge branch 'main' into ghanse/issue-943-extend-summary-metrics-chec…
ghanse a1141c1
Compact check-level metrics into single check_metrics row
ghanse 5e4c8a8
Merge branch 'main' into ghanse/issue-943-extend-summary-metrics-chec…
mwojtyczka 40614ca
code review feedback implementation
mwojtyczka 664a9c4
refactor
mwojtyczka b3eda66
refactor
mwojtyczka f42e0d3
updated docs and demo
mwojtyczka e2f3329
refactor
mwojtyczka 897a910
fmt
mwojtyczka 28844c0
updated docs
mwojtyczka 8075336
Merge branch 'main' into ghanse/issue-943-extend-summary-metrics-chec…
mwojtyczka 13e67f0
use uv for building deps for workflows
mwojtyczka a4b1bae
reduced test flakiness
mwojtyczka cb9f41f
reduce tests flakiness
mwojtyczka 7d2c966
increase token expiration time, fix assertions
mwojtyczka ce19c99
fixed building wheel
mwojtyczka a4a86a9
fix wheel build
mwojtyczka 1581e1e
fix build
mwojtyczka d022cfc
fix build
mwojtyczka 554f1e6
fix tests
mwojtyczka 798d825
reduce anomaly contention in CI
mwojtyczka b4941d9
bumped acceptance action
mwojtyczka c5b9ab0
updated tests to reduce flakiness
mwojtyczka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| from dataclasses import dataclass | ||
| import re | ||
| from dataclasses import dataclass, field | ||
| from datetime import datetime | ||
| from functools import cached_property | ||
| from typing import Any | ||
|
|
@@ -8,6 +9,23 @@ | |
| import pyspark.sql.functions as F | ||
|
|
||
|
|
||
| def _sanitize_metric_alias(name: str) -> str: | ||
| """Sanitize a check name to produce a valid Spark SQL column alias. | ||
|
|
||
| Replaces any non-alphanumeric character (except underscore) with an underscore | ||
| and collapses consecutive underscores. | ||
|
|
||
| Args: | ||
| name: The raw check name. | ||
|
|
||
| Returns: | ||
| A sanitized string safe for use as a Spark SQL alias. | ||
| """ | ||
| sanitized = re.sub(r"[^a-zA-Z0-9_]", "_", name) | ||
| sanitized = re.sub(r"_+", "_", sanitized) | ||
| return sanitized.strip("_") | ||
|
|
||
|
|
||
| OBSERVATION_TABLE_SCHEMA = ( | ||
| "run_id string, run_name string, input_location string, output_location string, quarantine_location string, " | ||
| "checks_location string, rule_set_fingerprint string, metric_name string, metric_value string, run_time timestamp, " | ||
|
|
@@ -70,6 +88,7 @@ class DQMetricsObserver: | |
|
|
||
| _error_column_name: str = "_errors" | ||
| _warning_column_name: str = "_warnings" | ||
| _check_names: list[str] = field(default_factory=list) | ||
|
|
||
| @cached_property | ||
| def id(self) -> str: | ||
|
|
@@ -81,24 +100,57 @@ def id(self) -> str: | |
| """ | ||
| return self.id_overwrite or str(uuid4()) | ||
|
|
||
|
mwojtyczka marked this conversation as resolved.
|
||
| @cached_property | ||
| @property | ||
| def metrics(self) -> list[str]: | ||
| """ | ||
| Gets the observer metrics as Spark SQL expressions. | ||
|
|
||
| Returns: | ||
| A list of Spark SQL expressions defining the observer metrics (both default and custom). | ||
| A list of Spark SQL expressions defining the observer metrics (both default, per-check, and custom). | ||
| """ | ||
| default_metrics = [ | ||
| "count(1) as input_row_count", | ||
| f"count(case when {self._error_column_name} is not null then 1 end) as error_row_count", | ||
| f"count(case when {self._warning_column_name} is not null then 1 end) as warning_row_count", | ||
| f"count(case when {self._error_column_name} is null and {self._warning_column_name} is null then 1 end) as valid_row_count", | ||
| ] | ||
| default_metrics.extend(self._build_per_check_metrics()) | ||
| if self.custom_metrics: | ||
|
mwojtyczka marked this conversation as resolved.
|
||
| default_metrics.extend(self.custom_metrics) | ||
| return default_metrics | ||
|
|
||
| def set_check_names(self, check_names: list[str]) -> None: | ||
| """ | ||
| Sets the check names used to generate per-check summary metrics. | ||
|
|
||
| Args: | ||
| check_names: List of check names from the applied quality rules. | ||
| """ | ||
| self._check_names = check_names | ||
|
|
||
| def _build_per_check_metrics(self) -> list[str]: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we need more compact way to report check level metrics, e.g.
|
||
| """ | ||
| Builds per-check metric SQL expressions for each registered check name. | ||
|
|
||
| For each check name, generates a count of rows where that check appears in the errors or warnings array. | ||
|
|
||
| Returns: | ||
| A list of Spark SQL expressions for per-check metrics. | ||
| """ | ||
| per_check_metrics: list[str] = [] | ||
| for check_name in self._check_names: | ||
| safe_alias = _sanitize_metric_alias(check_name) | ||
| escaped_name = check_name.replace("'", "\\'") | ||
|
ghanse marked this conversation as resolved.
Outdated
|
||
| per_check_metrics.append( | ||
| f"count(case when exists({self._error_column_name}, x -> x.name = '{escaped_name}') then 1 end) " | ||
| f"as {safe_alias}_error_count" | ||
| ) | ||
| per_check_metrics.append( | ||
| f"count(case when exists({self._warning_column_name}, x -> x.name = '{escaped_name}') then 1 end) " | ||
| f"as {safe_alias}_warning_count" | ||
| ) | ||
| return per_check_metrics | ||
|
|
||
| @property | ||
| def observation(self) -> Observation: | ||
| """ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.