Skip to content

Commit

Permalink
Track derived_from_semantic_models properly for LinkableMetrics
Browse files Browse the repository at this point in the history
  • Loading branch information
courtneyholcomb committed May 7, 2024
1 parent 62652c2 commit 0cd61b4
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

from metricflow_semantics.model.linkable_element_property import LinkableElementProperty
from metricflow_semantics.model.semantic_model_derivation import SemanticModelDerivation
from metricflow_semantics.specs.spec_classes import GroupByMetricReference

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -199,21 +200,32 @@ def path_key(self) -> ElementPathKey: # noqa: D102
)

@property
def reference(self) -> MetricReference: # noqa: D102
def metric_reference(self) -> MetricReference: # noqa: D102
return self.join_path.metric_subquery_join_path_element.metric_reference

@property
def reference(self) -> GroupByMetricReference: # noqa: D102
return GroupByMetricReference(self.metric_reference.element_name)

@property
def join_by_semantic_model(self) -> Optional[SemanticModelReference]: # noqa: D102
return self.join_path.last_semantic_model_reference

@property
@override
def derived_from_semantic_models(self) -> Sequence[SemanticModelReference]:
semantic_model_references = set()
for join_path_item in (
self.join_path.semantic_model_join_path.path_elements if self.join_path.semantic_model_join_path else ()
):
semantic_model_references.add(join_path_item.semantic_model_reference)
"""Semantic models needed to build and join to this LinkableMetric.
Includes semantic models used in the join paths for both the inner and outer queries (if applicable),
plus the semantic models the metric's measure(s) originated from.
"""
semantic_model_references = set(
self.join_path.metric_subquery_join_path_element.metric_derived_from_semantic_models
)
if self.join_path.semantic_model_join_path:
semantic_model_references.update(self.join_path.semantic_model_join_path.derived_from_semantic_models)
if self.metric_to_entity_join_path:
semantic_model_references.update(self.metric_to_entity_join_path.derived_from_semantic_models)

return sorted(semantic_model_references, key=lambda reference: reference.semantic_model_name)

Expand Down Expand Up @@ -274,6 +286,14 @@ def from_single_element(
)
)

@property
def derived_from_semantic_models(self) -> Sequence[SemanticModelReference]:
"""Unique semantic models used in this join path."""
return sorted(
[path_element.semantic_model_reference for path_element in self.path_elements],
key=lambda reference: reference.semantic_model_name,
)


