forked from hyrise/hyrise
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
396 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#include "predicate_merge_rule.hpp" | ||
|
||
#include "expression/expression_utils.hpp" | ||
#include "expression/logical_expression.hpp" | ||
#include "logical_query_plan/lqp_utils.hpp" | ||
#include "logical_query_plan/union_node.hpp" | ||
|
||
namespace opossum { | ||
|
||
PredicateMergeRule::PredicateMergeRule(const bool split_disjunction) : _split_disjunction(split_disjunction) {} | ||
|
||
bool PredicateMergeRule::_mergeConjunction(const std::shared_ptr<PredicateNode>& predicate_node) const { | ||
const auto flat_conjunction = flatten_logical_expressions(predicate_node->predicate(), LogicalOperator::And); | ||
if (flat_conjunction.size() <= 1) { | ||
return false; | ||
} | ||
|
||
/** | ||
* Split up PredicateNode with conjunctive chain (e.g., `PredicateNode(a AND b AND c)`) as its scan expression into | ||
* multiple consecutive PredicateNodes (e.g. `PredicateNode(c) -> PredicateNode(b) -> PredicateNode(a)`). | ||
*/ | ||
for (const auto& predicate_expression : flat_conjunction) { | ||
const auto& new_predicate_node = PredicateNode::make(predicate_expression); | ||
lqp_insert_node(predicate_node, LQPInputSide::Left, new_predicate_node); | ||
_mergeDisjunction(new_predicate_node); | ||
} | ||
lqp_remove_node(predicate_node); | ||
|
||
return true; | ||
} | ||
|
||
void PredicateMergeRule::_mergeDisjunction(const std::shared_ptr<PredicateNode>& predicate_node) const { | ||
if (!_split_disjunction) { | ||
return; | ||
} | ||
|
||
const auto flat_disjunction = flatten_logical_expressions(predicate_node->predicate(), LogicalOperator::Or); | ||
if (flat_disjunction.size() <= 1) { | ||
return; | ||
} | ||
|
||
/** | ||
* Split up PredicateNode with disjunctive chain (e.g., `PredicateNode(a OR b OR c)`) as their scan expression into | ||
* n-1 consecutive UnionNodes and n PredicateNodes. | ||
*/ | ||
auto previous_union_node = UnionNode::make(UnionMode::Positions); | ||
const auto left_input = predicate_node->left_input(); | ||
lqp_replace_node(predicate_node, previous_union_node); | ||
|
||
auto new_predicate_node = PredicateNode::make(flat_disjunction[0], left_input); | ||
previous_union_node->set_left_input(new_predicate_node); | ||
_mergeConjunction(new_predicate_node); | ||
|
||
new_predicate_node = PredicateNode::make(flat_disjunction[1], left_input); | ||
previous_union_node->set_right_input(new_predicate_node); | ||
_mergeConjunction(new_predicate_node); | ||
|
||
for (auto disjunction_idx = size_t{2}; disjunction_idx < flat_disjunction.size(); ++disjunction_idx) { | ||
const auto& predicate_expression = flat_disjunction[disjunction_idx]; | ||
auto next_union_node = UnionNode::make(UnionMode::Positions); | ||
lqp_insert_node(previous_union_node, LQPInputSide::Right, next_union_node); | ||
|
||
new_predicate_node = PredicateNode::make(predicate_expression, left_input); | ||
next_union_node->set_right_input(new_predicate_node); | ||
_mergeConjunction(new_predicate_node); | ||
|
||
previous_union_node = next_union_node; | ||
} | ||
} | ||
|
||
void PredicateMergeRule::apply_to(const std::shared_ptr<AbstractLQPNode>& root) const { | ||
Assert(root->type == LQPNodeType::Root, "PredicateSplitUpRule needs root to hold onto"); | ||
|
||
auto predicate_nodes = std::vector<std::shared_ptr<PredicateNode>>{}; | ||
visit_lqp(root, [&](const auto& sub_node) { | ||
if (const auto predicate_node = std::dynamic_pointer_cast<PredicateNode>(sub_node)) { | ||
predicate_nodes.emplace_back(predicate_node); | ||
} | ||
return LQPVisitation::VisitInputs; | ||
}); | ||
|
||
// _splitConjunction() and _splitDisjunction() split up logical expressions by calling each other recursively | ||
for (const auto& predicate_node : predicate_nodes) { | ||
if (!_mergeConjunction(predicate_node)) { | ||
// If there is no conjunction at the top level, try to split disjunction first | ||
_mergeDisjunction(predicate_node); | ||
} | ||
} | ||
} | ||
|
||
} // namespace opossum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include <vector> | ||
|
||
#include "abstract_rule.hpp" | ||
#include "logical_query_plan/predicate_node.hpp" | ||
|
||
namespace opossum { | ||
|
||
/** | ||
* This rule turns PredicateNodes with (nested) conjunctions ("and) and disjunctions ("or") | ||
* (e.g., `PredicateNode(a AND (b OR c))`) as their scan expression into an LQP of consecutive PredicateNodes (for the | ||
* conjunctions) and UnionNodes (for the disjunctions). | ||
* | ||
* Doing so enables other Optimizer rules to process these PredicateNodes and split-up PredicateNodes might take a | ||
* faster operator execution path. | ||
* | ||
* EXAMPLES: | ||
* TPC-H query 19 | ||
* This rule makes `p_partkey = l_partkey` available as a join predicate and the predicates on `l_shipmode` and | ||
* `l_shipinstruct` can be pulled below the join. | ||
* | ||
* TPC-DS query 35 | ||
* This rule splits up `EXISTS (...) OR EXISTS (...)` into two expressions that can later be rewritten into two | ||
* semi-joins. | ||
*/ | ||
class PredicateMergeRule : public AbstractRule { | ||
public: | ||
explicit PredicateMergeRule(const bool split_disjunction = true); | ||
void apply_to(const std::shared_ptr<AbstractLQPNode>& root) const override; | ||
|
||
private: | ||
/** | ||
* @return true if a conjunction was split up | ||
*/ | ||
bool _mergeConjunction(const std::shared_ptr<PredicateNode>& predicate_node) const; | ||
void _mergeDisjunction(const std::shared_ptr<PredicateNode>& predicate_node) const; | ||
|
||
bool _split_disjunction; | ||
}; | ||
|
||
} // namespace opossum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.