diff --git a/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py b/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py index e39e9063ec..02e7ea3a85 100644 --- a/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py +++ b/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py @@ -54,6 +54,14 @@ def __init__( max_entity_links=MAX_JOIN_HOPS, ) + # Cache for `get_min_queryable_time_granularity()` + self._metric_reference_to_min_metric_time_grain: Dict[MetricReference, TimeGranularity] = {} + + # Cache for `get_valid_agg_time_dimensions_for_metric()`. + self._metric_reference_to_valid_agg_time_dimension_specs: Dict[ + MetricReference, Sequence[TimeDimensionSpec] + ] = {} + @functools.lru_cache def linkable_elements_for_measure( self, @@ -183,6 +191,18 @@ def get_valid_agg_time_dimensions_for_metric( self, metric_reference: MetricReference ) -> Sequence[TimeDimensionSpec]: """Get the agg time dimension specs that can be used in place of metric time for this metric, if applicable.""" + result = self._metric_reference_to_valid_agg_time_dimension_specs.get(metric_reference) + if result is not None: + return result + + result = self._get_valid_agg_time_dimensions_for_metric(metric_reference) + self._metric_reference_to_valid_agg_time_dimension_specs[metric_reference] = result + + return result + + def _get_valid_agg_time_dimensions_for_metric( + self, metric_reference: MetricReference + ) -> Sequence[TimeDimensionSpec]: agg_time_dimension_specs = self._get_agg_time_dimension_specs_for_metric(metric_reference) distinct_agg_time_dimension_identifiers = set( [(spec.reference, spec.entity_links) for spec in agg_time_dimension_specs] @@ -204,6 +224,15 @@ def get_min_queryable_time_granularity(self, metric_reference: MetricReference) Maps to the largest granularity defined for any of the metric's agg_time_dimensions. """ + result = self._metric_reference_to_min_metric_time_grain.get(metric_reference) + if result is not None: + return result + + result = self._get_min_queryable_time_granularity(metric_reference) + self._metric_reference_to_min_metric_time_grain[metric_reference] = result + return result + + def _get_min_queryable_time_granularity(self, metric_reference: MetricReference) -> TimeGranularity: agg_time_dimension_specs = self._get_agg_time_dimension_specs_for_metric(metric_reference) assert ( agg_time_dimension_specs diff --git a/metricflow-semantics/metricflow_semantics/model/semantics/semantic_model_lookup.py b/metricflow-semantics/metricflow_semantics/model/semantics/semantic_model_lookup.py index 91ec266172..a3c3ef8388 100644 --- a/metricflow-semantics/metricflow_semantics/model/semantics/semantic_model_lookup.py +++ b/metricflow-semantics/metricflow_semantics/model/semantics/semantic_model_lookup.py @@ -67,6 +67,9 @@ def __init__(self, model: SemanticManifest, custom_granularities: Dict[str, Expa # Cache for defined time granularity. self._time_dimension_to_defined_time_granularity: Dict[TimeDimensionReference, TimeGranularity] = {} + # Cache for agg. time dimension for measure. + self._measure_reference_to_agg_time_dimension_specs: Dict[MeasureReference, Sequence[TimeDimensionSpec]] = {} + def get_dimension_references(self) -> Sequence[DimensionReference]: """Retrieve all dimension references from the collection of semantic models.""" return tuple(self._dimension_index.keys()) @@ -364,6 +367,17 @@ def get_agg_time_dimension_specs_for_measure( self, measure_reference: MeasureReference ) -> Sequence[TimeDimensionSpec]: """Get the agg time dimension specs that can be used in place of metric time for this measure.""" + result = self._measure_reference_to_agg_time_dimension_specs.get(measure_reference) + if result is not None: + return result + + result = self._get_agg_time_dimension_specs_for_measure(measure_reference) + self._measure_reference_to_agg_time_dimension_specs[measure_reference] = result + return result + + def _get_agg_time_dimension_specs_for_measure( + self, measure_reference: MeasureReference + ) -> Sequence[TimeDimensionSpec]: agg_time_dimension = self.get_agg_time_dimension_for_measure(measure_reference) # A measure's agg_time_dimension is required to be in the same semantic model as the measure, # so we can assume the same semantic model for both measure and dimension.