@dataclass(frozen=True)
class MetricSubqueryJoinPathElement:
Expand All @@ -283,15 +303,22 @@ class MetricSubqueryJoinPathElement:
metric_reference: The metric that's aggregated in the subquery.
join_on_entity: The entity that the metric is grouped by in the subquery. This will be updated in V2 to allow a list
of entitites & dimensions.
entity_links: Sequence of entities joined to get from a metric source to the `join_on_entity`.
metric_to_entity_join_path: Describes the join path used in the subquery to join the metric to the `join_on_entity`.
Can be none if all required elements are defined in the same semantic model.
"""

metric_reference: MetricReference
metric_derived_from_semantic_models: Tuple[SemanticModelReference, ...]
join_on_entity: EntityReference
entity_links: Tuple[EntityReference, ...]
metric_to_entity_join_path: Optional[SemanticModelJoinPath] = None

def __post_init__(self) -> None: # noqa: D105
assert (
self.metric_derived_from_semantic_models
), "There must be at least one semantic model from which the metric is derived."


@dataclass(frozen=True)
class SemanticModelToMetricSubqueryJoinPath:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,15 @@ def __init__(
continue
metric_reference = MetricReference(metric.name)
linkable_element_set_for_metric = self.get_linkable_elements_for_metrics([metric_reference])
defined_from_semantic_models = tuple(
self._semantic_model_lookup.get_semantic_model_for_measure(input_measure.measure_reference).reference
for input_measure in metric.input_measures
)
for linkable_entities in linkable_element_set_for_metric.path_key_to_linkable_entities.values():
for linkable_entity in linkable_entities:
metric_subquery_join_path_element = MetricSubqueryJoinPathElement(
metric_reference=metric_reference,
metric_derived_from_semantic_models=defined_from_semantic_models,
join_on_entity=linkable_entity.reference,
entity_links=linkable_entity.entity_links,
metric_to_entity_join_path=(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
_base_entity_reference = EntityReference(element_name="base_entity")
_base_dimension_reference = DimensionReference(element_name="base_dimension")
_time_dimension_reference = TimeDimensionReference(element_name="time_dimension")
_metric_semantic_model = SemanticModelReference(semantic_model_name="metric_semantic_model")
_base_metric_reference = MetricReference(element_name="base_metric")


Expand Down Expand Up @@ -136,6 +137,7 @@
join_path=SemanticModelToMetricSubqueryJoinPath(
metric_subquery_join_path_element=MetricSubqueryJoinPathElement(
metric_reference=_base_metric_reference,
metric_derived_from_semantic_models=(_metric_semantic_model,),
join_on_entity=_base_entity_reference,
entity_links=(_base_entity_reference,),
),
Expand All @@ -146,6 +148,7 @@
join_path=SemanticModelToMetricSubqueryJoinPath(
metric_subquery_join_path_element=MetricSubqueryJoinPathElement(
metric_reference=MetricReference(AMBIGUOUS_NAME),
metric_derived_from_semantic_models=(_metric_semantic_model,),
join_on_entity=_base_entity_reference,
entity_links=(_base_entity_reference,),
),
Expand All @@ -157,6 +160,7 @@
join_path=SemanticModelToMetricSubqueryJoinPath(
metric_subquery_join_path_element=MetricSubqueryJoinPathElement(
metric_reference=MetricReference(AMBIGUOUS_NAME),
metric_derived_from_semantic_models=(_metric_semantic_model,),
join_on_entity=_base_entity_reference,
entity_links=(_base_entity_reference,),
),
Expand Down Expand Up @@ -547,6 +551,8 @@ def linkable_set() -> LinkableElementSet: # noqa: D103
entity_2_source = SemanticModelReference("entity_2_source")
entity_3 = EntityReference("entity_3")
entity_3_source = SemanticModelReference("entity_3_source")
entity_4 = EntityReference("entity_4")
entity_4_source = SemanticModelReference("entity_4_source")

return LinkableElementSet(
path_key_to_linkable_dimensions={
Expand Down Expand Up @@ -626,8 +632,19 @@ def linkable_set() -> LinkableElementSet: # noqa: D103
join_path=SemanticModelToMetricSubqueryJoinPath(
metric_subquery_join_path_element=MetricSubqueryJoinPathElement(
metric_reference=MetricReference("metric_element"),
metric_derived_from_semantic_models=(_metric_semantic_model,),
join_on_entity=entity_3,
entity_links=(entity_3,),
entity_links=(entity_3, entity_4),
metric_to_entity_join_path=SemanticModelJoinPath(
path_elements=(
SemanticModelJoinPathElement(
semantic_model_reference=entity_4_source, join_on_entity=entity_4
),
SemanticModelJoinPathElement(
semantic_model_reference=entity_3_source, join_on_entity=entity_3
),
)
),
),
semantic_model_join_path=SemanticModelJoinPath.from_single_element(
semantic_model_reference=entity_3_source, join_on_entity=entity_3
Expand All @@ -641,14 +658,15 @@ def linkable_set() -> LinkableElementSet: # noqa: D103

def test_derived_semantic_models(linkable_set: LinkableElementSet) -> None:
"""Tests that the semantic models in the element set are returned via `derived_from_semantic_models`."""
# TODO: add metric source for linkable metrics
assert tuple(linkable_set.derived_from_semantic_models) == (
SemanticModelReference(semantic_model_name="dimension_source"),
SemanticModelReference(semantic_model_name="entity_0_source"),
SemanticModelReference(semantic_model_name="entity_1_source"),
SemanticModelReference(semantic_model_name="entity_2_source"),
SemanticModelReference(semantic_model_name="entity_3_source"),
SemanticModelReference(semantic_model_name="entity_4_source"),
SemanticModelReference(semantic_model_name="entity_source"),
SemanticModelReference(semantic_model_name="metric_semantic_model"),
SemanticModelReference(semantic_model_name="time_dimension_source"),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ def test_metric_in_filter( # noqa: D103
join_path=SemanticModelToMetricSubqueryJoinPath(
metric_subquery_join_path_element=MetricSubqueryJoinPathElement(
metric_reference=MetricReference("bookings"),
metric_derived_from_semantic_models=(SemanticModelReference("bookings"),),
join_on_entity=EntityReference("listing"),
entity_links=(EntityReference("listing"),),
)
Expand Down

0 comments on commit 0cd61b4

Please sign in to comment.