diff options
Diffstat (limited to 'searchlib/src')
75 files changed, 1006 insertions, 756 deletions
diff --git a/searchlib/src/apps/tests/memoryindexstress_test.cpp b/searchlib/src/apps/tests/memoryindexstress_test.cpp index 1cf7c4f95e5..763ba860fe6 100644 --- a/searchlib/src/apps/tests/memoryindexstress_test.cpp +++ b/searchlib/src/apps/tests/memoryindexstress_test.cpp @@ -63,7 +63,7 @@ const vespalib::string bar("bar"); const vespalib::string doc_type_name = "test"; const vespalib::string header_name = doc_type_name + ".header"; const vespalib::string body_name = doc_type_name + ".body"; - +uint32_t docid_limit = 100; // needed for relative estimates Schema makeSchema() @@ -332,13 +332,14 @@ Fixture::readWork(uint32_t cnt) LOG(error, "Did not get blueprint"); break; } + result->basic_plan(true, docid_limit); if (result->getState().estimate().empty) { ++emptyCount; } else { ++nonEmptyCount; } - result->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = result->createSearch(*match_data, true); + result->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = result->createSearch(*match_data); if (!EXPECT_TRUE(search)) { LOG(error, "Did not get search iterator"); break; @@ -429,11 +430,12 @@ verifyResult(const FakeResult &expect, if (!EXPECT_TRUE(result.get() != 0)) { return false; } + result->basic_plan(true, docid_limit); EXPECT_EQUAL(expect.inspect().size(), result->getState().estimate().estHits); EXPECT_EQUAL(expect.inspect().empty(), result->getState().estimate().empty); - result->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = result->createSearch(*match_data, true); + result->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = result->createSearch(*match_data); if (!EXPECT_TRUE(search.get() != 0)) { return false; } diff --git a/searchlib/src/tests/attribute/benchmark/attributesearcher.h b/searchlib/src/tests/attribute/benchmark/attributesearcher.h index a383b22e22f..6b8ccc5de59 100644 --- a/searchlib/src/tests/attribute/benchmark/attributesearcher.h +++ b/searchlib/src/tests/attribute/benchmark/attributesearcher.h @@ -140,7 +140,7 @@ AttributeFindSearcher<T>::doRun() _attrPtr->getSearch(vespalib::stringref(&_query[0], _query.size()), attribute::SearchContextParams()); - searchContext->fetchPostings(queryeval::ExecuteInfo::TRUE); + searchContext->fetchPostings(queryeval::ExecuteInfo::FULL, true); std::unique_ptr<queryeval::SearchIterator> iterator = searchContext->createIterator(nullptr, true); std::unique_ptr<ResultSet> results = performSearch(*iterator, _attrPtr->getNumDocs()); @@ -218,7 +218,7 @@ AttributeRangeSearcher::doRun() _attrPtr->getSearch(vespalib::stringref(&_query[0], _query.size()), attribute::SearchContextParams()); - searchContext->fetchPostings(queryeval::ExecuteInfo::TRUE); + searchContext->fetchPostings(queryeval::ExecuteInfo::FULL, true); std::unique_ptr<queryeval::SearchIterator> iterator = searchContext->createIterator(nullptr, true); std::unique_ptr<ResultSet> results = performSearch(*iterator, _attrPtr->getNumDocs()); @@ -257,7 +257,7 @@ AttributePrefixSearcher::doRun() _attrPtr->getSearch(vespalib::stringref(&_query[0], _query.size()), attribute::SearchContextParams()); - searchContext->fetchPostings(queryeval::ExecuteInfo::TRUE); + searchContext->fetchPostings(queryeval::ExecuteInfo::FULL, true); std::unique_ptr<queryeval::SearchIterator> iterator = searchContext->createIterator(nullptr, true); std::unique_ptr<ResultSet> results = performSearch(*iterator, _attrPtr->getNumDocs()); diff --git a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp index f9e6340560f..0e7308d0ede 100644 --- a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp @@ -426,7 +426,7 @@ BitVectorTest::checkSearch(AttributePtr v, bool checkStride) { TermFieldMatchData md; - sc->fetchPostings(search::queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(search::queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); checkSearch(std::move(v), std::move(sb), md, expFirstDocId, expLastDocId, expDocFreq, weights, diff --git a/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp b/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp index 87b771af8e6..1d66c59d2c9 100644 --- a/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp +++ b/searchlib/src/tests/attribute/direct_multi_term_blueprint/direct_multi_term_blueprint_test.cpp @@ -222,7 +222,6 @@ public: } else { validate_posting_lists<StringKey>(*store); } - blueprint->setDocIdLimit(doc_id_limit); if (need_term_field_match_data) { tfmd.needs_normal_features(); } else { @@ -263,8 +262,9 @@ public: add_term(value); } } - std::unique_ptr<SearchIterator> create_leaf_search(bool strict = true) const { - return blueprint->createLeafSearch(tfmda, strict); + std::unique_ptr<SearchIterator> create_leaf_search(bool strict = true) { + blueprint->basic_plan(strict, doc_id_limit); + return blueprint->createLeafSearch(tfmda); } vespalib::string resolve_iterator_with_unpack() const { if (in_operator) { diff --git a/searchlib/src/tests/attribute/enumeratedsave/enumeratedsave_test.cpp b/searchlib/src/tests/attribute/enumeratedsave/enumeratedsave_test.cpp index df58e839180..0795d85e4a2 100644 --- a/searchlib/src/tests/attribute/enumeratedsave/enumeratedsave_test.cpp +++ b/searchlib/src/tests/attribute/enumeratedsave/enumeratedsave_test.cpp @@ -665,7 +665,7 @@ EnumeratedSaveTest::testReload(AttributePtr v0, TermFieldMatchData md; SearchContextPtr sc = getSearch<VectorType>(as<VectorType>(v)); - sc->fetchPostings(search::queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(search::queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); sb->initFullRange(); sb->seek(1u); diff --git a/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp b/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp index 93ae9cb13cb..41ec377dece 100644 --- a/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp +++ b/searchlib/src/tests/attribute/imported_search_context/imported_search_context_test.cpp @@ -271,7 +271,7 @@ TEST_F("Non-strict iterator unpacks target match data for weighted set hit", Wse TEST_F("Strict iterator is marked as strict", Fixture) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -280,7 +280,7 @@ TEST_F("Strict iterator is marked as strict", Fixture) { TEST_F("Non-strict blueprint with high hit rate is strict", Fixture(false, FastSearchConfig::ExplicitlyEnabled)) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::createForTest(false, 0.02)); + ctx->fetchPostings(queryeval::ExecuteInfo::createForTest(0.02), false); TermFieldMatchData match; auto iter = f.create_iterator(*ctx, match, false); @@ -289,7 +289,7 @@ TEST_F("Non-strict blueprint with high hit rate is strict", Fixture(false, FastS TEST_F("Non-strict blueprint with low hit rate is non-strict", Fixture(false, FastSearchConfig::ExplicitlyEnabled)) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::createForTest(false, 0.01)); + ctx->fetchPostings(queryeval::ExecuteInfo::createForTest(0.01), false); TermFieldMatchData match; auto iter = f.create_iterator(*ctx, match, false); @@ -314,7 +314,7 @@ SingleValueFixture::~SingleValueFixture() = default; TEST_F("Strict iterator seeks to first available hit LID", SingleValueFixture) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -340,7 +340,7 @@ TEST_F("Strict iterator seeks to first available hit LID", SingleValueFixture) { TEST_F("Strict iterator unpacks target match data for single value hit", SingleValueFixture) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -352,7 +352,7 @@ TEST_F("Strict iterator unpacks target match data for single value hit", SingleV TEST_F("Strict iterator unpacks target match data for array hit", ArrayValueFixture) { auto ctx = f.create_context(word_term("1234")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -364,7 +364,7 @@ TEST_F("Strict iterator unpacks target match data for array hit", ArrayValueFixt TEST_F("Strict iterator unpacks target match data for weighted set hit", WsetValueFixture) { auto ctx = f.create_context(word_term("foo")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -375,7 +375,7 @@ TEST_F("Strict iterator unpacks target match data for weighted set hit", WsetVal TEST_F("Strict iterator handles seek outside of LID space", ArrayValueFixture) { auto ctx = f.create_context(word_term("1234")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); @@ -407,7 +407,7 @@ TEST_F("matches(weight) performs GID mapping and forwards to target attribute", TEST_F("Multiple iterators can be created from the same context", SingleValueFixture) { auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match1; auto iter1 = f.create_strict_iterator(*ctx, match1); @@ -490,7 +490,7 @@ TEST_F("Bit vector from search cache is used if found", SearchCacheFixture) f.imported_attr->getSearchCache()->insert("5678", makeSearchCacheEntry({2, 6}, f.get_imported_attr()->getNumDocs())); auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); TEST_DO(f.assertSearch({2, 6}, *iter)); // Note: would be {3, 5} if cache was not used @@ -509,7 +509,7 @@ TEST_F("Entry is inserted into search cache if bit vector posting list is used", { EXPECT_EQUAL(0u, f.imported_attr->getSearchCache()->size()); auto ctx = f.create_context(word_term("5678")); - ctx->fetchPostings(queryeval::ExecuteInfo::TRUE); + ctx->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData match; auto iter = f.create_strict_iterator(*ctx, match); TEST_DO(f.assertSearch({3, 5}, *iter)); diff --git a/searchlib/src/tests/attribute/postinglistattribute/postinglistattribute_test.cpp b/searchlib/src/tests/attribute/postinglistattribute/postinglistattribute_test.cpp index ed91cefd35c..8da9b4466d7 100644 --- a/searchlib/src/tests/attribute/postinglistattribute/postinglistattribute_test.cpp +++ b/searchlib/src/tests/attribute/postinglistattribute/postinglistattribute_test.cpp @@ -378,7 +378,7 @@ PostingListAttributeTest::assertSearch(const std::string &exp, StringAttribute & { TermFieldMatchData md; SearchContextPtr sc = getSearch<StringAttribute>(sa); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); bool retval = true; EXPECT_TRUE(assertIterator(exp, *sb)) << (retval = false, ""); @@ -391,7 +391,7 @@ PostingListAttributeTest::assertSearch(const std::string &exp, StringAttribute & { TermFieldMatchData md; SearchContextPtr sc = getSearch<StringAttribute, std::string>(sa, key, false); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); bool retval = true; EXPECT_TRUE(assertIterator(exp, *sb, &md)) << (retval = false, ""); @@ -403,7 +403,7 @@ PostingListAttributeTest::assertSearch(const std::string &exp, IntegerAttribute { TermFieldMatchData md; SearchContextPtr sc = getSearch<IntegerAttribute, int32_t>(ia, key, false); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); bool retval = true; EXPECT_TRUE(assertIterator(exp, *sb, &md)) << (retval = false, ""); @@ -497,7 +497,7 @@ PostingListAttributeTest::checkSearch(bool useBitVector, bool need_unpack, bool { SearchContextPtr sc = getSearch(vec, term, false, attribute::SearchContextParams().useBitVector(useBitVector)); EXPECT_FALSE( ! sc ); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); auto est = sc->calc_hit_estimate(); uint32_t est_hits = est.est_hits(); EXPECT_FALSE(est.is_unknown()); @@ -912,7 +912,7 @@ PostingListAttributeTest::testMinMax(AttributePtr &ptr1, uint32_t trimmed) { TermFieldMatchData md; SearchContextPtr sc = getSearch<VectorType>(as<VectorType>(ptr1)); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = sc->createIterator(&md, true); sb->initFullRange(); @@ -937,7 +937,7 @@ PostingListAttributeTest::testMinMax(AttributePtr &ptr1, uint32_t trimmed) EXPECT_EQ(1u, sb->getDocId()); sc = getSearch2<VectorType>(as<VectorType>(ptr1)); - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); sb = sc->createIterator(&md, true); sb->initFullRange(); diff --git a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp index 3b346601245..bc360e635c1 100644 --- a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp @@ -223,8 +223,9 @@ Result do_search(IAttributeManager &attribute_manager, const Node &node, bool st Blueprint::UP bp = source.createBlueprint(requestContext, FieldSpec(field, fieldId, handle), node); ASSERT_TRUE(bp); Result result(bp->getState().estimate().estHits, bp->getState().estimate().empty); - bp->fetchPostings(queryeval::ExecuteInfo::createForTest(strict)); - SearchIterator::UP iterator = bp->createSearch(*match_data, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(queryeval::ExecuteInfo::FULL); + SearchIterator::UP iterator = bp->createSearch(*match_data); ASSERT_TRUE(iterator); iterator->initRange(1, num_docs); extract_posting_info(result, iterator->getPostingInfo()); diff --git a/searchlib/src/tests/attribute/searchable/attribute_weighted_set_blueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attribute_weighted_set_blueprint_test.cpp index a8630ea569e..7a794795cce 100644 --- a/searchlib/src/tests/attribute/searchable/attribute_weighted_set_blueprint_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attribute_weighted_set_blueprint_test.cpp @@ -111,8 +111,9 @@ struct WS { FieldSpecList fields; fields.add(FieldSpec(field, fieldId, handle, ac.getAttribute(field)->getIsFilter())); queryeval::Blueprint::UP bp = searchable.createBlueprint(requestContext, fields, *node); - bp->fetchPostings(queryeval::ExecuteInfo::createForTest(strict)); - SearchIterator::UP sb = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(queryeval::ExecuteInfo::FULL); + SearchIterator::UP sb = bp->createSearch(*md); return sb; } bool isWeightedSetTermSearch(Searchable &searchable, const std::string &field, bool strict) const { @@ -127,8 +128,9 @@ struct WS { FieldSpecList fields; fields.add(FieldSpec(field, fieldId, handle)); queryeval::Blueprint::UP bp = searchable.createBlueprint(requestContext, fields, *node); - bp->fetchPostings(queryeval::ExecuteInfo::createForTest(strict)); - SearchIterator::UP sb = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(queryeval::ExecuteInfo::FULL); + SearchIterator::UP sb = bp->createSearch(*md); FakeResult result; sb->initRange(1, 10); for (uint32_t docId = 1; docId < 10; ++docId) { diff --git a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp index 50f7d170afc..4a7cc3984dd 100644 --- a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp @@ -127,9 +127,9 @@ do_search(const Node &node, IAttributeManager &attribute_manager, bool expect_at } else { EXPECT_TRUE(result->get_attribute_search_context() == nullptr); } - result->fetchPostings(queryeval::ExecuteInfo::TRUE); - result->setDocIdLimit(DOCID_LIMIT); - SearchIterator::UP iterator = result->createSearch(*md, true); + result->basic_plan(true, DOCID_LIMIT); + result->fetchPostings(queryeval::ExecuteInfo::FULL); + SearchIterator::UP iterator = result->createSearch(*md); assert((bool)iterator); iterator->initRange(1, DOCID_LIMIT); EXPECT_TRUE(!iterator->seek(1)); @@ -313,8 +313,8 @@ public: ~BlueprintFactoryFixture() {} Blueprint::UP create_blueprint(const Node& term) { auto result = source.createBlueprint(request_ctx, FieldSpec(attr_name, 0, 0), term); - result->fetchPostings(queryeval::ExecuteInfo::TRUE); - result->setDocIdLimit(DOCID_LIMIT); + result->basic_plan(true, DOCID_LIMIT); + result->fetchPostings(queryeval::ExecuteInfo::FULL); return result; } void expect_document_weight_attribute() { @@ -325,14 +325,14 @@ public: } void expect_filter_search(const SimpleResult& upper, const SimpleResult& lower, const Node& term) { auto blueprint = create_blueprint(term); - auto upper_itr = blueprint->createFilterSearch(true, BFC::UPPER_BOUND); - auto lower_itr = blueprint->createFilterSearch(true, BFC::LOWER_BOUND); + auto upper_itr = blueprint->createFilterSearch(BFC::UPPER_BOUND); + auto lower_itr = blueprint->createFilterSearch(BFC::LOWER_BOUND); EXPECT_EQ(upper, SimpleResult().search(*upper_itr, DOCID_LIMIT)); EXPECT_EQ(lower, SimpleResult().search(*lower_itr, DOCID_LIMIT)); } void expect_filter_wrapper(const Node& term) { auto blueprint = create_blueprint(term); - auto itr = blueprint->createFilterSearch(true, BFC::UPPER_BOUND); + auto itr = blueprint->createFilterSearch(BFC::UPPER_BOUND); downcast<FilterWrapper>(*itr); } }; diff --git a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp index 77acbe046ca..87e6b2320fd 100644 --- a/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp +++ b/searchlib/src/tests/attribute/searchcontext/searchcontext_test.cpp @@ -241,7 +241,7 @@ protected: // test search iterator unpacking void fillForSearchIteratorUnpackingTest(IntegerAttribute * ia, bool extra); void testSearchIteratorUnpacking(const AttributePtr & ptr, SearchContext & sc, bool extra, bool strict) { - sc.fetchPostings(queryeval::ExecuteInfo::createForTest(strict)); + sc.fetchPostings(queryeval::ExecuteInfo::FULL, true); for (bool withElementId : {false, true}) { testSearchIteratorUnpacking(ptr, sc, extra, strict, withElementId); } @@ -469,7 +469,7 @@ template <typename V, typename T> ResultSetPtr SearchContextTest::performSearch(const V & vec, const T & term) { - return performSearch(queryeval::ExecuteInfo::TRUE, vec, term, TermType::WORD); + return performSearch(queryeval::ExecuteInfo::FULL, vec, term, TermType::WORD); } template <typename V, typename T> @@ -478,7 +478,7 @@ SearchContextTest::performSearch(const queryeval::ExecuteInfo & executeInfo, con { TermFieldMatchData dummy; SearchContextPtr sc = getSearch(vec, term, termType); - sc->fetchPostings(executeInfo); + sc->fetchPostings(executeInfo, true); SearchBasePtr sb = sc->createIterator(&dummy, true); ResultSetPtr rs = performSearch(*sb, vec.getNumDocs()); return rs; @@ -504,7 +504,7 @@ void SearchContextTest::performSearch(const V & vec, const vespalib::string & term, const DocSet & expected, TermType termType) { - performSearch(queryeval::ExecuteInfo::TRUE, vec, term, expected, termType); + performSearch(queryeval::ExecuteInfo::FULL, vec, term, expected, termType); } void @@ -547,7 +547,7 @@ SearchContextTest::testFind(const PostingList<V, T> & pl, bool verify_hit_estima EXPECT_EQ(exp_est.est_hits(), act_est.est_hits()); EXPECT_EQ(exp_est.is_unknown(), act_est.is_unknown()); } - sc->fetchPostings(queryeval::ExecuteInfo::TRUE); + sc->fetchPostings(queryeval::ExecuteInfo::FULL, true); TermFieldMatchData dummy; SearchBasePtr sb = sc->createIterator(&dummy, true); ResultSetPtr rs = performSearch(*sb, pl.getAttribute().getNumDocs()); @@ -676,7 +676,7 @@ public: ~Verifier() override; SearchIterator::UP create(bool strict) const override { - _sc->fetchPostings(queryeval::ExecuteInfo::createForTest(strict)); + _sc->fetchPostings(queryeval::ExecuteInfo::FULL, strict); return _sc->createIterator(&_dummy, strict); } private: @@ -784,7 +784,7 @@ SearchContextTest::testStrictSearchIterator(SearchContext & threeHits, { TermFieldMatchData dummy; { // search for value with 3 hits - threeHits.fetchPostings(queryeval::ExecuteInfo::TRUE); + threeHits.fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = threeHits.createIterator(&dummy, true); sb->initRange(1, threeHits.attribute().getCommittedDocIdLimit()); EXPECT_TRUE(typeTester.matches(*sb)); @@ -805,7 +805,7 @@ SearchContextTest::testStrictSearchIterator(SearchContext & threeHits, } { // search for value with no hits - noHits.fetchPostings(queryeval::ExecuteInfo::TRUE); + noHits.fetchPostings(queryeval::ExecuteInfo::FULL, true); SearchBasePtr sb = noHits.createIterator(&dummy, true); sb->initRange(1, noHits.attribute().getCommittedDocIdLimit()); ASSERT_TRUE(typeTester.matches(*sb)); @@ -823,7 +823,7 @@ SearchContextTest::testNonStrictSearchIterator(SearchContext & threeHits, { TermFieldMatchData dummy; { // search for value with three hits - threeHits.fetchPostings(queryeval::ExecuteInfo::FALSE); + threeHits.fetchPostings(queryeval::ExecuteInfo::FULL, false); SearchBasePtr sb = threeHits.createIterator(&dummy, false); sb->initRange(1, threeHits.attribute().getCommittedDocIdLimit()); EXPECT_TRUE(typeTester.matches(*sb)); @@ -841,7 +841,7 @@ SearchContextTest::testNonStrictSearchIterator(SearchContext & threeHits, EXPECT_TRUE(sb->getDocId() == 5u || sb->isAtEnd()); } { // search for value with no hits - noHits.fetchPostings(queryeval::ExecuteInfo::FALSE); + noHits.fetchPostings(queryeval::ExecuteInfo::FULL, false); SearchBasePtr sb = noHits.createIterator(&dummy, false); sb->initRange(1, threeHits.attribute().getCommittedDocIdLimit()); @@ -1118,7 +1118,7 @@ SearchContextTest::performRangeSearch(const VectorType & vec, const vespalib::st { for (size_t num_threads : {1,3}) { vespalib::SimpleThreadBundle thread_bundle(num_threads); - auto executeInfo = queryeval::ExecuteInfo::create(true, 1.0, vespalib::Doom::never(), thread_bundle); + auto executeInfo = queryeval::ExecuteInfo::create(1.0, vespalib::Doom::never(), thread_bundle); performSearch(executeInfo, vec, term, expected, TermType::WORD); } } diff --git a/searchlib/src/tests/diskindex/diskindex/diskindex_test.cpp b/searchlib/src/tests/diskindex/diskindex/diskindex_test.cpp index 552ce0e2f0b..d298dc967e5 100644 --- a/searchlib/src/tests/diskindex/diskindex/diskindex_test.cpp +++ b/searchlib/src/tests/diskindex/diskindex/diskindex_test.cpp @@ -313,49 +313,53 @@ DiskIndexTest::requireThatBlueprintCanCreateSearchIterators() auto upper_bound = Blueprint::FilterConstraint::UPPER_BOUND; { // bit vector due to isFilter b = _index->createBlueprint(_requestContext, FieldSpec("f2", 0, 0, true), makeTerm("w2")); - b->fetchPostings(search::queryeval::ExecuteInfo::TRUE); + b->basic_plan(true, 1000); + b->fetchPostings(search::queryeval::ExecuteInfo::FULL); auto& leaf_b = dynamic_cast<LeafBlueprint&>(*b); - s = leaf_b.createLeafSearch(mda, true); + s = leaf_b.createLeafSearch(mda); EXPECT_TRUE(dynamic_cast<BitVectorIterator *>(s.get()) != NULL); EXPECT_EQ(result_f2_w2, SimpleResult().search(*s)); - EXPECT_EQ(result_f2_w2, SimpleResult().search(*leaf_b.createFilterSearch(true, upper_bound))); + EXPECT_EQ(result_f2_w2, SimpleResult().search(*leaf_b.createFilterSearch(upper_bound))); } { // bit vector due to no ranking needed b = _index->createBlueprint(_requestContext, FieldSpec("f2", 0, 0, false), makeTerm("w2")); - b->fetchPostings(ExecuteInfo::TRUE); + b->basic_plan(true, 1000); + b->fetchPostings(ExecuteInfo::FULL); auto& leaf_b = dynamic_cast<LeafBlueprint&>(*b); - s = leaf_b.createLeafSearch(mda, true); + s = leaf_b.createLeafSearch(mda); EXPECT_FALSE(dynamic_cast<BitVectorIterator *>(s.get()) != NULL); TermFieldMatchData md2; md2.tagAsNotNeeded(); TermFieldMatchDataArray mda2; mda2.add(&md2); EXPECT_TRUE(mda2[0]->isNotNeeded()); - s = (dynamic_cast<LeafBlueprint *>(b.get()))->createLeafSearch(mda2, true); + s = (dynamic_cast<LeafBlueprint *>(b.get()))->createLeafSearch(mda2); EXPECT_TRUE(dynamic_cast<BitVectorIterator *>(s.get()) != NULL); EXPECT_EQ(result_f2_w2, SimpleResult().search(*s)); - EXPECT_EQ(result_f2_w2, SimpleResult().search(*leaf_b.createFilterSearch(true, upper_bound))); + EXPECT_EQ(result_f2_w2, SimpleResult().search(*leaf_b.createFilterSearch(upper_bound))); } { // fake bit vector b = _index->createBlueprint(_requestContext, FieldSpec("f1", 0, 0, true), makeTerm("w2")); // std::cerr << "BP = " << typeid(*b).name() << std::endl; - b->fetchPostings(ExecuteInfo::TRUE); + b->basic_plan(true, 1000); + b->fetchPostings(ExecuteInfo::FULL); auto& leaf_b = dynamic_cast<LeafBlueprint&>(*b); - s = leaf_b.createLeafSearch(mda, true); + s = leaf_b.createLeafSearch(mda); // std::cerr << "SI = " << typeid(*s).name() << std::endl; EXPECT_TRUE((dynamic_cast<BooleanMatchIteratorWrapper *>(s.get()) != NULL) || dynamic_cast<EmptySearch *>(s.get())); EXPECT_EQ(result_f1_w2, SimpleResult().search(*s)); - EXPECT_EQ(result_f1_w2, SimpleResult().search(*leaf_b.createFilterSearch(true, upper_bound))); + EXPECT_EQ(result_f1_w2, SimpleResult().search(*leaf_b.createFilterSearch(upper_bound))); } { // posting list iterator b = _index->createBlueprint(_requestContext, FieldSpec("f1", 0, 0), makeTerm("w1")); - b->fetchPostings(ExecuteInfo::TRUE); + b->basic_plan(true, 1000); + b->fetchPostings(ExecuteInfo::FULL); auto& leaf_b = dynamic_cast<LeafBlueprint&>(*b); - s = leaf_b.createLeafSearch(mda, true); + s = leaf_b.createLeafSearch(mda); ASSERT_TRUE((dynamic_cast<ZcRareWordPosOccIterator<true, false> *>(s.get()) != NULL)); EXPECT_EQ(result_f1_w1, SimpleResult().search(*s)); - EXPECT_EQ(result_f1_w1, SimpleResult().search(*leaf_b.createFilterSearch(true, upper_bound))); + EXPECT_EQ(result_f1_w1, SimpleResult().search(*leaf_b.createFilterSearch(upper_bound))); } } diff --git a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp index 31e80b98e57..1b51ba90f7c 100644 --- a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp +++ b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp @@ -228,8 +228,9 @@ verifyResult(const FakeResult &expect, EXPECT_EQ(expect.inspect().size(), result->getState().estimate().estHits); EXPECT_EQ(expect.inspect().empty(), result->getState().estimate().empty); - result->fetchPostings(search::queryeval::ExecuteInfo::TRUE); - SearchIterator::UP search = result->createSearch(*match_data, true); + result->basic_plan(true, 100); + result->fetchPostings(search::queryeval::ExecuteInfo::FULL); + SearchIterator::UP search = result->createSearch(*match_data); bool valid_search = search.get() != 0; EXPECT_TRUE(valid_search); if (!valid_search) { @@ -256,7 +257,7 @@ verifyResult(const FakeResult &expect, using FilterConstraint = Blueprint::FilterConstraint; for (auto constraint : { FilterConstraint::LOWER_BOUND, FilterConstraint::UPPER_BOUND }) { constexpr uint32_t docid_limit = 10u; - auto filter_search = result->createFilterSearch(true, constraint); + auto filter_search = result->createFilterSearch(constraint); auto act_simple = SimpleResult().search(*filter_search, docid_limit); if (constraint == FilterConstraint::LOWER_BOUND) { EXPECT_TRUE(exp_simple.contains(act_simple)) << (success = false, ""); @@ -522,8 +523,9 @@ TEST(MemoryIndexTest, require_that_we_can_fake_bit_vector) Blueprint::UP res = searchable.createBlueprint(requestContext, fields, makeTerm(foo)); EXPECT_TRUE(res); - res->fetchPostings(search::queryeval::ExecuteInfo::TRUE); - SearchIterator::UP search = res->createSearch(*match_data, true); + res->basic_plan(true, 100); + res->fetchPostings(search::queryeval::ExecuteInfo::FULL); + SearchIterator::UP search = res->createSearch(*match_data); EXPECT_TRUE(search); EXPECT_TRUE(dynamic_cast<BooleanMatchIteratorWrapper *>(search.get()) != nullptr); search->initFullRange(); diff --git a/searchlib/src/tests/nearsearch/nearsearch_test.cpp b/searchlib/src/tests/nearsearch/nearsearch_test.cpp index 6f7cf85258b..4011366c7a1 100644 --- a/searchlib/src/tests/nearsearch/nearsearch_test.cpp +++ b/searchlib/src/tests/nearsearch/nearsearch_test.cpp @@ -229,11 +229,10 @@ Test::testNearSearch(MyQuery &query, uint32_t matchId) near_b->addChild(query.getTerm(i).make_blueprint(fieldId, i)); } bp->setDocIdLimit(1000); - auto opts = search::queryeval::Blueprint::Options::all(); - bp = search::queryeval::Blueprint::optimize_and_sort(std::move(bp), true, opts); - bp->fetchPostings(search::queryeval::ExecuteInfo::TRUE); + bp = search::queryeval::Blueprint::optimize_and_sort(std::move(bp)); + bp->fetchPostings(search::queryeval::ExecuteInfo::FULL); search::fef::MatchData::UP md(layout.createMatchData()); - search::queryeval::SearchIterator::UP near = bp->createSearch(*md, true); + search::queryeval::SearchIterator::UP near = bp->createSearch(*md); near->initFullRange(); bool foundMatch = false; for (near->seek(1u); ! near->isAtEnd(); near->seek(near->getDocId() + 1)) { diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp index 968e006622f..266dc6f8652 100644 --- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp @@ -17,8 +17,6 @@ using namespace search::fef; namespace { -auto opts = Blueprint::Options::all(); - //----------------------------------------------------------------------------- class MyOr : public IntermediateBlueprint @@ -45,19 +43,14 @@ public: std::sort(children.begin(), children.end(), TieredGreaterEstimate()); } - bool inheritStrict(size_t i) const override { - (void) i; - return true; - } - SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, MatchData &md) const override + MatchData &md) const override { - return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict); + return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict()); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } static MyOr& create() { return *(new MyOr()); } MyOr& add(Blueprint *n) { addChild(UP(n)); return *this; } @@ -71,9 +64,9 @@ private: public: SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, MatchData &md) const override + MatchData &md) const override { - return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict); + return std::make_unique<MySearch>("or", std::move(subSearches), &md, strict()); } static OtherOr& create() { return *(new OtherOr()); } @@ -95,15 +88,11 @@ public: return {}; } - bool inheritStrict(size_t i) const override { - return (i == 0); - } - SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, MatchData &md) const override + MatchData &md) const override { - return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict); + return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict()); } static MyAnd& create() { return *(new MyAnd()); } @@ -118,9 +107,9 @@ private: public: SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, MatchData &md) const override + MatchData &md) const override { - return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict); + return std::make_unique<MySearch>("and", std::move(subSearches), &md, strict()); } static OtherAnd& create() { return *(new OtherAnd()); } @@ -133,9 +122,9 @@ class OtherAndNot : public AndNotBlueprint public: SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, MatchData &md) const override + MatchData &md) const override { - return std::make_unique<MySearch>("andnot", std::move(subSearches), &md, strict); + return std::make_unique<MySearch>("andnot", std::move(subSearches), &md, strict()); } static OtherAndNot& create() { return *(new OtherAndNot()); } @@ -153,11 +142,11 @@ struct MyTerm : SimpleLeafBlueprint { FlowStats calculate_flow_stats(uint32_t docid_limit) const override { return default_flow_stats(docid_limit, getState().estimate().estHits, 0); } - SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &, bool) const override { + SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &) const override { return {}; } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; @@ -187,8 +176,9 @@ public: SearchIterator::UP Fixture::create(const Blueprint &blueprint) { - const_cast<Blueprint &>(blueprint).fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = blueprint.createSearch(*_md, true); + const_cast<Blueprint &>(blueprint).null_plan(true, 1000); + const_cast<Blueprint &>(blueprint).fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = blueprint.createSearch(*_md); MySearch::verifyAndInfer(search.get(), *_md); return search; } @@ -453,7 +443,7 @@ TEST_F("testChildAndNotCollapsing", Fixture) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); unsorted->setDocIdLimit(1000); - unsorted = Blueprint::optimize_and_sort(std::move(unsorted), true, opts); + unsorted = Blueprint::optimize_and_sort(std::move(unsorted)); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -493,7 +483,7 @@ TEST_F("testChildAndCollapsing", Fixture) TEST_DO(f.check_not_equal(*sorted, *unsorted)); unsorted->setDocIdLimit(1000); - unsorted = Blueprint::optimize_and_sort(std::move(unsorted), true, opts); + unsorted = Blueprint::optimize_and_sort(std::move(unsorted)); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -534,7 +524,7 @@ TEST_F("testChildOrCollapsing", Fixture) unsorted->setDocIdLimit(1000); // we sort non-strict here since a strict OR does not have a // deterministic sort order. - unsorted = Blueprint::optimize_and_sort(std::move(unsorted), false, opts); + unsorted = Blueprint::optimize_and_sort(std::move(unsorted), false); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -578,7 +568,7 @@ TEST_F("testChildSorting", Fixture) TEST_DO(f.check_not_equal(*sorted, *unsorted)); unsorted->setDocIdLimit(1000); - unsorted = Blueprint::optimize_and_sort(std::move(unsorted), true, opts); + unsorted = Blueprint::optimize_and_sort(std::move(unsorted)); TEST_DO(f.check_equal(*sorted, *unsorted)); } diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp index 6b3c068cd4d..9338436348b 100644 --- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp @@ -55,15 +55,13 @@ struct WeightOrder { }; struct RememberExecuteInfo : public MyLeaf { - bool is_strict; double hit_rate; - RememberExecuteInfo() : MyLeaf(), is_strict(false), hit_rate(0.0) {} - RememberExecuteInfo(FieldSpecBaseList fields) : MyLeaf(std::move(fields)), is_strict(false), hit_rate(0.0) {} + RememberExecuteInfo() : MyLeaf(), hit_rate(0.0) {} + RememberExecuteInfo(FieldSpecBaseList fields) : MyLeaf(std::move(fields)), hit_rate(0.0) {} void fetchPostings(const ExecuteInfo &execInfo) override { LeafBlueprint::fetchPostings(execInfo); - is_strict = execInfo.is_strict(); hit_rate = execInfo.hit_rate(); } }; @@ -75,16 +73,19 @@ bool got_global_filter(Blueprint &b) { return (static_cast<MyLeaf &>(b)).got_global_filter(); } -void check_sort_order(IntermediateBlueprint &self, BlueprintVector children, std::vector<size_t> order) { +void check_sort_order_and_strictness(std::unique_ptr<IntermediateBlueprint> self, bool self_strict, BlueprintVector children, std::vector<size_t> order, std::vector<bool> strict) { ASSERT_EQUAL(children.size(), order.size()); + ASSERT_EQUAL(children.size(), strict.size()); std::vector<const Blueprint *> unordered; - for (const auto & child: children) { + for (auto &&child: children) { unordered.push_back(child.get()); + self->addChild(std::move(child)); } - // TODO: sort by cost (requires both setDocIdLimit and optimize to be called) - self.sort(children, true, false); - for (size_t i = 0; i < children.size(); ++i) { - EXPECT_EQUAL(children[i].get(), unordered[order[i]]); + self->basic_plan(self_strict, 1000); + for (size_t i = 0; i < self->childCnt(); ++i) { + const auto &child = self->getChild(i); + EXPECT_EQUAL(&child, unordered[order[i]]); + EXPECT_EQUAL(child.strict(), strict[i]); } } @@ -126,18 +127,18 @@ TEST("test AndNot Blueprint") { EXPECT_EQUAL(false, got_global_filter(a.getChild(0))); EXPECT_EQUAL(true, got_global_filter(a.getChild(1))); } - check_sort_order(b, createLeafs({10, 20, 40, 30}), {0, 2, 3, 1}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(false, b.inheritStrict(1)); - EXPECT_EQUAL(false, b.inheritStrict(2)); - EXPECT_EQUAL(false, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<AndNotBlueprint>(), false, + createLeafs({10, 20, 40, 30}), {0, 2, 3, 1}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<AndNotBlueprint>(), true, + createLeafs({10, 20, 40, 30}), {0, 2, 3, 1}, + {true, false, false, false}); // createSearch tested by iterator unit test } template <typename BP> void optimize(std::unique_ptr<BP> &ref, bool strict) { - auto opts = Blueprint::Options::all(); - auto optimized = Blueprint::optimize_and_sort(std::move(ref), strict, opts); + auto optimized = Blueprint::optimize_and_sort(std::move(ref), strict); ref.reset(dynamic_cast<BP*>(optimized.get())); ASSERT_TRUE(ref); optimized.release(); @@ -151,11 +152,11 @@ TEST("test And propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(2000).create<RememberExecuteInfo>()->setSourceId(2))); bp->setDocIdLimit(5000); optimize(bp, true); - bp->fetchPostings(ExecuteInfo::TRUE); + bp->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL(3u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { const auto & child = dynamic_cast<const RememberExecuteInfo &>(bp->getChild(i)); - EXPECT_EQUAL((i == 0), child.is_strict); + EXPECT_EQUAL((i == 0), child.strict()); } EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).hit_rate); EXPECT_EQUAL(1.0/250, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).hit_rate); @@ -170,25 +171,25 @@ TEST("test Or propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(800).create<RememberExecuteInfo>()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(20).create<RememberExecuteInfo>()->setSourceId(2))); bp->setDocIdLimit(5000); - // NOTE: use non-strict OR ordering since strict OR ordering is non-deterministic - optimize(bp, false); //--- execute info when non-strict: - bp->fetchPostings(ExecuteInfo::FALSE); + optimize(bp, false); + bp->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL(4u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { const auto & child = dynamic_cast<const RememberExecuteInfo &>(bp->getChild(i)); - EXPECT_FALSE(child.is_strict); + EXPECT_FALSE(child.strict()); } EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).hit_rate); EXPECT_APPROX(0.5, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).hit_rate, 1e-6); EXPECT_APPROX(0.5*3.0/5.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(2)).hit_rate, 1e-6); EXPECT_APPROX(0.5*3.0*42.0/(5.0*50.0), dynamic_cast<const RememberExecuteInfo &>(bp->getChild(3)).hit_rate, 1e-6); //--- execute info when strict: - bp->fetchPostings(ExecuteInfo::TRUE); + optimize(bp, true); + bp->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL(4u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { const auto & child = dynamic_cast<const RememberExecuteInfo &>(bp->getChild(i)); - EXPECT_TRUE(child.is_strict); + EXPECT_TRUE(child.strict()); } EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(0)).hit_rate); EXPECT_EQUAL(1.0, dynamic_cast<const RememberExecuteInfo &>(bp->getChild(1)).hit_rate); @@ -227,12 +228,12 @@ TEST("test And Blueprint") { EXPECT_EQUAL(false, got_global_filter(a.getChild(0))); EXPECT_EQUAL(true, got_global_filter(a.getChild(1))); } - check_sort_order(b, createLeafs({20, 40, 10, 30}), {2, 0, 3, 1}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(false, b.inheritStrict(1)); - EXPECT_EQUAL(false, b.inheritStrict(2)); - EXPECT_EQUAL(false, b.inheritStrict(-1)); - + check_sort_order_and_strictness(std::make_unique<AndBlueprint>(), false, + createLeafs({20, 40, 10, 30}), {2, 0, 3, 1}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<AndBlueprint>(), true, + createLeafs({20, 40, 10, 30}), {2, 0, 3, 1}, + {true, false, false, false}); // createSearch tested by iterator unit test } @@ -291,11 +292,12 @@ TEST("test Or Blueprint") { EXPECT_EQUAL(false, got_global_filter(o.getChild(0))); EXPECT_EQUAL(true, got_global_filter(o.getChild(o.childCnt() - 1))); } - check_sort_order(b, createLeafs({10, 20, 40, 30}), {2, 3, 1, 0}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(true, b.inheritStrict(1)); - EXPECT_EQUAL(true, b.inheritStrict(2)); - EXPECT_EQUAL(true, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<OrBlueprint>(), false, + createLeafs({10, 20, 40, 30}), {2, 3, 1, 0}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<OrBlueprint>(), true, + createLeafs({10, 20, 40, 30}), {0, 1, 2, 3}, + {true, true, true, true}); // createSearch tested by iterator unit test } @@ -323,11 +325,12 @@ TEST("test Near Blueprint") { a.addChild(ap(MyLeafSpec(10).addField(1, 1).create())); EXPECT_EQUAL(0u, a.exposeFields().size()); } - check_sort_order(b, createLeafs({40, 10, 30, 20}), {1, 3, 2, 0}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(false, b.inheritStrict(1)); - EXPECT_EQUAL(false, b.inheritStrict(2)); - EXPECT_EQUAL(false, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<NearBlueprint>(7), false, + createLeafs({40, 10, 30, 20}), {1, 3, 2, 0}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<NearBlueprint>(7), true, + createLeafs({40, 10, 30, 20}), {1, 3, 2, 0}, + {true, false, false, false}); // createSearch tested by iterator unit test } @@ -355,11 +358,12 @@ TEST("test ONear Blueprint") { a.addChild(ap(MyLeafSpec(10).addField(1, 1).create())); EXPECT_EQUAL(0u, a.exposeFields().size()); } - check_sort_order(b, createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(false, b.inheritStrict(1)); - EXPECT_EQUAL(false, b.inheritStrict(2)); - EXPECT_EQUAL(false, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<ONearBlueprint>(7), false, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<ONearBlueprint>(7), true, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {true, false, false, false}); // createSearch tested by iterator unit test } @@ -395,11 +399,12 @@ TEST("test Rank Blueprint") { EXPECT_EQUAL(false, got_global_filter(a.getChild(0))); EXPECT_EQUAL(true, got_global_filter(a.getChild(1))); } - check_sort_order(b, createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(false, b.inheritStrict(1)); - EXPECT_EQUAL(false, b.inheritStrict(2)); - EXPECT_EQUAL(false, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<RankBlueprint>(), false, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<RankBlueprint>(), true, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {true, false, false, false}); // createSearch tested by iterator unit test } @@ -451,11 +456,12 @@ TEST("test SourceBlender Blueprint") { o.addChild(ap(MyLeafSpec(0, true).create())); EXPECT_EQUAL(0u, a->getState().numFields()); } - check_sort_order(b, createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(true, b.inheritStrict(1)); - EXPECT_EQUAL(true, b.inheritStrict(2)); - EXPECT_EQUAL(true, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<SourceBlenderBlueprint>(*selector), false, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<SourceBlenderBlueprint>(*selector), true, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {true, true, true, true}); // createSearch tested by iterator unit test } @@ -573,7 +579,7 @@ optimize_and_compare(Blueprint::UP top, Blueprint::UP expect, bool strict = true top->setDocIdLimit(1000); expect->setDocIdLimit(1000); TEST_DO(compare(*top, *expect, false)); - auto opts = Blueprint::Options::all().sort_by_cost(sort_by_cost); + auto opts = Blueprint::Options::default_options().sort_by_cost(sort_by_cost); top = Blueprint::optimize_and_sort(std::move(top), strict, opts); TEST_DO(compare(*top, *expect, true)); expect = Blueprint::optimize_and_sort(std::move(expect), strict, opts); @@ -705,12 +711,11 @@ TEST("test empty root node optimization and safeness") { //------------------------------------------------------------------------- auto expect_up = std::make_unique<EmptyBlueprint>(); - auto opts = Blueprint::Options::all(); - compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top1), true, opts), true); - compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top2), true, opts), true); - compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top3), true, opts), true); - compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top4), true, opts), true); - compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top5), true, opts), true); + compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top1)), true); + compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top2)), true); + compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top3)), true); + compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top4)), true); + compare(*expect_up, *Blueprint::optimize_and_sort(std::move(top5)), true); } TEST("and with one empty child is optimized away") { @@ -718,8 +723,7 @@ TEST("and with one empty child is optimized away") { Blueprint::UP top = ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(addLeafs(std::make_unique<AndBlueprint>(), {{0, true}, 10, 20}))); - auto opts = Blueprint::Options::all(); - top = Blueprint::optimize_and_sort(std::move(top), true, opts); + top = Blueprint::optimize_and_sort(std::move(top)); Blueprint::UP expect_up(ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(std::make_unique<EmptyBlueprint>()))); @@ -896,9 +900,8 @@ TEST("require that replaced blueprints retain source id") { addChild(ap(MyLeafSpec(30).create()->setSourceId(55))))); Blueprint::UP expect2_up(ap(MyLeafSpec(30).create()->setSourceId(42))); //------------------------------------------------------------------------- - auto opts = Blueprint::Options::all(); - top1_up = Blueprint::optimize_and_sort(std::move(top1_up), true, opts); - top2_up = Blueprint::optimize_and_sort(std::move(top2_up), true, opts); + top1_up = Blueprint::optimize_and_sort(std::move(top1_up)); + top2_up = Blueprint::optimize_and_sort(std::move(top2_up)); compare(*expect1_up, *top1_up, true); compare(*expect2_up, *top2_up, true); EXPECT_EQUAL(13u, top1_up->getSourceId()); @@ -960,11 +963,12 @@ TEST("test WeakAnd Blueprint") { a.addChild(ap(MyLeafSpec(10).addField(1, 1).create())); EXPECT_EQUAL(0u, a.exposeFields().size()); } - check_sort_order(b, createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}); - EXPECT_EQUAL(true, b.inheritStrict(0)); - EXPECT_EQUAL(true, b.inheritStrict(1)); - EXPECT_EQUAL(true, b.inheritStrict(2)); - EXPECT_EQUAL(true, b.inheritStrict(-1)); + check_sort_order_and_strictness(std::make_unique<WeakAndBlueprint>(1000), false, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {false, false, false, false}); + check_sort_order_and_strictness(std::make_unique<WeakAndBlueprint>(1000), true, + createLeafs({20, 10, 40, 30}), {0, 1, 2, 3}, + {true, true, true, true}); { FieldSpec field("foo", 1, 1); FakeResult x = FakeResult().doc(1).doc(2).doc(5); @@ -977,8 +981,9 @@ TEST("test WeakAnd Blueprint") { wa.addTerm(std::make_unique<FakeBlueprint>(field, z), 140); wa.addTerm(std::make_unique<FakeBlueprint>(field, y), 130); { - wa.fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = wa.createSearch(*md, true); + wa.basic_plan(true, 1000); + wa.fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = wa.createSearch(*md); EXPECT_TRUE(dynamic_cast<WeakAndSearch*>(search.get()) != nullptr); auto &s = dynamic_cast<WeakAndSearch&>(*search); EXPECT_EQUAL(456u, s.getN()); @@ -999,8 +1004,9 @@ TEST("test WeakAnd Blueprint") { EXPECT_EQUAL(0u, terms[2].maxScore); // NB: not set } { - wa.fetchPostings(ExecuteInfo::FALSE); - SearchIterator::UP search = wa.createSearch(*md, false); + wa.basic_plan(false, 1000); + wa.fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = wa.createSearch(*md); EXPECT_TRUE(dynamic_cast<WeakAndSearch*>(search.get()) != nullptr); EXPECT_TRUE(search->seek(1)); EXPECT_TRUE(search->seek(2)); @@ -1029,23 +1035,24 @@ TEST("require_that_unpack_of_or_over_multisearch_is_optimized") { addChild(std::move(child1)). addChild(std::move(child2)))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); + top_up->basic_plan(false, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(2)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::SelectiveUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(4)->tagAsNotNeeded(); md->resolveTermField(6)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::SelectiveUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(5)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::NoUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); } TEST("require_that_unpack_of_or_is_optimized") { @@ -1055,16 +1062,17 @@ TEST("require_that_unpack_of_or_is_optimized") { addChild(ap(MyLeafSpec(20).addField(2,2).create())). addChild(ap(MyLeafSpec(10).addField(3,3).create())))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); + top_up->basic_plan(false, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(2)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::(anonymous namespace)::SelectiveUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::OrLikeSearch<false, search::queryeval::NoUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); } TEST("require_that_unpack_of_and_is_optimized") { @@ -1074,16 +1082,17 @@ TEST("require_that_unpack_of_and_is_optimized") { addChild(ap(MyLeafSpec(20).addField(2,2).create())). addChild(ap(MyLeafSpec(10).addField(3,3).create())))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); + top_up->basic_plan(false, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(2)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::SelectiveUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::NoUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); } TEST("require_that_unpack_optimization_is_honoured_by_parents") { @@ -1094,16 +1103,17 @@ TEST("require_that_unpack_optimization_is_honoured_by_parents") { addChild(ap(MyLeafSpec(20).addField(2,2).create())). addChild(ap(MyLeafSpec(10).addField(3,3).create())))))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); + top_up->basic_plan(false, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(2)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::(anonymous namespace)::FullUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); EXPECT_EQUAL("search::queryeval::AndSearchNoStrict<search::queryeval::NoUnpack>", - top_up->createSearch(*md, false)->getClassName()); + top_up->createSearch(*md)->getClassName()); } namespace { @@ -1143,8 +1153,9 @@ TEST("require that children does not optimize when parents refuse them to") { FieldSpec("f2", 2, idxth21), makeTerm("w2")), 1.0))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); - SearchIterator::UP search = top_up->createSearch(*md, true); + top_up->basic_plan(true, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = top_up->createSearch(*md); EXPECT_EQUAL(strict_equiv_name, normalize_class_name(search->getClassName())); { const auto & e = dynamic_cast<const MultiSearch &>(*search); @@ -1154,7 +1165,7 @@ TEST("require that children does not optimize when parents refuse them to") { } md->resolveTermField(12)->tagAsNotNeeded(); - search = top_up->createSearch(*md, true); + search = top_up->createSearch(*md); EXPECT_EQUAL(strict_equiv_name, normalize_class_name(search->getClassName())); { const auto & e = dynamic_cast<const MultiSearch &>(*search); @@ -1181,8 +1192,9 @@ TEST("require_that_unpack_optimization_is_not_overruled_by_equiv") { addChild(ap(MyLeafSpec(10).addField(3,idxth3).create()))), 1.0))); MatchData::UP md = MatchData::makeTestInstance(100, 10); - top_up->fetchPostings(ExecuteInfo::FALSE); - SearchIterator::UP search = top_up->createSearch(*md, true); + top_up->basic_plan(true, 1000); + top_up->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = top_up->createSearch(*md); EXPECT_EQUAL(strict_equiv_name, normalize_class_name(search->getClassName())); { const auto & e = dynamic_cast<const MultiSearch &>(*search); @@ -1191,7 +1203,7 @@ TEST("require_that_unpack_optimization_is_not_overruled_by_equiv") { } md->resolveTermField(2)->tagAsNotNeeded(); - search = top_up->createSearch(*md, true); + search = top_up->createSearch(*md); EXPECT_EQUAL(strict_equiv_name, normalize_class_name(search->getClassName())); { const auto & e = dynamic_cast<const MultiSearch &>(*search); @@ -1201,7 +1213,7 @@ TEST("require_that_unpack_optimization_is_not_overruled_by_equiv") { md->resolveTermField(1)->tagAsNotNeeded(); md->resolveTermField(3)->tagAsNotNeeded(); - search = top_up->createSearch(*md, true); + search = top_up->createSearch(*md); EXPECT_EQUAL(strict_equiv_name, normalize_class_name(search->getClassName())); { const auto & e = dynamic_cast<const MultiSearch &>(*search); @@ -1213,8 +1225,7 @@ TEST("require_that_unpack_optimization_is_not_overruled_by_equiv") { TEST("require that ANDNOT without children is optimized to empty search") { Blueprint::UP top_up = std::make_unique<AndNotBlueprint>(); auto expect_up = std::make_unique<EmptyBlueprint>(); - auto opts = Blueprint::Options::all(); - top_up = Blueprint::optimize_and_sort(std::move(top_up), true, opts); + top_up = Blueprint::optimize_and_sort(std::move(top_up)); compare(*expect_up, *top_up, true); } diff --git a/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp index 44be9fb0fca..cb5473babbd 100644 --- a/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/leaf_blueprints_test.cpp @@ -29,8 +29,9 @@ Test::testEmptyBlueprint() EXPECT_EQUAL(1u, empty.getState().field(0).getFieldId()); EXPECT_EQUAL(11u, empty.getState().field(0).getHandle()); - empty.fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = empty.createSearch(*md, true); + empty.basic_plan(true, 100); + empty.fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = empty.createSearch(*md); SimpleResult res; res.search(*search); @@ -47,8 +48,9 @@ Test::testSimpleBlueprint() SimpleBlueprint simple(a); simple.tag("tag"); EXPECT_EQUAL("tag", simple.tag()); - simple.fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = simple.createSearch(*md, true); + simple.basic_plan(true, 100); + simple.fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = simple.createSearch(*md); SimpleResult res; res.search(*search); @@ -69,8 +71,9 @@ Test::testFakeBlueprint() TermFieldHandle handle = 0; FakeBlueprint orig(FieldSpec("<field>", fieldId, handle), fake); - orig.fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search = orig.createSearch(*md, true); + orig.basic_plan(true, 100); + orig.fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = orig.createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(1u)); EXPECT_EQUAL(10u, search->getDocId()); diff --git a/searchlib/src/tests/queryeval/blueprint/mysearch.h b/searchlib/src/tests/queryeval/blueprint/mysearch.h index 79c9885bb7d..e3b86a0eb84 100644 --- a/searchlib/src/tests/queryeval/blueprint/mysearch.h +++ b/searchlib/src/tests/queryeval/blueprint/mysearch.h @@ -109,9 +109,9 @@ class MyLeaf : public SimpleLeafBlueprint public: SearchIterator::UP - createLeafSearch(const TFMDA &tfmda, bool strict) const override + createLeafSearch(const TFMDA &tfmda) const override { - return std::make_unique<MySearch>("leaf", tfmda, strict); + return std::make_unique<MySearch>("leaf", tfmda, strict()); } MyLeaf() : SimpleLeafBlueprint() {} @@ -141,8 +141,8 @@ public: // make public using LeafBlueprint::set_want_global_filter; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; diff --git a/searchlib/src/tests/queryeval/dot_product/dot_product_test.cpp b/searchlib/src/tests/queryeval/dot_product/dot_product_test.cpp index d160b513534..542eb1bb4f8 100644 --- a/searchlib/src/tests/queryeval/dot_product/dot_product_test.cpp +++ b/searchlib/src/tests/queryeval/dot_product/dot_product_test.cpp @@ -74,8 +74,9 @@ struct DP { FieldSpecList fields; fields.add(FieldSpec(field, fieldId, handle, field_is_filter)); queryeval::Blueprint::UP bp = searchable.createBlueprint(requestContext, fields, *node); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP sb = bp->createSearch(*md, strict); + bp->basic_plan(strict, 10); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP sb = bp->createSearch(*md); EXPECT_TRUE(dynamic_cast<DotProductSearch*>(sb.get()) != 0); sb->initFullRange(); FakeResult result; diff --git a/searchlib/src/tests/queryeval/equiv/equiv_test.cpp b/searchlib/src/tests/queryeval/equiv/equiv_test.cpp index c570c06a60b..99045af7245 100644 --- a/searchlib/src/tests/queryeval/equiv/equiv_test.cpp +++ b/searchlib/src/tests/queryeval/equiv/equiv_test.cpp @@ -59,8 +59,9 @@ EquivTest::test_equiv(bool strict, bool unpack_normal_features, bool unpack_inte data.setNeedNormalFeatures(unpack_normal_features); data.setNeedInterleavedFeatures(unpack_interleaved_features); } - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(3)); diff --git a/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp b/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp index 8ddac327643..638ce30eb28 100644 --- a/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp +++ b/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp @@ -62,8 +62,9 @@ TEST_F(FakeSearchableTest, require_that_term_search_works) { bool strict = (i == 0); SCOPED_TRACE(strict ? "strict" : "non-strict"); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(3)); @@ -116,8 +117,9 @@ TEST_F(FakeSearchableTest, require_that_phrase_search_works) { bool strict = (i == 0); SCOPED_TRACE(strict ? "strict" : "non-strict"); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(3)); @@ -167,8 +169,9 @@ TEST_F(FakeSearchableTest, require_that_weigheted_set_search_works) { bool strict = (i == 0); SCOPED_TRACE(strict ? "strict" : "non-strict"); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(2)); @@ -238,8 +241,9 @@ TEST_F(FakeSearchableTest, require_that_multi_field_search_works) { bool strict = (i == 0); SCOPED_TRACE(strict ? "strict" : "non-strict"); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(3)); @@ -322,8 +326,9 @@ TEST_F(FakeSearchableTest, require_that_phrase_with_empty_child_works) { bool strict = (i == 0); SCOPED_TRACE(strict ? "strict" : "non-strict"); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(!search->seek(3)); @@ -342,8 +347,9 @@ TEST_F(FakeSearchableTest, require_that_match_data_is_compressed_for_attributes) fields.add(FieldSpec("attrfoo", 1, 1)); Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::FALSE); - SearchIterator::UP search = bp->createSearch(*md, false); + bp->basic_plan(false, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); EXPECT_TRUE(search->seek(5)); search->unpack(5u); @@ -369,8 +375,9 @@ TEST_F(FakeSearchableTest, require_that_relevant_data_can_be_obtained_from_fake_ fields.add(FieldSpec("attrfoo", 1, 1)); Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode); MatchData::UP md = MatchData::makeTestInstance(100, 10); - bp->fetchPostings(ExecuteInfo::FALSE); - SearchIterator::UP search = bp->createSearch(*md, false); + bp->basic_plan(false, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); EXPECT_TRUE(bp->get_attribute_search_context() != nullptr); const auto *attr_ctx = bp->get_attribute_search_context(); ASSERT_TRUE(attr_ctx); 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 c4d34ab3565..5c29c293d82 100644 --- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp +++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp @@ -36,8 +36,9 @@ constexpr auto upper_bound = Constraint::UPPER_BOUND; const uint32_t docid_limit = 100; template <typename T> -concept FilterFactory = requires(const T &a, bool strict, Constraint constraint) { - { a.createFilterSearch(strict, constraint) } -> std::same_as<std::unique_ptr<SearchIterator>>; +concept FilterFactory = requires(const T &a, T &ma, InFlow in_flow, uint32_t my_docid_limit, bool strict, Constraint constraint) { + ma.basic_plan(in_flow, my_docid_limit); + { a.createFilterSearch(constraint) } -> std::same_as<std::unique_ptr<SearchIterator>>; }; template <typename T> @@ -45,20 +46,6 @@ concept ChildCollector = requires(T a, std::unique_ptr<Blueprint> bp) { a.addChild(std::move(bp)); }; -// inherit Blueprint to capture the default filter factory -struct DefaultBlueprint : Blueprint { - FlowStats calculate_flow_stats(uint32_t) const override { abort(); } - void optimize(Blueprint* &, OptimizePass) override { abort(); } - double sort(InFlow, const Options &) override { abort(); } - const State &getState() const override { abort(); } - void fetchPostings(const ExecuteInfo &) override { abort(); } - void freeze() override { abort(); } - SearchIteratorUP createSearch(MatchData &, bool) const override { abort(); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); - } -}; - // proxy class used to make various decorators for leaf blueprints // may be used directly to add the use of a field to a leaf blueprint struct LeafProxy : SimpleLeafBlueprint { @@ -71,10 +58,20 @@ struct LeafProxy : SimpleLeafBlueprint { : SimpleLeafBlueprint(), child(std::move(child_in)) { init(); } LeafProxy(FieldSpecBase field, std::unique_ptr<Blueprint> child_in) : SimpleLeafBlueprint(field), child(std::move(child_in)) { init(); } - FlowStats calculate_flow_stats(uint32_t) const override { abort(); } - SearchIteratorUP createLeafSearch(const TermFieldMatchDataArray &, bool) const override { abort(); } - SearchIteratorUP createFilterSearch(bool strict, Constraint constraint) const override { - return child->createFilterSearch(strict, constraint); + void each_node_post_order(const std::function<void(Blueprint&)> &f) override { + child->each_node_post_order(f); + f(*this); + } + FlowStats calculate_flow_stats(uint32_t my_docid_limit) const override { + return child->calculate_flow_stats(my_docid_limit); + } + void sort(InFlow in_flow, const Options &opts) override { + strict(in_flow.strict()); + child->sort(in_flow, opts); + } + SearchIteratorUP createLeafSearch(const TermFieldMatchDataArray &) const override { abort(); } + SearchIteratorUP createFilterSearch(Constraint constraint) const override { + return child->createFilterSearch(constraint); } }; @@ -82,15 +79,22 @@ struct LeafProxy : SimpleLeafBlueprint { struct CheckParamsProxy : LeafProxy { static bool current_strict; // <- changed by test static Constraint current_constraint; // <- changed by test + bool expect_forced_strict = false; bool expect_inherit_strict; bool expect_same_constraint; CheckParamsProxy(std::unique_ptr<Blueprint> child_in, bool expect_inherit_strict_in, bool expect_same_constraint_in) : LeafProxy(std::move(child_in)), expect_inherit_strict(expect_inherit_strict_in), expect_same_constraint(expect_same_constraint_in) {} - SearchIteratorUP createFilterSearch(bool strict, Constraint constraint) const override { - EXPECT_EQ(strict, (current_strict && expect_inherit_strict)); + CheckParamsProxy(std::unique_ptr<Blueprint> child_in) + : LeafProxy(std::move(child_in)), expect_forced_strict(true), expect_inherit_strict(false), expect_same_constraint(true) {} + SearchIteratorUP createFilterSearch(Constraint constraint) const override { + if (expect_forced_strict) { + EXPECT_EQ(strict(), true); + } else { + EXPECT_EQ(strict(), (current_strict && expect_inherit_strict)); + } EXPECT_EQ((constraint == current_constraint), expect_same_constraint); - return child->createFilterSearch(strict, constraint); + return child->createFilterSearch(constraint); } }; bool CheckParamsProxy::current_strict = false; @@ -101,9 +105,9 @@ struct CheckDroppedProxy : LeafProxy { mutable bool used; CheckDroppedProxy(std::unique_ptr<Blueprint> child_in) : LeafProxy(std::move(child_in)), used(false) {} - SearchIteratorUP createFilterSearch(bool strict, Constraint constraint) const override { + SearchIteratorUP createFilterSearch(Constraint constraint) const override { used = true; - return child->createFilterSearch(strict, constraint); + return child->createFilterSearch(constraint); } ~CheckDroppedProxy() override { EXPECT_EQ(used, false); @@ -162,6 +166,10 @@ std::unique_ptr<Blueprint> check(std::unique_ptr<Blueprint> child, bool expect_i return std::make_unique<CheckParamsProxy>(std::move(child), expect_inherit_strict, expect_same_constraint); } +std::unique_ptr<Blueprint> check_forced(std::unique_ptr<Blueprint> child) { + return std::make_unique<CheckParamsProxy>(std::move(child)); +} + // check that create filter is not called std::unique_ptr<Blueprint> dropped(std::unique_ptr<Blueprint> child) { return std::make_unique<CheckDroppedProxy>(std::move(child)); @@ -191,6 +199,11 @@ struct Children { list.back() = [=](){ return ::check(old_factory(), expect_inherit_strict, expect_same_constraint); }; return *this; } + Children &check_forced() { + Factory old_factory = list.back(); + list.back() = [=](){ return ::check_forced(old_factory()); }; + return *this; + } Children &dropped() { Factory old_factory = list.back(); list.back() = [=](){ return ::dropped(old_factory()); }; @@ -204,29 +217,44 @@ struct Children { } }; +struct NoFlow { + NoFlow(InFlow) noexcept {} + void add(double) noexcept {}; + bool strict() noexcept { return false; } + double flow() noexcept { return 0.0; } +}; + // Combine children blueprints using a shared filter creation // algorithm. Satisfies the FilterFactory concept. +template <typename Flow> struct Combine { using factory_fun = std::function<std::unique_ptr<SearchIterator>(const Blueprint::Children &, bool, Constraint)>; factory_fun fun; + bool strict; Blueprint::Children list; - Combine(factory_fun fun_in, const Children &child_list); + Combine(factory_fun fun_in, const Children &child_list) + : fun(fun_in), strict(false), list() + { + child_list.apply(*this); + } ~Combine(); void addChild(std::unique_ptr<Blueprint> child) { list.push_back(std::move(child)); } - auto createFilterSearch(bool strict, Constraint constraint) const { + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + strict = in_flow.strict(); + Flow flow(in_flow); + for (auto &child: list) { + child->basic_plan(InFlow(flow.strict(), flow.flow()), my_docid_limit); + flow.add(child->estimate()); + } + } + auto createFilterSearch(Constraint constraint) const { return fun(list, strict, constraint); } }; - -Combine::Combine(factory_fun fun_in, const Children &child_list) - : fun(fun_in), list() -{ - child_list.apply(*this); -} - -Combine::~Combine() = default; +template <typename Flow> +Combine<Flow>::~Combine() = default; // enable Make-ing source blender struct SourceBlenderAdapter { @@ -236,8 +264,11 @@ struct SourceBlenderAdapter { void addChild(std::unique_ptr<Blueprint> child) { blueprint.addChild(std::move(child)); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -251,8 +282,11 @@ struct SimplePhraseAdapter { auto term = std::make_unique<LeafProxy>(child_field, std::move(child)); blueprint.addTerm(std::move(term)); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -264,8 +298,11 @@ struct EquivAdapter { void addChild(std::unique_ptr<Blueprint> child) { blueprint.addTerm(std::move(child), 1.0); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -280,8 +317,11 @@ struct WeightedSetTermAdapter { blueprint.addTerm(std::move(child), 100, estimate); blueprint.complete(estimate); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -301,8 +341,11 @@ struct DotProductAdapter { blueprint.addTerm(std::move(term), 100, estimate); blueprint.complete(estimate); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -321,8 +364,11 @@ struct ParallelWeakAndAdapter { blueprint.addTerm(std::move(term), 100, estimate); blueprint.complete(estimate); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -337,8 +383,11 @@ struct SameElementAdapter { auto term = std::make_unique<LeafProxy>(child_field, std::move(child)); blueprint.addTerm(std::move(term)); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -355,8 +404,11 @@ struct Make { Make(const Children &child_list, Args && ... args) : blueprint(std::forward<Args>(args)...) { child_list.apply(blueprint); } - auto createFilterSearch(bool strict, Constraint constraint) const { - return blueprint.createFilterSearch(strict, constraint); + void basic_plan(InFlow in_flow, uint32_t my_docid_limit) { + blueprint.basic_plan(in_flow, my_docid_limit); + } + auto createFilterSearch(Constraint constraint) const { + return blueprint.createFilterSearch(constraint); } }; @@ -381,10 +433,11 @@ struct Expect { }; template <FilterFactory Blueprint> -void verify(const Blueprint &blueprint, bool strict, Constraint constraint, const Expect &expect) { +void verify(Blueprint &&blueprint, bool strict, Constraint constraint, const Expect &expect) { CheckParamsProxy::current_strict = strict; CheckParamsProxy::current_constraint = constraint; - auto filter = blueprint.createFilterSearch(strict, constraint); + blueprint.basic_plan(strict, docid_limit); + auto filter = blueprint.createFilterSearch(constraint); if (expect.children > 0) { ASSERT_EQ(filter->isMultiSearch(), true); EXPECT_EQ(static_cast<MultiSearch*>(filter.get())->getChildren().size(), expect.children); @@ -409,14 +462,14 @@ void verify(const Blueprint &blueprint, bool strict, Constraint constraint, cons } template <FilterFactory Blueprint> -void verify(const Blueprint &blueprint, bool strict, const Expect &expect) { +void verify(Blueprint &&blueprint, bool strict, const Expect &expect) { for (auto constraint: {lower_bound, upper_bound}) { verify(blueprint, strict, constraint, expect); } } template <FilterFactory Blueprint> -void verify(const Blueprint &blueprint, const Expect &upper, const Expect &lower) { +void verify(Blueprint &&blueprint, const Expect &upper, const Expect &lower) { for (auto constraint: {lower_bound, upper_bound}) { const Expect &expect = (constraint == upper_bound) ? upper : lower; for (bool strict: {false, true}) { @@ -426,7 +479,7 @@ void verify(const Blueprint &blueprint, const Expect &upper, const Expect &lower } template <FilterFactory Blueprint> -void verify(const Blueprint &blueprint, const Expect &upper_and_lower) { +void verify(Blueprint &&blueprint, const Expect &upper_and_lower) { verify(blueprint, upper_and_lower, upper_and_lower); } @@ -443,12 +496,12 @@ TEST(FilterSearchTest, custom_leaf) { } TEST(FilterSearchTest, default_filter) { - verify(DefaultBlueprint(), Expect::full(), Expect::empty()); - auto adapter = [](const auto &ignore_children, bool strict, Constraint constraint) { + auto adapter = [](const auto &ignore_children, bool ignore_strict, Constraint constraint) { (void) ignore_children; - return Blueprint::create_default_filter(strict, constraint); + (void) ignore_strict; + return Blueprint::create_default_filter(constraint); }; - verify(Combine(adapter, Children()), Expect::full(), Expect::empty()); + verify(Combine<NoFlow>(adapter, Children()), Expect::full(), Expect::empty()); } TEST(FilterSearchTest, simple_or) { @@ -457,39 +510,55 @@ TEST(FilterSearchTest, simple_or) { .hits({7}).check(true, true) .hits({3, 11}).check(true, true); auto expected = Expect::hits({3, 5, 7, 10, 11}); - verify(Combine(Blueprint::create_or_filter, child_list), expected); + verify(Combine<OrFlow>(Blueprint::create_or_filter, child_list), expected); verify(Make<OrBlueprint>(child_list), expected); verify(Make<EquivAdapter>(child_list), expected); - verify(Make<WeightedSetTermAdapter>(child_list), expected); - verify(Make<DotProductAdapter>(child_list), expected); - verify(Combine(Blueprint::create_atmost_or_filter, child_list), expected, Expect::empty()); + verify(Combine<OrFlow>(Blueprint::create_atmost_or_filter, child_list), expected, Expect::empty()); verify(Make<WeakAndBlueprint>(child_list, 100), expected, Expect::empty()); verify(Make<SourceBlenderAdapter>(child_list), expected, Expect::empty()); verify(Make<ParallelWeakAndAdapter>(child_list), expected, Expect::empty()); } +TEST(FilterSearchTest, forced_or) { + auto child_list = Children() + .hits({5, 10}).check_forced() + .hits({7}).check_forced() + .hits({3, 11}).check_forced(); + auto expected = Expect::hits({3, 5, 7, 10, 11}); + verify(Make<WeightedSetTermAdapter>(child_list), expected); + verify(Make<DotProductAdapter>(child_list), expected); +} + TEST(FilterSearchTest, simple_and) { auto child_list = Children() - .hits({1, 2, 3, 4, 5, 6}).check(true, true) - .hits({2, 4, 6, 7}).check(false, true) - .hits({1, 4, 6, 7, 10}).check(false, true); + .hits({2, 4, 6, 7}).check(true, true) + .hits({1, 4, 6, 7, 10}).check(false, true) + .hits({1, 2, 3, 4, 5, 6}).check(false, true); auto expected = Expect::hits({4, 6}); - verify(Combine(Blueprint::create_and_filter, child_list), expected); + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), expected); verify(Make<AndBlueprint>(child_list), expected); - verify(Combine(Blueprint::create_atmost_and_filter, child_list), expected, Expect::empty()); + verify(Combine<AndFlow>(Blueprint::create_atmost_and_filter, child_list), expected, Expect::empty()); verify(Make<NearBlueprint>(child_list, 3), expected, Expect::empty()); verify(Make<ONearBlueprint>(child_list, 3), expected, Expect::empty()); - verify(Make<SimplePhraseAdapter>(child_list), expected, Expect::empty()); verify(Make<SameElementAdapter>(child_list), expected, Expect::empty()); } +TEST(FilterSearchTest, eager_and) { + auto child_list = Children() + .hits({2, 4, 6, 7}).check(true, true) + .hits({1, 4, 6, 7, 10}).check(true, true) + .hits({1, 2, 3, 4, 5, 6}).check(true, true); + auto expected = Expect::hits({4, 6}); + verify(Make<SimplePhraseAdapter>(child_list), expected, Expect::empty()); +} + TEST(FilterSearchTest, simple_andnot) { auto child_list = Children() .hits({1, 2, 3, 4, 5, 6}).check(true, true) .hits({2, 4, 6}).check(false, false) .hits({4, 6, 7}).check(false, false); auto expected = Expect::hits({1, 3, 5}); - verify(Combine(Blueprint::create_andnot_filter, child_list), expected); + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), expected); verify(Make<AndNotBlueprint>(child_list), expected); } @@ -497,9 +566,13 @@ TEST(FilterSearchTest, rank_filter) { auto child_list1 = Children().hits({1,2,3}).empty().full(); auto child_list2 = Children().empty().hits({1,2,3}).full(); auto child_list3 = Children().full().hits({1,2,3}).empty(); - verify(Combine(Blueprint::create_first_child_filter, child_list1), Expect::hits({1,2,3})); - verify(Combine(Blueprint::create_first_child_filter, child_list2), Expect::empty()); - verify(Combine(Blueprint::create_first_child_filter, child_list3), Expect::full()); + auto adapter = [](const auto &children, bool ignore_strict, Constraint constraint) { + (void) ignore_strict; + return Blueprint::create_first_child_filter(children, constraint); + }; + verify(Combine<RankFlow>(adapter, child_list1), Expect::hits({1,2,3})); + verify(Combine<RankFlow>(adapter, child_list2), Expect::empty()); + verify(Combine<RankFlow>(adapter, child_list3), Expect::full()); verify(Make<RankBlueprint>(child_list1), Expect::hits({1,2,3})); verify(Make<RankBlueprint>(child_list2), Expect::empty()); verify(Make<RankBlueprint>(child_list3), Expect::full()); @@ -510,7 +583,7 @@ TEST(FilterSearchTest, or_short_circuit) { .hits({5, 10}).check(true, true) .full().check(true, true) .hits({3, 11}).check(true, true).dropped(); - verify(Combine(Blueprint::create_or_filter, child_list), + verify(Combine<OrFlow>(Blueprint::create_or_filter, child_list), Expect::full()); } @@ -519,7 +592,7 @@ TEST(FilterSearchTest, or_pruning) { .empty().check(true, true) .empty().check(true, true) .empty().check(true, true); - verify(Combine(Blueprint::create_or_filter, child_list), + verify(Combine<OrFlow>(Blueprint::create_or_filter, child_list), Expect::empty()); } @@ -528,7 +601,7 @@ TEST(FilterSearchTest, or_partial_pruning) { .hits({5, 10}).check(true, true) .empty().check(true, true) .hits({3, 11}).check(true, true); - verify(Combine(Blueprint::create_or_filter, child_list), + verify(Combine<OrFlow>(Blueprint::create_or_filter, child_list), Expect::hits({3, 5, 10, 11}).child_count(2)); } @@ -537,7 +610,7 @@ TEST(FilterSearchTest, and_short_circuit) { .hits({1, 2, 3}).check(true, true) .empty().check(false, true) .hits({2, 3, 4}).check(false, true).dropped(); - verify(Combine(Blueprint::create_and_filter, child_list), + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), Expect::empty()); } @@ -546,7 +619,7 @@ TEST(FilterSearchTest, and_pruning) { .full().check(true, true) .full().check(false, true) .full().check(false, true); - verify(Combine(Blueprint::create_and_filter, child_list), + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), Expect::full()); } @@ -555,7 +628,7 @@ TEST(FilterSearchTest, and_partial_pruning) { .hits({1, 2, 3}).check(true, true) .full().check(false, true) .hits({2, 3, 4}).check(false, true); - verify(Combine(Blueprint::create_and_filter, child_list), + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), Expect::hits({2, 3}).child_count(2)); } @@ -563,7 +636,7 @@ TEST(FilterSearchTest, andnot_positive_short_circuit) { auto child_list = Children() .empty().check(true, true) .hits({1, 2, 3}).check(false, false).dropped(); - verify(Combine(Blueprint::create_andnot_filter, child_list), + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), Expect::empty()); } @@ -573,7 +646,7 @@ TEST(FilterSearchTest, andnot_negative_short_circuit) { .hits({1}).check(false, false) .full().check(false, false) .hits({3}).check(false, false).dropped(); - verify(Combine(Blueprint::create_andnot_filter, child_list), + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), Expect::empty()); } @@ -583,7 +656,7 @@ TEST(FilterSearchTest, andnot_negative_pruning) { .empty().check(false, false) .empty().check(false, false) .empty().check(false, false); - verify(Combine(Blueprint::create_andnot_filter, child_list), + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), Expect::full()); } @@ -593,7 +666,7 @@ TEST(FilterSearchTest, andnot_partial_negative_pruning) { .hits({1}).check(false, false) .empty().check(false, false) .hits({3}).check(false, false); - verify(Combine(Blueprint::create_andnot_filter, child_list), + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), Expect::hits({2}).child_count(3)); } @@ -602,7 +675,7 @@ TEST(FilterSearchTest, first_or_child_can_be_partially_pruned) { .empty().check(true, true) .hits({5, 10}).check(true, true) .hits({3, 11}).check(true, true); - verify(Combine(Blueprint::create_or_filter, child_list), + verify(Combine<OrFlow>(Blueprint::create_or_filter, child_list), Expect::hits({3, 5, 10, 11}).child_count(2)); } @@ -611,9 +684,9 @@ TEST(FilterSearchTest, first_and_child_can_only_be_partially_pruned_when_nonstri .full().check(true, true) .hits({1, 2, 3}).check(false, true) .hits({2, 3, 4}).check(false, true); - verify(Combine(Blueprint::create_and_filter, child_list), true, + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), true, Expect::hits({2, 3}).child_count(3)); - verify(Combine(Blueprint::create_and_filter, child_list), false, + verify(Combine<AndFlow>(Blueprint::create_and_filter, child_list), false, Expect::hits({2, 3}).child_count(2)); } @@ -623,19 +696,19 @@ TEST(FilterSearchTest, first_negative_andnot_child_can_be_partially_pruned) { .empty().check(false, false) .hits({1}).check(false, false) .hits({3}).check(false, false); - verify(Combine(Blueprint::create_andnot_filter, child_list), + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, child_list), Expect::hits({2}).child_count(3)); } TEST(FilterSearchTest, need_atleast_one_child) { - verify(Combine(Blueprint::create_and_filter, Children().full()), Expect::full()); - verify(Combine(Blueprint::create_or_filter, Children().empty()), Expect::empty()); - verify(Combine(Blueprint::create_andnot_filter, Children().full()), Expect::full()); - EXPECT_THROW(verify(Combine(Blueprint::create_and_filter, Children()), Expect::empty()), + verify(Combine<AndFlow>(Blueprint::create_and_filter, Children().full()), Expect::full()); + verify(Combine<OrFlow>(Blueprint::create_or_filter, Children().empty()), Expect::empty()); + verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, Children().full()), Expect::full()); + EXPECT_THROW(verify(Combine<AndFlow>(Blueprint::create_and_filter, Children()), Expect::empty()), vespalib::RequireFailedException); - EXPECT_THROW(verify(Combine(Blueprint::create_or_filter, Children()), Expect::empty()), + EXPECT_THROW(verify(Combine<OrFlow>(Blueprint::create_or_filter, Children()), Expect::empty()), vespalib::RequireFailedException); - EXPECT_THROW(verify(Combine(Blueprint::create_andnot_filter, Children()), Expect::empty()), + EXPECT_THROW(verify(Combine<AndNotFlow>(Blueprint::create_andnot_filter, Children()), Expect::empty()), vespalib::RequireFailedException); } diff --git a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp index 202ba8c180e..33c2e067255 100644 --- a/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp +++ b/searchlib/src/tests/queryeval/iterator_benchmark/iterator_benchmark_test.cpp @@ -156,7 +156,7 @@ get_class_name(const auto& obj) BenchmarkResult strict_search(Blueprint& blueprint, MatchData& md, uint32_t docid_limit) { - auto itr = blueprint.createSearch(md, true); + auto itr = blueprint.createSearch(md); assert(itr.get()); BenchmarkTimer timer(budget_sec); uint32_t hits = 0; @@ -176,9 +176,9 @@ strict_search(Blueprint& blueprint, MatchData& md, uint32_t docid_limit) } BenchmarkResult -non_strict_search(Blueprint& blueprint, MatchData& md, uint32_t docid_limit, double filter_hit_ratio, bool force_strict) +non_strict_search(Blueprint& blueprint, MatchData& md, uint32_t docid_limit, double filter_hit_ratio) { - auto itr = blueprint.createSearch(md, force_strict); + auto itr = blueprint.createSearch(md); assert(itr.get()); BenchmarkTimer timer(budget_sec); uint32_t seeks = 0; @@ -209,16 +209,15 @@ non_strict_search(Blueprint& blueprint, MatchData& md, uint32_t docid_limit, dou BenchmarkResult benchmark_search(Blueprint::UP blueprint, uint32_t docid_limit, bool strict_context, bool force_strict, double filter_hit_ratio) { - auto opts = Blueprint::Options::all(); - blueprint->sort(strict_context || force_strict, opts); - blueprint->fetchPostings(ExecuteInfo::createForTest(strict_context || force_strict)); + blueprint->basic_plan(strict_context || force_strict, docid_limit); + blueprint->fetchPostings(ExecuteInfo::FULL); // Note: All blueprints get the same TermFieldMatchData instance. // This is OK as long as we don't do unpacking and only use 1 thread. auto md = MatchData::makeTestInstance(1, 1); if (strict_context) { return strict_search(*blueprint, *md, docid_limit); } else { - return non_strict_search(*blueprint, *md, docid_limit, filter_hit_ratio, force_strict); + return non_strict_search(*blueprint, *md, docid_limit, filter_hit_ratio); } } 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 7a7abb20cdf..992ac320385 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 @@ -179,9 +179,9 @@ struct WandBlueprintSpec Node::UP term = createNode(); Blueprint::UP bp = blueprint(searchable, field, *term); MatchData::UP md(MatchData::makeTestInstance(1, 1)); - bp->fetchPostings(ExecuteInfo::TRUE); - bp->setDocIdLimit(docIdLimit); - SearchIterator::UP sb = bp->createSearch(*md, true); + bp->basic_plan(true, docIdLimit); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP sb = bp->createSearch(*md); EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != 0); return sb; } @@ -194,9 +194,9 @@ struct WandBlueprintSpec FakeResult search(Searchable &searchable, const std::string &field, const search::query::Node &term) const { Blueprint::UP bp = blueprint(searchable, field, term); MatchData::UP md(MatchData::makeTestInstance(1, 1)); - bp->fetchPostings(ExecuteInfo::TRUE); - bp->setDocIdLimit(docIdLimit); - SearchIterator::UP sb = bp->createSearch(*md, true); + bp->basic_plan(true, docIdLimit); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP sb = bp->createSearch(*md); EXPECT_TRUE(dynamic_cast<ParallelWeakAndSearch*>(sb.get()) != 0); return doSearch(*sb, *md->resolveTermField(handle)); } diff --git a/searchlib/src/tests/queryeval/predicate/predicate_blueprint_test.cpp b/searchlib/src/tests/queryeval/predicate/predicate_blueprint_test.cpp index ed349480ff4..ffa2905ce0e 100644 --- a/searchlib/src/tests/queryeval/predicate/predicate_blueprint_test.cpp +++ b/searchlib/src/tests/queryeval/predicate/predicate_blueprint_test.cpp @@ -128,13 +128,14 @@ TEST_F("require that blueprint with zstar-compressed estimates non-empty.", Fixt void runQuery(Fixture & f, std::vector<uint32_t> expected, bool expectCachedSize, uint32_t expectedKV) { PredicateBlueprint blueprint(f.field, f.guard(), f.query); - blueprint.fetchPostings(ExecuteInfo::TRUE); + blueprint.basic_plan(true, 100); + blueprint.fetchPostings(ExecuteInfo::FULL); EXPECT_EQUAL(expectCachedSize, blueprint.getCachedFeatures().size()); for (uint32_t docId : expected) { EXPECT_EQUAL(expectedKV, uint32_t(blueprint.getKV()[docId])); } TermFieldMatchDataArray tfmda; - SearchIterator::UP it = blueprint.createLeafSearch(tfmda, true); + SearchIterator::UP it = blueprint.createLeafSearch(tfmda); ASSERT_TRUE(it.get()); it->initFullRange(); EXPECT_EQUAL(SearchIterator::beginId(), it->getDocId()); @@ -172,9 +173,10 @@ TEST_F("require that blueprint can create more advanced search", Fixture) { f.indexEmptyDocument(doc_id + 2); PredicateBlueprint blueprint(f.field, f.guard(), f.query); - blueprint.fetchPostings(ExecuteInfo::TRUE); + blueprint.basic_plan(true, 100); + blueprint.fetchPostings(ExecuteInfo::FULL); TermFieldMatchDataArray tfmda; - SearchIterator::UP it = blueprint.createLeafSearch(tfmda, true); + SearchIterator::UP it = blueprint.createLeafSearch(tfmda); ASSERT_TRUE(it.get()); it->initFullRange(); EXPECT_EQUAL(SearchIterator::beginId(), it->getDocId()); @@ -195,9 +197,10 @@ TEST_F("require that blueprint can create NOT search", Fixture) { f.indexDocument(doc_id, annotations); PredicateBlueprint blueprint(f.field, f.guard(), f.query); - blueprint.fetchPostings(ExecuteInfo::TRUE); + blueprint.basic_plan(true, 100); + blueprint.fetchPostings(ExecuteInfo::FULL); TermFieldMatchDataArray tfmda; - SearchIterator::UP it = blueprint.createLeafSearch(tfmda, true); + SearchIterator::UP it = blueprint.createLeafSearch(tfmda); ASSERT_TRUE(it.get()); it->initFullRange(); EXPECT_TRUE(it->seek(doc_id)); @@ -211,9 +214,10 @@ TEST_F("require that blueprint can create compressed NOT search", Fixture) { f.indexDocument(doc_id, annotations); PredicateBlueprint blueprint(f.field, f.guard(), f.query); - blueprint.fetchPostings(ExecuteInfo::TRUE); + blueprint.basic_plan(true, 100); + blueprint.fetchPostings(ExecuteInfo::FULL); TermFieldMatchDataArray tfmda; - SearchIterator::UP it = blueprint.createLeafSearch(tfmda, true); + SearchIterator::UP it = blueprint.createLeafSearch(tfmda); ASSERT_TRUE(it.get()); it->initFullRange(); EXPECT_TRUE(it->seek(doc_id)); @@ -235,9 +239,10 @@ TEST_F("require that blueprint can set up search with subqueries", Fixture) { query.getTerm()->addFeature("key2", "value", 2); PredicateBlueprint blueprint(f.field, f.guard(), query); - blueprint.fetchPostings(ExecuteInfo::TRUE); + blueprint.basic_plan(true, 100); + blueprint.fetchPostings(ExecuteInfo::FULL); TermFieldMatchDataArray tfmda; - SearchIterator::UP it = blueprint.createLeafSearch(tfmda, true); + SearchIterator::UP it = blueprint.createLeafSearch(tfmda); ASSERT_TRUE(it.get()); it->initFullRange(); EXPECT_FALSE(it->seek(doc_id)); diff --git a/searchlib/src/tests/queryeval/queryeval_test.cpp b/searchlib/src/tests/queryeval/queryeval_test.cpp index e8f30ba84ff..b72481d24cf 100644 --- a/searchlib/src/tests/queryeval/queryeval_test.cpp +++ b/searchlib/src/tests/queryeval/queryeval_test.cpp @@ -220,8 +220,9 @@ TEST(QueryEvalTest, test_and) { auto and_b = std::make_unique<AndBlueprint>(); and_b->addChild(std::make_unique<SimpleBlueprint>(a)); and_b->addChild(std::make_unique<SimpleBlueprint>(b)); - and_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP and_ab = and_b->createSearch(*md, true); + and_b->basic_plan(true, 1000); + and_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP and_ab = and_b->createSearch(*md); EXPECT_TRUE(dynamic_cast<const AndSearch *>(and_ab.get()) != nullptr); EXPECT_EQ(4u, dynamic_cast<AndSearch &>(*and_ab).estimate()); @@ -231,14 +232,16 @@ TEST(QueryEvalTest, test_and) { expect.addHit(5).addHit(30); EXPECT_EQ(res, expect); - SearchIterator::UP filter_ab = and_b->createFilterSearch(true, upper_bound); + SearchIterator::UP filter_ab = and_b->createFilterSearch(upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "AndSearchStrict.*NoUnpack.*SimpleSearch.*upper.*SimpleSearch.*upper"); - filter_ab = and_b->createFilterSearch(false, lower_bound); + and_b->basic_plan(false, 1000); + and_b->fetchPostings(ExecuteInfo::FULL); + filter_ab = and_b->createFilterSearch(lower_bound); dump = filter_ab->asString(); expect_match(dump, "lower"); expect_match(dump, "AndSearchNoStrict.*NoUnpack.*SimpleSearch.*lower.*SimpleSearch.*lower"); @@ -256,8 +259,9 @@ TEST(QueryEvalTest, test_or) auto or_b = std::make_unique<OrBlueprint>(); or_b->addChild(std::make_unique<SimpleBlueprint>(a)); or_b->addChild(std::make_unique<SimpleBlueprint>(b)); - or_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP or_ab = or_b->createSearch(*md, true); + or_b->basic_plan(true, 1000); + or_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP or_ab = or_b->createSearch(*md); SimpleResult res; res.search(*or_ab); @@ -265,14 +269,16 @@ TEST(QueryEvalTest, test_or) expect.addHit(5).addHit(10).addHit(17).addHit(30); EXPECT_EQ(res, expect); - SearchIterator::UP filter_ab = or_b->createFilterSearch(true, upper_bound); + SearchIterator::UP filter_ab = or_b->createFilterSearch(upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "StrictHeapOrSearch.*NoUnpack.*SimpleSearch.*upper.*SimpleSearch.*upper"); - filter_ab = or_b->createFilterSearch(false, lower_bound); + or_b->basic_plan(false, 1000); + or_b->fetchPostings(ExecuteInfo::FULL); + filter_ab = or_b->createFilterSearch(lower_bound); dump = filter_ab->asString(); expect_match(dump, "lower"); expect_match(dump, "OrLikeSearch.false.*NoUnpack.*SimpleSearch.*lower.*SimpleSearch.*lower"); @@ -365,13 +371,13 @@ public: : default_flow_stats(docid_limit, est.est_hits(), 0); } SearchIterator::UP - createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override + createLeafSearch(const TermFieldMatchDataArray &tfmda) const override { (void) tfmda; - return _sc->createIterator(&_tfmd, strict); + return _sc->createIterator(&_tfmd, strict()); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } private: search::SingleBoolAttribute _a; @@ -392,8 +398,9 @@ TEST(QueryEvalTest, test_andnot) auto andnot_b = std::make_unique<AndNotBlueprint>(); andnot_b->addChild(std::make_unique<SimpleBlueprint>(a)); andnot_b->addChild(std::make_unique<SimpleBlueprint>(b)); - andnot_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP andnot_ab = andnot_b->createSearch(*md, true); + andnot_b->basic_plan(true, 1000); + andnot_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP andnot_ab = andnot_b->createSearch(*md); SimpleResult res; res.search(*andnot_ab); @@ -401,14 +408,16 @@ TEST(QueryEvalTest, test_andnot) expect.addHit(10); EXPECT_EQ(res, expect); - SearchIterator::UP filter_ab = andnot_b->createFilterSearch(true, upper_bound); + SearchIterator::UP filter_ab = andnot_b->createFilterSearch(upper_bound); SimpleResult filter_res; filter_res.search(*filter_ab); EXPECT_EQ(res, expect); std::string dump = filter_ab->asString(); expect_match(dump, "upper"); expect_match(dump, "AndNotSearch.*SimpleSearch.*<strict,upper>.*SimpleSearch.*<nostrict,lower>"); - filter_ab = andnot_b->createFilterSearch(false, lower_bound); + andnot_b->basic_plan(false, 1000); + andnot_b->fetchPostings(ExecuteInfo::FULL); + filter_ab = andnot_b->createFilterSearch(lower_bound); dump = filter_ab->asString(); expect_match(dump, "lower"); expect_match(dump, "AndNotSearch.*SimpleSearch.*<nostrict,lower>.*SimpleSearch.*<nostrict,upper>"); @@ -423,8 +432,9 @@ TEST(QueryEvalTest, test_andnot) auto andnot_b = std::make_unique<AndNotBlueprint>(); andnot_b->addChild(std::make_unique<SimpleBlueprint>(a)); andnot_b->addChild(std::make_unique<DummySingleValueBitNumericAttributeBlueprint>(b)); - andnot_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP andnot_ab = andnot_b->createSearch(*md, true); + andnot_b->basic_plan(true, 1000); + andnot_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP andnot_ab = andnot_b->createSearch(*md); SimpleResult res; res.search(*andnot_ab); @@ -449,8 +459,9 @@ TEST(QueryEvalTest, test_andnot) auto and_b = std::make_unique<AndBlueprint>(); and_b->addChild(std::make_unique<SimpleBlueprint>(c)); and_b->addChild(std::move(andnot_b)); - and_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP and_cab = and_b->createSearch(*md, true); + and_b->basic_plan(true, 1000); + and_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP and_cab = and_b->createSearch(*md); SimpleResult res; res.search(*and_cab); @@ -475,8 +486,9 @@ TEST(QueryEvalTest, test_rank) auto rank_b = std::make_unique<RankBlueprint>(); rank_b->addChild(std::make_unique<SimpleBlueprint>(a)); rank_b->addChild(std::make_unique<SimpleBlueprint>(b)); - rank_b->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP rank_ab = rank_b->createSearch(*md, true); + rank_b->basic_plan(true, 1000); + rank_b->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP rank_ab = rank_b->createSearch(*md); SimpleResult res; res.search(*rank_ab); diff --git a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp index 64f4fafd2d1..9d93ade71d9 100644 --- a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp +++ b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp @@ -46,9 +46,8 @@ std::unique_ptr<SameElementBlueprint> make_blueprint(const std::vector<FakeResul } Blueprint::UP finalize(Blueprint::UP bp, bool strict) { - auto opts = Blueprint::Options::all(); - Blueprint::UP result = Blueprint::optimize_and_sort(std::move(bp), true, opts); - result->fetchPostings(ExecuteInfo::createForTest(strict)); + Blueprint::UP result = Blueprint::optimize_and_sort(std::move(bp), strict); + result->fetchPostings(ExecuteInfo::FULL); result->freeze(); return result; } @@ -56,7 +55,7 @@ Blueprint::UP finalize(Blueprint::UP bp, bool strict) { SimpleResult find_matches(const std::vector<FakeResult> &children) { auto md = make_match_data(); auto bp = finalize(make_blueprint(children), false); - auto search = bp->createSearch(*md, false); + auto search = bp->createSearch(*md); return SimpleResult().search(*search, 1000); } @@ -85,7 +84,7 @@ TEST("require that matching elements can be identified") { auto b = make_result({{5, {3,5,7,10}}, {10, {4,5,6}}}); auto bp = finalize(make_blueprint({a,b}), false); auto md = make_match_data(); - auto search = bp->createSearch(*md, false); + auto search = bp->createSearch(*md); search->initRange(1, 1000); auto *se = dynamic_cast<SameElementSearch*>(search.get()); ASSERT_TRUE(se != nullptr); @@ -107,7 +106,7 @@ TEST("require that strict iterator seeks to next hit and can unpack matching doc auto a = make_result({{5, {1,2}}, {7, {1,2}}, {8, {1,2}}, {9, {1,2}}}); auto b = make_result({{5, {3}}, {6, {1,2}}, {7, {2,4}}, {9, {1}}}); auto bp = finalize(make_blueprint({a,b}), true); - auto search = bp->createSearch(*md, true); + auto search = bp->createSearch(*md); auto* tfmd = md->resolveTermField(0); search->initRange(1, 1000); EXPECT_LESS(search->getDocId(), 1u); @@ -145,9 +144,9 @@ TEST("require that children are sorted") { TEST("require that attribute iterators are wrapped for element unpacking") { auto a = make_result({{5, {1,3,7}}}); auto b = make_result({{5, {3,5,10}}}); - auto bp = finalize(make_blueprint({a,b}, true), true); + auto bp = finalize(make_blueprint({a,b}, true), false); auto md = make_match_data(); - auto search = bp->createSearch(*md, false); + auto search = bp->createSearch(*md); auto *se = dynamic_cast<SameElementSearch*>(search.get()); ASSERT_TRUE(se != nullptr); ASSERT_EQUAL(se->children().size(), 2u); diff --git a/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp b/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp index 99812900d40..3e779bdca14 100644 --- a/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp +++ b/searchlib/src/tests/queryeval/simple_phrase/simple_phrase_test.cpp @@ -38,11 +38,11 @@ struct MyTerm : public search::queryeval::SimpleLeafBlueprint { FlowStats calculate_flow_stats(uint32_t docid_limit) const override { return default_flow_stats(docid_limit, getState().estimate().estHits, 0); } - SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &, bool) const override { + SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &) const override { return {}; } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; @@ -146,12 +146,14 @@ public: void fetchPostings(bool useBlueprint) { - ExecuteInfo execInfo = ExecuteInfo::createForTest(_strict); + ExecuteInfo execInfo = ExecuteInfo::FULL; if (useBlueprint) { + _phrase.basic_plan(_strict, 100); _phrase.fetchPostings(execInfo); return; } for (const auto & i : _children) { + i->basic_plan(_strict, 100); i->fetchPostings(execInfo); } } @@ -160,7 +162,7 @@ public: SearchIterator *createSearch(bool useBlueprint) { SearchIterator::UP search; if (useBlueprint) { - search = _phrase.createSearch(*_md, _strict); + search = _phrase.createSearch(*_md); } else { search::fef::TermFieldMatchDataArray childMatch; for (size_t i = 0; i < _children.size(); ++i) { @@ -171,7 +173,7 @@ public: } SimplePhraseSearch::Children children; for (const auto & i : _children) { - children.push_back(i->createSearch(*_md, _strict)); + children.push_back(i->createSearch(*_md)); } search = std::make_unique<SimplePhraseSearch>(std::move(children), MatchData::UP(), childMatch, _order, diff --git a/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp b/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp index a266902445b..b84cb02a357 100644 --- a/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp +++ b/searchlib/src/tests/queryeval/sourceblender/sourceblender_test.cpp @@ -76,8 +76,9 @@ TEST(SourceBlenderTest, test_strictness) blend_b->addChild(std::move(a_b)); blend_b->addChild(std::move(b_b)); Blueprint::UP bp(blend_b); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - SearchIterator::UP search = bp->createSearch(*md, strict); + bp->basic_plan(strict, 100); + bp->fetchPostings(ExecuteInfo::FULL); + SearchIterator::UP search = bp->createSearch(*md); search->initFullRange(); SearchIterator &blend = *search; diff --git a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp index 2a3ce66dba6..310c6d628e3 100644 --- a/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp +++ b/searchlib/src/tests/queryeval/termwise_eval/termwise_eval_test.cpp @@ -86,13 +86,11 @@ struct MyBlueprint : SimpleLeafBlueprint { FlowStats calculate_flow_stats(uint32_t docid_limit) const override { return default_flow_stats(docid_limit, getState().estimate().estHits, 0); } - SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &, - bool strict) const override - { - return std::make_unique<MyTerm>(hits, strict); + SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &) const override { + return std::make_unique<MyTerm>(hits, strict()); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; @@ -416,7 +414,8 @@ TEST(TermwiseEvalTest, require_that_basic_termwise_evaluation_works) my_or.addChild(UP(new MyBlueprint({1}, true, 1))); my_or.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); } } @@ -431,7 +430,8 @@ TEST(TermwiseEvalTest, require_that_the_hit_rate_must_be_high_enough_for_termwis my_or.addChild(UP(new MyBlueprint({1}, true, 1))); my_or.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_TRUE(my_or.createSearch(*md, strict)->asString().find("TermwiseSearch") == vespalib::string::npos); + my_or.basic_plan(strict, 100); + EXPECT_TRUE(my_or.createSearch(*md)->asString().find("TermwiseSearch") == vespalib::string::npos); } } @@ -446,7 +446,8 @@ TEST(TermwiseEvalTest, require_that_enough_unranked_termwise_terms_are_present_f my_or.addChild(UP(new MyBlueprint({2}, false, 2))); // <- not termwise my_or.addChild(UP(new MyBlueprint({3}, true, 3))); // <- ranked for (bool strict: {true, false}) { - EXPECT_TRUE(my_or.createSearch(*md, strict)->asString().find("TermwiseSearch") == vespalib::string::npos); + my_or.basic_plan(strict, 100); + EXPECT_TRUE(my_or.createSearch(*md)->asString().find("TermwiseSearch") == vespalib::string::npos); } } @@ -464,7 +465,8 @@ TEST(TermwiseEvalTest, require_that_termwise_evaluation_can_be_multi_level_but_n child->addChild(UP(new MyBlueprint({3}, true, 3))); my_or.addChild(std::move(child)); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), make_termwise(OR({ TERM({1}, strict), ORz({ TERM({2}, strict), TERM({3}, strict) }, strict) }, strict), strict)->asString()); @@ -483,7 +485,8 @@ TEST(TermwiseEvalTest, require_that_or_can_be_completely_termwise) my_or.addChild(UP(new MyBlueprint({1}, true, 1))); my_or.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), make_termwise(OR({ TERM({1}, strict), TERM({2}, strict) }, strict), strict)->asString()); } } @@ -499,7 +502,8 @@ TEST(TermwiseEvalTest, require_that_or_can_be_partially_termwise) my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), ORs({ make_termwise(OR({ TERM({1}, strict), TERM({3}, strict) }, strict), strict), TERM({2}, strict) }, strict)->asString()); } @@ -516,7 +520,8 @@ TEST(TermwiseEvalTest, require_that_or_puts_termwise_subquery_at_the_right_place my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), ORs({ TERM({1}, strict), make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), strict) }, strict)->asString()); @@ -535,7 +540,8 @@ TEST(TermwiseEvalTest, require_that_or_can_use_termwise_eval_also_when_having_no my_or.addChild(UP(new MyBlueprint({2}, true, 2))); my_or.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_or.createSearch(*md, strict)->asString(), + my_or.basic_plan(strict, 100); + EXPECT_EQ(my_or.createSearch(*md)->asString(), ORz({ TERM({1}, strict), make_termwise(OR({ TERM({2}, strict), TERM({3}, strict) }, strict), strict)}, @@ -555,7 +561,8 @@ TEST(TermwiseEvalTest, require_that_and_can_be_completely_termwise) my_and.addChild(UP(new MyBlueprint({1}, true, 1))); my_and.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), + my_and.basic_plan(strict, 100); + EXPECT_EQ(my_and.createSearch(*md)->asString(), make_termwise(AND({ TERM({1}, strict), TERM({2}, false) }, strict), strict)->asString()); } } @@ -571,7 +578,8 @@ TEST(TermwiseEvalTest, require_that_and_can_be_partially_termwise) my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), + my_and.basic_plan(strict, 100); + EXPECT_EQ(my_and.createSearch(*md)->asString(), ANDs({ make_termwise(AND({ TERM({1}, strict), TERM({3}, false) }, strict), strict), @@ -590,7 +598,8 @@ TEST(TermwiseEvalTest, require_that_and_puts_termwise_subquery_at_the_right_plac my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), + my_and.basic_plan(strict, 100); + EXPECT_EQ(my_and.createSearch(*md)->asString(), ANDs({ TERM({1}, strict), make_termwise(AND({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); @@ -609,7 +618,8 @@ TEST(TermwiseEvalTest, require_that_and_can_use_termwise_eval_also_when_having_n my_and.addChild(UP(new MyBlueprint({2}, true, 2))); my_and.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_and.createSearch(*md, strict)->asString(), + my_and.basic_plan(strict, 100); + EXPECT_EQ(my_and.createSearch(*md)->asString(), ANDz({ TERM({1}, strict), make_termwise(AND({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); @@ -627,7 +637,8 @@ TEST(TermwiseEvalTest, require_that_andnot_can_be_completely_termwise) my_andnot.addChild(UP(new MyBlueprint({1}, true, 1))); my_andnot.addChild(UP(new MyBlueprint({2}, true, 2))); for (bool strict: {true, false}) { - EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), + my_andnot.basic_plan(strict, 100); + EXPECT_EQ(my_andnot.createSearch(*md)->asString(), make_termwise(ANDNOT({ TERM({1}, strict), TERM({2}, false) }, strict), strict)->asString()); } @@ -642,7 +653,8 @@ TEST(TermwiseEvalTest, require_that_andnot_can_be_partially_termwise) my_andnot.addChild(UP(new MyBlueprint({2}, true, 2))); my_andnot.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), + my_andnot.basic_plan(strict, 100); + EXPECT_EQ(my_andnot.createSearch(*md)->asString(), ANDNOT({ TERM({1}, strict), make_termwise(OR({ TERM({2}, false), TERM({3}, false) }, false), false) }, strict)->asString()); @@ -659,7 +671,8 @@ TEST(TermwiseEvalTest, require_that_andnot_can_be_partially_termwise_with_first_ my_andnot.addChild(UP(new MyBlueprint({2}, false, 2))); my_andnot.addChild(UP(new MyBlueprint({3}, true, 3))); for (bool strict: {true, false}) { - EXPECT_EQ(my_andnot.createSearch(*md, strict)->asString(), + my_andnot.basic_plan(strict, 100); + EXPECT_EQ(my_andnot.createSearch(*md)->asString(), ANDNOT({ make_termwise(ANDNOT({ TERM({1}, strict), TERM({3}, false) }, strict), strict), TERM({2}, false) }, strict)->asString()); diff --git a/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp b/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp index 54663e48060..57e41fef13b 100644 --- a/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp +++ b/searchlib/src/tests/queryeval/weighted_set_term/weighted_set_term_test.cpp @@ -69,8 +69,9 @@ struct WS { FieldSpecList fields; fields.add(FieldSpec(field, fieldId, handle)); auto bp = searchable.createBlueprint(requestContext, fields, *node); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - auto sb = bp->createSearch(*md, strict); + bp->basic_plan(strict, 1000); + bp->fetchPostings(ExecuteInfo::FULL); + auto sb = bp->createSearch(*md); return (dynamic_cast<WeightedSetTermSearch*>(sb.get()) != nullptr); } @@ -84,8 +85,9 @@ struct WS { FieldSpecList fields; fields.add(FieldSpec(field, fieldId, handle, field_is_filter)); auto bp = searchable.createBlueprint(requestContext, fields, *node); - bp->fetchPostings(ExecuteInfo::createForTest(strict)); - auto sb = bp->createSearch(*md, strict); + bp->basic_plan(strict, 1000); + bp->fetchPostings(ExecuteInfo::FULL); + auto sb = bp->createSearch(*md); sb->initFullRange(); FakeResult result; for (uint32_t docId = 1; docId < 10; ++docId) { @@ -333,7 +335,7 @@ struct VerifyMatchData { VerifyMatchData &vmd; MyBlueprint(VerifyMatchData &vmd_in, FieldSpecBase spec_in) : SimpleLeafBlueprint(spec_in), vmd(vmd_in) {} - [[nodiscard]] SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const override { + [[nodiscard]] SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override { EXPECT_EQ(tfmda.size(), 1u); EXPECT_TRUE(tfmda[0] != nullptr); if (vmd.child_tfmd == nullptr) { @@ -347,8 +349,8 @@ struct VerifyMatchData { FlowStats calculate_flow_stats(uint32_t docid_limit) const override { return default_flow_stats(docid_limit, 0, 0); } - [[nodiscard]] SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + [[nodiscard]] SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; size_t child_cnt = 0; @@ -371,7 +373,12 @@ TEST(WeightedSetTermTest, require_that_children_get_a_common_yet_separate_term_f } blueprint.complete(estimate); auto match_data = layout.createMatchData(); - auto search = blueprint.createSearch(*match_data, true); + blueprint.basic_plan(true, 1000); + { + Blueprint &bp = blueprint; + bp.fetchPostings(ExecuteInfo::FULL); + } + auto search = blueprint.createSearch(*match_data); auto top_tfmd = match_data->resolveTermField(top_handle); EXPECT_EQ(vmd.child_cnt, 5u); EXPECT_TRUE(vmd.child_tfmd != nullptr); diff --git a/searchlib/src/vespa/searchcommon/attribute/i_search_context.h b/searchlib/src/vespa/searchcommon/attribute/i_search_context.h index 8ea6f0f60af..a4703232c2b 100644 --- a/searchlib/src/vespa/searchcommon/attribute/i_search_context.h +++ b/searchlib/src/vespa/searchcommon/attribute/i_search_context.h @@ -48,7 +48,7 @@ public: * Create temporary posting lists. * Should be called before createIterator() is called. */ - virtual void fetchPostings(const queryeval::ExecuteInfo &execInfo) = 0; + virtual void fetchPostings(const queryeval::ExecuteInfo &execInfo, bool strict) = 0; virtual bool valid() const = 0; virtual Int64Range getAsIntegerTerm() const = 0; diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp index e70c498d3c3..707b98b1cf3 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp @@ -170,26 +170,26 @@ public: } } - SearchIteratorUP createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override { + SearchIteratorUP createLeafSearch(const TermFieldMatchDataArray &tfmda) const override { assert(tfmda.size() == 1); - return _search_context->createIterator(tfmda[0], strict); + return _search_context->createIterator(tfmda[0], strict()); } - SearchIterator::UP createSearch(fef::MatchData &md, bool strict) const override { + SearchIterator::UP createSearch(fef::MatchData &md) const override { const State &state = getState(); assert(state.numFields() == 1); - return _search_context->createIterator(state.field(0).resolve(md), strict); + return _search_context->createIterator(state.field(0).resolve(md), strict()); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { (void) constraint; // We provide an iterator with exact results, so no need to take constraint into consideration. auto wrapper = std::make_unique<FilterWrapper>(getState().numFields()); - wrapper->wrap(createLeafSearch(wrapper->tfmda(), strict)); + wrapper->wrap(createLeafSearch(wrapper->tfmda())); return wrapper; } void fetchPostings(const queryeval::ExecuteInfo &execInfo) override { - _search_context->fetchPostings(execInfo); + _search_context->fetchPostings(execInfo, strict()); } void visitMembers(vespalib::ObjectVisitor &visitor) const override; @@ -287,6 +287,9 @@ public: bool should_use() const { return _should_use; } + void sort(queryeval::InFlow in_flow, const Options &) override { + strict(in_flow.strict()); + } queryeval::FlowStats calculate_flow_stats(uint32_t docid_limit) const override { using OrFlow = search::queryeval::OrFlow; struct MyAdapter { @@ -306,13 +309,13 @@ public: } SearchIterator::UP - createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override + createLeafSearch(const TermFieldMatchDataArray &tfmda) const override { OrSearch::Children children; for (auto & search : _rangeSearches) { - children.push_back(search->createIterator(tfmda[0], strict)); + children.push_back(search->createIterator(tfmda[0], strict())); } - if (strict) { + if (strict()) { if (children.size() < 0x70) { using Parent = StrictHeapOrSearch<NoUnpack, vespalib::LeftArrayHeap, uint8_t>; return std::make_unique<LocationPreFilterIterator<true, Parent>>(std::move(children)); @@ -325,13 +328,13 @@ public: return std::make_unique<LocationPreFilterIterator<false, Parent>>(std::move(children)); } } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } void fetchPostings(const queryeval::ExecuteInfo &execInfo) override { for (auto & search : _rangeSearches) { - search->fetchPostings(execInfo); + search->fetchPostings(execInfo, strict()); } } @@ -371,24 +374,28 @@ public: const common::Location &location() const { return _location; } + void sort(queryeval::InFlow in_flow, const Options &) override { + strict(in_flow.strict()); + } + queryeval::FlowStats calculate_flow_stats(uint32_t) const override { return default_flow_stats(0); } SearchIterator::UP - createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override + createLeafSearch(const TermFieldMatchDataArray &tfmda) const override { if (tfmda.size() == 1) { // search in exactly one field fef::TermFieldMatchData &tfmd = *tfmda[0]; - return common::create_location_iterator(tfmd, _attribute.getNumDocs(), strict, _location); + return common::create_location_iterator(tfmd, _attribute.getNumDocs(), strict(), _location); } else { LOG(debug, "wrong size tfmda: %zu (fallback to old location iterator)\n", tfmda.size()); } - return FastS_AllocLocationIterator(_attribute.getNumDocs(), strict, _location); + return FastS_AllocLocationIterator(_attribute.getNumDocs(), strict(), _location); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } void visitMembers(vespalib::ObjectVisitor& visitor) const override { LeafBlueprint::visitMembers(visitor); @@ -500,6 +507,10 @@ public: setEstimate(estimate); } + void sort(queryeval::InFlow in_flow, const Options &) override { + strict(in_flow.strict()); + } + queryeval::FlowStats calculate_flow_stats(uint32_t docid_limit) const override { using OrFlow = search::queryeval::OrFlow; struct MyAdapter { @@ -523,7 +534,7 @@ public: OrFlow::cost_of(MyAdapter(docid_limit), _terms, true) + queryeval::flow::heap_cost(est, _terms.size())}; } - SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override { + SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray &tfmda) const override { assert(tfmda.size() == 1); if (_terms.empty()) { return std::make_unique<queryeval::EmptySearch>(); @@ -531,17 +542,17 @@ public: return queryeval::ParallelWeakAndSearch::create(*tfmda[0], queryeval::ParallelWeakAndSearch::MatchParams(_scores, _scoreThreshold, _thresholdBoostFactor, _scoresAdjustFrequency) - .setDocIdLimit(get_docid_limit()), - _weights, _terms, _attr, strict); + .setDocIdLimit(get_docid_limit()), + _weights, _terms, _attr, strict()); } - std::unique_ptr<SearchIterator> createFilterSearch(bool strict, FilterConstraint constraint) const override; + std::unique_ptr<SearchIterator> createFilterSearch(FilterConstraint constraint) const override; bool always_needs_unpack() const override { return true; } }; DirectWandBlueprint::~DirectWandBlueprint() = default; std::unique_ptr<SearchIterator> -DirectWandBlueprint::createFilterSearch(bool, FilterConstraint constraint) const +DirectWandBlueprint::createFilterSearch(FilterConstraint constraint) const { if (constraint == Blueprint::FilterConstraint::UPPER_BOUND) { std::vector<DocidWithWeightIterator> iterators; diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.cpp index 18748641ca4..81a7a06030e 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.cpp @@ -121,6 +121,12 @@ AttributeWeightedSetBlueprint::addToken(std::unique_ptr<ISearchContext> context, _contexts.push_back(context.release()); } +void +AttributeWeightedSetBlueprint::sort(queryeval::InFlow in_flow, const Options &) +{ + strict(in_flow.strict()); +} + queryeval::FlowStats AttributeWeightedSetBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -141,16 +147,16 @@ AttributeWeightedSetBlueprint::calculate_flow_stats(uint32_t docid_limit) const } queryeval::SearchIterator::UP -AttributeWeightedSetBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const +AttributeWeightedSetBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); assert(getState().numFields() == 1); fef::TermFieldMatchData &tfmd = *tfmda[0]; bool field_is_filter = getState().fields()[0].isFilter(); if ((tfmd.isNotNeeded() || field_is_filter) && (_contexts.size() == 1)) { - return _contexts[0]->createIterator(&tfmd, strict); + return _contexts[0]->createIterator(&tfmd, strict()); } - if (strict) { // use generic weighted set search + if (strict()) { // use generic weighted set search fef::MatchDataLayout layout; auto handle = layout.allocTermField(tfmd.getFieldId()); auto match_data = layout.createMatchData(); @@ -174,24 +180,24 @@ AttributeWeightedSetBlueprint::createLeafSearch(const fef::TermFieldMatchDataArr } queryeval::SearchIterator::UP -AttributeWeightedSetBlueprint::createFilterSearch(bool strict, FilterConstraint) const +AttributeWeightedSetBlueprint::createFilterSearch(FilterConstraint) const { std::vector<std::unique_ptr<queryeval::SearchIterator>> children; children.reserve(_contexts.size()); for (auto& context : _contexts) { auto wrapper = std::make_unique<queryeval::FilterWrapper>(1); - wrapper->wrap(context->createIterator(wrapper->tfmda()[0], strict)); + wrapper->wrap(context->createIterator(wrapper->tfmda()[0], strict())); children.emplace_back(std::move(wrapper)); } - return queryeval::OrSearch::create(std::move(children), strict, queryeval::UnpackInfo()); + return queryeval::OrSearch::create(std::move(children), strict(), queryeval::UnpackInfo()); } void AttributeWeightedSetBlueprint::fetchPostings(const queryeval::ExecuteInfo &execInfo) { - if (execInfo.is_strict()) { + if (strict()) { for (auto * context : _contexts) { - context->fetchPostings(execInfo); + context->fetchPostings(execInfo, strict()); } } } diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.h b/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.h index 32632403e42..18cfd6ed5ce 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.h +++ b/searchlib/src/vespa/searchlib/attribute/attribute_weighted_set_blueprint.h @@ -31,9 +31,10 @@ public: AttributeWeightedSetBlueprint(const queryeval::FieldSpec &field, const IAttributeVector & attr); ~AttributeWeightedSetBlueprint(); void addToken(std::unique_ptr<ISearchContext> context, int32_t weight); + void sort(queryeval::InFlow in_flow, const Options &opts) override; queryeval::FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - queryeval::SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - queryeval::SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + queryeval::SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + queryeval::SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; void fetchPostings(const queryeval::ExecuteInfo &execInfo) override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; }; diff --git a/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.h b/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.h index 5aafe4af72b..7dfc7fe3a78 100644 --- a/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.h +++ b/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.h @@ -72,6 +72,10 @@ public: setEstimate(estimate); } + void sort(queryeval::InFlow in_flow, const Options &) override { + strict(in_flow.strict()); + } + queryeval::FlowStats calculate_flow_stats(uint32_t docid_limit) const override { using OrFlow = search::queryeval::OrFlow; struct MyAdapter { @@ -93,9 +97,9 @@ public: OrFlow::cost_of(MyAdapter(docid_limit), _terms, true) + queryeval::flow::heap_cost(est, _terms.size())}; } - std::unique_ptr<queryeval::SearchIterator> createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const override; + std::unique_ptr<queryeval::SearchIterator> createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; - std::unique_ptr<queryeval::SearchIterator> createFilterSearch(bool strict, FilterConstraint constraint) const override; + std::unique_ptr<queryeval::SearchIterator> createFilterSearch(FilterConstraint constraint) const override; std::unique_ptr<queryeval::MatchingElementsSearch> create_matching_elements_search(const MatchingElementsFields &fields) const override { if (fields.has_field(_iattr.getName())) { return queryeval::MatchingElementsSearch::create(_iattr, _dictionary_snapshot, vespalib::ConstArrayRef<IDirectPostingStore::LookupResult>(_terms)); diff --git a/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.hpp b/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.hpp index 0a3b24142a5..817eab3e070 100644 --- a/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.hpp +++ b/searchlib/src/vespa/searchlib/attribute/direct_multi_term_blueprint.hpp @@ -164,20 +164,20 @@ DirectMultiTermBlueprint<PostingStoreType, SearchType>::create_search_helper(con template <typename PostingStoreType, typename SearchType> std::unique_ptr<queryeval::SearchIterator> -DirectMultiTermBlueprint<PostingStoreType, SearchType>::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const +DirectMultiTermBlueprint<PostingStoreType, SearchType>::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); assert(getState().numFields() == 1); - return create_search_helper<SearchType::filter_search>(tfmda, strict); + return create_search_helper<SearchType::filter_search>(tfmda, strict()); } template <typename PostingStoreType, typename SearchType> std::unique_ptr<queryeval::SearchIterator> -DirectMultiTermBlueprint<PostingStoreType, SearchType>::createFilterSearch(bool strict, FilterConstraint) const +DirectMultiTermBlueprint<PostingStoreType, SearchType>::createFilterSearch(FilterConstraint) const { assert(getState().numFields() == 1); auto wrapper = std::make_unique<FilterWrapper>(getState().numFields()); - wrapper->wrap(create_search_helper<true>(wrapper->tfmda(), strict)); + wrapper->wrap(create_search_helper<true>(wrapper->tfmda(), strict())); return wrapper; } diff --git a/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.cpp b/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.cpp index 22362231cc1..62a845e79c4 100644 --- a/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.cpp +++ b/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.cpp @@ -41,7 +41,7 @@ EnumHintSearchContext::lookupRange(const vespalib::datastore::EntryComparator &l } void -EnumHintSearchContext::fetchPostings(const queryeval::ExecuteInfo &) +EnumHintSearchContext::fetchPostings(const queryeval::ExecuteInfo &, bool) { } diff --git a/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.h b/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.h index 23a0a6c560b..53feb4b5085 100644 --- a/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.h +++ b/searchlib/src/vespa/searchlib/attribute/enumhintsearchcontext.h @@ -39,7 +39,7 @@ protected: std::unique_ptr<queryeval::SearchIterator> createPostingIterator(fef::TermFieldMatchData *matchData, bool strict) override; - void fetchPostings(const queryeval::ExecuteInfo & execInfo) override; + void fetchPostings(const queryeval::ExecuteInfo & execInfo, bool strict) override; HitEstimate calc_hit_estimate() const override; uint32_t get_committed_docid_limit() const noexcept { return _docIdLimit; } }; diff --git a/searchlib/src/vespa/searchlib/attribute/imported_search_context.cpp b/searchlib/src/vespa/searchlib/attribute/imported_search_context.cpp index 79a021989fc..7829003da4b 100644 --- a/searchlib/src/vespa/searchlib/attribute/imported_search_context.cpp +++ b/searchlib/src/vespa/searchlib/attribute/imported_search_context.cpp @@ -305,10 +305,10 @@ ImportedSearchContext::considerAddSearchCacheEntry() } void -ImportedSearchContext::fetchPostings(const queryeval::ExecuteInfo &execInfo) { +ImportedSearchContext::fetchPostings(const queryeval::ExecuteInfo &execInfo, bool strict) { if (!_searchCacheLookup) { - _target_search_context->fetchPostings(execInfo); - if (!_merger.merge_done() && (execInfo.is_strict() || (_target_attribute.getIsFastSearch() && execInfo.hit_rate() > 0.01))) { + _target_search_context->fetchPostings(execInfo, strict); + if (!_merger.merge_done() && (strict || (_target_attribute.getIsFastSearch() && execInfo.hit_rate() > 0.01))) { makeMergedPostings(_target_attribute.getIsFilter()); considerAddSearchCacheEntry(); } diff --git a/searchlib/src/vespa/searchlib/attribute/imported_search_context.h b/searchlib/src/vespa/searchlib/attribute/imported_search_context.h index 305a8bf2379..45eff967547 100644 --- a/searchlib/src/vespa/searchlib/attribute/imported_search_context.h +++ b/searchlib/src/vespa/searchlib/attribute/imported_search_context.h @@ -66,7 +66,7 @@ public: std::unique_ptr<queryeval::SearchIterator> createIterator(fef::TermFieldMatchData* matchData, bool strict) override; HitEstimate calc_hit_estimate() const override; - void fetchPostings(const queryeval::ExecuteInfo &execInfo) override; + void fetchPostings(const queryeval::ExecuteInfo &execInfo, bool strict) override; bool valid() const override; Int64Range getAsIntegerTerm() const override; DoubleRange getAsDoubleTerm() const override; diff --git a/searchlib/src/vespa/searchlib/attribute/ipostinglistsearchcontext.h b/searchlib/src/vespa/searchlib/attribute/ipostinglistsearchcontext.h index ac1abc56329..e0cdc38076d 100644 --- a/searchlib/src/vespa/searchlib/attribute/ipostinglistsearchcontext.h +++ b/searchlib/src/vespa/searchlib/attribute/ipostinglistsearchcontext.h @@ -29,7 +29,7 @@ protected: virtual ~IPostingListSearchContext() { } public: - virtual void fetchPostings(const queryeval::ExecuteInfo & execInfo) = 0; + virtual void fetchPostings(const queryeval::ExecuteInfo & execInfo, bool strict) = 0; virtual std::unique_ptr<queryeval::SearchIterator> createPostingIterator(fef::TermFieldMatchData *matchData, bool strict) = 0; virtual HitEstimate calc_hit_estimate() const = 0; }; diff --git a/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.h b/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.h index 41a12dce756..5518d60f25f 100644 --- a/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.h +++ b/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.h @@ -110,7 +110,7 @@ protected: virtual void fillArray(); virtual void fillBitVector(const ExecuteInfo &); - void fetchPostings(const ExecuteInfo & strict) override; + void fetchPostings(const ExecuteInfo &exec, bool strict) override; // this will be called instead of the fetchPostings function in some cases void diversify(bool forward, size_t wanted_hits, const IAttributeVector &diversity_attr, size_t max_per_group, size_t cutoff_groups, bool cutoff_strict); @@ -224,7 +224,7 @@ private: ? HitEstimate(limit) : estimate; } - void fetchPostings(const ExecuteInfo & execInfo) override { + void fetchPostings(const ExecuteInfo & execInfo, bool strict) override { if (params().diversityAttribute() != nullptr) { bool forward = (this->getRangeLimit() > 0); size_t wanted_hits = std::abs(this->getRangeLimit()); @@ -232,7 +232,7 @@ private: *(params().diversityAttribute()), this->getMaxPerGroup(), params().diversityCutoffGroups(), params().diversityCutoffStrict()); } else { - PostingListSearchContextT<DataT>::fetchPostings(execInfo); + PostingListSearchContextT<DataT>::fetchPostings(execInfo, strict); } } diff --git a/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.hpp b/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.hpp index 77f773d0469..0ea17ab1d1e 100644 --- a/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.hpp +++ b/searchlib/src/vespa/searchlib/attribute/postinglistsearchcontext.hpp @@ -137,7 +137,7 @@ PostingListSearchContextT<DataT>::fillBitVector(const ExecuteInfo & exec_info) template <typename DataT> void -PostingListSearchContextT<DataT>::fetchPostings(const ExecuteInfo & exec_info) +PostingListSearchContextT<DataT>::fetchPostings(const ExecuteInfo & exec_info, bool strict) { // The following constant is derived after running parts of // the range search performance test with 10M documents on an Apple M1 Pro with 32 GB memory. @@ -168,7 +168,7 @@ PostingListSearchContextT<DataT>::fetchPostings(const ExecuteInfo & exec_info) // The threshold for when to use array merging is therefore 0.0025 (0.08 / 32). constexpr float threshold_for_using_array = 0.0025; if (!_merger.merge_done() && _uniqueValues >= 2u && this->_dictionary.get_has_btree_dictionary()) { - if (exec_info.is_strict() || use_posting_lists_when_non_strict(exec_info)) { + if (strict || use_posting_lists_when_non_strict(exec_info)) { size_t sum = estimated_hits_in_range(); //TODO Honour soft_doom and forward it to merge code if (sum < (_docIdLimit * threshold_for_using_array)) { diff --git a/searchlib/src/vespa/searchlib/attribute/search_context.cpp b/searchlib/src/vespa/searchlib/attribute/search_context.cpp index 0c0318bf1e3..2b68cf58ae6 100644 --- a/searchlib/src/vespa/searchlib/attribute/search_context.cpp +++ b/searchlib/src/vespa/searchlib/attribute/search_context.cpp @@ -50,10 +50,10 @@ SearchContext::createFilterIterator(fef::TermFieldMatchData* matchData, bool str void -SearchContext::fetchPostings(const queryeval::ExecuteInfo& execInfo) +SearchContext::fetchPostings(const queryeval::ExecuteInfo& execInfo, bool strict) { if (_plsc != nullptr) { - _plsc->fetchPostings(execInfo); + _plsc->fetchPostings(execInfo, strict); } } diff --git a/searchlib/src/vespa/searchlib/attribute/search_context.h b/searchlib/src/vespa/searchlib/attribute/search_context.h index a18e15ae8f4..1b17a27b6db 100644 --- a/searchlib/src/vespa/searchlib/attribute/search_context.h +++ b/searchlib/src/vespa/searchlib/attribute/search_context.h @@ -34,7 +34,7 @@ public: HitEstimate calc_hit_estimate() const override; std::unique_ptr<queryeval::SearchIterator> createIterator(fef::TermFieldMatchData* matchData, bool strict) override; - void fetchPostings(const queryeval::ExecuteInfo& execInfo) override; + void fetchPostings(const queryeval::ExecuteInfo& execInfo, bool strict) override; bool valid() const override { return false; } Int64Range getAsIntegerTerm() const override { return Int64Range(); } DoubleRange getAsDoubleTerm() const override { return DoubleRange(); } diff --git a/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp b/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp index 4713f452adc..b635e207a4f 100644 --- a/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp +++ b/searchlib/src/vespa/searchlib/attribute/singleboolattribute.cpp @@ -130,7 +130,7 @@ public: std::unique_ptr<queryeval::SearchIterator> createFilterIterator(fef::TermFieldMatchData * matchData, bool strict) override; - void fetchPostings(const queryeval::ExecuteInfo &execInfo) override; + void fetchPostings(const queryeval::ExecuteInfo &execInfo, bool strict) override; std::unique_ptr<queryeval::SearchIterator> createPostingIterator(fef::TermFieldMatchData *matchData, bool strict) override; HitEstimate calc_hit_estimate() const override; uint32_t get_committed_docid_limit() const noexcept override; @@ -162,7 +162,7 @@ BitVectorSearchContext::createFilterIterator(fef::TermFieldMatchData * matchData } void -BitVectorSearchContext::fetchPostings(const queryeval::ExecuteInfo &) { +BitVectorSearchContext::fetchPostings(const queryeval::ExecuteInfo &, bool) { } std::unique_ptr<queryeval::SearchIterator> diff --git a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp index 99be653a398..c0d0b1baa8c 100644 --- a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp +++ b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.cpp @@ -76,12 +76,12 @@ DiskTermBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -DiskTermBlueprint::createLeafSearch(const TermFieldMatchDataArray & tfmda, bool strict) const +DiskTermBlueprint::createLeafSearch(const TermFieldMatchDataArray & tfmda) const { if (_bitVector && (_useBitVector || tfmda[0]->isNotNeeded())) { LOG(debug, "Return BitVectorIterator: %s, wordNum(%" PRIu64 "), docCount(%" PRIu64 ")", getName(_lookupRes->indexId).c_str(), _lookupRes->wordNum, _lookupRes->counts._numDocs); - return BitVectorIterator::create(_bitVector.get(), *tfmda[0], strict); + return BitVectorIterator::create(_bitVector.get(), *tfmda[0], strict()); } SearchIterator::UP search(_postingHandle->createIterator(_lookupRes->counts, tfmda, _useBitVector)); if (_useBitVector) { @@ -95,12 +95,12 @@ DiskTermBlueprint::createLeafSearch(const TermFieldMatchDataArray & tfmda, bool } SearchIterator::UP -DiskTermBlueprint::createFilterSearch(bool strict, FilterConstraint) const +DiskTermBlueprint::createFilterSearch(FilterConstraint) const { auto wrapper = std::make_unique<queryeval::FilterWrapper>(getState().numFields()); auto & tfmda = wrapper->tfmda(); if (_bitVector) { - wrapper->wrap(BitVectorIterator::create(_bitVector.get(), *tfmda[0], strict)); + wrapper->wrap(BitVectorIterator::create(_bitVector.get(), *tfmda[0], strict())); } else { wrapper->wrap(_postingHandle->createIterator(_lookupRes->counts, tfmda, _useBitVector)); } diff --git a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.h b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.h index a8754663aab..abdecf29c45 100644 --- a/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.h +++ b/searchlib/src/vespa/searchlib/diskindex/disktermblueprint.h @@ -41,11 +41,11 @@ public: // Inherit doc from Blueprint. // For now, this DiskTermBlueprint instance must have longer lifetime than the created iterator. - std::unique_ptr<queryeval::SearchIterator> createLeafSearch(const fef::TermFieldMatchDataArray & tfmda, bool strict) const override; + std::unique_ptr<queryeval::SearchIterator> createLeafSearch(const fef::TermFieldMatchDataArray & tfmda) const override; void fetchPostings(const queryeval::ExecuteInfo &execInfo) override; - std::unique_ptr<queryeval::SearchIterator> createFilterSearch(bool strict, FilterConstraint) const override; + std::unique_ptr<queryeval::SearchIterator> createFilterSearch(FilterConstraint) const override; void visitMembers(vespalib::ObjectVisitor& visitor) const override; }; diff --git a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp index e2bb5e76751..eba135d8519 100644 --- a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp +++ b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp @@ -264,7 +264,7 @@ public: return {rel_est, btree_cost(), btree_strict_cost(rel_est)}; } - SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray& tfmda, bool) const override { + SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray& tfmda) const override { auto result = make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda); if (_use_bit_vector) { LOG(debug, "Return BooleanMatchIteratorWrapper: field_id(%u), doc_count(%zu)", @@ -276,7 +276,7 @@ public: return result; } - SearchIterator::UP createFilterSearch(bool, FilterConstraint) const override { + SearchIterator::UP createFilterSearch(FilterConstraint) const override { auto wrapper = std::make_unique<queryeval::FilterWrapper>(getState().numFields()); auto & tfmda = wrapper->tfmda(); wrapper->wrap(make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda)); diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp index 5f3cf0567bc..78bcd33fcb4 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp @@ -121,12 +121,41 @@ Blueprint::Blueprint() noexcept _flow_stats(0.0, 0.0, 0.0), _sourceId(0xffffffff), _docid_limit(0), + _strict(false), _frozen(false) { } Blueprint::~Blueprint() = default; +void +Blueprint::each_node_post_order(const std::function<void(Blueprint&)> &f) +{ + f(*this); +} + +void +Blueprint::basic_plan(InFlow in_flow, uint32_t docid_limit) +{ + setDocIdLimit(docid_limit); + each_node_post_order([docid_limit](Blueprint &bp){ + bp.update_flow_stats(docid_limit); + }); + auto opts = Options().sort_by_cost(true); + sort(in_flow, opts); +} + +void +Blueprint::null_plan(InFlow in_flow, uint32_t docid_limit) +{ + setDocIdLimit(docid_limit); + each_node_post_order([docid_limit](Blueprint &bp){ + bp.update_flow_stats(docid_limit); + }); + auto opts = Options().sort_by_cost(true).keep_order(true); + sort(in_flow, opts); +} + Blueprint::UP Blueprint::optimize(Blueprint::UP bp) { Blueprint *root = bp.release(); @@ -194,10 +223,6 @@ Blueprint::FilterConstraint invert(Blueprint::FilterConstraint constraint) { abort(); } -template <typename Op> bool inherit_strict(size_t); -template <> bool inherit_strict<AndSearch>(size_t i) { return (i == 0); } -template <> bool inherit_strict<OrSearch>(size_t) { return true; } - template <typename Op> bool should_short_circuit(Trinary); template <> bool should_short_circuit<AndSearch>(Trinary matches_any) { return (matches_any == Trinary::False); } template <> bool should_short_circuit<OrSearch>(Trinary matches_any) { return (matches_any == Trinary::True); } @@ -217,8 +242,7 @@ create_op_filter(const Blueprint::Children &children, bool strict, Blueprint::Fi std::unique_ptr<SearchIterator> spare; list.reserve(children.size()); for (size_t i = 0; i < children.size(); ++i) { - auto strict_child = strict && inherit_strict<Op>(i); - auto filter = children[i]->createFilterSearch(strict_child, constraint); + auto filter = children[i]->createFilterSearch(constraint); auto matches_any = filter->matches_any(); if (should_short_circuit<Op>(matches_any)) { return filter; @@ -281,14 +305,14 @@ Blueprint::create_andnot_filter(const Children &children, bool strict, Blueprint MultiSearch::Children list; list.reserve(children.size()); { - auto filter = children[0]->createFilterSearch(strict, constraint); + auto filter = children[0]->createFilterSearch(constraint); if (filter->matches_any() == Trinary::False) { return filter; } list.push_back(std::move(filter)); } for (size_t i = 1; i < children.size(); ++i) { - auto filter = children[i]->createFilterSearch(false, invert(constraint)); + auto filter = children[i]->createFilterSearch(invert(constraint)); auto matches_any = filter->matches_any(); if (matches_any == Trinary::True) { return std::make_unique<EmptySearch>(); @@ -305,14 +329,14 @@ Blueprint::create_andnot_filter(const Children &children, bool strict, Blueprint } std::unique_ptr<SearchIterator> -Blueprint::create_first_child_filter(const Children &children, bool strict, Blueprint::FilterConstraint constraint) +Blueprint::create_first_child_filter(const Children &children, Blueprint::FilterConstraint constraint) { REQUIRE(!children.empty()); - return children[0]->createFilterSearch(strict, constraint); + return children[0]->createFilterSearch(constraint); } std::unique_ptr<SearchIterator> -Blueprint::create_default_filter(bool, FilterConstraint constraint) +Blueprint::create_default_filter(FilterConstraint constraint) { if (constraint == FilterConstraint::UPPER_BOUND) { return std::make_unique<FullSearch>(); @@ -374,6 +398,7 @@ Blueprint::visitMembers(vespalib::ObjectVisitor &visitor) const visitor.visitFloat("strict_cost", strict_cost()); visitor.visitInt("sourceId", _sourceId); visitor.visitInt("docid_limit", _docid_limit); + // visitor.visitBool("strict", _strict); } namespace blueprint { @@ -412,6 +437,15 @@ IntermediateBlueprint::setDocIdLimit(uint32_t limit) noexcept } } +void +IntermediateBlueprint::each_node_post_order(const std::function<void(Blueprint&)> &f) +{ + for (Blueprint::UP &child : _children) { + f(*child); + } + f(*this); +} + Blueprint::HitEstimate IntermediateBlueprint::calculateEstimate() const { @@ -568,17 +602,18 @@ IntermediateBlueprint::optimize(Blueprint* &self, OptimizePass pass) maybe_eliminate_self(self, get_replacement()); } -double +void IntermediateBlueprint::sort(InFlow in_flow, const Options &opts) { - sort(_children, in_flow.strict(), opts.sort_by_cost()); + strict(in_flow.strict()); // authorative strict tag (->fetchPostings,->createSearch,->createFilterSearch) + if (!opts.keep_order()) [[likely]] { + sort(_children, in_flow.strict(), opts.sort_by_cost()); + } auto flow = my_flow(in_flow); for (size_t i = 0; i < _children.size(); ++i) { _children[i]->sort(InFlow(flow.strict(), flow.flow()), opts); flow.add(_children[i]->estimate()); } - // TODO: better cost estimate (due to known in-flow and eagerness) - return in_flow.strict() ? strict_cost() : in_flow.rate() * cost(); } void @@ -592,15 +627,14 @@ IntermediateBlueprint::set_global_filter(const GlobalFilter &global_filter, doub } SearchIterator::UP -IntermediateBlueprint::createSearch(fef::MatchData &md, bool strict) const +IntermediateBlueprint::createSearch(fef::MatchData &md) const { MultiSearch::Children subSearches; subSearches.reserve(_children.size()); for (size_t i = 0; i < _children.size(); ++i) { - bool strictChild = (strict && inheritStrict(i)); - subSearches.push_back(_children[i]->createSearch(md, strictChild)); + subSearches.push_back(_children[i]->createSearch(md)); } - return createIntermediateSearch(std::move(subSearches), strict, md); + return createIntermediateSearch(std::move(subSearches), md); } IntermediateBlueprint::IntermediateBlueprint() noexcept = default; @@ -645,11 +679,11 @@ IntermediateBlueprint::visitMembers(vespalib::ObjectVisitor &visitor) const void IntermediateBlueprint::fetchPostings(const ExecuteInfo &execInfo) { - auto flow = my_flow(InFlow(execInfo.is_strict(), execInfo.hit_rate())); + auto flow = my_flow(InFlow(strict(), execInfo.hit_rate())); for (size_t i = 0; i < _children.size(); ++i) { double nextHitRate = flow.flow(); Blueprint & child = *_children[i]; - child.fetchPostings(ExecuteInfo::create(execInfo.is_strict() && inheritStrict(i), nextHitRate, execInfo)); + child.fetchPostings(ExecuteInfo::create(nextHitRate, execInfo)); flow.add(child.estimate()); } } @@ -738,7 +772,7 @@ LeafBlueprint::freeze() } SearchIterator::UP -LeafBlueprint::createSearch(fef::MatchData &md, bool strict) const +LeafBlueprint::createSearch(fef::MatchData &md) const { const State &state = getState(); fef::TermFieldMatchDataArray tfmda; @@ -746,7 +780,7 @@ LeafBlueprint::createSearch(fef::MatchData &md, bool strict) const for (size_t i = 0; i < state.numFields(); ++i) { tfmda.add(state.field(i).resolve(md)); } - return createLeafSearch(tfmda, strict); + return createLeafSearch(tfmda); } bool @@ -765,13 +799,6 @@ LeafBlueprint::optimize(Blueprint* &self, OptimizePass pass) maybe_eliminate_self(self, get_replacement()); } -double -LeafBlueprint::sort(InFlow in_flow, const Options &) -{ - // TODO: better cost estimate (due to known in-flow and eagerness) - return in_flow.strict() ? strict_cost() : in_flow.rate() * cost(); -} - void LeafBlueprint::set_cost_tier(uint32_t value) { @@ -796,6 +823,12 @@ LeafBlueprint::set_tree_size(uint32_t value) //----------------------------------------------------------------------------- +void +SimpleLeafBlueprint::sort(InFlow in_flow, const Options &) +{ + strict(in_flow.strict()); // authorative strict tag (->fetchPostings,->createSearch,->createFilterSearch) +} + } void visit(vespalib::ObjectVisitor &self, const vespalib::string &name, diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.h b/searchlib/src/vespa/searchlib/queryeval/blueprint.h index b2edfb8a3ba..0fc5c690a25 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.h @@ -59,6 +59,7 @@ public: private: bool _sort_by_cost; bool _allow_force_strict; + bool _keep_order; public: constexpr Options() noexcept : _sort_by_cost(false), @@ -73,8 +74,13 @@ public: _allow_force_strict = value; return *this; } - static constexpr Options all() noexcept { - return Options().sort_by_cost(true).allow_force_strict(true); + constexpr bool keep_order() const noexcept { return _keep_order; } + constexpr Options &keep_order(bool value) noexcept { + _keep_order = value; + return *this; + } + static Options default_options() noexcept { + return Options().sort_by_cost(true); } }; @@ -205,6 +211,7 @@ private: FlowStats _flow_stats; uint32_t _sourceId; uint32_t _docid_limit; + bool _strict; bool _frozen; protected: @@ -218,6 +225,12 @@ protected: _frozen = true; } + // Should be called by sort; sort is responsible for propagating + // strict tagging throughout the blueprint tree. Note that calling + // this directly breaks some tests using leaf proxy decorators + // that are not able to forward the non-virtual call. + void strict(bool value) noexcept { _strict = value; } + public: class IPredicate { public: @@ -246,13 +259,44 @@ public: virtual void setDocIdLimit(uint32_t limit) noexcept { _docid_limit = limit; } uint32_t get_docid_limit() const noexcept { return _docid_limit; } + bool strict() const noexcept { return _strict; } + + virtual void each_node_post_order(const std::function<void(Blueprint&)> &f); + + // The combination of 'optimize' (2 passes bottom-up) and 'sort' + // (1 pass top-down) is considered 'planning'. Flow stats are + // calculated during the last optimize pass (which itself requires + // knowledge about the docid limit) and strict tagging is done + // during sorting. Strict tagging is needed for fetchPostings + // (which also needs the estimate part of the flow stats), + // createSearch and createFilterSearch to work correctly. This + // means we always need to perform some form of planning. + // + // This function will perform basic planning. The docid limit will + // be tagged on all nodes, flow stats will be calculated for all + // nodes, sorting will be performed based on optimal flow cost and + // strict tagging will be conservative. The only structural change + // allowed is child node reordering. + void basic_plan(InFlow in_flow, uint32_t docid_limit); + + // Similar to basic_plan, but will not reorder children. Note that + // this means that flow stats will be misleading as they assume + // optimal ordering. Used for testing. + void null_plan(InFlow in_flow, uint32_t docid_limit); + static Blueprint::UP optimize(Blueprint::UP bp); - virtual double sort(InFlow in_flow, const Options &opts) = 0; + virtual void sort(InFlow in_flow, const Options &opts) = 0; static Blueprint::UP optimize_and_sort(Blueprint::UP bp, InFlow in_flow, const Options &opts) { auto result = optimize(std::move(bp)); result->sort(in_flow, opts); return result; } + static Blueprint::UP optimize_and_sort(Blueprint::UP bp, InFlow in_flow) { + return optimize_and_sort(std::move(bp), in_flow, Options::default_options()); + } + static Blueprint::UP optimize_and_sort(Blueprint::UP bp) { + return optimize_and_sort(std::move(bp), true, Options::default_options()); + } virtual void optimize(Blueprint* &self, OptimizePass pass) = 0; virtual void optimize_self(OptimizePass pass); virtual Blueprint::UP get_replacement(); @@ -308,15 +352,15 @@ public: virtual void freeze() = 0; bool frozen() const { return _frozen; } - virtual SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const = 0; - virtual SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const = 0; + virtual SearchIteratorUP createSearch(fef::MatchData &md) const = 0; + virtual SearchIteratorUP createFilterSearch(FilterConstraint constraint) const = 0; static SearchIteratorUP create_and_filter(const Children &children, bool strict, FilterConstraint constraint); static SearchIteratorUP create_or_filter(const Children &children, bool strict, FilterConstraint constraint); static SearchIteratorUP create_atmost_and_filter(const Children &children, bool strict, FilterConstraint constraint); static SearchIteratorUP create_atmost_or_filter(const Children &children, bool strict, FilterConstraint constraint); static SearchIteratorUP create_andnot_filter(const Children &children, bool strict, FilterConstraint constraint); - static SearchIteratorUP create_first_child_filter(const Children &children, bool strict, FilterConstraint constraint); - static SearchIteratorUP create_default_filter(bool strict, FilterConstraint constraint); + static SearchIteratorUP create_first_child_filter(const Children &children, FilterConstraint constraint); + static SearchIteratorUP create_default_filter(FilterConstraint constraint); // for debug dumping vespalib::string asString() const; @@ -406,9 +450,10 @@ public: ~IntermediateBlueprint() override; void setDocIdLimit(uint32_t limit) noexcept final; + void each_node_post_order(const std::function<void(Blueprint&)> &f) override; void optimize(Blueprint* &self, OptimizePass pass) final; - double sort(InFlow in_flow, const Options &opts) override; + void sort(InFlow in_flow, const Options &opts) override; void set_global_filter(const GlobalFilter &global_filter, double estimated_hit_ratio) override; IndexList find(const IPredicate & check) const; @@ -420,15 +465,13 @@ public: 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; + SearchIteratorUP createSearch(fef::MatchData &md) const override; virtual HitEstimate combine(const std::vector<HitEstimate> &data) const = 0; virtual FieldSpecBaseList exposeFields() const = 0; virtual void sort(Children &children, bool strict, bool sort_by_cost) const = 0; - virtual bool inheritStrict(size_t i) const = 0; virtual SearchIteratorUP - createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const = 0; + createIntermediateSearch(MultiSearch::Children subSearches, fef::MatchData &md) const = 0; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void fetchPostings(const ExecuteInfo &execInfo) override; @@ -445,7 +488,6 @@ private: State _state; protected: void optimize(Blueprint* &self, OptimizePass pass) final; - double sort(InFlow in_flow, const Options &opts) override; void setEstimate(HitEstimate est) { _state.estimate(est); notifyChange(); @@ -480,11 +522,11 @@ public: const State &getState() const final { return _state; } void fetchPostings(const ExecuteInfo &execInfo) override; void freeze() final; - SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; + SearchIteratorUP createSearch(fef::MatchData &md) const override; const LeafBlueprint * asLeaf() const noexcept final { return this; } virtual bool getRange(vespalib::string & from, vespalib::string & to) const; - virtual SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const = 0; + virtual SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const = 0; }; // for leaf nodes representing a single term @@ -492,6 +534,7 @@ struct SimpleLeafBlueprint : LeafBlueprint { explicit SimpleLeafBlueprint() noexcept : LeafBlueprint(true) {} explicit SimpleLeafBlueprint(FieldSpecBase field) noexcept : LeafBlueprint(field, true) {} explicit SimpleLeafBlueprint(FieldSpecBaseList fields) noexcept: LeafBlueprint(std::move(fields), true) {} + void sort(InFlow in_flow, const Options &opts) override; }; // for leaf nodes representing more complex structures like wand/phrase diff --git a/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.cpp index 7cd00d02bb3..7491215cb59 100644 --- a/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.cpp @@ -39,6 +39,15 @@ DotProductBlueprint::addTerm(Blueprint::UP term, int32_t weight, HitEstimate & e _terms.push_back(std::move(term)); } +void +DotProductBlueprint::sort(InFlow, const Options &opts) +{ + strict(true); + for (auto &term: _terms) { + term->sort(true, opts); + } +} + FlowStats DotProductBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -51,7 +60,7 @@ DotProductBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -DotProductBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool) const +DotProductBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); assert(getState().numFields() == 1); @@ -63,16 +72,16 @@ DotProductBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray assert(childState.numFields() == 1); childMatch.push_back(childState.field(0).resolve(*md)); // TODO: pass ownership with unique_ptr - children[i] = _terms[i]->createSearch(*md, true).release(); + children[i] = _terms[i]->createSearch(*md).release(); } bool field_is_filter = getState().fields()[0].isFilter(); return DotProductSearch::create(children, *tfmda[0], field_is_filter, childMatch, _weights, std::move(md)); } SearchIterator::UP -DotProductBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +DotProductBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_or_filter(_terms, strict, constraint); + return create_or_filter(_terms, strict(), constraint); } void diff --git a/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.h index ca59f84fce8..370895dd94f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/dot_product_blueprint.h @@ -33,10 +33,11 @@ public: setEstimate(estimate); } + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIteratorUP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIteratorUP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void fetchPostings(const ExecuteInfo &execInfo) override; diff --git a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.cpp index 27624abf515..c42f05b64c7 100644 --- a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.cpp @@ -53,6 +53,17 @@ EquivBlueprint::EquivBlueprint(FieldSpecBaseList fields, EquivBlueprint::~EquivBlueprint() = default; +void +EquivBlueprint::sort(InFlow in_flow, const Options &opts) +{ + strict(in_flow.strict()); + auto flow = OrFlow(in_flow); + for (auto &term: _terms) { + term->sort(InFlow(flow.strict(), flow.flow()), opts); + flow.add(term->estimate()); + } +} + FlowStats EquivBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -65,7 +76,7 @@ EquivBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -EquivBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &outputs, bool strict) const +EquivBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &outputs) const { fef::MatchData::UP md = _layout.createMatchData(); MultiSearch::Children children; @@ -82,15 +93,15 @@ EquivBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &outputs, bo unpack_needs[child_term_field_match_data->getFieldId()].notify(*child_term_field_match_data); childMatch.emplace_back(child_term_field_match_data, _exactness[i]); } - children.push_back(_terms[i]->createSearch(*md, strict)); + children.push_back(_terms[i]->createSearch(*md)); } - return EquivSearch::create(std::move(children), std::move(md), childMatch, outputs, strict); + return EquivSearch::create(std::move(children), std::move(md), childMatch, outputs, strict()); } SearchIterator::UP -EquivBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +EquivBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_or_filter(_terms, strict, constraint); + return create_or_filter(_terms, strict(), constraint); } void diff --git a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h index 27e990b3320..147f8269ecd 100644 --- a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h @@ -22,10 +22,11 @@ public: // used by create visitor EquivBlueprint& addTerm(Blueprint::UP term, double exactness); + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void fetchPostings(const ExecuteInfo &execInfo) override; diff --git a/searchlib/src/vespa/searchlib/queryeval/executeinfo.cpp b/searchlib/src/vespa/searchlib/queryeval/executeinfo.cpp index c9ec6edb225..9bdc005529d 100644 --- a/searchlib/src/vespa/searchlib/queryeval/executeinfo.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/executeinfo.cpp @@ -5,16 +5,15 @@ using vespalib::Doom; namespace search::queryeval { -const ExecuteInfo ExecuteInfo::TRUE(true, 1.0, Doom::never(), vespalib::ThreadBundle::trivial()); -const ExecuteInfo ExecuteInfo::FALSE(false, 1.0, Doom::never(), vespalib::ThreadBundle::trivial()); +const ExecuteInfo ExecuteInfo::FULL(1.0, Doom::never(), vespalib::ThreadBundle::trivial()); ExecuteInfo::ExecuteInfo() noexcept - : ExecuteInfo(false, 1.0, Doom::never(), vespalib::ThreadBundle::trivial()) + : ExecuteInfo(1.0, Doom::never(), vespalib::ThreadBundle::trivial()) { } ExecuteInfo -ExecuteInfo::createForTest(bool strict, double hitRate) noexcept { - return createForTest(strict, hitRate, Doom::never()); +ExecuteInfo::createForTest(double hitRate) noexcept { + return createForTest(hitRate, Doom::never()); } } diff --git a/searchlib/src/vespa/searchlib/queryeval/executeinfo.h b/searchlib/src/vespa/searchlib/queryeval/executeinfo.h index fa2c69e0400..4f9cf8ebdc1 100644 --- a/searchlib/src/vespa/searchlib/queryeval/executeinfo.h +++ b/searchlib/src/vespa/searchlib/queryeval/executeinfo.h @@ -14,44 +14,40 @@ namespace search::queryeval { class ExecuteInfo { public: ExecuteInfo() noexcept; - bool is_strict() const noexcept { return _strict; } double hit_rate() const noexcept { return _hitRate; } const vespalib::Doom & doom() const noexcept { return _doom; } vespalib::ThreadBundle & thread_bundle() const noexcept { return _thread_bundle; } - static const ExecuteInfo TRUE; - static const ExecuteInfo FALSE; - static ExecuteInfo create(bool strict, const ExecuteInfo & org) noexcept { - return create(strict, org._hitRate, org); + static const ExecuteInfo FULL; + static ExecuteInfo create(const ExecuteInfo & org) noexcept { + return create(org._hitRate, org); } - static ExecuteInfo create(bool strict, double hitRate, const ExecuteInfo & org) noexcept { - return {strict, hitRate, org._doom, org.thread_bundle()}; + static ExecuteInfo create(double hitRate, const ExecuteInfo & org) noexcept { + return {hitRate, org._doom, org.thread_bundle()}; } - static ExecuteInfo create(bool strict, double hitRate, const vespalib::Doom & doom, + static ExecuteInfo create(double hitRate, const vespalib::Doom & doom, vespalib::ThreadBundle & thread_bundle_in) noexcept { - return {strict, hitRate, doom, thread_bundle_in}; + return {hitRate, doom, thread_bundle_in}; } - static ExecuteInfo createForTest(bool strict) noexcept { - return createForTest(strict, 1.0); + static ExecuteInfo createForTest() noexcept { + return createForTest(1.0); } - static ExecuteInfo createForTest(bool strict, double hitRate) noexcept; - static ExecuteInfo createForTest(bool strict, double hitRate, const vespalib::Doom & doom) noexcept { - return create(strict, hitRate, doom, vespalib::ThreadBundle::trivial()); + static ExecuteInfo createForTest(double hitRate) noexcept; + static ExecuteInfo createForTest(double hitRate, const vespalib::Doom & doom) noexcept { + return create(hitRate, doom, vespalib::ThreadBundle::trivial()); } private: - ExecuteInfo(bool strict, double hitRate_in, const vespalib::Doom & doom, + ExecuteInfo(double hitRate_in, const vespalib::Doom & doom, vespalib::ThreadBundle & thread_bundle_in) noexcept : _doom(doom), _thread_bundle(thread_bundle_in), - _hitRate(hitRate_in), - _strict(strict) + _hitRate(hitRate_in) { } const vespalib::Doom _doom; vespalib::ThreadBundle & _thread_bundle; double _hitRate; - bool _strict; }; } diff --git a/searchlib/src/vespa/searchlib/queryeval/global_filter.cpp b/searchlib/src/vespa/searchlib/queryeval/global_filter.cpp index ef00d7a3a75..b3ca97cd053 100644 --- a/searchlib/src/vespa/searchlib/queryeval/global_filter.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/global_filter.cpp @@ -109,9 +109,8 @@ struct MakePart : Runnable { bool is_first_thread() const { return (begin == 1); } bool should_trace(int level) const { return trace && trace->shouldTrace(level); } void run() override { - bool strict = true; auto constraint = Blueprint::FilterConstraint::UPPER_BOUND; - auto filter = blueprint.createFilterSearch(strict, constraint); + auto filter = blueprint.createFilterSearch(constraint); if (is_first_thread() && should_trace(7)) { vespalib::slime::ObjectInserter inserter(trace->createCursor("iterator"), "optimized"); filter->asSlime(inserter); diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp index bc8eaa98541..fb1bb0b6cf1 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp @@ -173,20 +173,15 @@ AndNotBlueprint::sort(Children &children, bool strict, bool sort_by_cost) const } } -bool -AndNotBlueprint::inheritStrict(size_t i) const -{ - return (i == 0); -} - SearchIterator::UP AndNotBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData &md) const + search::fef::MatchData &md) const { UnpackInfo unpack_info(calculateUnpackInfo(md)); if (should_do_termwise_eval(unpack_info, md.get_termwise_limit())) { TermwiseBlueprintHelper helper(*this, std::move(sub_searches), unpack_info); - bool termwise_strict = (strict && inheritStrict(helper.first_termwise)); + bool termwise_strict = ((helper.first_termwise < childCnt()) && + getChild(helper.first_termwise).strict()); auto termwise_search = (helper.first_termwise == 0) ? AndNotSearch::create(helper.get_termwise_children(), termwise_strict) : OrSearch::create(helper.get_termwise_children(), termwise_strict); @@ -195,15 +190,15 @@ AndNotBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, if (rearranged.size() == 1) { return std::move(rearranged[0]); } - return AndNotSearch::create(std::move(rearranged), strict); + return AndNotSearch::create(std::move(rearranged), strict()); } - return AndNotSearch::create(std::move(sub_searches), strict); + return AndNotSearch::create(std::move(sub_searches), strict()); } SearchIterator::UP -AndNotBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +AndNotBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_andnot_filter(get_children(), strict, constraint); + return create_andnot_filter(get_children(), strict(), constraint); } @@ -271,40 +266,35 @@ AndBlueprint::sort(Children &children, bool strict, bool sort_by_cost) const } } -bool -AndBlueprint::inheritStrict(size_t i) const -{ - return (i == 0); -} - SearchIterator::UP AndBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData & md) const + search::fef::MatchData & md) const { UnpackInfo unpack_info(calculateUnpackInfo(md)); std::unique_ptr<AndSearch> search; if (should_do_termwise_eval(unpack_info, md.get_termwise_limit())) { TermwiseBlueprintHelper helper(*this, std::move(sub_searches), unpack_info); - bool termwise_strict = (strict && inheritStrict(helper.first_termwise)); + bool termwise_strict = ((helper.first_termwise < childCnt()) && + getChild(helper.first_termwise).strict()); auto termwise_search = AndSearch::create(helper.get_termwise_children(), termwise_strict); helper.insert_termwise(std::move(termwise_search), termwise_strict); auto rearranged = helper.get_result(); if (rearranged.size() == 1) { return std::move(rearranged[0]); } else { - search = AndSearch::create(std::move(rearranged), strict, helper.termwise_unpack); + search = AndSearch::create(std::move(rearranged), strict(), helper.termwise_unpack); } } else { - search = AndSearch::create(std::move(sub_searches), strict, unpack_info); + search = AndSearch::create(std::move(sub_searches), strict(), unpack_info); } search->estimate(getState().estimate().estHits); return search; } SearchIterator::UP -AndBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +AndBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_and_filter(get_children(), strict, constraint); + return create_and_filter(get_children(), strict(), constraint); } AnyFlow @@ -376,35 +366,30 @@ OrBlueprint::sort(Children &children, bool strict, bool sort_by_cost) const } } -bool -OrBlueprint::inheritStrict(size_t) const -{ - return true; -} - SearchIterator::UP OrBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData & md) const + search::fef::MatchData & md) const { UnpackInfo unpack_info(calculateUnpackInfo(md)); if (should_do_termwise_eval(unpack_info, md.get_termwise_limit())) { TermwiseBlueprintHelper helper(*this, std::move(sub_searches), unpack_info); - bool termwise_strict = (strict && inheritStrict(helper.first_termwise)); + bool termwise_strict = ((helper.first_termwise < childCnt()) && + getChild(helper.first_termwise).strict()); auto termwise_search = OrSearch::create(helper.get_termwise_children(), termwise_strict); helper.insert_termwise(std::move(termwise_search), termwise_strict); auto rearranged = helper.get_result(); if (rearranged.size() == 1) { return std::move(rearranged[0]); } - return OrSearch::create(std::move(rearranged), strict, helper.termwise_unpack); + return OrSearch::create(std::move(rearranged), strict(), helper.termwise_unpack); } - return OrSearch::create(std::move(sub_searches), strict, unpack_info); + return OrSearch::create(std::move(sub_searches), strict(), unpack_info); } SearchIterator::UP -OrBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +OrBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_or_filter(get_children(), strict, constraint); + return create_or_filter(get_children(), strict(), constraint); } AnyFlow @@ -467,12 +452,6 @@ WeakAndBlueprint::sort(Children &, bool, bool) const } bool -WeakAndBlueprint::inheritStrict(size_t) const -{ - return true; -} - -bool WeakAndBlueprint::always_needs_unpack() const { return true; @@ -480,7 +459,7 @@ WeakAndBlueprint::always_needs_unpack() const SearchIterator::UP WeakAndBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData &) const + search::fef::MatchData &) const { WeakAndSearch::Terms terms; assert(sub_searches.size() == childCnt()); @@ -491,13 +470,13 @@ WeakAndBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, _weights[i], getChild(i).getState().estimate().estHits); } - return WeakAndSearch::create(terms, _n, strict); + return WeakAndSearch::create(terms, _n, strict()); } SearchIterator::UP -WeakAndBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +WeakAndBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_or_filter(get_children(), strict, constraint); + return create_atmost_or_filter(get_children(), strict(), constraint); } //----------------------------------------------------------------------------- @@ -538,22 +517,16 @@ NearBlueprint::sort(Children &children, bool strict, bool sort_by_cost) const } } -bool -NearBlueprint::inheritStrict(size_t i) const -{ - return (i == 0); -} - SearchIterator::UP -NearBlueprint::createSearch(fef::MatchData &md, bool strict) const +NearBlueprint::createSearch(fef::MatchData &md) const { need_normal_features_for_children(*this, md); - return IntermediateBlueprint::createSearch(md, strict); + return IntermediateBlueprint::createSearch(md); } SearchIterator::UP NearBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData &md) const + search::fef::MatchData &md) const { search::fef::TermFieldMatchDataArray tfmda; for (size_t i = 0; i < childCnt(); ++i) { @@ -562,13 +535,13 @@ NearBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, tfmda.add(cs.field(j).resolve(md)); } } - return SearchIterator::UP(new NearSearch(std::move(sub_searches), tfmda, _window, strict)); + return SearchIterator::UP(new NearSearch(std::move(sub_searches), tfmda, _window, strict())); } SearchIterator::UP -NearBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +NearBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_and_filter(get_children(), strict, constraint); + return create_atmost_and_filter(get_children(), strict(), constraint); } //----------------------------------------------------------------------------- @@ -605,22 +578,16 @@ ONearBlueprint::sort(Children &, bool, bool) const // ordered near cannot sort children here } -bool -ONearBlueprint::inheritStrict(size_t i) const -{ - return (i == 0); -} - SearchIterator::UP -ONearBlueprint::createSearch(fef::MatchData &md, bool strict) const +ONearBlueprint::createSearch(fef::MatchData &md) const { need_normal_features_for_children(*this, md); - return IntermediateBlueprint::createSearch(md, strict); + return IntermediateBlueprint::createSearch(md); } SearchIterator::UP ONearBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData &md) const + search::fef::MatchData &md) const { search::fef::TermFieldMatchDataArray tfmda; for (size_t i = 0; i < childCnt(); ++i) { @@ -631,13 +598,13 @@ ONearBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, } // could sort sub_searches here // but then strictness inheritance would also need to be fixed - return SearchIterator::UP(new ONearSearch(std::move(sub_searches), tfmda, _window, strict)); + return SearchIterator::UP(new ONearSearch(std::move(sub_searches), tfmda, _window, strict())); } SearchIterator::UP -ONearBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +ONearBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_and_filter(get_children(), strict, constraint); + return create_atmost_and_filter(get_children(), strict(), constraint); } //----------------------------------------------------------------------------- @@ -696,19 +663,13 @@ RankBlueprint::sort(Children &, bool, bool) const { } -bool -RankBlueprint::inheritStrict(size_t i) const -{ - return (i == 0); -} - SearchIterator::UP RankBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData & md) const + search::fef::MatchData & md) const { UnpackInfo unpack_info(calculateUnpackInfo(md)); if (unpack_info.unpackAll()) { - return RankSearch::create(std::move(sub_searches), strict); + return RankSearch::create(std::move(sub_searches), strict()); } else { MultiSearch::Children require_unpack; require_unpack.reserve(sub_searches.size()); @@ -723,15 +684,15 @@ RankBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, if (require_unpack.size() == 1) { return std::move(require_unpack[0]); } else { - return RankSearch::create(std::move(require_unpack), strict); + return RankSearch::create(std::move(require_unpack), strict()); } } } SearchIterator::UP -RankBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +RankBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_first_child_filter(get_children(), strict, constraint); + return create_first_child_filter(get_children(), constraint); } AnyFlow @@ -783,15 +744,9 @@ SourceBlenderBlueprint::sort(Children &, bool, bool) const { } -bool -SourceBlenderBlueprint::inheritStrict(size_t) const -{ - return true; -} - SearchIterator::UP SourceBlenderBlueprint::createIntermediateSearch(MultiSearch::Children sub_searches, - bool strict, search::fef::MatchData &) const + search::fef::MatchData &) const { SourceBlenderSearch::Children children; assert(sub_searches.size() == childCnt()); @@ -800,13 +755,13 @@ SourceBlenderBlueprint::createIntermediateSearch(MultiSearch::Children sub_searc children.emplace_back(sub_searches[i].release(), getChild(i).getSourceId()); assert(children.back().sourceId != 0xffffffff); } - return SourceBlenderSearch::create(_selector.createIterator(), children, strict); + return SourceBlenderSearch::create(_selector.createIterator(), children, strict()); } SearchIterator::UP -SourceBlenderBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +SourceBlenderBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_or_filter(get_children(), strict, constraint); + return create_atmost_or_filter(get_children(), strict(), constraint); } bool diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h index e0f4be4be06..5d6d098510f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h @@ -22,12 +22,11 @@ public: AndNotBlueprint * asAndNot() noexcept final { return this; } Blueprint::UP get_replacement() override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; + fef::MatchData &md) const override; SearchIterator::UP - createFilterSearch(bool strict, FilterConstraint constraint) const override; + createFilterSearch(FilterConstraint constraint) const override; private: AnyFlow my_flow(InFlow in_flow) const override; uint8_t calculate_cost_tier() const override { @@ -50,12 +49,11 @@ public: AndBlueprint * asAnd() noexcept final { return this; } Blueprint::UP get_replacement() override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; + fef::MatchData &md) const override; SearchIterator::UP - createFilterSearch(bool strict, FilterConstraint constraint) const override; + createFilterSearch(FilterConstraint constraint) const override; private: AnyFlow my_flow(InFlow in_flow) const override; }; @@ -75,12 +73,11 @@ public: OrBlueprint * asOr() noexcept final { return this; } Blueprint::UP get_replacement() override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; + fef::MatchData &md) const override; SearchIterator::UP - createFilterSearch(bool strict, FilterConstraint constraint) const override; + createFilterSearch(FilterConstraint constraint) const override; private: AnyFlow my_flow(InFlow in_flow) const override; uint8_t calculate_cost_tier() const override; @@ -100,13 +97,12 @@ public: HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children, bool strict, bool sort_on_cost) 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; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + fef::MatchData &md) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; explicit WeakAndBlueprint(uint32_t n) noexcept : _n(n) {} ~WeakAndBlueprint() override; @@ -131,12 +127,11 @@ public: HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; - SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; + SearchIteratorUP createSearch(fef::MatchData &md) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + fef::MatchData &md) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; explicit NearBlueprint(uint32_t window) noexcept : _window(window) {} }; @@ -154,12 +149,11 @@ public: HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; - SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; + SearchIteratorUP createSearch(fef::MatchData &md) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + fef::MatchData &md) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; explicit ONearBlueprint(uint32_t window) noexcept : _window(window) {} }; @@ -175,13 +169,12 @@ public: void optimize_self(OptimizePass pass) override; Blueprint::UP get_replacement() override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; bool isRank() const noexcept final { return true; } SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; + fef::MatchData &md) const override; SearchIterator::UP - createFilterSearch(bool strict, FilterConstraint constraint) const override; + createFilterSearch(FilterConstraint constraint) const override; uint8_t calculate_cost_tier() const override { return (childCnt() > 0) ? get_children()[0]->getState().cost_tier() : State::COST_TIER_NORMAL; } @@ -204,12 +197,11 @@ public: HitEstimate combine(const std::vector<HitEstimate> &data) const override; FieldSpecBaseList exposeFields() const override; void sort(Children &children, bool strict, bool sort_by_cost) const override; - bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, - bool strict, fef::MatchData &md) const override; + fef::MatchData &md) const override; SearchIterator::UP - createFilterSearch(bool strict, FilterConstraint constraint) const override; + createFilterSearch(FilterConstraint constraint) const override; /** check if this blueprint has the same source selector as the other */ bool isCompatibleWith(const SourceBlenderBlueprint &other) const; diff --git a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp index b12c2eea404..d825c9e1a20 100644 --- a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp @@ -17,13 +17,13 @@ EmptyBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -EmptyBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &, bool) const +EmptyBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &) const { return std::make_unique<EmptySearch>(); } SearchIterator::UP -EmptyBlueprint::createFilterSearch(bool /*strict*/, FilterConstraint /* constraint */) const +EmptyBlueprint::createFilterSearch(FilterConstraint /* constraint */) const { return std::make_unique<EmptySearch>(); } @@ -40,13 +40,13 @@ AlwaysTrueBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -AlwaysTrueBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &, bool) const +AlwaysTrueBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &) const { return std::make_unique<FullSearch>(); } SearchIterator::UP -AlwaysTrueBlueprint::createFilterSearch(bool /*strict*/, FilterConstraint /* constraint */) const +AlwaysTrueBlueprint::createFilterSearch(FilterConstraint /* constraint */) const { return std::make_unique<FullSearch>(); } @@ -65,19 +65,19 @@ SimpleBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -SimpleBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &, bool strict) const +SimpleBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &) const { - auto search = std::make_unique<SimpleSearch>(_result, strict); + auto search = std::make_unique<SimpleSearch>(_result, strict()); search->tag(_tag); return search; } SearchIterator::UP -SimpleBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +SimpleBlueprint::createFilterSearch(FilterConstraint constraint) const { - auto search = std::make_unique<SimpleSearch>(_result, strict); + auto search = std::make_unique<SimpleSearch>(_result, strict()); search->tag(_tag + - (strict ? "<strict," : "<nostrict,") + + (strict() ? "<strict," : "<nostrict,") + (constraint == FilterConstraint::UPPER_BOUND ? "upper>" : "lower>")); return search; } @@ -127,7 +127,7 @@ struct FakeContext : attribute::ISearchContext { } attribute::HitEstimate calc_hit_estimate() const override { return attribute::HitEstimate(0); } std::unique_ptr<SearchIterator> createIterator(fef::TermFieldMatchData *, bool) override { abort(); } - void fetchPostings(const ExecuteInfo &) override { } + void fetchPostings(const ExecuteInfo &, bool) override { } bool valid() const override { return true; } Int64Range getAsIntegerTerm() const override { abort(); } DoubleRange getAsDoubleTerm() const override { abort(); } @@ -146,7 +146,7 @@ FakeContext::get_committed_docid_limit() const noexcept } SearchIterator::UP -FakeBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const +FakeBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { auto result = std::make_unique<FakeSearch>(_tag, _field.getName(), _term, _result, tfmda); result->attr_ctx(_ctx.get()); diff --git a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h index d967933fbee..2657c5cf15f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h +++ b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h @@ -14,24 +14,24 @@ namespace search::queryeval { class EmptyBlueprint : public SimpleLeafBlueprint { protected: - SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const override; + SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const override; public: EmptyBlueprint(FieldSpecBaseList fields); EmptyBlueprint(FieldSpecBase field) : SimpleLeafBlueprint(field) {} EmptyBlueprint() = default; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; EmptyBlueprint *as_empty() noexcept final override { return this; } }; class AlwaysTrueBlueprint : public SimpleLeafBlueprint { protected: - SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const override; + SearchIterator::UP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const override; public: AlwaysTrueBlueprint(); FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; }; //----------------------------------------------------------------------------- @@ -44,14 +44,14 @@ private: protected: SearchIterator::UP - createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const override; + createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const override; public: SimpleBlueprint(const SimpleResult &result); ~SimpleBlueprint() override; SimpleBlueprint &tag(const vespalib::string &tag); const vespalib::string &tag() const { return _tag; } FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIterator::UP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIterator::UP createFilterSearch(FilterConstraint constraint) const override; }; //----------------------------------------------------------------------------- @@ -67,7 +67,7 @@ private: protected: SearchIterator::UP - createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; + createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; public: FakeBlueprint(const FieldSpec &field, const FakeResult &result); @@ -95,8 +95,8 @@ public: return default_flow_stats(docid_limit, _result.inspect().size(), 0); } - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } }; diff --git a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp index 8ab258ef58e..faa4b65e3b0 100644 --- a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.cpp @@ -125,8 +125,14 @@ NearestNeighborBlueprint::perform_top_k(const search::tensor::NearestNeighborInd } } +void +NearestNeighborBlueprint::sort(InFlow in_flow, const Options &) +{ + strict(in_flow.strict()); +} + std::unique_ptr<SearchIterator> -NearestNeighborBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray& tfmda, bool strict) const +NearestNeighborBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray& tfmda) const { assert(tfmda.size() == 1); fef::TermFieldMatchData &tfmd = *tfmda[0]; // always search in only one field @@ -137,7 +143,7 @@ NearestNeighborBlueprint::createLeafSearch(const search::fef::TermFieldMatchData default: ; } - return NearestNeighborIterator::create(strict, tfmd, + return NearestNeighborIterator::create(strict(), tfmd, std::make_unique<search::tensor::DistanceCalculator>(_attr_tensor, _query_tensor), _distance_heap, *_global_filter); } diff --git a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.h index 73608b8172b..864ae6c2d47 100644 --- a/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/nearest_neighbor_blueprint.h @@ -69,14 +69,14 @@ public: Algorithm get_algorithm() const { return _algorithm; } double get_distance_threshold() const { return _distance_threshold; } + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override { return default_flow_stats(docid_limit, getState().estimate().estHits, 0); } - std::unique_ptr<SearchIterator> createLeafSearch(const search::fef::TermFieldMatchDataArray& tfmda, - bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + std::unique_ptr<SearchIterator> createLeafSearch(const search::fef::TermFieldMatchDataArray& tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } void visitMembers(vespalib::ObjectVisitor& visitor) const override; bool always_needs_unpack() const override; diff --git a/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.cpp index 6dd4b241830..48d2e957252 100644 --- a/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.cpp @@ -279,8 +279,14 @@ PredicateBlueprint::fetchPostings(const ExecuteInfo &) { } } +void +PredicateBlueprint::sort(InFlow in_flow, const Options &) +{ + strict(in_flow.strict()); +} + SearchIterator::UP -PredicateBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const { +PredicateBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { const auto &attribute = predicate_attribute(); PredicateAttribute::MinFeatureHandle mfh = attribute.getMinFeatureVector(); auto interval_range_vector = attribute.getIntervalRangeVector(); diff --git a/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.h index d9c432b38bd..5cba0f1b949 100644 --- a/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/predicate_blueprint.h @@ -49,15 +49,16 @@ public: ~PredicateBlueprint(); void fetchPostings(const ExecuteInfo &execInfo) override; + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t) const override { return default_flow_stats(_interval_btree_iterators.size() + _interval_vector_iterators.size() + _bounds_btree_iterators.size() + _bounds_vector_iterators.size() + 2); } SearchIterator::UP - createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override { - return create_default_filter(strict, constraint); + createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override { + return create_default_filter(constraint); } // Exposed for testing diff --git a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp index 628020cfea2..7ba4bfc5711 100644 --- a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp @@ -44,6 +44,17 @@ SameElementBlueprint::addTerm(Blueprint::UP term) _terms.push_back(std::move(term)); } +void +SameElementBlueprint::sort(InFlow in_flow, const Options &opts) +{ + strict(in_flow.strict()); + auto flow = AndFlow(in_flow); + for (auto &term: _terms) { + term->sort(InFlow(flow.strict(), flow.flow()), opts); + flow.add(term->estimate()); + } +} + FlowStats SameElementBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -75,19 +86,19 @@ SameElementBlueprint::fetchPostings(const ExecuteInfo &execInfo) double hit_rate = execInfo.hit_rate() * _terms[0]->estimate(); for (size_t i = 1; i < _terms.size(); ++i) { Blueprint & term = *_terms[i]; - term.fetchPostings(ExecuteInfo::create(false, hit_rate, execInfo)); + term.fetchPostings(ExecuteInfo::create(hit_rate, execInfo)); hit_rate = hit_rate * _terms[i]->estimate(); } } std::unique_ptr<SameElementSearch> -SameElementBlueprint::create_same_element_search(search::fef::TermFieldMatchData& tfmd, bool strict) const +SameElementBlueprint::create_same_element_search(search::fef::TermFieldMatchData& tfmd) const { fef::MatchData::UP md = _layout.createMatchData(); std::vector<ElementIterator::UP> children(_terms.size()); for (size_t i = 0; i < _terms.size(); ++i) { const State &childState = _terms[i]->getState(); - SearchIterator::UP child = _terms[i]->createSearch(*md, (strict && (i == 0))); + SearchIterator::UP child = _terms[i]->createSearch(*md); const attribute::ISearchContext *context = _terms[i]->get_attribute_search_context(); if (context == nullptr) { children[i] = std::make_unique<ElementIteratorWrapper>(std::move(child), *childState.field(0).resolve(*md)); @@ -95,20 +106,20 @@ SameElementBlueprint::create_same_element_search(search::fef::TermFieldMatchData children[i] = std::make_unique<attribute::SearchContextElementIterator>(std::move(child), *context); } } - return std::make_unique<SameElementSearch>(tfmd, std::move(md), std::move(children), strict); + return std::make_unique<SameElementSearch>(tfmd, std::move(md), std::move(children), strict()); } SearchIterator::UP -SameElementBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const +SameElementBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); - return create_same_element_search(*tfmda[0], strict); + return create_same_element_search(*tfmda[0]); } SearchIterator::UP -SameElementBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +SameElementBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_and_filter(_terms, strict, constraint); + return create_atmost_and_filter(_terms, strict(), constraint); } void diff --git a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h index 279a5f7d654..61e2a85d5e2 100644 --- a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h @@ -34,15 +34,15 @@ public: // used by create visitor void addTerm(Blueprint::UP term); + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; void optimize_self(OptimizePass pass) override; void fetchPostings(const ExecuteInfo &execInfo) override; - std::unique_ptr<SameElementSearch> create_same_element_search(search::fef::TermFieldMatchData& tfmd, bool strict) const; - SearchIteratorUP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, - bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override; + std::unique_ptr<SameElementSearch> create_same_element_search(search::fef::TermFieldMatchData& tfmd) const; + SearchIteratorUP createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; const std::vector<Blueprint::UP> &terms() const { return _terms; } const vespalib::string &field_name() const { return _field_name; } diff --git a/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.cpp index 953e7350074..0867a072c3b 100644 --- a/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.cpp @@ -45,6 +45,15 @@ SimplePhraseBlueprint::addTerm(Blueprint::UP term) _terms.push_back(std::move(term)); } +void +SimplePhraseBlueprint::sort(InFlow in_flow, const Options &opts) +{ + strict(in_flow.strict()); + for (auto &term: _terms) { + term->sort(in_flow, opts); + } +} + FlowStats SimplePhraseBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -58,7 +67,7 @@ SimplePhraseBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -SimplePhraseBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const +SimplePhraseBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); fef::MatchData::UP md = _layout.createMatchData(); @@ -73,24 +82,23 @@ SimplePhraseBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmd child_term_field_match_data->setNeedInterleavedFeatures(tfmda[0]->needs_interleaved_features()); child_term_field_match_data->setNeedNormalFeatures(true); childMatch.add(child_term_field_match_data); - children.push_back(_terms[i]->createSearch(*md, strict)); + children.push_back(_terms[i]->createSearch(*md)); order_map.insert(std::make_pair(childState.estimate().estHits, i)); } std::vector<uint32_t> eval_order; eval_order.reserve(order_map.size()); for (const auto & child : order_map) { eval_order.push_back(child.second); - } - + } return std::make_unique<SimplePhraseSearch>(std::move(children), std::move(md), std::move(childMatch), - std::move(eval_order), *tfmda[0], strict); + std::move(eval_order), *tfmda[0], strict()); } SearchIterator::UP -SimplePhraseBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +SimplePhraseBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_and_filter(_terms, strict, constraint); + return create_atmost_and_filter(_terms, strict(), constraint); } void diff --git a/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.h index da7ec9c9b36..14717742c30 100644 --- a/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/simple_phrase_blueprint.h @@ -30,10 +30,11 @@ public: // used by create visitor void addTerm(Blueprint::UP term); + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void fetchPostings(const ExecuteInfo &execInfo) override; }; diff --git a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.cpp index 78fe3882aab..e85649a3758 100644 --- a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.cpp @@ -66,6 +66,17 @@ ParallelWeakAndBlueprint::addTerm(Blueprint::UP term, int32_t weight, HitEstimat _terms.push_back(std::move(term)); } +void +ParallelWeakAndBlueprint::sort(InFlow in_flow, const Options &opts) +{ + strict(in_flow.strict()); + auto flow = OrFlow(in_flow); + for (auto &term: _terms) { + term->sort(InFlow(flow.strict(), flow.flow()), opts); + flow.add(term->estimate()); + } +} + FlowStats ParallelWeakAndBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -80,7 +91,7 @@ ParallelWeakAndBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -ParallelWeakAndBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda, bool strict) const +ParallelWeakAndBlueprint::createLeafSearch(const search::fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); fef::MatchData::UP childrenMatchData = _layout.createMatchData(); @@ -90,7 +101,7 @@ ParallelWeakAndBlueprint::createLeafSearch(const search::fef::TermFieldMatchData const State &childState = _terms[i]->getState(); assert(childState.numFields() == 1); // TODO: pass ownership with unique_ptr - terms.emplace_back(_terms[i]->createSearch(*childrenMatchData, true).release(), + terms.emplace_back(_terms[i]->createSearch(*childrenMatchData).release(), _weights[i], childState.estimate().estHits, childState.field(0).resolve(*childrenMatchData)); @@ -102,13 +113,13 @@ ParallelWeakAndBlueprint::createLeafSearch(const search::fef::TermFieldMatchData _thresholdBoostFactor, _scoresAdjustFrequency).setDocIdLimit(get_docid_limit()), ParallelWeakAndSearch::RankParams(*tfmda[0], - std::move(childrenMatchData)), strict)); + std::move(childrenMatchData)), strict())); } std::unique_ptr<SearchIterator> -ParallelWeakAndBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +ParallelWeakAndBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_atmost_or_filter(_terms, strict, constraint); + return create_atmost_or_filter(_terms, strict(), constraint); } void diff --git a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.h index ade64577c80..22f8ee1bf6f 100644 --- a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_blueprint.h @@ -62,10 +62,11 @@ public: set_tree_size(_terms.size() + 1); } + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - std::unique_ptr<SearchIterator> createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIterator::UP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + std::unique_ptr<SearchIterator> createFilterSearch(FilterConstraint constraint) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void fetchPostings(const ExecuteInfo &execInfo) override; bool always_needs_unpack() const override; diff --git a/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.cpp index 8bf2dd53470..8f4f8d50c43 100644 --- a/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.cpp @@ -34,7 +34,7 @@ WeightedSetTermMatchingElementsSearch::WeightedSetTermMatchingElementsSearch(con _search() { _tfmda.add(&_tfmd); - _search.reset(static_cast<WeightedSetTermSearch *>(bp.createLeafSearch(_tfmda, false).release())); + _search.reset(static_cast<WeightedSetTermSearch *>(bp.createLeafSearch(_tfmda).release())); } @@ -93,6 +93,15 @@ WeightedSetTermBlueprint::addTerm(Blueprint::UP term, int32_t weight, HitEstimat _terms.push_back(std::move(term)); } +void +WeightedSetTermBlueprint::sort(InFlow, const Options &opts) +{ + strict(true); + for (auto &term: _terms) { + term->sort(true, opts); + } +} + FlowStats WeightedSetTermBlueprint::calculate_flow_stats(uint32_t docid_limit) const { @@ -105,14 +114,14 @@ WeightedSetTermBlueprint::calculate_flow_stats(uint32_t docid_limit) const } SearchIterator::UP -WeightedSetTermBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const +WeightedSetTermBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const { assert(tfmda.size() == 1); if ((_terms.size() == 1) && tfmda[0]->isNotNeeded()) { if (const LeafBlueprint * leaf = _terms[0]->asLeaf(); leaf != nullptr) { // Always returnin a strict iterator independently of what was required, // as that is what we do with all the children when there are more. - return leaf->createLeafSearch(tfmda, true); + return leaf->createLeafSearch(tfmda); } } fef::MatchData::UP md = _layout.createMatchData(); @@ -120,15 +129,15 @@ WeightedSetTermBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &t children.reserve(_terms.size()); for (const auto & _term : _terms) { // TODO: pass ownership with unique_ptr - children.push_back(_term->createSearch(*md, true).release()); + children.push_back(_term->createSearch(*md).release()); } return WeightedSetTermSearch::create(children, *tfmda[0], _children_field.isFilter(), _weights, std::move(md)); } SearchIterator::UP -WeightedSetTermBlueprint::createFilterSearch(bool strict, FilterConstraint constraint) const +WeightedSetTermBlueprint::createFilterSearch(FilterConstraint constraint) const { - return create_or_filter(_terms, strict, constraint); + return create_or_filter(_terms, strict(), constraint); } std::unique_ptr<MatchingElementsSearch> diff --git a/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.h index 240b2a47eb3..47deff058a0 100644 --- a/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/weighted_set_term_blueprint.h @@ -35,10 +35,11 @@ public: setEstimate(estimate); } + void sort(InFlow in_flow, const Options &opts) override; FlowStats calculate_flow_stats(uint32_t docid_limit) const override; - SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool strict) const override; - SearchIteratorUP createFilterSearch(bool strict, FilterConstraint constraint) const override; + SearchIteratorUP createLeafSearch(const fef::TermFieldMatchDataArray &tfmda) const override; + SearchIteratorUP createFilterSearch(FilterConstraint constraint) const override; std::unique_ptr<MatchingElementsSearch> create_matching_elements_search(const MatchingElementsFields &fields) const override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; private: |