From f1b0afd9a67b9b95d55a76c6022905af20c23d89 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Tue, 22 Sep 2015 11:19:52 +0200 Subject: [PATCH] Started to implement functions to find indexes for each Condition sub part --- arangod/Aql/Condition.cpp | 382 ++++++++++++++++++--------------- arangod/Aql/Condition.h | 34 ++- arangod/Aql/OptimizerRules.cpp | 1 + 3 files changed, 238 insertions(+), 179 deletions(-) diff --git a/arangod/Aql/Condition.cpp b/arangod/Aql/Condition.cpp index c62cbfd845..136ff5366d 100644 --- a/arangod/Aql/Condition.cpp +++ b/arangod/Aql/Condition.cpp @@ -134,7 +134,36 @@ void Condition::andCombine (AstNode const* node) { //////////////////////////////////////////////////////////////////////////////// /// @brief locate indices for each condition //////////////////////////////////////////////////////////////////////////////// -void Condition::findIndices() { + +void Condition::findIndices (EnumerateCollectionNode const* node) { + // We can only start after DNF transform + Variable const* reference = node->outVariable(); + TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR); + for (size_t i = 0; i < _root->numMembers(); ++i) { + findIndexForAndNode(_root->getMember(i), reference, node); + } +} + +void Condition::findIndexForAndNode (AstNode const* node, Variable const* reference, EnumerateCollectionNode const* colNode) { + // We are not iterating through the DNF properly + TRI_ASSERT(node->type == NODE_TYPE_OPERATOR_NARY_AND); + std::unordered_set attributes; + for (size_t i = 0; i < node->numMembers(); ++i) { + auto compareNode = node->getMember(i); + switch (compareNode->type) { + default: + for (size_t j = 0; j < compareNode->numMembers(); ++j) { + auto fuxxNode = compareNode->getMember(j); + if (fuxxNode->type == NODE_TYPE_ATTRIBUTE_ACCESS) { + // if (static_cast(fuxxNode->getMember(0)->getData()) == reference) { + if (fuxxNode->getMember(0)->getData() == reference) { + attributes.emplace(fuxxNode->getStringValue()); + } + } + } + } + } + // std::string node->getStringValue() } //////////////////////////////////////////////////////////////////////////////// @@ -148,181 +177,6 @@ void Condition::normalize (ExecutionPlan* plan) { return; } - std::function transformNode = [this, &transformNode] (AstNode* node) -> AstNode* { - if (node == nullptr) { - return nullptr; - } - - if (node->type == NODE_TYPE_OPERATOR_BINARY_AND || - node->type == NODE_TYPE_OPERATOR_BINARY_OR) { - // convert binary AND/OR into n-ary AND/OR - auto lhs = node->getMember(0); - auto rhs = node->getMember(1); - node = _ast->createNodeBinaryOperator(Ast::NaryOperatorType(node->type), lhs, rhs); - } - - TRI_ASSERT(node->type != NODE_TYPE_OPERATOR_BINARY_AND && - node->type != NODE_TYPE_OPERATOR_BINARY_OR); - - if (node->type == NODE_TYPE_OPERATOR_NARY_AND) { - // first recurse into subnodes - node->changeMember(0, transformNode(node->getMember(0))); - node->changeMember(1, transformNode(node->getMember(1))); - - auto lhs = node->getMember(0); - auto rhs = node->getMember(1); - - if (lhs->type == NODE_TYPE_OPERATOR_NARY_OR && - rhs->type == NODE_TYPE_OPERATOR_NARY_OR) { - auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(0), rhs->getMember(0))); - auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(0), rhs->getMember(1))); - auto or1 = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); - - auto and3 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(1), rhs->getMember(0))); - auto and4 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(1), rhs->getMember(1))); - auto or2 = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and3, and4); - - return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, or1, or2); - } - else if (lhs->type == NODE_TYPE_OPERATOR_NARY_OR) { - auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, rhs, lhs->getMember(0))); - auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, rhs, lhs->getMember(1))); - - return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); - } - else if (rhs->type == NODE_TYPE_OPERATOR_NARY_OR) { - auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs, rhs->getMember(0))); - auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs, rhs->getMember(1))); - - return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); - } - } - else if (node->type == NODE_TYPE_OPERATOR_NARY_OR) { - // recurse into subnodes - node->changeMember(0, transformNode(node->getMember(0))); - node->changeMember(1, transformNode(node->getMember(1))); - } - else if (node->type == NODE_TYPE_OPERATOR_UNARY_NOT) { - // push down logical negations - auto sub = node->getMemberUnchecked(0); - - if (sub->type == NODE_TYPE_OPERATOR_NARY_AND || - sub->type == NODE_TYPE_OPERATOR_BINARY_AND) { - // ! (a && b) => (! a) || (! b) - auto neg1 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(0))); - auto neg2 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(1))); - - neg1 = _ast->optimizeNotExpression(neg1); - neg2 = _ast->optimizeNotExpression(neg2); - - return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, neg1, neg2); - } - else if (sub->type == NODE_TYPE_OPERATOR_NARY_OR || - sub->type == NODE_TYPE_OPERATOR_BINARY_OR) { - // ! (a || b) => (! a) && (! b) - auto neg1 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(0))); - auto neg2 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(1))); - - neg1 = _ast->optimizeNotExpression(neg1); - neg2 = _ast->optimizeNotExpression(neg2); - - return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, neg1, neg2); - } - - node->changeMember(0, transformNode(sub)); - return node; - } - - return node; - }; - - // collapse function. - // this will collapse nested logical AND/OR nodes - std::function collapseNesting = [this, &collapseNesting] (AstNode* node) -> AstNode* { - if (node == nullptr) { - return nullptr; - } - - if (node->type == NODE_TYPE_OPERATOR_NARY_AND || - node->type == NODE_TYPE_OPERATOR_NARY_OR) { - // first recurse into subnodes - size_t const n = node->numMembers(); - - for (size_t i = 0; i < n; ++i) { - auto sub = collapseNesting(node->getMemberUnchecked(i)); - - if (sub->type == node->type) { - // sub-node has the same type as parent node - // now merge the sub-nodes of the sub-node into the parent node - size_t const subNumMembers = sub->numMembers(); - - for (size_t j = 0; j < subNumMembers; ++j) { - node->addMember(sub->getMemberUnchecked(j)); - } - // invalidate the child node which we just expanded - node->changeMember(i, _ast->createNodeNop()); - } - else { - // different type - node->changeMember(i, sub); - } - } - } - - return node; - }; - - // finally create a top-level OR node if it does not already exist, and make sure that all second - // level nodes are AND nodes - // additionally, this processing step will remove all NOP nodes - std::function fixRoot = [this, &fixRoot] (AstNode* node, int level) -> AstNode* { - if (node == nullptr) { - return nullptr; - } - - AstNodeType type; - - if (level == 0) { - type = NODE_TYPE_OPERATOR_NARY_OR; - } - else { - type = NODE_TYPE_OPERATOR_NARY_AND; - } - // check if first-level node is an OR node - if (node->type != type) { - // create new root node - node = _ast->createNodeNaryOperator(type, node); - } - - size_t const n = node->numMembers(); - size_t j = 0; - - for (size_t i = 0; i < n; ++i) { - auto sub = node->getMemberUnchecked(i); - - if (sub->type == NODE_TYPE_NOP) { - // ignore this node - continue; - } - - if (level == 0) { - // recurse into next level - node->changeMember(j, fixRoot(sub, level + 1)); - } - else if (i != j) { - node->changeMember(j, sub); - } - ++j; - } - - if (j != n) { - // adjust number of members (because of the NOP nodes removes) - node->reduceMembers(j); - } - - return node; - }; - _root = transformNode(_root); _root = collapseNesting(_root); _root = fixRoot(_root, 0); @@ -332,7 +186,6 @@ void Condition::normalize (ExecutionPlan* plan) { std::cout << "\n"; dump(); std::cout << "\n"; - _isNormalized = true; } @@ -403,6 +256,7 @@ ConditionPart::ConditionPartCompareResult ConditionPart::ResultsTable[3][7][7] = {DISJOINT, DISJOINT, DISJOINT, DISJOINT, DISJOINT, DISJOINT, DISJOINT} } }; + void Condition::optimize (ExecutionPlan* plan) { // normalize(); @@ -558,7 +412,7 @@ void Condition::optimize (ExecutionPlan* plan) { } // cross compare sub-and-nodes } // foreach sub-and-node fastForwardToNextOrItem: - true; + continue; } } @@ -587,6 +441,9 @@ void Condition::dump () const { else if (node->type == NODE_TYPE_ATTRIBUTE_ACCESS) { std::cout << " (attribute " << node->getStringValue() << ")"; } + else if (node->type == NODE_TYPE_REFERENCE) { + std::cout << " (name " << node->getStringValue() << ")"; + } std::cout << "\n"; for (size_t i = 0; i < node->numMembers(); ++i) { @@ -597,6 +454,175 @@ void Condition::dump () const { dumpNode(_root, 0); } +AstNode* Condition::transformNode (AstNode* node) { + if (node == nullptr) { + return nullptr; + } + + if (node->type == NODE_TYPE_OPERATOR_BINARY_AND || + node->type == NODE_TYPE_OPERATOR_BINARY_OR) { + // convert binary AND/OR into n-ary AND/OR + auto lhs = node->getMember(0); + auto rhs = node->getMember(1); + node = _ast->createNodeBinaryOperator(Ast::NaryOperatorType(node->type), lhs, rhs); + } + + TRI_ASSERT(node->type != NODE_TYPE_OPERATOR_BINARY_AND && + node->type != NODE_TYPE_OPERATOR_BINARY_OR); + + if (node->type == NODE_TYPE_OPERATOR_NARY_AND) { + // first recurse into subnodes + node->changeMember(0, transformNode(node->getMember(0))); + node->changeMember(1, transformNode(node->getMember(1))); + + auto lhs = node->getMember(0); + auto rhs = node->getMember(1); + + if (lhs->type == NODE_TYPE_OPERATOR_NARY_OR && + rhs->type == NODE_TYPE_OPERATOR_NARY_OR) { + auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(0), rhs->getMember(0))); + auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(0), rhs->getMember(1))); + auto or1 = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); + + auto and3 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(1), rhs->getMember(0))); + auto and4 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs->getMember(1), rhs->getMember(1))); + auto or2 = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and3, and4); + + return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, or1, or2); + } + else if (lhs->type == NODE_TYPE_OPERATOR_NARY_OR) { + auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, rhs, lhs->getMember(0))); + auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, rhs, lhs->getMember(1))); + + return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); + } + else if (rhs->type == NODE_TYPE_OPERATOR_NARY_OR) { + auto and1 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs, rhs->getMember(0))); + auto and2 = transformNode(_ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, lhs, rhs->getMember(1))); + + return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, and1, and2); + } + } + else if (node->type == NODE_TYPE_OPERATOR_NARY_OR) { + // recurse into subnodes + node->changeMember(0, transformNode(node->getMember(0))); + node->changeMember(1, transformNode(node->getMember(1))); + } + else if (node->type == NODE_TYPE_OPERATOR_UNARY_NOT) { + // push down logical negations + auto sub = node->getMemberUnchecked(0); + + if (sub->type == NODE_TYPE_OPERATOR_NARY_AND || + sub->type == NODE_TYPE_OPERATOR_BINARY_AND) { + // ! (a && b) => (! a) || (! b) + auto neg1 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(0))); + auto neg2 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(1))); + + neg1 = _ast->optimizeNotExpression(neg1); + neg2 = _ast->optimizeNotExpression(neg2); + + return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_OR, neg1, neg2); + } + else if (sub->type == NODE_TYPE_OPERATOR_NARY_OR || + sub->type == NODE_TYPE_OPERATOR_BINARY_OR) { + // ! (a || b) => (! a) && (! b) + auto neg1 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(0))); + auto neg2 = transformNode(_ast->createNodeUnaryOperator(NODE_TYPE_OPERATOR_UNARY_NOT, sub->getMember(1))); + + neg1 = _ast->optimizeNotExpression(neg1); + neg2 = _ast->optimizeNotExpression(neg2); + + return _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_NARY_AND, neg1, neg2); + } + + node->changeMember(0, transformNode(sub)); + return node; + } + + return node; +} + +AstNode* Condition::collapseNesting (AstNode* node) { + if (node == nullptr) { + return nullptr; + } + + if (node->type == NODE_TYPE_OPERATOR_NARY_AND || + node->type == NODE_TYPE_OPERATOR_NARY_OR) { + // first recurse into subnodes + size_t const n = node->numMembers(); + + for (size_t i = 0; i < n; ++i) { + auto sub = collapseNesting(node->getMemberUnchecked(i)); + + if (sub->type == node->type) { + // sub-node has the same type as parent node + // now merge the sub-nodes of the sub-node into the parent node + size_t const subNumMembers = sub->numMembers(); + + for (size_t j = 0; j < subNumMembers; ++j) { + node->addMember(sub->getMemberUnchecked(j)); + } + // invalidate the child node which we just expanded + node->changeMember(i, _ast->createNodeNop()); + } + else { + // different type + node->changeMember(i, sub); + } + } + } + + return node; +} + +AstNode* Condition::fixRoot (AstNode* node, int level) { + if (node == nullptr) { + return nullptr; + } + + AstNodeType type; + + if (level == 0) { + type = NODE_TYPE_OPERATOR_NARY_OR; + } + else { + type = NODE_TYPE_OPERATOR_NARY_AND; + } + // check if first-level node is an OR node + if (node->type != type) { + // create new root node + node = _ast->createNodeNaryOperator(type, node); + } + + size_t const n = node->numMembers(); + size_t j = 0; + + for (size_t i = 0; i < n; ++i) { + auto sub = node->getMemberUnchecked(i); + + if (sub->type == NODE_TYPE_NOP) { + // ignore this node + continue; + } + + if (level == 0) { + // recurse into next level + node->changeMember(j, fixRoot(sub, level + 1)); + } + else if (i != j) { + node->changeMember(j, sub); + } + ++j; + } + + if (j != n) { + // adjust number of members (because of the NOP nodes removes) + node->reduceMembers(j); + } + + return node; +} // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE diff --git a/arangod/Aql/Condition.h b/arangod/Aql/Condition.h index ed69517fdb..525d8a8357 100644 --- a/arangod/Aql/Condition.h +++ b/arangod/Aql/Condition.h @@ -32,6 +32,7 @@ #include "Basics/Common.h" #include "Aql/AstNode.h" +#include "Aql/ExecutionNode.h" namespace triagens { namespace aql { @@ -171,7 +172,7 @@ namespace triagens { /// @brief locate indices which can be used for conditions //////////////////////////////////////////////////////////////////////////////// - void findIndices (); + void findIndices (EnumerateCollectionNode const*); //////////////////////////////////////////////////////////////////////////////// /// @brief dump the condition @@ -180,6 +181,37 @@ namespace triagens { void dump () const; // ----------------------------------------------------------------------------- +// --SECTION-- private methods +// ----------------------------------------------------------------------------- + + private: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Transforms the AstNode +//////////////////////////////////////////////////////////////////////////////// + + AstNode* transformNode (AstNode*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Collapses nested logical AND/OR nodes +//////////////////////////////////////////////////////////////////////////////// + + AstNode* collapseNesting (AstNode*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Creates a top-level OR node if it does not already exist, and make sure that all second +/// level nodes are AND nodes. Additionally, this processing step will +/// remove all NOP nodes. +//////////////////////////////////////////////////////////////////////////////// + + AstNode* fixRoot (AstNode*, int); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Finds all indexes that can match this single node +//////////////////////////////////////////////////////////////////////////////// + + void findIndexForAndNode (AstNode const*, Variable const*, EnumerateCollectionNode const*); +// ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- diff --git a/arangod/Aql/OptimizerRules.cpp b/arangod/Aql/OptimizerRules.cpp index c4e976c78d..e1095eca95 100644 --- a/arangod/Aql/OptimizerRules.cpp +++ b/arangod/Aql/OptimizerRules.cpp @@ -2119,6 +2119,7 @@ class ConditionFinder : public WalkerWorker { // auto node = static_cast(en); // auto var = node->getVariablesSetHere()[0]; // should only be 1 _condition->normalize(_plan); + _condition->findIndices(static_cast(en)); break; } }