From d9729796b35cd47b81fac180122235223e14237a Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Thu, 27 Oct 2022 15:31:27 +0000 Subject: [PATCH] Add more tests for createFilterSearch() on attribute blueprints. --- .../searchable/attributeblueprint_test.cpp | 127 +++++++++++++----- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp index 504cc6506b54..b211261ef57e 100644 --- a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp @@ -35,9 +35,12 @@ using search::fef::TermFieldMatchData; using search::query::Location; using search::query::Node; using search::query::Point; +using search::query::SimpleDotProduct; using search::query::SimpleLocationTerm; using search::query::SimplePrefixTerm; using search::query::SimpleStringTerm; +using search::query::SimpleWandTerm; +using search::query::SimpleWeightedSetTerm; using search::query::Weight; using search::queryeval::Blueprint; using search::queryeval::EmptyBlueprint; @@ -46,6 +49,7 @@ using search::queryeval::FieldSpec; using search::queryeval::FilterWrapper; using search::queryeval::NearestNeighborBlueprint; using search::queryeval::SearchIterator; +using search::queryeval::SimpleResult; using std::string; using std::vector; using vespalib::eval::TensorSpec; @@ -102,7 +106,7 @@ class MyAttributeManager : public IAttributeManager { } }; -constexpr uint32_t DOCID_LIMIT = 3; +constexpr uint32_t DOCID_LIMIT = 4; bool do_search(const Node &node, IAttributeManager &attribute_manager, bool expect_attribute_search_context = true) @@ -114,7 +118,7 @@ do_search(const Node &node, IAttributeManager &attribute_manager, bool expect_at Blueprint::UP result = source.createBlueprint(requestContext, FieldSpec(field, 0, 0), node); assert(result.get()); EXPECT_TRUE(!result->getState().estimate().empty); - EXPECT_EQ(3u, result->getState().estimate().estHits); + EXPECT_EQ(DOCID_LIMIT, result->getState().estimate().estHits); if (expect_attribute_search_context) { EXPECT_TRUE(result->get_attribute_search_context() != nullptr); } else { @@ -124,9 +128,10 @@ do_search(const Node &node, IAttributeManager &attribute_manager, bool expect_at result->setDocIdLimit(DOCID_LIMIT); SearchIterator::UP iterator = result->createSearch(*md, true); assert((bool)iterator); - iterator->initRange(1, 3); + iterator->initRange(1, DOCID_LIMIT); EXPECT_TRUE(!iterator->seek(1)); - return iterator->seek(2); + EXPECT_TRUE(!iterator->seek(2)); + return iterator->seek(3); } bool @@ -147,26 +152,32 @@ downcast(ParentType& parent) } AttributeVector::SP -make_string_attribute(const std::string& value) +make_string_attribute(const std::vector& values) { Config cfg(BasicType::STRING, CollectionType::SINGLE); - return AttributeBuilder(field, cfg).fill({"", value}).get(); + return AttributeBuilder(field, cfg).fill(values).get(); } AttributeVector::SP -make_wset_string_attribute(const std::string& value) +make_string_attribute(const std::string& value) +{ + return make_string_attribute({"", "", value}); +} + +AttributeVector::SP +make_wset_string_attribute(const std::vector>& values) { Config cfg(BasicType::STRING, CollectionType::WSET); // fast-search is needed to trigger use of DirectAttributeBlueprint. cfg.setFastSearch(true); - return AttributeBuilder(field, cfg).fill_array({{}, {value}}).get(); + return AttributeBuilder(field, cfg).fill_array(values).get(); } AttributeVector::SP make_int_attribute(int64_t value) { Config cfg(BasicType::INT32, CollectionType::SINGLE); - return AttributeBuilder(field, cfg).fill({-1, value}).get(); + return AttributeBuilder(field, cfg).fill({-1, -1, value}).get(); } AttributeVector::SP @@ -174,7 +185,7 @@ make_fast_search_long_attribute(int64_t value) { Config cfg(BasicType::fromType(int64_t()), CollectionType::SINGLE); cfg.setFastSearch(true); - return AttributeBuilder(field, cfg).fill({-1, value}).get(); + return AttributeBuilder(field, cfg).fill({-1, -1, value}).get(); } MyAttributeManager @@ -276,17 +287,21 @@ make_int_attribute(const vespalib::string& name) return AttributeFactory::createAttribute(name, cfg); } +using BFC = Blueprint::FilterConstraint; + class BlueprintFactoryFixture { public: + AttributeVector::SP attr; MyAttributeManager mgr; vespalib::string attr_name; AttributeContext attr_ctx; FakeRequestContext request_ctx; AttributeBlueprintFactory source; - BlueprintFactoryFixture(AttributeVector::SP attr) - : mgr(attr), - attr_name(attr->getName()), + BlueprintFactoryFixture(AttributeVector::SP attr_in) + : attr(attr_in), + mgr(attr_in), + attr_name(attr_in->getName()), attr_ctx(mgr), request_ctx(&attr_ctx), source() @@ -299,12 +314,30 @@ class BlueprintFactoryFixture { result->setDocIdLimit(DOCID_LIMIT); return result; } + void expect_document_weight_attribute() { + EXPECT_TRUE(attr->asDocumentWeightAttribute() != nullptr); + } + void expect_filter_search(const SimpleResult& upper_and_lower, const Node& term) { + expect_filter_search(upper_and_lower, upper_and_lower, term); + } + 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); + 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); + downcast(*itr); + } }; class NearestNeighborFixture : public BlueprintFactoryFixture { public: - NearestNeighborFixture(AttributeVector::SP attr) - : BlueprintFactoryFixture(std::move(attr)) + NearestNeighborFixture(AttributeVector::SP attr_in) + : BlueprintFactoryFixture(std::move(attr_in)) { } ~NearestNeighborFixture() {} @@ -376,30 +409,60 @@ TEST(AttributeBlueprintTest, empty_blueprint_is_created_when_nearest_neighbor_te expect_empty_blueprint(make_tensor_attribute(field, "tensor(x[2])"), dense_x_3); // tensor types are not same size } -TEST(AttributeBlueprintTest, attribute_field_blueprint_wraps_filter_search_iterator) +TEST(AttributeBlueprintTest, attribute_field_blueprint_creates_exact_filter_search) { - BlueprintFactoryFixture f(make_string_attribute("foo")); + BlueprintFactoryFixture f(make_string_attribute({"foo", "x", "foo"})); SimpleStringTerm term("foo", field, 0, Weight(0)); - auto blueprint = f.create_blueprint(term); - - auto itr = blueprint->createFilterSearch(true, Blueprint::FilterConstraint::UPPER_BOUND); - auto& wrapper = downcast(*itr); - wrapper.initRange(1, 3); - EXPECT_FALSE(wrapper.seek(1)); - EXPECT_TRUE(wrapper.seek(2)); + f.expect_filter_search(SimpleResult({1, 3}), term); + f.expect_filter_wrapper(term); } -TEST(AttributeBlueprintTest, direct_attribute_blueprint_wraps_filter_search_iterator) +TEST(AttributeBlueprintTest, direct_attribute_blueprint_creates_exact_filter_search) { - BlueprintFactoryFixture f(make_wset_string_attribute("foo")); + BlueprintFactoryFixture f(make_wset_string_attribute({{"foo"}, {}, {"foo"}})); + f.expect_document_weight_attribute(); SimpleStringTerm term("foo", field, 0, Weight(0)); - auto blueprint = f.create_blueprint(term); + f.expect_filter_search(SimpleResult({1, 3}), term); + f.expect_filter_wrapper(term); +} - auto itr = blueprint->createFilterSearch(true, Blueprint::FilterConstraint::UPPER_BOUND); - auto& wrapper = downcast(*itr); - wrapper.initRange(1, 3); - EXPECT_FALSE(wrapper.seek(1)); - EXPECT_TRUE(wrapper.seek(2)); +TEST(AttributeBlueprintTest, direct_wand_blueprint_creates_or_like_filter_search) +{ + BlueprintFactoryFixture f(make_wset_string_attribute({{"foo"}, {"x"}, {"bar"}})); + f.expect_document_weight_attribute(); + SimpleWandTerm term(2, field, 0, Weight(0), DOCID_LIMIT, 1000, 1.0); + term.addTerm("foo", Weight(10)); + term.addTerm("bar", Weight(20)); + f.expect_filter_search(SimpleResult({1, 3}), SimpleResult(), term); +} + +TEST(AttributeBlueprintTest, direct_weighted_set_blueprint_creates_or_like_filter_search) +{ + BlueprintFactoryFixture f(make_wset_string_attribute({{"foo"}, {"x"}, {"bar"}})); + f.expect_document_weight_attribute(); + { + SimpleWeightedSetTerm term(2, field, 0, Weight(0)); + term.addTerm("foo", Weight(10)); + term.addTerm("bar", Weight(20)); + f.expect_filter_search(SimpleResult({1, 3}), term); + } + { + SimpleDotProduct term(2, field, 0, Weight(0)); + term.addTerm("foo", Weight(10)); + term.addTerm("bar", Weight(20)); + f.expect_filter_search(SimpleResult({1, 3}), term); + } +} + +TEST(AttributeBlueprintTest, attribute_weighted_set_blueprint_creates_or_like_filter_search) +{ + BlueprintFactoryFixture f(make_string_attribute({"foo", "x", "bar"})); + { + SimpleWeightedSetTerm term(2, field, 0, Weight(0)); + term.addTerm("foo", Weight(10)); + term.addTerm("bar", Weight(20)); + f.expect_filter_search(SimpleResult({1, 3}), term); + } } GTEST_MAIN_RUN_ALL_TESTS()