aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'searchlib/src/tests')
-rw-r--r--searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp2
-rw-r--r--searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp172
-rw-r--r--searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp199
3 files changed, 214 insertions, 159 deletions
diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
index 8e8327584a7..3c0b49da762 100644
--- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp
@@ -30,7 +30,7 @@ public:
return mixChildrenFields();
}
- virtual void sort(std::vector<Blueprint*> &children) const override {
+ virtual void sort(Children &children) const override {
std::sort(children.begin(), children.end(), TieredGreaterEstimate());
}
diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
index 2379213b87b..ef0fd56840a 100644
--- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
+++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp
@@ -56,6 +56,18 @@ bool got_global_filter(Blueprint &b) {
return (static_cast<MyLeaf &>(b)).got_global_filter();
}
+void check_sort_order(IntermediateBlueprint &self, std::vector<Blueprint*> unordered, std::vector<size_t> order) {
+ ASSERT_EQUAL(unordered.size(), order.size());
+ std::vector<Blueprint::UP> children;
+ for (auto *child: unordered) {
+ children.push_back(std::unique_ptr<Blueprint>(child));
+ }
+ self.sort(children);
+ for (size_t i = 0; i < children.size(); ++i) {
+ EXPECT_EQUAL(children[i].get(), unordered[order[i]]);
+ }
+}
+
TEST("test AndNot Blueprint") {
AndNotBlueprint b;
{ // combine
@@ -86,20 +98,12 @@ TEST("test AndNot Blueprint") {
EXPECT_EQUAL(true, got_global_filter(a.getChild(1)));
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(10).create());
- Blueprint::UP c2 = ap(MyLeafSpec(20).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c1.get(), children[0]);
- EXPECT_EQUAL(c3.get(), children[1]);
- EXPECT_EQUAL(c4.get(), children[2]);
- EXPECT_EQUAL(c2.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(10).create(),
+ MyLeafSpec(20).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {0, 2, 3, 1});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -161,20 +165,12 @@ TEST("test And Blueprint") {
EXPECT_EQUAL(true, got_global_filter(a.getChild(1)));
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(20).create());
- Blueprint::UP c2 = ap(MyLeafSpec(40).create());
- Blueprint::UP c3 = ap(MyLeafSpec(10).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c3.get(), children[0]);
- EXPECT_EQUAL(c1.get(), children[1]);
- EXPECT_EQUAL(c4.get(), children[2]);
- EXPECT_EQUAL(c2.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(20).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(30).create()},
+ {2, 0, 3, 1});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -241,20 +237,12 @@ TEST("test Or Blueprint") {
EXPECT_EQUAL(true, got_global_filter(o.getChild(o.childCnt() - 1)));
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(10).create());
- Blueprint::UP c2 = ap(MyLeafSpec(20).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c3.get(), children[0]);
- EXPECT_EQUAL(c4.get(), children[1]);
- EXPECT_EQUAL(c2.get(), children[2]);
- EXPECT_EQUAL(c1.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(10).create(),
+ MyLeafSpec(20).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {2, 3, 1, 0});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -290,20 +278,12 @@ TEST("test Near Blueprint") {
EXPECT_EQUAL(0u, a.exposeFields().size());
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(40).create());
- Blueprint::UP c2 = ap(MyLeafSpec(10).create());
- Blueprint::UP c3 = ap(MyLeafSpec(30).create());
- Blueprint::UP c4 = ap(MyLeafSpec(20).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c2.get(), children[0]);
- EXPECT_EQUAL(c4.get(), children[1]);
- EXPECT_EQUAL(c3.get(), children[2]);
- EXPECT_EQUAL(c1.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(40).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(30).create(),
+ MyLeafSpec(20).create()},
+ {1, 3, 2, 0});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -339,20 +319,12 @@ TEST("test ONear Blueprint") {
EXPECT_EQUAL(0u, a.exposeFields().size());
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(20).create());
- Blueprint::UP c2 = ap(MyLeafSpec(10).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c1.get(), children[0]);
- EXPECT_EQUAL(c2.get(), children[1]);
- EXPECT_EQUAL(c3.get(), children[2]);
- EXPECT_EQUAL(c4.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(20).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {0, 1, 2, 3});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -396,20 +368,12 @@ TEST("test Rank Blueprint") {
EXPECT_EQUAL(true, got_global_filter(a.getChild(1)));
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(20).create());
- Blueprint::UP c2 = ap(MyLeafSpec(10).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c1.get(), children[0]);
- EXPECT_EQUAL(c2.get(), children[1]);
- EXPECT_EQUAL(c3.get(), children[2]);
- EXPECT_EQUAL(c4.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(20).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {0, 1, 2, 3});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -469,20 +433,12 @@ TEST("test SourceBlender Blueprint") {
EXPECT_EQUAL(0u, a->getState().numFields());
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(20).create());
- Blueprint::UP c2 = ap(MyLeafSpec(10).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c1.get(), children[0]);
- EXPECT_EQUAL(c2.get(), children[1]);
- EXPECT_EQUAL(c3.get(), children[2]);
- EXPECT_EQUAL(c4.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(20).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {0, 1, 2, 3});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
@@ -1080,20 +1036,12 @@ TEST("test WeakAnd Blueprint") {
EXPECT_EQUAL(0u, a.exposeFields().size());
}
{
- std::vector<Blueprint *> children;
- Blueprint::UP c1 = ap(MyLeafSpec(10).create());
- Blueprint::UP c2 = ap(MyLeafSpec(20).create());
- Blueprint::UP c3 = ap(MyLeafSpec(40).create());
- Blueprint::UP c4 = ap(MyLeafSpec(30).create());
- children.push_back(c1.get());
- children.push_back(c2.get());
- children.push_back(c3.get());
- children.push_back(c4.get());
- b.sort(children);
- EXPECT_EQUAL(c1.get(), children[0]);
- EXPECT_EQUAL(c2.get(), children[1]);
- EXPECT_EQUAL(c3.get(), children[2]);
- EXPECT_EQUAL(c4.get(), children[3]);
+ check_sort_order(b,
+ {MyLeafSpec(20).create(),
+ MyLeafSpec(10).create(),
+ MyLeafSpec(40).create(),
+ MyLeafSpec(30).create()},
+ {0, 1, 2, 3});
}
{
EXPECT_EQUAL(true, b.inheritStrict(0));
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 fe9f6424b9c..5741d210079 100644
--- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp
+++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp
@@ -2,18 +2,17 @@
#include <vespa/searchlib/queryeval/simpleresult.h>
#include <vespa/searchlib/queryeval/blueprint.h>
+#include <vespa/searchlib/queryeval/intermediate_blueprints.h>
#include <vespa/searchlib/queryeval/leaf_blueprints.h>
+#include <vespa/searchlib/queryeval/isourceselector.h>
#include <vespa/vespalib/util/trinary.h>
#include <vespa/vespalib/util/require.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <functional>
-using search::queryeval::AlwaysTrueBlueprint;
-using search::queryeval::Blueprint;
-using search::queryeval::EmptyBlueprint;
-using search::queryeval::SimpleBlueprint;
-using search::queryeval::SimpleResult;
-using search::queryeval::SearchIterator;
+namespace search::fef { class MatchData; }
+
+using namespace search::queryeval;
using vespalib::Trinary;
using Constraint = Blueprint::FilterConstraint;
@@ -27,37 +26,29 @@ concept FilterFactory = requires(const T &a, bool strict, Constraint upper_or_lo
{ a.createFilterSearch(strict, upper_or_lower) } -> std::same_as<std::unique_ptr<SearchIterator>>;
};
-using factory_fun = std::function<std::unique_ptr<SearchIterator>(const std::vector<Blueprint*> &, bool, Constraint)>;
-
-// Combine children blueprints using a shared filter creation
-// algorithm. Satisfies the FilterFactory concept.
-struct Combine {
- factory_fun fun;
- std::vector<Blueprint*> list;
- Combine(factory_fun fun_in) : fun(fun_in), list() {}
- Combine &&add(std::unique_ptr<Blueprint> child) && {
- list.push_back(child.release());
- return std::move(*this);
- }
- auto createFilterSearch(bool strict, Constraint upper_or_lower) const {
- return fun(list, strict, upper_or_lower);
- }
- ~Combine() {
- for (auto *ptr: list) {
- delete ptr;
- }
- }
+template <typename T>
+concept FilterFactoryBuilder = requires(T a, std::unique_ptr<Blueprint> bp) {
+ { std::move(a).add(std::move(bp)) } -> std::same_as<T&&>;
};
-// create a leaf blueprint that matches no documents
-std::unique_ptr<Blueprint> empty() {
- return std::make_unique<EmptyBlueprint>();
-}
+// inherit Blueprint to capture the default filter factory
+struct DefaultBlueprint : Blueprint {
+ void optimize(Blueprint* &) override { abort(); }
+ const State &getState() const override { abort(); }
+ void fetchPostings(const ExecuteInfo &) override { abort(); }
+ void freeze() override { abort(); }
+ SearchIteratorUP createSearch(search::fef::MatchData &, bool) const override { abort(); }
+};
-// create a leaf blueprint that matches all documents
-std::unique_ptr<Blueprint> full() {
- return std::make_unique<AlwaysTrueBlueprint>();
-}
+// need one of these to be able to create a SourceBlender
+struct NullSelector : ISourceSelector {
+ NullSelector() : ISourceSelector(7) {}
+ void setSource(uint32_t, Source) override { abort(); }
+ uint32_t getDocIdLimit() const override { abort(); }
+ void compactLidSpace(uint32_t) override { abort(); }
+ std::unique_ptr<sourceselector::Iterator> createIterator() const override { abort(); }
+};
+NullSelector null_selector;
// make a simple result containing the given documents
SimpleResult make_result(const std::vector<uint32_t> &docs) {
@@ -82,11 +73,89 @@ SimpleResult make_empty_result() {
return SimpleResult();
}
+// create a leaf blueprint that matches no documents
+std::unique_ptr<Blueprint> empty() {
+ return std::make_unique<EmptyBlueprint>();
+}
+
+// create a leaf blueprint that matches all documents
+std::unique_ptr<Blueprint> full() {
+ return std::make_unique<AlwaysTrueBlueprint>();
+}
+
// create a leaf blueprint with the specified hits
std::unique_ptr<Blueprint> leaf(const std::vector<uint32_t> &docs) {
return std::make_unique<SimpleBlueprint>(make_result(docs));
}
+// Describes blueprint children with a list of simple factories that
+// can later be used to create them.
+struct Children {
+ using Factory = std::function<Blueprint::UP()>;
+ std::vector<Factory> list;
+ Children() : list() {}
+ size_t size() const { return list.size(); }
+ Children &&leaf(const std::vector<uint32_t> &docs) && {
+ list.push_back([docs](){ return ::leaf(docs); });
+ return std::move(*this);
+ }
+ Children &&full() && {
+ list.push_back([](){ return ::full(); });
+ return std::move(*this);
+ }
+ Children &&empty() && {
+ list.push_back([](){ return ::empty(); });
+ return std::move(*this);
+ }
+ template <FilterFactoryBuilder Builder>
+ Builder &&apply(Builder &&builder) const {
+ for (const Factory &make_child: list) {
+ std::move(builder).add(make_child());
+ }
+ return std::move(builder);
+ }
+};
+
+// Combine children blueprints using a shared filter creation
+// algorithm. Satisfies the FilterFactory concept.
+struct Combine {
+ using factory_fun = std::function<std::unique_ptr<SearchIterator>(const Blueprint::Children &, bool, Constraint)>;
+ factory_fun fun;
+ Blueprint::Children list;
+ Combine(factory_fun fun_in) noexcept : fun(fun_in), list() {}
+ Combine &&add(std::unique_ptr<Blueprint> child) && {
+ list.push_back(std::move(child));
+ return std::move(*this);
+ }
+ Combine &&add(const Children &children) && {
+ return children.apply(std::move(*this));
+ }
+ auto createFilterSearch(bool strict, Constraint upper_or_lower) const {
+ return fun(list, strict, upper_or_lower);
+ }
+ ~Combine();
+};
+Combine::~Combine() = default;
+
+// Make a specific (intermediate) blueprint that you can add children
+// to. Satisfies the FilterFactory concept.
+template <FilterFactory T>
+struct Make {
+ T blueprint;
+ template <typename ... Args>
+ Make(Args && ... args) : blueprint(std::forward<Args>(args)...) {}
+ Make &&add(std::unique_ptr<Blueprint> child) && {
+ blueprint.addChild(std::move(child));
+ return std::move(*this);
+ }
+ Make &&add(const Children &children) && {
+ return children.apply(std::move(*this));
+ }
+ auto createFilterSearch(bool strict, Constraint upper_or_lower) const {
+ return blueprint.createFilterSearch(strict, upper_or_lower);
+ }
+};
+
// what kind of results are we expecting from a filter search?
struct Expect {
Trinary matches_any;
@@ -101,6 +170,8 @@ struct Expect {
hits = make_empty_result();
}
}
+ static Expect empty() { return Expect(Trinary::False); }
+ static Expect full() { return Expect(Trinary::True); }
};
template <FilterFactory Blueprint>
@@ -127,31 +198,67 @@ void verify(const Blueprint &blueprint, const Expect &upper_and_lower) {
}
TEST(FilterSearchTest, empty_leaf) {
- verify(*empty(), Expect(Trinary::False));
+ verify(*empty(), Expect::empty());
}
TEST(FilterSearchTest, full_leaf) {
- verify(*full(), Expect(Trinary::True));
+ verify(*full(), Expect::full());
}
TEST(FilterSearchTest, custom_leaf) {
verify(*leaf({5,10,20}), Expect({5,10,20}));
}
+TEST(FilterSearchTest, default_blueprint) {
+ verify(DefaultBlueprint(), Expect::full(), Expect::empty());
+}
+
TEST(FilterSearchTest, simple_or) {
- verify(Combine(Blueprint::create_or_filter)
- .add(leaf({5, 10}))
- .add(leaf({7}))
- .add(leaf({3, 11})),
- Expect({3, 5, 7, 10, 11}));
+ auto child_list = Children()
+ .leaf({5, 10})
+ .leaf({7})
+ .leaf({3, 11});
+ auto expected = Expect({3, 5, 7, 10, 11});
+ verify(Combine(Blueprint::create_or_filter).add(child_list), expected);
+ verify(Make<OrBlueprint>().add(child_list), expected);
+ verify(Combine(Blueprint::create_atmost_or_filter).add(child_list), expected, Expect::empty());
+ verify(Make<WeakAndBlueprint>(child_list.size()).add(child_list), expected, Expect::empty());
+ verify(Make<SourceBlenderBlueprint>(null_selector).add(child_list), expected, Expect::empty());
}
TEST(FilterSearchTest, simple_and) {
- verify(Combine(Blueprint::create_and_filter)
- .add(leaf({1, 2, 3, 4, 5, 6}))
- .add(leaf({2, 4, 6, 7}))
- .add(leaf({1, 4, 6, 7, 10})),
- Expect({4, 6}));
+ auto child_list = Children()
+ .leaf({1, 2, 3, 4, 5, 6})
+ .leaf({2, 4, 6, 7})
+ .leaf({1, 4, 6, 7, 10});
+ auto expected = Expect({4, 6});
+ verify(Combine(Blueprint::create_and_filter).add(child_list), expected);
+ verify(Make<AndBlueprint>().add(child_list), expected);
+ verify(Combine(Blueprint::create_atmost_and_filter).add(child_list), expected, Expect::empty());
+ verify(Make<NearBlueprint>(3).add(child_list), expected, Expect::empty());
+ verify(Make<ONearBlueprint>(3).add(child_list), expected, Expect::empty());
+}
+
+TEST(FilterSearchTest, simple_andnot) {
+ auto child_list = Children()
+ .leaf({1, 2, 3, 4, 5, 6})
+ .leaf({2, 4, 6})
+ .leaf({4, 6, 7});
+ auto expected = Expect({1, 3, 5});
+ verify(Combine(Blueprint::create_andnot_filter).add(child_list), expected);
+ verify(Make<AndNotBlueprint>().add(child_list), expected);
+}
+
+TEST(FilterSearchTest, rank_filter) {
+ auto child_list1 = Children().leaf({1,2,3}).empty().full();
+ auto child_list2 = Children().empty().leaf({1,2,3}).full();
+ auto child_list3 = Children().full().leaf({1,2,3}).empty();
+ verify(Combine(Blueprint::create_first_child_filter).add(child_list1), Expect({1,2,3}));
+ verify(Combine(Blueprint::create_first_child_filter).add(child_list2), Expect::empty());
+ verify(Combine(Blueprint::create_first_child_filter).add(child_list3), Expect::full());
+ verify(Make<RankBlueprint>().add(child_list1), Expect({1,2,3}));
+ verify(Make<RankBlueprint>().add(child_list2), Expect::empty());
+ verify(Make<RankBlueprint>().add(child_list3), Expect::full());
}
GTEST_MAIN_RUN_ALL_TESTS()