Skip to content
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

Use MetricTimeDefaultGranularityPattern to resolve metric_time granularity #1332

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240628-074617.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Use Metric.time_granularity to resolve metric_time.
time: 2024-06-28T07:46:17.768805-07:00
custom:
Author: courtneyholcomb
Issue: "1310"
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
)
from metricflow_semantics.query.suggestion_generator import QueryItemSuggestionGenerator
from metricflow_semantics.specs.instance_spec import LinkableInstanceSpec
from metricflow_semantics.specs.patterns.metric_time_default_granularity import MetricTimeDefaultGranularityPattern
from metricflow_semantics.specs.patterns.minimum_time_grain import MinimumTimeGrainPattern
from metricflow_semantics.specs.patterns.no_group_by_metric import NoGroupByMetricPattern
from metricflow_semantics.specs.patterns.spec_pattern import SpecPattern
Expand Down Expand Up @@ -81,10 +82,10 @@ def resolve_matching_item_for_querying(
spec_pattern: SpecPattern,
suggestion_generator: Optional[QueryItemSuggestionGenerator],
) -> GroupByItemResolution:
"""Returns the spec that corresponds the one described by spec_pattern and is valid for the query.
"""Returns the spec that corresponds to the one described by spec_pattern and is valid for the query.

For queries, if the pattern matches to a spec for the same element at different grains, the spec with the finest
common grain is returned.
common grain is returned, unless the spec is metric_time, in which case the default grain is returned.
"""
push_down_visitor = _PushDownGroupByItemCandidatesVisitor(
manifest_lookup=self._manifest_lookup,
Expand All @@ -101,9 +102,13 @@ def resolve_matching_item_for_querying(
issue_set=push_down_result.issue_set,
)

push_down_result = push_down_result.filter_candidates_by_pattern(
for candidate_filter in (
# Default pattern must come first to avoid removing default grain options prematurely.
MetricTimeDefaultGranularityPattern(push_down_result.max_metric_default_time_granularity),
MinimumTimeGrainPattern(),
)
):
push_down_result = push_down_result.filter_candidates_by_pattern(candidate_filter)

logger.info(
f"Spec pattern:\n"
f"{indent(mf_pformat(spec_pattern))}\n"
Expand Down Expand Up @@ -152,12 +157,19 @@ def resolve_matching_item_for_filters(

push_down_visitor = _PushDownGroupByItemCandidatesVisitor(
manifest_lookup=self._manifest_lookup,
source_spec_patterns=(spec_pattern, MinimumTimeGrainPattern()),
source_spec_patterns=(spec_pattern,),
suggestion_generator=suggestion_generator,
)

push_down_result: PushDownResult = resolution_node.accept(push_down_visitor)

for candidate_filter in (
# Default pattern must come first to avoid removing default grain options prematurely.
MetricTimeDefaultGranularityPattern(push_down_result.max_metric_default_time_granularity),
MinimumTimeGrainPattern(),
):
push_down_result = push_down_result.filter_candidates_by_pattern(candidate_filter)

if push_down_result.candidate_set.num_candidates == 0:
return GroupByItemResolution(
spec=None,
Expand Down
17 changes: 11 additions & 6 deletions metricflow-semantics/metricflow_semantics/query/query_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ def _get_saved_query(self, saved_query_parameter: SavedQueryParameter) -> SavedQ
return matching_saved_queries[0]

@staticmethod
def _metric_time_granularity(time_dimension_specs: Sequence[TimeDimensionSpec]) -> Optional[TimeGranularity]:
def _get_smallest_requested_metric_time_granularity(
time_dimension_specs: Sequence[TimeDimensionSpec],
) -> Optional[TimeGranularity]:
matching_specs: Sequence[InstanceSpec] = time_dimension_specs

for pattern_to_apply in (
Expand All @@ -172,18 +174,21 @@ def _adjust_time_constraint(
time_dimension_specs_in_query: Sequence[TimeDimensionSpec],
time_constraint: TimeRangeConstraint,
) -> TimeRangeConstraint:
metric_time_granularity = MetricFlowQueryParser._metric_time_granularity(time_dimension_specs_in_query)
"""Change the time range so that the ends are at the ends of the requested time granularity windows.

e.g. [2020-01-15, 2020-2-15] with MONTH granularity -> [2020-01-01, 2020-02-29]
"""
metric_time_granularity = MetricFlowQueryParser._get_smallest_requested_metric_time_granularity(
time_dimension_specs_in_query
)
if metric_time_granularity is None:
# This indicates there were no metric time specs in the query, so use smallest available granularity for metric_time.
group_by_item_resolver = GroupByItemResolver(
manifest_lookup=self._manifest_lookup,
resolution_dag=resolution_dag,
)
metric_time_granularity = group_by_item_resolver.resolve_min_metric_time_grain()

"""Change the time range so that the ends are at the ends of the appropriate time granularity windows.

