summaryrefslogtreecommitdiffstats
path: root/searchcore/src/tests/proton/matching
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2022-09-04 21:41:42 +0000
committerHenning Baldersheim <balder@yahoo-inc.com>2022-09-08 07:50:16 +0000
commit8a2279f1c8a50903960a8e3854c270377eed3f54 (patch)
treed6ac792c2df814fed4dfedce28c2ffad52d657d9 /searchcore/src/tests/proton/matching
parent5425fb81e33874f0d767743b01859b9efe26139b (diff)
Find and locate range query item in the 'and' path of a query.
If found and correlates with match phase limiter, copy the limits into the limiter.
Diffstat (limited to 'searchcore/src/tests/proton/matching')
-rw-r--r--searchcore/src/tests/proton/matching/match_phase_limiter/CMakeLists.txt1
-rw-r--r--searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp108
2 files changed, 103 insertions, 6 deletions
diff --git a/searchcore/src/tests/proton/matching/match_phase_limiter/CMakeLists.txt b/searchcore/src/tests/proton/matching/match_phase_limiter/CMakeLists.txt
index e2ebb119045..276a0dcbf6b 100644
--- a/searchcore/src/tests/proton/matching/match_phase_limiter/CMakeLists.txt
+++ b/searchcore/src/tests/proton/matching/match_phase_limiter/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchcore_match_phase_limiter_test_app TEST
match_phase_limiter_test.cpp
DEPENDS
searchcore_matching
+ searchlib_test
)
vespa_add_test(NAME searchcore_match_phase_limiter_test_app COMMAND searchcore_match_phase_limiter_test_app)
diff --git a/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp b/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
index 5b3b9f962f7..59eff86fab4 100644
--- a/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
+++ b/searchcore/src/tests/proton/matching/match_phase_limiter/match_phase_limiter_test.cpp
@@ -1,15 +1,22 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchcore/proton/matching/match_phase_limiter.h>
+#include <vespa/searchcore/proton/matching/rangequerylocator.h>
#include <vespa/searchlib/queryeval/termasstring.h>
#include <vespa/searchlib/queryeval/andsearchstrict.h>
#include <vespa/searchlib/queryeval/searchable.h>
#include <vespa/searchlib/queryeval/fake_requestcontext.h>
#include <vespa/searchlib/queryeval/blueprint.h>
+#include <vespa/searchlib/query/tree/simplequery.h>
#include <vespa/searchlib/fef/termfieldmatchdataarray.h>
#include <vespa/searchlib/fef/termfieldmatchdata.h>
+#include <vespa/searchlib/test/mock_attribute_manager.h>
+#include <vespa/searchlib/attribute/attribute_blueprint_factory.h>
+#include <vespa/searchlib/attribute/attributefactory.h>
+#include <vespa/searchcommon/attribute/config.h>
#include <vespa/searchlib/engine/trace.h>
#include <vespa/vespalib/data/slime/slime.h>
+#include <vespa/vespalib/util/stringfmt.h>
using namespace proton::matching;
using namespace search::engine;
@@ -24,6 +31,9 @@ using search::queryeval::AndSearchStrict;
using search::queryeval::termAsString;
using search::queryeval::FakeRequestContext;
using search::fef::TermFieldMatchDataArray;
+using search::attribute::BasicType;
+using search::attribute::Config;
+using vespalib::make_string_short::fmt;
//-----------------------------------------------------------------------------
@@ -90,6 +100,15 @@ struct MockSearchable : Searchable {
}
};
+class MockRangeLocator : public RangeQueryLocator {
+public:
+ RangeLimitMetaInfo locate() const override {
+ return {};
+ }
+
+public:
+};
+
//-----------------------------------------------------------------------------
TEST("require that match phase limit calculator gives expert values") {
@@ -160,12 +179,14 @@ TEST("require that max group size is calculated correctly") {
TEST("require that the attribute limiter works correctly") {
FakeRequestContext requestContext;
+ MockRangeLocator rangeLocator;
for (int i = 0; i <= 7; ++i) {
bool descending = (i & 1) != 0;
bool strict = (i & 2) != 0;
bool diverse = (i & 4) != 0;
MockSearchable searchable;
- AttributeLimiter limiter(searchable, requestContext, "limiter_attribute", descending, "category", 10.0, AttributeLimiter::LOOSE);
+ AttributeLimiter limiter(rangeLocator, searchable, requestContext, "limiter_attribute", descending,
+ "category", 10.0, AttributeLimiter::LOOSE);
EXPECT_EQUAL(0u, searchable.create_cnt);
EXPECT_FALSE(limiter.was_used());
SearchIterator::UP s1 = limiter.create_search(42, diverse ? 3 : 42, strict);
@@ -215,7 +236,8 @@ TEST("require that no limiter has no behavior") {
TEST("require that the match phase limiter may chose not to limit the query") {
FakeRequestContext requestContext;
MockSearchable searchable;
- MatchPhaseLimiter yes_limiter(10000, searchable, requestContext,
+ MockRangeLocator rangeLocator;
+ MatchPhaseLimiter yes_limiter(10000, rangeLocator, searchable, requestContext,
DegradationParams("limiter_attribute", 1000, true, 1.0, 0.2, 1.0),
DiversityParams("", 1, 10.0, AttributeLimiter::LOOSE));
MaybeMatchPhaseLimiter &limiter = yes_limiter;
@@ -234,9 +256,10 @@ struct MaxFilterCoverageLimiterFixture {
FakeRequestContext requestContext;
MockSearchable searchable;
+ MockRangeLocator rangeLocator;
MatchPhaseLimiter::UP getMaxFilterCoverageLimiter() {
- auto yes_limiter = std::make_unique<MatchPhaseLimiter>(10000, searchable, requestContext,
+ auto yes_limiter = std::make_unique<MatchPhaseLimiter>(10000, rangeLocator, searchable, requestContext,
DegradationParams("limiter_attribute", 10000, true, 0.05, 1.0, 1.0),
DiversityParams("", 1, 10.0, AttributeLimiter::LOOSE));
MaybeMatchPhaseLimiter &limiter = *yes_limiter;
@@ -286,7 +309,8 @@ void verify(vespalib::stringref expected, const vespalib::Slime & slime) {
TEST("require that the match phase limiter is able to pre-limit the query") {
FakeRequestContext requestContext;
MockSearchable searchable;
- MatchPhaseLimiter yes_limiter(10000, searchable, requestContext,
+ MockRangeLocator rangeLocator;
+ MatchPhaseLimiter yes_limiter(10000, rangeLocator, searchable, requestContext,
DegradationParams("limiter_attribute", 500, true, 1.0, 0.2, 1.0),
DiversityParams("", 1, 10.0, AttributeLimiter::LOOSE));
MaybeMatchPhaseLimiter &limiter = yes_limiter;
@@ -341,7 +365,8 @@ TEST("require that the match phase limiter is able to pre-limit the query") {
TEST("require that the match phase limiter is able to post-limit the query") {
MockSearchable searchable;
FakeRequestContext requestContext;
- MatchPhaseLimiter yes_limiter(10000, searchable, requestContext,
+ MockRangeLocator rangeLocator;
+ MatchPhaseLimiter yes_limiter(10000, rangeLocator, searchable, requestContext,
DegradationParams("limiter_attribute", 1500, true, 1.0, 0.2, 1.0),
DiversityParams("", 1, 10.0, AttributeLimiter::LOOSE));
MaybeMatchPhaseLimiter &limiter = yes_limiter;
@@ -373,7 +398,8 @@ void verifyDiversity(AttributeLimiter::DiversityCutoffStrategy strategy)
{
MockSearchable searchable;
FakeRequestContext requestContext;
- MatchPhaseLimiter yes_limiter(10000, searchable, requestContext,
+ MockRangeLocator rangeLocator;
+ MatchPhaseLimiter yes_limiter(10000, rangeLocator, searchable, requestContext,
DegradationParams("limiter_attribute", 500, true, 1.0, 0.2, 1.0),
DiversityParams("category", 10, 13.1, strategy));
MaybeMatchPhaseLimiter &limiter = yes_limiter;
@@ -401,4 +427,74 @@ TEST("require that the match phase limiter can use strict diversity") {
verifyDiversity(AttributeLimiter::STRICT);
}
+struct RangeLimitFixture {
+ RangeLimitFixture()
+ : attrSearchable(),
+ attrManager(),
+ attributeContext(attrManager.createContext()),
+ requestContext(attributeContext.get()),
+ a1FieldSpec("a1", 1, 1),
+ f1FieldSpec("f1", 2, 2)
+ {
+ attrManager.addAttribute(search::AttributeFactory::createAttribute(a1FieldSpec.getName(), Config(BasicType("int64"))));
+ attrManager.addAttribute(search::AttributeFactory::createAttribute(f1FieldSpec.getName(), Config(BasicType("double"))));
+ }
+ search::AttributeBlueprintFactory attrSearchable;
+ search::attribute::test::MockAttributeManager attrManager;
+ search::attribute::IAttributeContext::UP attributeContext;
+ FakeRequestContext requestContext;
+ FieldSpec a1FieldSpec;
+ FieldSpec f1FieldSpec;
+};
+
+void
+verifyLocateRange(const vespalib::string & from, const vespalib::string & to,
+ const FieldSpec & fieldSpec, RangeLimitFixture & f)
+{
+ search::query::SimpleNumberTerm term(fmt("[%s;%s]", from.c_str(), to.c_str()), fieldSpec.getName(), 0, search::query::Weight(1));
+ Blueprint::UP bp = f.attrSearchable.createBlueprint(f.requestContext, fieldSpec, term);
+ EXPECT_FALSE(LocateRangeItemFromQuery(*bp, 0).locate().valid());
+ EXPECT_TRUE(LocateRangeItemFromQuery(*bp, fieldSpec.getFieldId()).locate().valid());
+ LocateRangeItemFromQuery locator(*bp, fieldSpec.getFieldId());
+ RangeLimitMetaInfo rangeInfo = locator.locate();
+ EXPECT_EQUAL(from, rangeInfo.low());
+ EXPECT_EQUAL(to, rangeInfo.high());
+}
+
+TEST_F("require that RangeLocator locates range from attribute blueprint", RangeLimitFixture) {
+ verifyLocateRange("7", "100", f.a1FieldSpec, f);
+ verifyLocateRange("7.7", "100.3", f.f1FieldSpec, f);
+}
+
+
+void
+verifyRangeIsReflectedInLimiter(const vespalib::string & from, const vespalib::string & to,
+ const FieldSpec & fieldSpec, RangeLimitFixture & f)
+{
+ search::query::SimpleNumberTerm term(fmt("[%s;%s]", from.c_str(), to.c_str()), fieldSpec.getName(), 0, search::query::Weight(1));
+ Blueprint::UP bp = f.attrSearchable.createBlueprint(f.requestContext, fieldSpec, term);
+ LocateRangeItemFromQuery locator(*bp, fieldSpec.getFieldId());
+ RangeLimitMetaInfo rangeInfo = locator.locate();
+ EXPECT_EQUAL(from, rangeInfo.low());
+ EXPECT_EQUAL(to, rangeInfo.high());
+
+ MockSearchable mockSearchable;
+ MatchPhaseLimiter yes_limiter(10000, locator, mockSearchable, f.requestContext,
+ DegradationParams(fieldSpec.getName(), 500, true, 1.0, 0.2, 1.0),
+ DiversityParams());
+ MaybeMatchPhaseLimiter &limiter = yes_limiter;
+ SearchIterator::UP search = limiter.maybe_limit(prepare(new MockSearch("search")), 0.1, 100000, nullptr);
+ limiter.updateDocIdSpaceEstimate(1000, 9000);
+ EXPECT_EQUAL(1680u, limiter.getDocIdSpaceEstimate());
+ auto *strict_and = dynamic_cast<LimitedSearch *>(search.get());
+ ASSERT_TRUE(strict_and != nullptr);
+ const auto *ms1 = dynamic_cast<const MockSearch *>(&strict_and->getFirst());
+ ASSERT_TRUE(ms1 != nullptr);
+ EXPECT_EQUAL(fmt("[%s;%s;-5000]", from.c_str(), to.c_str()), ms1->term);
+}
+TEST_F("require that range term is used to adjust limiter", RangeLimitFixture) {
+ verifyRangeIsReflectedInLimiter("7", "100", f.a1FieldSpec, f);
+ verifyRangeIsReflectedInLimiter("7.7", "100.3", f.f1FieldSpec, f);
+}
+
TEST_MAIN() { TEST_RUN_ALL(); }