diff options
author | Geir Storli <geirst@verizonmedia.com> | 2020-05-27 19:10:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-27 19:10:43 +0200 |
commit | d8f546d2ad27423474d14e53a8eda3a1ef74f4dc (patch) | |
tree | 0e5e4f3ad0994fef916ce83907974d956710a2fb /searchlib | |
parent | 5a628aa443a9b720ab483e669f558f6f0693bbb6 (diff) | |
parent | 960fa7e1efbf9413cfeede2a3f1d14856a13d9ec (diff) |
Merge pull request #13406 from vespa-engine/geirst/add-create-filter-search-on-attribute-field-blueprint
Add create filter search on attribute field blueprint
Diffstat (limited to 'searchlib')
-rw-r--r-- | searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp | 152 | ||||
-rw-r--r-- | searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp | 20 |
2 files changed, 115 insertions, 57 deletions
diff --git a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp index 665803b3057..cb2bc1ee752 100644 --- a/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attributeblueprint_test.cpp @@ -12,14 +12,15 @@ #include <vespa/searchlib/attribute/singlenumericattribute.h> #include <vespa/searchlib/attribute/singlenumericattribute.hpp> #include <vespa/searchlib/attribute/singlenumericpostattribute.hpp> +#include <vespa/searchlib/fef/matchdata.h> #include <vespa/searchlib/query/tree/location.h> #include <vespa/searchlib/query/tree/point.h> #include <vespa/searchlib/query/tree/simplequery.h> #include <vespa/searchlib/queryeval/fake_requestcontext.h> +#include <vespa/searchlib/queryeval/filter_wrapper.h> #include <vespa/searchlib/queryeval/leaf_blueprints.h> #include <vespa/searchlib/queryeval/nearest_neighbor_blueprint.h> #include <vespa/searchlib/tensor/dense_tensor_attribute.h> -#include <vespa/searchlib/fef/matchdata.h> #include <vespa/vespalib/gtest/gtest.h> #include <vespa/log/log.h> @@ -41,10 +42,11 @@ using search::query::SimpleStringTerm; using search::query::Weight; using search::queryeval::Blueprint; using search::queryeval::EmptyBlueprint; +using search::queryeval::FakeRequestContext; using search::queryeval::FieldSpec; +using search::queryeval::FilterWrapper; using search::queryeval::NearestNeighborBlueprint; using search::queryeval::SearchIterator; -using search::queryeval::FakeRequestContext; using std::string; using std::vector; using vespalib::eval::TensorSpec; @@ -67,10 +69,6 @@ public: _attribute_vector(std::move(rhs._attribute_vector)) { } - MyAttributeManager(AttributeVector *attr) - : _attribute_vector(attr) - { - } MyAttributeManager(AttributeVector::SP attr) : _attribute_vector(std::move(attr)) @@ -141,54 +139,89 @@ search_for_term(const string &term, IAttributeManager &attribute_manager) return ret; } -template <typename T> -struct AttributeVectorTypeFinder { - typedef SingleStringExtAttribute Type; - static void add(Type & a, const T & v) { a.add(v, weight); } -}; +template <typename ChildType, typename ParentType> +ChildType& +downcast(ParentType& parent) +{ + auto* result = dynamic_cast<ChildType*>(&parent); + assert(result != nullptr); + return *result; +} -template <> -struct AttributeVectorTypeFinder<int64_t> { - typedef search::SingleValueNumericAttribute<search::IntegerAttributeTemplate<int64_t> > Type; - static void add(Type & a, int64_t v) { a.set(a.getNumDocs()-1, v); a.commit(); } +struct StringAttributeFiller { + using ValueType = vespalib::string; + static void add(AttributeVector& attr, const vespalib::string& value) { + auto& real = downcast<StringAttribute>(attr); + real.update(attr.getNumDocs() - 1, value); + real.commit(); + } }; -struct FastSearchLongAttribute { - typedef search::SingleValueNumericPostingAttribute< search::EnumAttribute<search::IntegerAttributeTemplate<int64_t> > > Type; - static void add(Type & a, int64_t v) { a.update(a.getNumDocs()-1, v); a.commit(); } +struct IntegerAttributeFiller { + using ValueType = int64_t; + static void add(AttributeVector& attr, int64_t value) { + auto& real = downcast<IntegerAttribute>(attr); + real.update(attr.getNumDocs() - 1, value); + real.commit(); + } }; -template <typename AT, typename T> -MyAttributeManager -fill(typename AT::Type * attr, T value) +template <typename FillerType> +void +fill(AttributeVector& attr, typename FillerType::ValueType value) { AttributeVector::DocId docid; - attr->addDoc(docid); - attr->addDoc(docid); - attr->addDoc(docid); + attr.addDoc(docid); + attr.addDoc(docid); + attr.addDoc(docid); assert(DOCID_LIMIT-1 == docid); - AT::add(*attr, value); - return MyAttributeManager(attr); + FillerType::add(attr, value); +} + +AttributeVector::SP +make_string_attribute(const std::string& value) +{ + Config cfg(BasicType::STRING, CollectionType::SINGLE); + auto attr = AttributeFactory::createAttribute(field, cfg); + fill<StringAttributeFiller>(*attr, value); + return attr; +} + +AttributeVector::SP +make_int_attribute(int64_t value) +{ + Config cfg(BasicType::INT32, CollectionType::SINGLE); + auto attr = AttributeFactory::createAttribute(field, cfg); + fill<IntegerAttributeFiller>(*attr, value); + return attr; +} + +AttributeVector::SP +make_fast_search_long_attribute(int64_t value) +{ + Config cfg(BasicType::fromType(int64_t()), CollectionType::SINGLE); + cfg.setFastSearch(true); + auto attr = AttributeFactory::createAttribute(field, cfg); + fill<IntegerAttributeFiller>(*attr, value); + return attr; } -template <typename T> MyAttributeManager -makeAttributeManager(T value) +makeAttributeManager(const std::string& value) { - typedef AttributeVectorTypeFinder<T> AT; - typedef typename AT::Type AttributeVectorType; - AttributeVectorType *attr = new AttributeVectorType(field); - return fill<AT, T>(attr, value); + return MyAttributeManager(make_string_attribute(value)); +} + +MyAttributeManager +makeAttributeManager(int64_t value) +{ + return MyAttributeManager(make_int_attribute(value)); } MyAttributeManager makeFastSearchLongAttribute(int64_t value) { - typedef FastSearchLongAttribute::Type AttributeVectorType; - Config cfg(BasicType::fromType(int64_t()), CollectionType::SINGLE); - cfg.setFastSearch(true); - AttributeVectorType *attr = new AttributeVectorType(field, cfg); - return fill<FastSearchLongAttribute, int64_t>(attr, value); + return MyAttributeManager(make_fast_search_long_attribute(value)); } } // namespace @@ -265,16 +298,7 @@ make_int_attribute(const vespalib::string& name) return AttributeFactory::createAttribute(name, cfg); } -template <typename BlueprintType> -const BlueprintType& -as_type(const Blueprint& blueprint) -{ - const auto* result = dynamic_cast<const BlueprintType*>(&blueprint); - assert(result != nullptr); - return *result; -} - -class NearestNeighborFixture { +class BlueprintFactoryFixture { public: MyAttributeManager mgr; vespalib::string attr_name; @@ -282,7 +306,7 @@ public: FakeRequestContext request_ctx; AttributeBlueprintFactory source; - NearestNeighborFixture(AttributeVector::SP attr) + BlueprintFactoryFixture(AttributeVector::SP attr) : mgr(attr), attr_name(attr->getName()), attr_ctx(mgr), @@ -290,13 +314,28 @@ public: source() { } + ~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); + return result; + } +}; + +class NearestNeighborFixture : public BlueprintFactoryFixture { +public: + NearestNeighborFixture(AttributeVector::SP attr) + : BlueprintFactoryFixture(std::move(attr)) + { + } ~NearestNeighborFixture() {} void set_query_tensor(const TensorSpec& tensor_spec) { request_ctx.set_query_tensor("query_tensor", tensor_spec); } Blueprint::UP create_blueprint() { query::NearestNeighborTerm term("query_tensor", attr_name, 0, Weight(0), 7, true, 33); - return source.createBlueprint(request_ctx, FieldSpec(attr_name, 0, 0), term); + return BlueprintFactoryFixture::create_blueprint(term); } }; @@ -309,7 +348,7 @@ expect_nearest_neighbor_blueprint(const vespalib::string& attribute_tensor_type_ f.set_query_tensor(query_tensor); auto result = f.create_blueprint(); - const auto& nearest = as_type<NearestNeighborBlueprint>(*result); + const auto& nearest = downcast<const NearestNeighborBlueprint>(*result); EXPECT_EQ(attribute_tensor_type_spec, nearest.get_attribute_tensor().getTensorType().to_spec()); EXPECT_EQ(converted_query_tensor, DefaultTensorEngine::ref().to_spec(nearest.get_query_tensor())); EXPECT_EQ(7u, nearest.get_target_num_hits()); @@ -359,4 +398,17 @@ 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) +{ + BlueprintFactoryFixture f(make_string_attribute("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<FilterWrapper>(*itr); + wrapper.initRange(1, 3); + EXPECT_FALSE(wrapper.seek(1)); + EXPECT_TRUE(wrapper.seek(2)); +} + GTEST_MAIN_RUN_ALL_TESTS() diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp index 14d33914d05..d838013c0ef 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp @@ -18,6 +18,8 @@ #include <vespa/searchlib/queryeval/dot_product_blueprint.h> #include <vespa/searchlib/queryeval/dot_product_search.h> #include <vespa/searchlib/queryeval/emptysearch.h> +#include <vespa/searchlib/queryeval/field_spec.hpp> +#include <vespa/searchlib/queryeval/filter_wrapper.h> #include <vespa/searchlib/queryeval/get_weight_from_node.h> #include <vespa/searchlib/queryeval/intermediate_blueprints.h> #include <vespa/searchlib/queryeval/leaf_blueprints.h> @@ -28,7 +30,6 @@ #include <vespa/searchlib/queryeval/wand/parallel_weak_and_search.h> #include <vespa/searchlib/queryeval/weighted_set_term_blueprint.h> #include <vespa/searchlib/queryeval/weighted_set_term_search.h> -#include <vespa/searchlib/queryeval/field_spec.hpp> #include <vespa/searchlib/tensor/dense_tensor_attribute.h> #include <vespa/vespalib/util/regexp.h> #include <vespa/vespalib/util/stringfmt.h> @@ -62,6 +63,7 @@ using search::queryeval::CreateBlueprintVisitorHelper; using search::queryeval::DotProductBlueprint; using search::queryeval::FieldSpec; using search::queryeval::FieldSpecBaseList; +using search::queryeval::FilterWrapper; using search::queryeval::IRequestContext; using search::queryeval::NoUnpack; using search::queryeval::OrLikeSearch; @@ -126,21 +128,25 @@ public: .diversityCutoffStrict(diversityCutoffStrict)) {} - SearchIterator::UP - createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override { + SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray &tfmda, bool strict) const override { assert(tfmda.size() == 1); return _search_context->createIterator(tfmda[0], strict); } - SearchIterator::UP - createSearch(fef::MatchData &md, bool strict) const override { + SearchIterator::UP createSearch(fef::MatchData &md, bool strict) const override { const State &state = getState(); assert(state.numFields() == 1); return _search_context->createIterator(state.field(0).resolve(md), strict); } - void - fetchPostings(const queryeval::ExecuteInfo &execInfo) override { + SearchIteratorUP createFilterSearch(bool strict, 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()); + wrapper->wrap(createLeafSearch(wrapper->tfmda(), strict)); + return wrapper; + } + + void fetchPostings(const queryeval::ExecuteInfo &execInfo) override { _search_context->fetchPostings(execInfo); } |