e.g. [2020-01-15, 2020-2-15] with MONTH granularity -> [2020-01-01, 2020-02-29]
"""
return self._time_period_adjuster.expand_time_constraint_to_fill_granularity(
time_constraint=time_constraint,
granularity=metric_time_granularity,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,108 +1,44 @@
GroupByItemResolution(
linkable_element_set=LinkableElementSet(),
issue_set=MetricFlowQueryResolutionIssueSet(
issues=(
NoCommonItemsInParents(
issue_type=ERROR,
query_resolution_path=MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_5),
MetricGroupByItemResolutionNode(node_id=mtr_10),
spec=TimeDimensionSpec(element_name='metric_time', time_granularity=YEAR),
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=YEAR,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
),
parent_candidate_sets=(
GroupByItemCandidateSet(
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=MONTH,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
),
properties=frozenset(
'METRIC_TIME',
),
time_granularity=MONTH,
),
),
},
),
measure_paths=(
MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_5),
MetricGroupByItemResolutionNode(node_id=mtr_10),
MetricGroupByItemResolutionNode(node_id=mtr_8),
MeasureGroupByItemSourceNode(node_id=msr_7),
),
),
),
path_from_leaf_node=MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_5),
MetricGroupByItemResolutionNode(node_id=mtr_10),
MetricGroupByItemResolutionNode(node_id=mtr_8),
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
),
GroupByItemCandidateSet(
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=YEAR,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
),
properties=frozenset(
'METRIC_TIME',
),
time_granularity=YEAR,
),
),
},
),
measure_paths=(
MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_5),
MetricGroupByItemResolutionNode(node_id=mtr_10),
MetricGroupByItemResolutionNode(node_id=mtr_9),
MeasureGroupByItemSourceNode(node_id=msr_8),
),
),
),
path_from_leaf_node=MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_5),
MetricGroupByItemResolutionNode(node_id=mtr_10),
MetricGroupByItemResolutionNode(node_id=mtr_9),
),
properties=frozenset(
'DERIVED_TIME_GRANULARITY',
'METRIC_TIME',
),
time_granularity=YEAR,
),
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
),
properties=frozenset('METRIC_TIME',),
time_granularity=YEAR,
),
),
),
},
),
)
Original file line number Diff line number Diff line change
@@ -1,101 +1,44 @@
GroupByItemResolution(
linkable_element_set=LinkableElementSet(),
issue_set=MetricFlowQueryResolutionIssueSet(
issues=(
NoCommonItemsInParents(
issue_type=ERROR,
query_resolution_path=MetricFlowQueryResolutionPath(
resolution_path_nodes=(QueryGroupByItemResolutionNode(node_id=qr_3),),
),
parent_candidate_sets=(
GroupByItemCandidateSet(
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=MONTH,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
),
properties=frozenset(
'METRIC_TIME',
),
time_granularity=MONTH,
),
),
},
),
measure_paths=(
MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_3),
MetricGroupByItemResolutionNode(node_id=mtr_3),
MeasureGroupByItemSourceNode(node_id=msr_3),
),
),
),
path_from_leaf_node=MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_3),
MetricGroupByItemResolutionNode(node_id=mtr_3),
),
),
spec=TimeDimensionSpec(element_name='metric_time', time_granularity=YEAR),
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=YEAR,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
GroupByItemCandidateSet(
linkable_element_set=LinkableElementSet(
path_key_to_linkable_dimensions={
ElementPathKey(
element_name='metric_time',
element_type=TIME_DIMENSION,
time_granularity=YEAR,
): (
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
),
properties=frozenset(
'METRIC_TIME',
),
time_granularity=YEAR,
),
),
},
),
measure_paths=(
MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_3),
MetricGroupByItemResolutionNode(node_id=mtr_4),
MeasureGroupByItemSourceNode(node_id=msr_4),
),
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='monthly_measures_source',
),
path_from_leaf_node=MetricFlowQueryResolutionPath(
resolution_path_nodes=(
QueryGroupByItemResolutionNode(node_id=qr_3),
MetricGroupByItemResolutionNode(node_id=mtr_4),
),
),
properties=frozenset(
'DERIVED_TIME_GRANULARITY',
'METRIC_TIME',
),
time_granularity=YEAR,
),
LinkableDimension(
defined_in_semantic_model=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
element_name='metric_time',
dimension_type=TIME,
join_path=SemanticModelJoinPath(
left_semantic_model_reference=SemanticModelReference(
semantic_model_name='yearly_measure_source',
),
),
properties=frozenset('METRIC_TIME',),
time_granularity=YEAR,
),
),
),
},
),
)
Loading
Loading