summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorGeir Storli <geirst@verizonmedia.com>2020-05-27 19:10:43 +0200
committerGitHub <noreply@github.com>2020-05-27 19:10:43 +0200
commitd8f546d2ad27423474d14e53a8eda3a1ef74f4dc (patch)
tree0e5e4f3ad0994fef916ce83907974d956710a2fb /searchlib
parent5a628aa443a9b720ab483e669f558f6f0693bbb6 (diff)
parent960fa7e1efbf9413cfeede2a3f1d14856a13d9ec (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.cpp152
-rw-r--r--searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp20
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);
}