diff options
Diffstat (limited to 'searchlib/src/vespa')
4 files changed, 27 insertions, 14 deletions
diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp index a8e2e77623f..639805e116e 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp @@ -36,8 +36,8 @@ void maybe_eliminate_self(Blueprint* &self, Blueprint::UP replacement) { self->setSourceId(discard->getSourceId()); discard->setParent(nullptr); } - // replace with empty blueprint if empty - if (self->getState().estimate().empty) { + // replace with empty blueprint if empty, skip if already empty blueprint + if ((self->as_empty() == nullptr) && self->getState().estimate().empty) { Blueprint::UP discard(self); self = new EmptyBlueprint(discard->getState().fields()); self->setParent(discard->getParent()); @@ -130,7 +130,6 @@ Blueprint::UP Blueprint::optimize(Blueprint::UP bp) { Blueprint *root = bp.release(); root->optimize(root, OptimizePass::FIRST); - root->optimize(root, OptimizePass::SECOND); root->optimize(root, OptimizePass::LAST); return Blueprint::UP(root); } diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.h b/searchlib/src/vespa/searchlib/queryeval/blueprint.h index 81d225661d0..a02cb7dd17f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.h @@ -32,6 +32,7 @@ class SourceBlenderBlueprint; class AndBlueprint; class AndNotBlueprint; class OrBlueprint; +class EmptyBlueprint; /** * A Blueprint is an intermediate representation of a search. More @@ -50,7 +51,7 @@ public: using Children = std::vector<Blueprint::UP>; using SearchIteratorUP = std::unique_ptr<SearchIterator>; - enum class OptimizePass { FIRST, SECOND, LAST }; + enum class OptimizePass { FIRST, LAST }; struct HitEstimate { uint32_t estHits; @@ -270,6 +271,9 @@ public: virtual bool isRank() const noexcept { return false; } virtual const attribute::ISearchContext *get_attribute_search_context() const noexcept { return nullptr; } + // to avoid replacing an empty blueprint with another empty blueprint + virtual EmptyBlueprint *as_empty() noexcept { return nullptr; } + // For document summaries with matched-elements-only set. virtual std::unique_ptr<MatchingElementsSearch> create_matching_elements_search(const MatchingElementsFields &fields) const; }; @@ -347,6 +351,7 @@ public: IntermediateBlueprint & insertChild(size_t n, Blueprint::UP child); IntermediateBlueprint &addChild(Blueprint::UP child); Blueprint::UP removeChild(size_t n); + Blueprint::UP removeLastChild() { return removeChild(childCnt() - 1); } SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; virtual HitEstimate combine(const std::vector<HitEstimate> &data) const = 0; diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp index b315965b5f4..4d0656b421c 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp @@ -52,7 +52,7 @@ void optimize_source_blenders(IntermediateBlueprint &self, size_t begin_idx) { source_blenders.pop_back(); SourceBlenderBlueprint * blender = blender_up->asSourceBlender(); while (blender->childCnt() > 0) { - Blueprint::UP child_up = blender->removeChild(blender->childCnt() - 1); + Blueprint::UP child_up = blender->removeLastChild(); size_t source_idx = lookup_create_source(sources, child_up->getSourceId(), self.get_docid_limit()); sources[source_idx]->addChild(std::move(child_up)); } @@ -107,14 +107,24 @@ AndNotBlueprint::optimize_self(OptimizePass pass) return; } if (pass == OptimizePass::FIRST) { - AndNotBlueprint * child = getChild(0).asAndNot(); - if (child != nullptr) { + if (auto *child = getChild(0).asAndNot()) { while (child->childCnt() > 1) { - addChild(child->removeChild(1)); + addChild(child->removeLastChild()); } insertChild(1, child->removeChild(0)); removeChild(0); } + if (auto *child = getChild(0).asAnd()) { + for (size_t i = 0; i < child->childCnt(); ++i) { + if (auto *grand_child = child->getChild(i).asAndNot()) { + while (grand_child->childCnt() > 1) { + addChild(grand_child->removeLastChild()); + } + child->addChild(grand_child->removeChild(0)); + child->removeChild(i--); + } + } + } for (size_t i = 1; i < childCnt(); ++i) { if (getChild(i).getState().estimate().empty) { removeChild(i--); @@ -195,10 +205,9 @@ AndBlueprint::optimize_self(OptimizePass pass) { if (pass == OptimizePass::FIRST) { for (size_t i = 0; i < childCnt(); ++i) { - AndBlueprint * child = getChild(i).asAnd(); - if (child != nullptr) { + if (auto *child = getChild(i).asAnd()) { while (child->childCnt() > 0) { - addChild(child->removeChild(0)); + addChild(child->removeLastChild()); } removeChild(i--); } @@ -297,10 +306,9 @@ OrBlueprint::optimize_self(OptimizePass pass) { if (pass == OptimizePass::FIRST) { for (size_t i = 0; (childCnt() > 1) && (i < childCnt()); ++i) { - OrBlueprint * child = getChild(i).asOr(); - if (child != nullptr) { + if (auto *child = getChild(i).asOr()) { while (child->childCnt() > 0) { - addChild(child->removeChild(0)); + addChild(child->removeLastChild()); } removeChild(i--); } else if (getChild(i).getState().estimate().empty) { diff --git a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h index a95ca0efc72..a1c23649dd6 100644 --- a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h +++ b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h @@ -20,6 +20,7 @@ public: EmptyBlueprint(FieldSpecBase field) : SimpleLeafBlueprint(field) {} EmptyBlueprint() = default; SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + EmptyBlueprint *as_empty() noexcept final override { return this; } }; class AlwaysTrueBlueprint : public SimpleLeafBlueprint |