diff options
10 files changed, 212 insertions, 24 deletions
diff --git a/searchcore/src/tests/proton/documentmetastore/lid_allocator/lid_allocator_test.cpp b/searchcore/src/tests/proton/documentmetastore/lid_allocator/lid_allocator_test.cpp index b2fa8675835..e136e491f05 100644 --- a/searchcore/src/tests/proton/documentmetastore/lid_allocator/lid_allocator_test.cpp +++ b/searchcore/src/tests/proton/documentmetastore/lid_allocator/lid_allocator_test.cpp @@ -102,10 +102,15 @@ protected: } return result; } - - SimpleResult get_active_lids_in_search_iterator(uint32_t docid_limit, bool filter) { + + Blueprint::UP make_whitelist_blueprint(uint32_t docid_limit) { auto blueprint = _allocator.createWhiteListBlueprint(); blueprint->setDocIdLimit(docid_limit); + return blueprint; + } + + SimpleResult get_active_lids_in_search_iterator(uint32_t docid_limit, bool filter) { + auto blueprint = make_whitelist_blueprint(docid_limit); std::unique_ptr<SearchIterator> iterator; MatchData md(MatchData::params()); if (filter) { @@ -119,8 +124,7 @@ protected: } Trinary filter_search_iterator_matches_any(uint32_t docid_limit) { - auto blueprint = _allocator.createWhiteListBlueprint(); - blueprint->setDocIdLimit(docid_limit); + auto blueprint = make_whitelist_blueprint(docid_limit); auto iterator = blueprint->createFilterSearch(true, Blueprint::FilterConstraint::UPPER_BOUND); return iterator->matches_any(); } @@ -170,6 +174,17 @@ TEST_F(LidAllocatorTest, filter_search_iterator_matches_all_when_all_lids_are_ac EXPECT_EQ(SimpleResult({1, 2, 3, 4}), get_active_lids_in_search_iterator(6, false)); } +TEST_F(LidAllocatorTest, whitelist_blueprint_can_maximize_relative_estimate) +{ + register_lids({ 1, 2, 3, 4 }); + activate_lids({ 1, 2, 3, 4 }, true); + // the number of hits are overestimated based on the number of + // documents that could be active (100 in this test fixture) + EXPECT_EQ(make_whitelist_blueprint(1000)->estimate(), 0.1); + EXPECT_EQ(make_whitelist_blueprint(200)->estimate(), 0.5); + EXPECT_EQ(make_whitelist_blueprint(5)->estimate(), 1.0); +} + class LidAllocatorPerformanceTest : public LidAllocatorTest, public testing::WithParamInterface<bool> { diff --git a/searchcore/src/vespa/searchcore/proton/documentmetastore/lid_allocator.cpp b/searchcore/src/vespa/searchcore/proton/documentmetastore/lid_allocator.cpp index 95e4eac437c..9e9199bc8ba 100644 --- a/searchcore/src/vespa/searchcore/proton/documentmetastore/lid_allocator.cpp +++ b/searchcore/src/vespa/searchcore/proton/documentmetastore/lid_allocator.cpp @@ -222,6 +222,10 @@ public: setEstimate(HitEstimate(_activeLids.size(), false)); } + double calculate_relative_estimate() const final { + return abs_to_rel_est(getState().estimate().estHits, get_docid_limit()); + } + bool isWhiteList() const noexcept final { return true; } SearchIterator::UP createFilterSearch(bool strict, FilterConstraint) const override { diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp index 372b76fa9af..2d621fa1011 100644 --- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp @@ -22,6 +22,7 @@ class MyOr : public IntermediateBlueprint { private: public: + double calculate_relative_estimate() const final { return 0.5; } HitEstimate combine(const std::vector<HitEstimate> &data) const override { return max(data); } @@ -639,6 +640,7 @@ getExpectedBlueprint() " estimate: HitEstimate {\n" " empty: false\n" " estHits: 9\n" + " relative_estimate: 0.5\n" " cost_tier: 1\n" " tree_size: 2\n" " allow_termwise_eval: false\n" @@ -658,6 +660,7 @@ getExpectedBlueprint() " estimate: HitEstimate {\n" " empty: false\n" " estHits: 9\n" + " relative_estimate: 0.5\n" " cost_tier: 1\n" " tree_size: 1\n" " allow_termwise_eval: true\n" @@ -687,6 +690,7 @@ getExpectedSlimeBlueprint() { " '[type]': 'HitEstimate'," " empty: false," " estHits: 9," + " relative_estimate: 0.5," " cost_tier: 1," " tree_size: 2," " allow_termwise_eval: false" @@ -711,6 +715,7 @@ getExpectedSlimeBlueprint() { " '[type]': 'HitEstimate'," " empty: false," " estHits: 9," + " relative_estimate: 0.5," " cost_tier: 1," " tree_size: 1," " allow_termwise_eval: true" @@ -767,9 +772,9 @@ TEST("requireThatDocIdLimitInjectionWorks") } TEST("Control object sizes") { - EXPECT_EQUAL(32u, sizeof(Blueprint::State)); + EXPECT_EQUAL(40u, sizeof(Blueprint::State)); EXPECT_EQUAL(32u, sizeof(Blueprint)); - EXPECT_EQUAL(64u, sizeof(LeafBlueprint)); + EXPECT_EQUAL(72u, sizeof(LeafBlueprint)); } TEST_MAIN() { diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp index 38e7e27163d..5078672e84e 100644 --- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp @@ -157,9 +157,9 @@ TEST("test Or propagates updated histestimate") { EXPECT_TRUE(child.executeInfo.isStrict()); } EXPECT_EQUAL(1.0f, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).executeInfo.hitRate()); - EXPECT_EQUAL(1.0f, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).executeInfo.hitRate()); - EXPECT_EQUAL(3.0f/5.0f, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(2)).executeInfo.hitRate()); - EXPECT_EQUAL(3.0f*42.0f/(5.0f*50.0f), dynamic_cast<const RememberExecuteInfo &>(bp->getChild(3)).executeInfo.hitRate()); + EXPECT_APPROX(0.5f, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).executeInfo.hitRate(), 1e-6); + EXPECT_APPROX(0.5*3.0f/5.0f, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(2)).executeInfo.hitRate(), 1e-6); + EXPECT_APPROX(0.5*3.0f*42.0f/(5.0f*50.0f), dynamic_cast<const RememberExecuteInfo &>(bp->getChild(3)).executeInfo.hitRate(), 1e-6); } TEST("test And Blueprint") { @@ -644,7 +644,11 @@ struct make { child->setSourceId(source_tag); source_tag = invalid_source; } - making->addChild(std::move(child)); + if (auto *weak_and = making->asWeakAnd()) { + weak_and->addTerm(std::move(child), 1); + } else { + making->addChild(std::move(child)); + } return std::move(*this); } make &&leaf(uint32_t estimate) && { @@ -661,6 +665,9 @@ struct make { static make RANK() { return make(std::make_unique<RankBlueprint>()); } static make ANDNOT() { return make(std::make_unique<AndNotBlueprint>()); } static make SB(ISourceSelector &selector) { return make(std::make_unique<SourceBlenderBlueprint>(selector)); } + static make NEAR(uint32_t window) { return make(std::make_unique<NearBlueprint>(window)); } + static make ONEAR(uint32_t window) { return make(std::make_unique<ONearBlueprint>(window)); } + static make WEAKAND(uint32_t n) { return make(std::make_unique<WeakAndBlueprint>(n)); } }; TEST("AND AND collapsing") { @@ -1181,4 +1188,45 @@ TEST("require that OR blueprint use saturated sum as estimate") { TEST_DO(verify_or_est({{100, false},{300, false},{200, false}}, {300, false})); } +void verify_relative_estimate(make &&mk, double expect) { + EXPECT_EQUAL(mk.making->estimate(), 0.0); + Blueprint::UP bp = std::move(mk).leafs({200,300,950}); + bp->setDocIdLimit(1000); + EXPECT_EQUAL(bp->estimate(), expect); +} + +TEST("relative estimate for OR") { + verify_relative_estimate(make::OR(), 1.0-0.8*0.7*0.5); +} + +TEST("relative estimate for AND") { + verify_relative_estimate(make::AND(), 0.2*0.3*0.5); +} + +TEST("relative estimate for RANK") { + verify_relative_estimate(make::RANK(), 0.2); +} + +TEST("relative estimate for ANDNOT") { + verify_relative_estimate(make::ANDNOT(), 0.2); +} + +TEST("relative estimate for SB") { + InvalidSelector sel; + verify_relative_estimate(make::SB(sel), 1.0-0.8*0.7*0.5); +} + +TEST("relative estimate for NEAR") { + verify_relative_estimate(make::NEAR(1), 0.2*0.3*0.5); +} + +TEST("relative estimate for ONEAR") { + verify_relative_estimate(make::ONEAR(1), 0.2*0.3*0.5); +} + +TEST("relative estimate for WEAKAND") { + verify_relative_estimate(make::WEAKAND(1000), 1.0-0.8*0.7*0.5); + verify_relative_estimate(make::WEAKAND(50), 0.05); +} + TEST_MAIN() { TEST_DEBUG("lhs.out", "rhs.out"); TEST_RUN_ALL(); } diff --git a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp index 5933122d7a2..f910ff5be1b 100644 --- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp +++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp @@ -47,6 +47,7 @@ concept ChildCollector = requires(T a, std::unique_ptr<Blueprint> bp) { // inherit Blueprint to capture the default filter factory struct DefaultBlueprint : Blueprint { + double calculate_relative_estimate() const override { abort(); } void optimize(Blueprint* &, OptimizePass) override { abort(); } const State &getState() const override { abort(); } void fetchPostings(const ExecuteInfo &) override { abort(); } diff --git a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp index 58f22f19da1..2a59a578ec9 100644 --- a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp +++ b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp @@ -594,6 +594,7 @@ TEST_F("require that asString() on blueprint works", BlueprintAsStringFixture) " estimate: HitEstimate {\n" " empty: false\n" " estHits: 2\n" + " relative_estimate: 0.5\n" " cost_tier: 1\n" " tree_size: 2\n" " allow_termwise_eval: false\n" @@ -616,6 +617,7 @@ TEST_F("require that asString() on blueprint works", BlueprintAsStringFixture) " estimate: HitEstimate {\n" " empty: false\n" " estHits: 2\n" + " relative_estimate: 0.5\n" " cost_tier: 1\n" " tree_size: 1\n" " allow_termwise_eval: true\n" diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp index 1088decb8d6..96c7de928e5 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp @@ -89,6 +89,7 @@ Blueprint::sat_sum(const std::vector<HitEstimate> &data, uint32_t docid_limit) Blueprint::State::State() noexcept : _fields(), + _relative_estimate(0.0), _estimateHits(0), _tree_size(1), _estimateEmpty(true), @@ -105,6 +106,7 @@ Blueprint::State::State(FieldSpecBase field) noexcept Blueprint::State::State(FieldSpecBaseList fields_in) noexcept : _fields(std::move(fields_in)), + _relative_estimate(0.0), _estimateHits(0), _tree_size(1), _estimateEmpty(true), @@ -350,6 +352,7 @@ Blueprint::visitMembers(vespalib::ObjectVisitor &visitor) const visitor.openStruct("estimate", "HitEstimate"); visitor.visitBool("empty", state.estimate().empty); visitor.visitInt("estHits", state.estimate().estHits); + visitor.visitFloat("relative_estimate", state.relative_estimate()); visitor.visitInt("cost_tier", state.cost_tier()); visitor.visitInt("tree_size", state.tree_size()); visitor.visitBool("allow_termwise_eval", state.allow_termwise_eval()); @@ -373,8 +376,10 @@ StateCache::updateState() const void StateCache::notifyChange() { assert(!frozen()); - Blueprint::notifyChange(); - _stale = true; + if (!_stale) { + Blueprint::notifyChange(); + _stale = true; + } } } // namespace blueprint @@ -386,9 +391,11 @@ IntermediateBlueprint::~IntermediateBlueprint() = default; void IntermediateBlueprint::setDocIdLimit(uint32_t limit) noexcept { - Blueprint::setDocIdLimit(limit); - for (Blueprint::UP &child : _children) { - child->setDocIdLimit(limit); + if (limit != get_docid_limit()) { + Blueprint::setDocIdLimit(limit); + for (Blueprint::UP &child : _children) { + child->setDocIdLimit(limit); + } } } @@ -511,6 +518,7 @@ IntermediateBlueprint::calculateState() const { State state(exposeFields()); state.estimate(calculateEstimate()); + state.relative_estimate(calculate_relative_estimate()); state.cost_tier(calculate_cost_tier()); state.allow_termwise_eval(infer_allow_termwise_eval()); state.want_global_filter(infer_want_global_filter()); @@ -703,6 +711,27 @@ IntermediateBlueprint::calculateUnpackInfo(const fef::MatchData & md) const //----------------------------------------------------------------------------- void +LeafBlueprint::setDocIdLimit(uint32_t limit) noexcept { + if (limit != get_docid_limit()) { + Blueprint::setDocIdLimit(limit); + _state.relative_estimate(calculate_relative_estimate()); + notifyChange(); + } +} + +double +LeafBlueprint::calculate_relative_estimate() const +{ + double rel_est = abs_to_rel_est(_state.estimate().estHits, get_docid_limit()); + if (rel_est > 0.9) { + // Assume we do not really know how much we are matching when + // we claim to match 'everything' + return 0.5; + } + return rel_est; +} + +void LeafBlueprint::fetchPostings(const ExecuteInfo &) { } diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.h b/searchlib/src/vespa/searchlib/queryeval/blueprint.h index a61d435ac25..3261d380f36 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.h @@ -29,6 +29,7 @@ class MatchingElementsSearch; class LeafBlueprint; class IntermediateBlueprint; class SourceBlenderBlueprint; +class WeakAndBlueprint; class AndBlueprint; class AndNotBlueprint; class OrBlueprint; @@ -74,6 +75,7 @@ public: { private: FieldSpecBaseList _fields; + double _relative_estimate; uint32_t _estimateHits; uint32_t _tree_size : 20; bool _estimateEmpty : 1; @@ -109,6 +111,9 @@ public: return nullptr; } + void relative_estimate(double value) noexcept { _relative_estimate = value; } + double relative_estimate() const noexcept { return _relative_estimate; } + void estimate(HitEstimate est) noexcept { _estimateHits = est.estHits; _estimateEmpty = est.empty; @@ -117,10 +122,9 @@ public: HitEstimate estimate() const noexcept { return {_estimateHits, _estimateEmpty}; } double hit_ratio(uint32_t docid_limit) const noexcept { - uint32_t total_hits = _estimateHits; - uint32_t total_docs = std::max(total_hits, docid_limit); - return (total_docs == 0) ? 0.0 : double(total_hits) / double(total_docs); + return abs_to_rel_est(_estimateHits, docid_limit); } + void tree_size(uint32_t value) noexcept { assert(value < 0x100000); _tree_size = value; @@ -133,6 +137,12 @@ public: void cost_tier(uint8_t value) noexcept { _cost_tier = value; } uint8_t cost_tier() const noexcept { return _cost_tier; } }; + + // converts from an absolute to a relative estimate + static double abs_to_rel_est(uint32_t est, uint32_t docid_limit) noexcept { + uint32_t total_docs = std::max(est, docid_limit); + return (total_docs == 0) ? 0.0 : double(est) / double(total_docs); + } // utility that just takes maximum estimate static HitEstimate max(const std::vector<HitEstimate> &data); @@ -238,9 +248,9 @@ public: virtual const State &getState() const = 0; const Blueprint &root() const; - double hit_ratio() const noexcept { return getState().hit_ratio(_docid_limit); } - // TODO Call getState().estimate() when it return a normalized estimate - double estimate() const noexcept { return getState().hit_ratio(_docid_limit); } + double hit_ratio() const { return getState().hit_ratio(_docid_limit); } + double estimate() const { return getState().relative_estimate(); } + virtual double calculate_relative_estimate() const = 0; virtual void fetchPostings(const ExecuteInfo &execInfo) = 0; virtual void freeze() = 0; @@ -272,6 +282,7 @@ public: bool isAndNot() const noexcept { return const_cast<Blueprint *>(this)->asAndNot() != nullptr; } virtual OrBlueprint * asOr() noexcept { return nullptr; } virtual SourceBlenderBlueprint * asSourceBlender() noexcept { return nullptr; } + virtual WeakAndBlueprint * asWeakAnd() noexcept { return nullptr; } virtual bool isRank() const noexcept { return false; } virtual const attribute::ISearchContext *get_attribute_search_context() const noexcept { return nullptr; } @@ -357,7 +368,7 @@ public: 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; virtual FieldSpecBaseList exposeFields() const = 0; virtual void sort(Children &children) const = 0; @@ -383,6 +394,7 @@ protected: void optimize(Blueprint* &self, OptimizePass pass) final; void setEstimate(HitEstimate est) { _state.estimate(est); + _state.relative_estimate(calculate_relative_estimate()); notifyChange(); } void set_cost_tier(uint32_t value); @@ -413,7 +425,8 @@ protected: public: ~LeafBlueprint() override = default; const State &getState() const final { return _state; } - void setDocIdLimit(uint32_t limit) noexcept final { Blueprint::setDocIdLimit(limit); } + void setDocIdLimit(uint32_t limit) noexcept final; + double calculate_relative_estimate() const override; void fetchPostings(const ExecuteInfo &execInfo) override; void freeze() final; SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp index c4044ba3d00..7d992b510b5 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp @@ -81,10 +81,35 @@ need_normal_features_for_children(const IntermediateBlueprint &blueprint, fef::M } } +double rel_est_first_child(const Blueprint::Children &children) { + return children.empty() ? 0.0 : children[0]->getState().relative_estimate(); +} + +double rel_est_and(const Blueprint::Children &children) { + double flow = 1.0; + for (const Blueprint::UP &child: children) { + flow *= child->getState().relative_estimate(); + } + return children.empty() ? 0.0 : flow; +} + +double rel_est_or(const Blueprint::Children &children) { + double flow = 1.0; + for (const Blueprint::UP &child: children) { + flow *= (1.0 - child->getState().relative_estimate()); + } + return (1.0 - flow); +} + } // namespace search::queryeval::<unnamed> //----------------------------------------------------------------------------- +double +AndNotBlueprint::calculate_relative_estimate() const { + return rel_est_first_child(get_children()); +} + Blueprint::HitEstimate AndNotBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -188,6 +213,11 @@ AndNotBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) co //----------------------------------------------------------------------------- +double +AndBlueprint::calculate_relative_estimate() const { + return rel_est_and(get_children()); +} + Blueprint::HitEstimate AndBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -282,7 +312,7 @@ OrBlueprint::computeNextHitRate(const Blueprint & child, double hit_rate, bool u constexpr double MIN_INVERSE_HIT_RATIO = 0.10; double estimate = use_estimate ? child.estimate() : child.hit_ratio(); double inverse_child_estimate = 1.0 - estimate; - return (inverse_child_estimate > MIN_INVERSE_HIT_RATIO) + return (use_estimate || (inverse_child_estimate > MIN_INVERSE_HIT_RATIO)) ? hit_rate * inverse_child_estimate : hit_rate; } @@ -291,6 +321,11 @@ OrBlueprint::computeNextHitRate(const Blueprint & child, double hit_rate, bool u OrBlueprint::~OrBlueprint() = default; +double +OrBlueprint::calculate_relative_estimate() const { + return rel_est_or(get_children()); +} + Blueprint::HitEstimate OrBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -382,6 +417,13 @@ OrBlueprint::calculate_cost_tier() const //----------------------------------------------------------------------------- WeakAndBlueprint::~WeakAndBlueprint() = default; +double +WeakAndBlueprint::calculate_relative_estimate() const { + double child_est = rel_est_or(get_children()); + double my_est = abs_to_rel_est(_n, get_docid_limit()); + return std::min(my_est, child_est); +} + Blueprint::HitEstimate WeakAndBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -441,6 +483,11 @@ WeakAndBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) c //----------------------------------------------------------------------------- +double +NearBlueprint::calculate_relative_estimate() const { + return rel_est_and(get_children()); +} + Blueprint::HitEstimate NearBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -494,6 +541,11 @@ NearBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) cons //----------------------------------------------------------------------------- +double +ONearBlueprint::calculate_relative_estimate() const { + return rel_est_and(get_children()); +} + Blueprint::HitEstimate ONearBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -550,6 +602,11 @@ ONearBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) con //----------------------------------------------------------------------------- +double +RankBlueprint::calculate_relative_estimate() const { + return rel_est_first_child(get_children()); +} + Blueprint::HitEstimate RankBlueprint::combine(const std::vector<HitEstimate> &data) const { @@ -642,6 +699,11 @@ SourceBlenderBlueprint::SourceBlenderBlueprint(const ISourceSelector &selector) SourceBlenderBlueprint::~SourceBlenderBlueprint() = default; +double +SourceBlenderBlueprint::calculate_relative_estimate() const { + return rel_est_or(get_children()); +} + Blueprint::HitEstimate SourceBlenderBlueprint::combine(const std::vector<HitEstimate> &data) const { diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h index 1d88b3b21eb..b9306ea307d 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h @@ -15,6 +15,7 @@ class AndNotBlueprint : public IntermediateBlueprint { public: bool supports_termwise_children() const override { return true; } + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void optimize_self(OptimizePass pass) override; @@ -41,6 +42,7 @@ class AndBlueprint : public IntermediateBlueprint { public: bool supports_termwise_children() const override { return true; } + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void optimize_self(OptimizePass pass) override; @@ -65,6 +67,7 @@ class OrBlueprint : public IntermediateBlueprint public: ~OrBlueprint() override; bool supports_termwise_children() const override { return true; } + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void optimize_self(OptimizePass pass) override; @@ -91,11 +94,13 @@ private: std::vector<uint32_t> _weights; public: + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children) const override; bool inheritStrict(size_t i) const override; bool always_needs_unpack() const override; + WeakAndBlueprint * asWeakAnd() noexcept final { return this; } SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, bool strict, fef::MatchData &md) const override; @@ -119,6 +124,7 @@ private: uint32_t _window; public: + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; bool should_optimize_children() const override { return false; } @@ -141,6 +147,7 @@ private: uint32_t _window; public: + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; bool should_optimize_children() const override { return false; } @@ -160,6 +167,7 @@ public: class RankBlueprint final : public IntermediateBlueprint { public: + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void optimize_self(OptimizePass pass) override; @@ -187,6 +195,7 @@ private: public: explicit SourceBlenderBlueprint(const ISourceSelector &selector) noexcept; ~SourceBlenderBlueprint() override; + double calculate_relative_estimate() const final; HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children) const override; |