// static MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) { // root->isLogical() is true now. We care about AND, OR, and NOT. NOR currently scares us. if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) { // We could have AND of AND of AND. Make sure we clean up our children before merging // them. // UNITTEST 11738048 for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } // If any of our children are of the same logical operator that we are, we remove the // child's children and append them to ourselves after we examine all children. std::vector<MatchExpression*> absorbedChildren; for (size_t i = 0; i < root->numChildren();) { MatchExpression* child = root->getChild(i); if (child->matchType() == root->matchType()) { // AND of an AND or OR of an OR. Absorb child's children into ourself. for (size_t j = 0; j < child->numChildren(); ++j) { absorbedChildren.push_back(child->getChild(j)); } // TODO(opt): this is possibly n^2-ish root->getChildVector()->erase(root->getChildVector()->begin() + i); child->getChildVector()->clear(); // Note that this only works because we cleared the child's children delete child; // Don't increment 'i' as the current child 'i' used to be child 'i+1' } else { ++i; } } root->getChildVector()->insert( root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end()); // AND of 1 thing is the thing, OR of 1 thing is the thing. if (1 == root->numChildren()) { MatchExpression* ret = root->getChild(0); root->getChildVector()->clear(); delete root; return ret; } } else if (MatchExpression::NOT == root->matchType()) { // Normalize the rest of the tree hanging off this NOT node. NotMatchExpression* nme = static_cast<NotMatchExpression*>(root); MatchExpression* child = nme->releaseChild(); // normalizeTree(...) takes ownership of 'child', and then // transfers ownership of its return value to 'nme'. nme->resetChild(normalizeTree(child)); } else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) { // Just normalize our children. for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } } return root; }
Status CanonicalQuery::init(LiteParsedQuery* lpq, const MatchExpressionParser::WhereCallback& whereCallback, MatchExpression* root) { _pq.reset(lpq); // Normalize, sort and validate tree. root = normalizeTree(root); sortTree(root); _root.reset(root); Status validStatus = isValid(root, *_pq); if (!validStatus.isOK()) { return validStatus; } // Validate the projection if there is one. if (!_pq->getProj().isEmpty()) { ParsedProjection* pp; Status projStatus = ParsedProjection::make(_pq->getProj(), _root.get(), &pp, whereCallback); if (!projStatus.isOK()) { return projStatus; } _proj.reset(pp); } return Status::OK(); }
Status CanonicalQuery::init(LiteParsedQuery* lpq) { _pq.reset(lpq); // Build a parse tree from the BSONObj in the parsed query. StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter()); if (!swme.isOK()) { return swme.getStatus(); } MatchExpression* root = swme.getValue(); root = normalizeTree(root); Status validStatus = isValid(root); if (!validStatus.isOK()) { return validStatus; } _root.reset(root); // Validate the projection if there is one. if (!_pq->getProj().isEmpty()) { ParsedProjection* pp; Status projStatus = ParsedProjection::make(_pq->getProj(), root, &pp); if (!projStatus.isOK()) { return projStatus; } _proj.reset(pp); } return Status::OK(); }
Status CanonicalQuery::init(LiteParsedQuery* lpq, const ExtensionsCallback& extensionsCallback, MatchExpression* root) { _pq.reset(lpq); _hasNoopExtensions = extensionsCallback.hasNoopExtensions(); _isIsolated = LiteParsedQuery::isQueryIsolated(lpq->getFilter()); // Normalize, sort and validate tree. root = normalizeTree(root); sortTree(root); _root.reset(root); Status validStatus = isValid(root, *_pq); if (!validStatus.isOK()) { return validStatus; } // Validate the projection if there is one. if (!_pq->getProj().isEmpty()) { ParsedProjection* pp; Status projStatus = ParsedProjection::make(_pq->getProj(), _root.get(), &pp, extensionsCallback); if (!projStatus.isOK()) { return projStatus; } _proj.reset(pp); } if (_proj && _proj->wantSortKey() && _pq->getSort().isEmpty()) { return Status(ErrorCodes::BadValue, "cannot use sortKey $meta projection without a sort"); } return Status::OK(); }
Status CanonicalQuery::init(LiteParsedQuery* lpq) { _pq.reset(lpq); // Build a parse tree from the BSONObj in the parsed query. StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter()); if (!swme.isOK()) { return swme.getStatus(); } MatchExpression* root = swme.getValue(); root = normalizeTree(root); Status validStatus = isValid(root); if (!validStatus.isOK()) { return validStatus; } _root.reset(root); if (!_pq->getProj().isEmpty()) { LiteProjection* liteProj = NULL; Status liteProjStatus = LiteProjection::make(_pq->getFilter(), _pq->getProj(), &liteProj); if (!liteProjStatus.isOK()) { return liteProjStatus; } _liteProj.reset(liteProj); } return Status::OK(); }
// static MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) { // root->isLogical() is true now. We care about AND and OR. Negations currently scare us. if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) { // We could have AND of AND of AND. Make sure we clean up our children before merging // them. // UNITTEST 11738048 for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } // If any of our children are of the same logical operator that we are, we remove the // child's children and append them to ourselves after we examine all children. vector<MatchExpression*> absorbedChildren; for (size_t i = 0; i < root->numChildren();) { MatchExpression* child = root->getChild(i); if (child->matchType() == root->matchType()) { // AND of an AND or OR of an OR. Absorb child's children into ourself. for (size_t j = 0; j < child->numChildren(); ++j) { absorbedChildren.push_back(child->getChild(j)); } // TODO(opt): this is possibly n^2-ish root->getChildVector()->erase(root->getChildVector()->begin() + i); child->getChildVector()->clear(); // Note that this only works because we cleared the child's children delete child; // Don't increment 'i' as the current child 'i' used to be child 'i+1' } else { ++i; } } root->getChildVector()->insert(root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end()); // AND of 1 thing is the thing, OR of 1 thing is the thing. if (1 == root->numChildren()) { MatchExpression* ret = root->getChild(0); root->getChildVector()->clear(); delete root; return ret; } } return root; }
// static // XXX TODO: This does not belong here at all. MatchExpression* CanonicalQuery::logicalRewrite(MatchExpression* tree) { // Only thing we do is pull an OR up at the root. if (MatchExpression::AND != tree->matchType()) { return tree; } // We want to bail out ASAP if we have nothing to do here. size_t numOrs = 0; for (size_t i = 0; i < tree->numChildren(); ++i) { if (MatchExpression::OR == tree->getChild(i)->matchType()) { ++numOrs; } } // Only do this for one OR right now. if (1 != numOrs) { return tree; } // Detach the OR from the root. invariant(NULL != tree->getChildVector()); std::vector<MatchExpression*>& rootChildren = *tree->getChildVector(); MatchExpression* orChild = NULL; for (size_t i = 0; i < rootChildren.size(); ++i) { if (MatchExpression::OR == rootChildren[i]->matchType()) { orChild = rootChildren[i]; rootChildren.erase(rootChildren.begin() + i); break; } } // AND the existing root with each or child. invariant(NULL != orChild); invariant(NULL != orChild->getChildVector()); std::vector<MatchExpression*>& orChildren = *orChild->getChildVector(); for (size_t i = 0; i < orChildren.size(); ++i) { AndMatchExpression* ama = new AndMatchExpression(); ama->add(orChildren[i]); ama->add(tree->shallowClone()); orChildren[i] = ama; } delete tree; // Clean up any consequences from this tomfoolery. return normalizeTree(orChild); }
//void AssociationTree::solve(std::vector<std::pair<unsigned int, unsigned int> > & _pairs, std::vector<unsigned int> & _unassoc) void AssociationTree::solve(std::vector<std::pair<unsigned int, unsigned int> > & _pairs, std::vector<bool> & _associated_mask) { std::list<AssociationNode*>::iterator best_node; bool rootReached = false; AssociationNode *anPtr; //grows tree exploring all likely hypothesis growTree(); //computes tree probs computeTree(); //normalizes tree probs normalizeTree(); //if terminus_node_list_ is empty exit withou pairing if ( terminus_node_list_.empty() ) return; //choose best node based on best tree probability chooseBestTerminus(best_node); //resize _associated_mask and resets it to false _associated_mask.resize(nd_,false); //set pairs anPtr = *best_node; //init pointer int ii=0; while( ! anPtr->isRoot() ) //set pairs { // if ( anPtr->getTargetIndex() == nt_) //detection with void target -> unassociated detection // { // _unassoc.push_back(anPtr->getDetectionIndex()); // } // else // { // _pairs.push_back( std::pair<unsigned int, unsigned int>(anPtr->getDetectionIndex(), anPtr->getTargetIndex()) ); // } if ( anPtr->getTargetIndex() < nt_ ) //association pair { _associated_mask.at(anPtr->getDetectionIndex()) = true; _pairs.push_back( std::pair<unsigned int, unsigned int>(anPtr->getDetectionIndex(), anPtr->getTargetIndex()) ); } anPtr = anPtr->upNodePtr(); } }
Status CanonicalQuery::init(LiteParsedQuery* lpq) { _pq.reset(lpq); // Build a parse tree from the BSONObj in the parsed query. StatusWithMatchExpression swme = MatchExpressionParser::parse(_pq->getFilter()); if (!swme.isOK()) { return swme.getStatus(); } MatchExpression* root = swme.getValue(); normalizeTree(root); _root.reset(root); if (!_pq->getProj().isEmpty()) { ParsedProjection* proj; Status projStatus = ProjectionParser::parseFindSyntax(_pq->getProj(), &proj); if (!projStatus.isOK()) { return projStatus; } _proj.reset(proj); } return Status::OK(); }
Status CanonicalQuery::init(std::unique_ptr<QueryRequest> qr, const ExtensionsCallback& extensionsCallback, MatchExpression* root, std::unique_ptr<CollatorInterface> collator) { _qr = std::move(qr); _collator = std::move(collator); _hasNoopExtensions = extensionsCallback.hasNoopExtensions(); _isIsolated = QueryRequest::isQueryIsolated(_qr->getFilter()); // Normalize, sort and validate tree. root = normalizeTree(root); sortTree(root); _root.reset(root); Status validStatus = isValid(root, *_qr); if (!validStatus.isOK()) { return validStatus; } // Validate the projection if there is one. if (!_qr->getProj().isEmpty()) { ParsedProjection* pp; Status projStatus = ParsedProjection::make(_qr->getProj(), _root.get(), &pp, extensionsCallback); if (!projStatus.isOK()) { return projStatus; } _proj.reset(pp); } if (_proj && _proj->wantSortKey() && _qr->getSort().isEmpty()) { return Status(ErrorCodes::BadValue, "cannot use sortKey $meta projection without a sort"); } return Status::OK(); }
Status CanonicalQuery::normalize(MatchExpression* root) { _root.reset(normalizeTree(root)); sortTree(_root.get()); return isValid(_root.get()); }
// static MatchExpression* CanonicalQuery::normalizeTree(MatchExpression* root) { if (MatchExpression::AND == root->matchType() || MatchExpression::OR == root->matchType()) { // We could have AND of AND of AND. Make sure we clean up our children before merging them. for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } // If any of our children are of the same logical operator that we are, we remove the // child's children and append them to ourselves after we examine all children. std::vector<MatchExpression*> absorbedChildren; for (size_t i = 0; i < root->numChildren();) { MatchExpression* child = root->getChild(i); if (child->matchType() == root->matchType()) { // AND of an AND or OR of an OR. Absorb child's children into ourself. for (size_t j = 0; j < child->numChildren(); ++j) { absorbedChildren.push_back(child->getChild(j)); } // TODO(opt): this is possibly n^2-ish root->getChildVector()->erase(root->getChildVector()->begin() + i); child->getChildVector()->clear(); // Note that this only works because we cleared the child's children delete child; // Don't increment 'i' as the current child 'i' used to be child 'i+1' } else { ++i; } } root->getChildVector()->insert( root->getChildVector()->end(), absorbedChildren.begin(), absorbedChildren.end()); // AND of 1 thing is the thing, OR of 1 thing is the thing. if (1 == root->numChildren()) { MatchExpression* ret = root->getChild(0); root->getChildVector()->clear(); delete root; return ret; } } else if (MatchExpression::NOR == root->matchType()) { // First clean up children. for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } // NOR of one thing is NOT of the thing. if (1 == root->numChildren()) { // Detach the child and assume ownership. std::unique_ptr<MatchExpression> child(root->getChild(0)); root->getChildVector()->clear(); // Delete the root when this goes out of scope. std::unique_ptr<NorMatchExpression> ownedRoot(static_cast<NorMatchExpression*>(root)); // Make a NOT to be the new root and transfer ownership of the child to it. auto newRoot = stdx::make_unique<NotMatchExpression>(); newRoot->init(child.release()).transitional_ignore(); return newRoot.release(); } } else if (MatchExpression::NOT == root->matchType()) { // Normalize the rest of the tree hanging off this NOT node. NotMatchExpression* nme = static_cast<NotMatchExpression*>(root); MatchExpression* child = nme->releaseChild(); // normalizeTree(...) takes ownership of 'child', and then // transfers ownership of its return value to 'nme'. nme->resetChild(normalizeTree(child)); } else if (MatchExpression::ELEM_MATCH_OBJECT == root->matchType()) { // Normalize the rest of the tree hanging off this ELEM_MATCH_OBJECT node. ElemMatchObjectMatchExpression* emome = static_cast<ElemMatchObjectMatchExpression*>(root); auto child = emome->releaseChild(); // normalizeTree(...) takes ownership of 'child', and then // transfers ownership of its return value to 'emome'. emome->resetChild(std::unique_ptr<MatchExpression>(normalizeTree(child.release()))); } else if (MatchExpression::ELEM_MATCH_VALUE == root->matchType()) { // Just normalize our children. for (size_t i = 0; i < root->getChildVector()->size(); ++i) { (*root->getChildVector())[i] = normalizeTree(root->getChild(i)); } } else if (MatchExpression::MATCH_IN == root->matchType()) { std::unique_ptr<InMatchExpression> in(static_cast<InMatchExpression*>(root)); // IN of 1 regex is the regex. if (in->getRegexes().size() == 1 && in->getEqualities().empty()) { RegexMatchExpression* childRe = in->getRegexes().begin()->get(); invariant(!childRe->getTag()); // Create a new RegexMatchExpression, because 'childRe' does not have a path. auto re = stdx::make_unique<RegexMatchExpression>(); re->init(in->path(), childRe->getString(), childRe->getFlags()).transitional_ignore(); if (in->getTag()) { re->setTag(in->getTag()->clone()); } return normalizeTree(re.release()); } // IN of 1 equality is the equality. if (in->getEqualities().size() == 1 && in->getRegexes().empty()) { auto eq = stdx::make_unique<EqualityMatchExpression>(); eq->init(in->path(), *(in->getEqualities().begin())).transitional_ignore(); eq->setCollator(in->getCollator()); if (in->getTag()) { eq->setTag(in->getTag()->clone()); } return eq.release(); } return in.release(); } return root; }