From 7bf03b5d631e7397bf7da6903f88be56fe827eb7 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Fri, 5 Jul 2024 13:02:55 -0700 Subject: [PATCH] /* PR_START p--query-resolution-perf 16 */ Make patterns dataclasses. --- .../metricflow_semantics/query/query_resolver.py | 2 +- .../specs/patterns/match_list_pattern.py | 13 +++++++++---- .../patterns/metric_time_default_granularity.py | 8 ++++---- .../specs/patterns/metric_time_pattern.py | 2 ++ .../specs/patterns/minimum_time_grain.py | 2 ++ .../specs/patterns/no_group_by_metric.py | 2 ++ .../specs/patterns/none_date_part.py | 2 ++ 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/metricflow-semantics/metricflow_semantics/query/query_resolver.py b/metricflow-semantics/metricflow_semantics/query/query_resolver.py index d04af1ebfa..72ea1cb506 100644 --- a/metricflow-semantics/metricflow_semantics/query/query_resolver.py +++ b/metricflow-semantics/metricflow_semantics/query/query_resolver.py @@ -157,7 +157,7 @@ def _resolve_group_by_item_input( input_str=str(group_by_item_input.input_obj), candidate_filters=QueryItemSuggestionGenerator.GROUP_BY_ITEM_CANDIDATE_FILTERS + ( - MatchListSpecPattern( + MatchListSpecPattern.create( listed_specs=valid_group_by_item_specs_for_querying, ), ), diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/match_list_pattern.py b/metricflow-semantics/metricflow_semantics/specs/patterns/match_list_pattern.py index ea57b2d36b..df6f8eda8b 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/match_list_pattern.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/match_list_pattern.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Sequence +from dataclasses import dataclass +from typing import Sequence, Tuple from typing_extensions import override @@ -8,15 +9,19 @@ from metricflow_semantics.specs.patterns.spec_pattern import SpecPattern +@dataclass(frozen=True) class MatchListSpecPattern(SpecPattern): """A spec pattern that matches based on a configured list of specs. This is useful for filtering possible group-by-items to ones valid for a query. """ - def __init__(self, listed_specs: Sequence[InstanceSpec]) -> None: # noqa: D107 - self._listed_specs = set(listed_specs) + listed_specs: Tuple[InstanceSpec, ...] + + @staticmethod + def create(listed_specs: Sequence[InstanceSpec]) -> MatchListSpecPattern: # noqa: D102 + return MatchListSpecPattern(tuple(listed_specs)) @override def match(self, candidate_specs: Sequence[InstanceSpec]) -> Sequence[InstanceSpec]: - return tuple(spec for spec in candidate_specs if spec in self._listed_specs) + return tuple(spec for spec in candidate_specs if spec in self.listed_specs) diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_default_granularity.py b/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_default_granularity.py index eb273a221b..5a28db0787 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_default_granularity.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_default_granularity.py @@ -1,6 +1,7 @@ from __future__ import annotations from collections import defaultdict +from dataclasses import dataclass from typing import Dict, Optional, Sequence, Set, Tuple from dbt_semantic_interfaces.type_enums import TimeGranularity @@ -18,6 +19,7 @@ from metricflow_semantics.time.granularity import ExpandedTimeGranularity +@dataclass(frozen=True) class MetricTimeDefaultGranularityPattern(SpecPattern): """A pattern that matches metric_time specs if they have the default granularity for the requested metrics. @@ -42,13 +44,11 @@ class MetricTimeDefaultGranularityPattern(SpecPattern): ] """ - def __init__(self, max_metric_default_time_granularity: Optional[TimeGranularity]) -> None: # noqa: D107 - self._max_metric_default_time_granularity = max_metric_default_time_granularity + max_metric_default_time_granularity: Optional[TimeGranularity] @override def match(self, candidate_specs: Sequence[InstanceSpec]) -> Sequence[InstanceSpec]: spec_set = group_specs_by_type(candidate_specs) - # If there are no metric_time specs in the query, skip this filter. if not spec_set.metric_time_specs: return candidate_specs @@ -56,7 +56,7 @@ def match(self, candidate_specs: Sequence[InstanceSpec]) -> Sequence[InstanceSpe # If there are metrics in the query, use max metric default. For no-metric queries, use standard default. # TODO: [custom granularity] allow custom granularities to be used as defaults if appropriate default_granularity = ExpandedTimeGranularity.from_time_granularity( - self._max_metric_default_time_granularity or DEFAULT_TIME_GRANULARITY + self.max_metric_default_time_granularity or DEFAULT_TIME_GRANULARITY ) spec_key_to_grains: Dict[TimeDimensionSpecComparisonKey, Set[ExpandedTimeGranularity]] = defaultdict(set) diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_pattern.py b/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_pattern.py index 9482c37cc3..d032bbf469 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_pattern.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/metric_time_pattern.py @@ -1,5 +1,6 @@ from __future__ import annotations +from dataclasses import dataclass from typing import Sequence from dbt_semantic_interfaces.naming.keywords import METRIC_TIME_ELEMENT_NAME @@ -11,6 +12,7 @@ from metricflow_semantics.specs.time_dimension_spec import TimeDimensionSpec +@dataclass(frozen=True) class MetricTimePattern(SpecPattern): """Pattern that matches to only metric_time specs. diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/minimum_time_grain.py b/metricflow-semantics/metricflow_semantics/specs/patterns/minimum_time_grain.py index ce76718fb6..f9459f3661 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/minimum_time_grain.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/minimum_time_grain.py @@ -1,6 +1,7 @@ from __future__ import annotations from collections import defaultdict +from dataclasses import dataclass from typing import Dict, List, Sequence, Set from dbt_semantic_interfaces.type_enums import TimeGranularity @@ -17,6 +18,7 @@ from metricflow_semantics.time.granularity import ExpandedTimeGranularity +@dataclass(frozen=True) class MinimumTimeGrainPattern(SpecPattern): """A pattern that matches linkable specs, but for time dimension specs, only the one with the finest base grain. diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/no_group_by_metric.py b/metricflow-semantics/metricflow_semantics/specs/patterns/no_group_by_metric.py index ffb2f62ec3..714aceb3f6 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/no_group_by_metric.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/no_group_by_metric.py @@ -1,5 +1,6 @@ from __future__ import annotations +from dataclasses import dataclass from typing import List, Sequence from typing_extensions import override @@ -9,6 +10,7 @@ from metricflow_semantics.specs.spec_set import group_specs_by_type +@dataclass(frozen=True) class NoGroupByMetricPattern(SpecPattern): """Matches to linkable specs, but only if they're not group by metrics. diff --git a/metricflow-semantics/metricflow_semantics/specs/patterns/none_date_part.py b/metricflow-semantics/metricflow_semantics/specs/patterns/none_date_part.py index 8046f6e263..52d9c9589c 100644 --- a/metricflow-semantics/metricflow_semantics/specs/patterns/none_date_part.py +++ b/metricflow-semantics/metricflow_semantics/specs/patterns/none_date_part.py @@ -1,5 +1,6 @@ from __future__ import annotations +from dataclasses import dataclass from typing import List, Sequence from typing_extensions import override @@ -9,6 +10,7 @@ from metricflow_semantics.specs.spec_set import group_specs_by_type +@dataclass(frozen=True) class NoneDatePartPattern(SpecPattern): """Matches to linkable specs, but for time dimension specs, only matches to ones without date_part.