Refactor profiler column metrics into an extensible registry - #1384
Conversation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
mwojtyczka
left a comment
There was a problem hiding this comment.
Follow-up review of the head commit. The six earlier threads are all addressed — resolved them. A few new points on the extension point and conventions:
|
Hello, @mwojtyczka! Thanks for a review. The previous feedback has been addressed. Would it be possible to have another round? |
mwojtyczka
left a comment
There was a problem hiding this comment.
2 comments are still not fixed. Left a few additional small comments
…nKurchenko/dqx into feature/profiler_additional_metrics
mwojtyczka
left a comment
There was a problem hiding this comment.
Re-review at head 863ecf27 — all previously-flagged issues verified resolved. One doc-correctness finding inline. (The other item from the pass — empty_count returning F.lit(0) for non-text columns — is the intentional backward-compat trade-off already discussed here, so no action needed.) Resolving the review threads that are now fixed.
DataFrame.summary() emits percentile rows labelled 25%/50%/75%, and the
profiler stores them verbatim (_summarize: metric = row_dict["summary"]).
The reference table listed them as 25/50/75, so a custom builder doing
profiler_metrics.get("50") always got None. Document the literal keys.
Co-authored-by: Isaac <no-reply@databricks.com>
Docs feedback — "Extending the profiler with custom column metrics" (
|
|
One more wording nit in the same section:
The profiler produces candidate rules for review, not final rules (the sampling admonition earlier says "Manually review and tune rules generated from profiles"). Suggest:
|
|
…and as with the custom-metric example, this builder example needs a brief explanation of the function interface right next to it — a reader shouldn't have to reverse-engineer it from the sample. The code-verified contract (also listed in point 3 of my earlier comment): Custom profile builder —
|
…ferences - Call register_profile_column_metric / register_profile_builder decorators - Drop misleading 'at no extra cost'; note each metric adds work per run - Tie profile_column_metric_type to the concrete decorator argument - Document the metric and builder function interfaces (inputs/outputs) - Frame generated profiles as data quality rule suggestions - Cross-reference the reference page's Custom Column Metrics section Co-authored-by: Isaac <no-reply@databricks.com>
…overwrite - Add integration test for the full extension path: a custom column metric consumed by a custom register_profile_builder builder, producing a DQProfile via the public profile() API (also asserts the built-in count_distinct metric) - Add a builder-registry snapshot fixture for test isolation - Add a unit test for the column-metric overwrite-and-warn path Co-authored-by: Isaac <no-reply@databricks.com>
|
Addressed all the docs and testing feedback above directly on this branch (commits Docs (
Tests:
|
mwojtyczka
left a comment
There was a problem hiding this comment.
LGTM - made some small doc changes and increased code coverage
Changes
Sets up an extension point for the profiler by moving inline column-metric aggregation in
DQProfiler._profileinto a registry-based system. Users can now register their own column metric functions via the@register_profile_column_metric()decorator, mirroring the existingregister_rule/register_profile_builderextension patterns.The three existing metrics (
count_non_null,count_distinct,empty_count) are moved into this registry with no behavioural change._build_column_metricsbuilds the aggregation from whatever is registered.Rationale for landing the refactoring without new metrics
The profiling pipeline is:
column metrics → profile builder → check. Adding a new metric only adds value once a builder consumes it and generates a check. Two paths were considered for #1067:is_aggr_not_less_than/is_aggr_not_greater_thanchecks. But these checks are mostly useful for measurement data (revenue, sales amount, latency, temperature) and not meaningful for keys or categorical columns. Applying them indiscriminately would generate false positives. Selective, purpose-aware application is tracked in [FEATURE]: Profile classification support #1343.This PR takes option 2. New built-in metrics can be added later, together with the specific builder that consumes them, once the classification work in #1343 makes selective application safe.
What changed
PROFILE_COLUMN_METRIC_REGISTRYandregister_profile_column_metricdecorator inprofiler/profiler_column_metrics.pycount_non_null,count_distinct,empty_count) moved into the registryDQProfiler._profilerefactored: inline aggregation extracted into_build_column_metrics, which iterates the registryis_texthelper moved fromprofile_builder.pytoprofiler/common.py(now used across modules)Linked issues
Relates to #1067, related to #1343
Tests
Unit tests cover: registry (register, overwrite, function-name key); built-in metric functions across column types;
is_texthelper;_build_column_metrics(alias correctness,count_nullderivation, summary merge, empty DataFrame,None-returning metrics). Existing integration tests already cover the refactored aggregation path end-to-end.Documentation and Demos
New sections in
data_profiling.mdxguide andprofiler.mdxreference showing how to register custom metrics;dqx-profile-and-generate/SKILL.mdupdated with the extension point.🤖 Generated with Claude Code