-
Notifications
You must be signed in to change notification settings - Fork 97
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
Bug fix: source node evaluation #801
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
kind: Fixes | ||
body: Prioritize source nodes based on correct cost | ||
time: 2023-10-09T19:53:12.491719-07:00 | ||
custom: | ||
Author: courtneyholcomb | ||
Issue: "801" |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -553,20 +553,22 @@ def _find_measure_recipe( | |
# this is going to be the lowest cost solution. | ||
if len(evaluation.join_recipes) == 0: | ||
logger.info("Not evaluating other nodes since we found one that doesn't require joins") | ||
break | ||
|
||
logger.info(f"Found {len(node_to_evaluation)} candidate measure nodes.") | ||
|
||
if len(node_to_evaluation) > 0: | ||
cost_function = DefaultCostFunction() | ||
|
||
node_with_lowest_cost = min(node_to_evaluation, key=cost_function.calculate_cost) | ||
evaluation = node_to_evaluation[node_with_lowest_cost] | ||
# All source nodes cost the same. Find evaluation with lowest number of joins. | ||
node_with_lowest_cost_plan = min( | ||
node_to_evaluation, key=lambda node: len(node_to_evaluation[node].join_recipes) | ||
) | ||
evaluation = node_to_evaluation[node_with_lowest_cost_plan] | ||
logger.info( | ||
"Lowest cost node is:\n" | ||
"Lowest cost plan is:\n" | ||
+ pformat_big_objects( | ||
lowest_cost_node=dataflow_dag_as_text(node_with_lowest_cost), | ||
node=dataflow_dag_as_text(node_with_lowest_cost_plan), | ||
evaluation=evaluation, | ||
cost=cost_function.calculate_cost(node_with_lowest_cost), | ||
joins=len(node_to_evaluation[node_with_lowest_cost_plan].join_recipes), | ||
Comment on lines
+561
to
+571
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice find! We have Yet Another Inscrutable Visitor doing this complex cost calculation, but it can only go from leaf node to root node, not the other way around. Since measure nodes are currently ONLY source nodes the cost comparison is pointless. Using minimum join count is probably the right answer here. Later on it'll matter more what the user requests, because eventually the measure nodes could be on the right. In theory, this kind of graph walk cost computation will be useful then, but my worry about this block of logic was always that it the results might diverge as the join layout changes. However, since we have now committed to always picking the shortest join paths I think this gets us closer to where we need to be. |
||
) | ||
) | ||
|
||
|
@@ -584,14 +586,14 @@ def _find_measure_recipe( | |
) | ||
|
||
return MeasureRecipe( | ||
measure_node=node_with_lowest_cost, | ||
measure_node=node_with_lowest_cost_plan, | ||
required_local_linkable_specs=( | ||
evaluation.local_linkable_specs | ||
+ required_local_entity_specs | ||
+ required_local_dimension_specs | ||
+ required_local_time_dimension_specs | ||
), | ||
join_linkable_instances_recipes=node_to_evaluation[node_with_lowest_cost].join_recipes, | ||
join_linkable_instances_recipes=node_to_evaluation[node_with_lowest_cost_plan].join_recipes, | ||
) | ||
|
||
logger.error("No recipe could be constructed.") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.