summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2019-10-08 15:19:27 +0000
committerHåvard Pettersen <havardpe@oath.com>2019-10-08 15:25:56 +0000
commit0f21137ac41a01ce9a77460b67d96fe7d76c2983 (patch)
tree00447d787793b5092ffe827ccf776bbf17e7bf1d /searchlib
parent60f301c40a1a57634247f3d240fdd1f2341a4420 (diff)
improve fake searchable attributes
blueprint/search iterator now exposes a more functional attribute search context fake attribute searches will now unpack a single entry containing the sum of all matched weights improve matcher test for same element matching by also using the attribute element iterator added tests for identifying matching elements in docsum request
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/queryeval/fake_searchable/CMakeLists.txt1
-rw-r--r--searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp273
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/fake_search.cpp41
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/fake_search.h10
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/fake_searchable.cpp17
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/fake_searchable.h16
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp49
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h13
8 files changed, 236 insertions, 184 deletions
diff --git a/searchlib/src/tests/queryeval/fake_searchable/CMakeLists.txt b/searchlib/src/tests/queryeval/fake_searchable/CMakeLists.txt
index e5f5e6aadf3..c98306aa179 100644
--- a/searchlib/src/tests/queryeval/fake_searchable/CMakeLists.txt
+++ b/searchlib/src/tests/queryeval/fake_searchable/CMakeLists.txt
@@ -4,5 +4,6 @@ vespa_add_executable(searchlib_fake_searchable_test_app TEST
fake_searchable_test.cpp
DEPENDS
searchlib
+ gtest
)
vespa_add_test(NAME searchlib_fake_searchable_test_app COMMAND searchlib_fake_searchable_test_app)
diff --git a/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp b/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp
index 661ca9c2ba3..6cef4479439 100644
--- a/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp
+++ b/searchlib/src/tests/queryeval/fake_searchable/fake_searchable_test.cpp
@@ -1,5 +1,6 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <vespa/vespalib/testkit/testapp.h>
+
+#include <vespa/vespalib/gtest/gtest.h>
#include <vespa/searchlib/queryeval/fake_searchable.h>
#include <vespa/searchlib/queryeval/fake_requestcontext.h>
@@ -8,76 +9,58 @@
#include <vespa/searchlib/query/tree/simplequery.h>
#include <vespa/searchlib/fef/matchdata.h>
-#include <vespa/log/log.h>
-LOG_SETUP("fake_searchable_test");
-
using namespace search::queryeval;
using namespace search::query;
using namespace search::fef;
-class Test : public vespalib::TestApp {
-public:
- ~Test();
- int Main() override;
- void testTestFakeResult();
- void testTerm();
- void testPhrase();
- void testWeightedSet();
- void testMultiField();
- void testPhraseWithEmptyChild();
-private:
- FakeRequestContext _requestContext;
+struct FakeSearchableTest : ::testing::Test {
+ Weight w;
+ FakeRequestContext req_ctx;
+ FakeSearchable source;
+ FakeSearchableTest() : w(100), req_ctx(), source() {}
};
-Test::~Test() {}
-void
-Test::testTestFakeResult()
-{
- EXPECT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6).elem(6).doc(6),
- FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6).elem(6).doc(6));
+TEST(FakeResultTest, require_that_fake_result_works) {
+ EXPECT_EQ(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6).elem(6).doc(6),
+ FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6).elem(6).doc(6));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(1).elem(5).len(15).weight(5).pos(5));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(1).elem(5).len(15).weight(5).pos(5));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(1).len(15).weight(5).pos(5));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(1).len(15).weight(5).pos(5));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(19).weight(5).pos(5));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(19).weight(5).pos(5));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(15).weight(1).pos(5));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(15).weight(1).pos(5));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(15).weight(5).pos(1));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(15).weight(5).pos(1));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).doc(6));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).doc(6));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).elem(6));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).elem(6));
- EXPECT_NOT_EQUAL(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5),
- FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6));
+ EXPECT_FALSE(FakeResult().doc(5).elem(5).len(15).weight(5).pos(5) ==
+ FakeResult().doc(5).elem(5).len(15).weight(5).pos(5).pos(6));
}
-void
-Test::testTerm()
-{
- Weight w(100);
-
- FakeSearchable source;
+TEST_F(FakeSearchableTest, require_that_term_search_works) {
source.addResult("fieldfoo", "word1",
- FakeResult().doc(5).pos(3));
+ FakeResult().doc(5).elem(2).pos(3).elem(4).pos(5));
SimpleStringTerm termNode("word1", "viewfoo", 1, w);
FieldSpecList fields;
fields.add(FieldSpec("fieldfoo", 1, 1));
- Blueprint::UP bp = source.createBlueprint(_requestContext, fields, termNode);
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode);
for (int i = 0; i <= 1; ++i) {
bool strict = (i == 0);
- TEST_STATE(strict ? "strict" : "non-strict");
+ SCOPED_TRACE(strict ? "strict" : "non-strict");
MatchData::UP md = MatchData::makeTestInstance(100, 10);
bp->fetchPostings(strict);
SearchIterator::UP search = bp->createSearch(*md, strict);
@@ -85,21 +68,26 @@ Test::testTerm()
EXPECT_TRUE(!search->seek(3));
if (strict) {
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
} else {
EXPECT_TRUE(search->seek(5u));
}
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
{ // test doc 5 results
search->unpack(5u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_EQUAL(5u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(5u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(2u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(3u, itr.getPosition());
+ EXPECT_EQ(2u, itr.getElementId());
+ EXPECT_EQ(3u, itr.getPosition());
+ itr.next();
+ ASSERT_TRUE(itr.valid());
+ EXPECT_EQ(4u, itr.getElementId());
+ EXPECT_EQ(5u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -111,12 +99,7 @@ Test::testTerm()
}
}
-void
-Test::testPhrase()
-{
- Weight w(100);
-
- FakeSearchable source;
+TEST_F(FakeSearchableTest, require_that_phrase_search_works) {
source.addResult("fieldfoo", "word1",
FakeResult().doc(3).pos(7).doc(5).pos(3));
source.addResult("fieldfoo", "word2",
@@ -128,10 +111,10 @@ Test::testPhrase()
FieldSpecList fields;
fields.add(FieldSpec("fieldfoo", 1, 1));
- Blueprint::UP bp = source.createBlueprint(_requestContext, fields, phraseNode);
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, phraseNode);
for (int i = 0; i <= 1; ++i) {
bool strict = (i == 0);
- TEST_STATE(strict ? "strict" : "non-strict");
+ SCOPED_TRACE(strict ? "strict" : "non-strict");
MatchData::UP md = MatchData::makeTestInstance(100, 10);
bp->fetchPostings(strict);
SearchIterator::UP search = bp->createSearch(*md, strict);
@@ -139,21 +122,21 @@ Test::testPhrase()
EXPECT_TRUE(!search->seek(3));
if (strict) {
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
} else {
EXPECT_TRUE(search->seek(5u));
}
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
{ // test doc 5 results
search->unpack(5u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_EQUAL(5u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(5u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(3u, itr.getPosition());
+ EXPECT_EQ(3u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -165,12 +148,7 @@ Test::testPhrase()
}
}
-void
-Test::testWeightedSet()
-{
- Weight w(100);
-
- FakeSearchable source;
+TEST_F(FakeSearchableTest, require_that_weigheted_set_search_works) {
source.addResult("fieldfoo", "friend1",
FakeResult().doc(3).doc(5).doc(7).doc(9));
source.addResult("fieldfoo", "friend2",
@@ -184,10 +162,10 @@ Test::testWeightedSet()
FieldSpecList fields;
fields.add(FieldSpec("fieldfoo", 1, 1));
- Blueprint::UP bp = source.createBlueprint(_requestContext, fields, weightedSet);
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, weightedSet);
for (int i = 0; i <= 1; ++i) {
bool strict = (i == 0);
- TEST_STATE(strict ? "strict" : "non-strict");
+ SCOPED_TRACE(strict ? "strict" : "non-strict");
MatchData::UP md = MatchData::makeTestInstance(100, 10);
bp->fetchPostings(strict);
SearchIterator::UP search = bp->createSearch(*md, strict);
@@ -195,24 +173,24 @@ Test::testWeightedSet()
EXPECT_TRUE(!search->seek(2));
if (strict) {
- EXPECT_EQUAL(3u, search->getDocId());
+ EXPECT_EQ(3u, search->getDocId());
} else {
EXPECT_TRUE(search->seek(3u));
}
- EXPECT_EQUAL(3u, search->getDocId());
+ EXPECT_EQ(3u, search->getDocId());
{ // test doc 3 results
search->unpack(3u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_EQUAL(3u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(3u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(2u, itr.size());
+ EXPECT_EQ(2u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(2, itr.getElementWeight());
+ EXPECT_EQ(2, itr.getElementWeight());
itr.next();
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(1, itr.getElementWeight());
+ EXPECT_EQ(1, itr.getElementWeight());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -227,12 +205,12 @@ Test::testWeightedSet()
search->unpack(9u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_EQUAL(9u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(9u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(1, itr.getElementWeight());
+ EXPECT_EQ(1, itr.getElementWeight());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -244,12 +222,7 @@ Test::testWeightedSet()
}
}
-void
-Test::testMultiField()
-{
- Weight w(100);
-
- FakeSearchable source;
+TEST_F(FakeSearchableTest, require_that_multi_field_search_works) {
source.addResult("fieldfoo", "word1",
FakeResult().doc(5).pos(3));
source.addResult("fieldbar", "word1",
@@ -260,10 +233,10 @@ Test::testMultiField()
FieldSpecList fields;
fields.add(FieldSpec("fieldfoo", 1, 1));
fields.add(FieldSpec("fieldbar", 2, 2));
- Blueprint::UP bp = source.createBlueprint(_requestContext, fields, termNode);
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode);
for (int i = 0; i <= 1; ++i) {
bool strict = (i == 0);
- TEST_STATE(strict ? "strict" : "non-strict");
+ SCOPED_TRACE(strict ? "strict" : "non-strict");
MatchData::UP md = MatchData::makeTestInstance(100, 10);
bp->fetchPostings(strict);
SearchIterator::UP search = bp->createSearch(*md, strict);
@@ -271,58 +244,58 @@ Test::testMultiField()
EXPECT_TRUE(!search->seek(3));
if (strict) {
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
} else {
EXPECT_TRUE(search->seek(5u));
}
- EXPECT_EQUAL(5u, search->getDocId());
+ EXPECT_EQ(5u, search->getDocId());
{ // test doc 5 results
search->unpack(5u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_EQUAL(5u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(5u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(3u, itr.getPosition());
+ EXPECT_EQ(3u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
{
TermFieldMatchData &data = *md->resolveTermField(2);
- EXPECT_EQUAL(2u, data.getFieldId());
- EXPECT_EQUAL(5u, data.getDocId());
+ EXPECT_EQ(2u, data.getFieldId());
+ EXPECT_EQ(5u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(7u, itr.getPosition());
+ EXPECT_EQ(7u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
}
EXPECT_TRUE(!search->seek(7));
if (strict) {
- EXPECT_EQUAL(10u, search->getDocId());
+ EXPECT_EQ(10u, search->getDocId());
} else {
EXPECT_TRUE(search->seek(10u));
}
- EXPECT_EQUAL(10u, search->getDocId());
+ EXPECT_EQ(10u, search->getDocId());
{ // test doc 10 results
search->unpack(10u);
{
TermFieldMatchData &data = *md->resolveTermField(1);
- EXPECT_EQUAL(1u, data.getFieldId());
- EXPECT_NOT_EQUAL(10u, data.getDocId());
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_NE(10u, data.getDocId());
}
{
TermFieldMatchData &data = *md->resolveTermField(2);
- EXPECT_EQUAL(2u, data.getFieldId());
- EXPECT_EQUAL(10u, data.getDocId());
+ EXPECT_EQ(2u, data.getFieldId());
+ EXPECT_EQ(10u, data.getDocId());
FieldPositionsIterator itr = data.getIterator();
- EXPECT_EQUAL(1u, itr.size());
+ EXPECT_EQ(1u, itr.size());
ASSERT_TRUE(itr.valid());
- EXPECT_EQUAL(2u, itr.getPosition());
+ EXPECT_EQ(2u, itr.getPosition());
itr.next();
EXPECT_TRUE(!itr.valid());
}
@@ -334,12 +307,7 @@ Test::testMultiField()
}
}
-void
-Test::testPhraseWithEmptyChild()
-{
- Weight w(100);
-
- FakeSearchable source;
+TEST_F(FakeSearchableTest, require_that_phrase_with_empty_child_works) {
source.addResult("fieldfoo", "word1",
FakeResult().doc(3).pos(7).doc(5).pos(3));
@@ -349,10 +317,10 @@ Test::testPhraseWithEmptyChild()
FieldSpecList fields;
fields.add(FieldSpec("fieldfoo", 1, 1));
- Blueprint::UP bp = source.createBlueprint(_requestContext, fields, phraseNode);
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, phraseNode);
for (int i = 0; i <= 1; ++i) {
bool strict = (i == 0);
- TEST_STATE(strict ? "strict" : "non-strict");
+ SCOPED_TRACE(strict ? "strict" : "non-strict");
MatchData::UP md = MatchData::makeTestInstance(100, 10);
bp->fetchPostings(strict);
SearchIterator::UP search = bp->createSearch(*md, strict);
@@ -365,17 +333,58 @@ Test::testPhraseWithEmptyChild()
}
}
-int
-Test::Main()
-{
- TEST_INIT("fake_searchable_test");
- testTestFakeResult();
- testTerm();
- testPhrase();
- testWeightedSet();
- testMultiField();
- testPhraseWithEmptyChild();
- TEST_DONE();
+TEST_F(FakeSearchableTest, require_that_match_data_is_compressed_for_attributes) {
+ source.is_attr(true);
+ source.addResult("attrfoo", "word1",
+ FakeResult().doc(5).elem(2).weight(6).pos(3).elem(4).weight(8).pos(5));
+ SimpleStringTerm termNode("word1", "viewfoo", 1, w);
+ FieldSpecList fields;
+ fields.add(FieldSpec("attrfoo", 1, 1));
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode);
+ MatchData::UP md = MatchData::makeTestInstance(100, 10);
+ bp->fetchPostings(false);
+ SearchIterator::UP search = bp->createSearch(*md, false);
+ search->initFullRange();
+ EXPECT_TRUE(search->seek(5));
+ search->unpack(5u);
+ {
+ TermFieldMatchData &data = *md->resolveTermField(1);
+ EXPECT_EQ(1u, data.getFieldId());
+ EXPECT_EQ(5u, data.getDocId());
+ FieldPositionsIterator itr = data.getIterator();
+ EXPECT_EQ(1u, itr.size());
+ ASSERT_TRUE(itr.valid());
+ EXPECT_EQ(14u, itr.getElementWeight()); // 6 + 8
+ itr.next();
+ EXPECT_TRUE(!itr.valid());
+ }
+}
+
+TEST_F(FakeSearchableTest, require_that_relevant_data_can_be_obtained_from_fake_attribute_search_context) {
+ source.is_attr(true);
+ source.addResult("attrfoo", "word1",
+ FakeResult().doc(5).elem(2).weight(6).pos(3).elem(4).weight(8).pos(5));
+ SimpleStringTerm termNode("word1", "viewfoo", 1, w);
+ FieldSpecList fields;
+ fields.add(FieldSpec("attrfoo", 1, 1));
+ Blueprint::UP bp = source.createBlueprint(req_ctx, fields, termNode);
+ MatchData::UP md = MatchData::makeTestInstance(100, 10);
+ bp->fetchPostings(false);
+ SearchIterator::UP search = bp->createSearch(*md, false);
+ EXPECT_EQ(bp->get_attribute_search_context(), search->getAttributeSearchContext());
+ const auto *attr_ctx = bp->get_attribute_search_context();
+ ASSERT_TRUE(attr_ctx);
+ EXPECT_EQ(attr_ctx->attributeName(), "attrfoo");
+ int32_t elem_weight = 0;
+ EXPECT_EQ(attr_ctx->find(4, 0, elem_weight), -1);
+ int32_t elem_id = attr_ctx->find(5, 0, elem_weight);
+ EXPECT_EQ(elem_id, 2);
+ EXPECT_EQ(elem_weight, 6);
+ elem_id = attr_ctx->find(5, 3, elem_weight);
+ EXPECT_EQ(elem_id, 4);
+ EXPECT_EQ(elem_weight, 8);
+ EXPECT_EQ(attr_ctx->find(5, 5, elem_weight), -1);
+ EXPECT_EQ(attr_ctx->find(6, 0, elem_weight), -1);
}
-TEST_APPHOOK(Test);
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_search.cpp b/searchlib/src/vespa/searchlib/queryeval/fake_search.cpp
index 099e28f552a..4ee214b0f16 100644
--- a/searchlib/src/vespa/searchlib/queryeval/fake_search.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/fake_search.cpp
@@ -9,32 +9,6 @@
namespace search {
namespace queryeval {
-namespace {
-
-struct FakeContext : search::attribute::ISearchContext {
- int32_t onFind(DocId, int32_t, int32_t &) const override { return -1; }
- int32_t onFind(DocId, int32_t) const override { return -1; }
- unsigned int approximateHits() const override { return 0; }
- std::unique_ptr<SearchIterator> createIterator(fef::TermFieldMatchData *, bool) override { abort(); }
- void fetchPostings(bool) override { }
- bool valid() const override { return true; }
- search::Int64Range getAsIntegerTerm() const override { abort(); }
- const search::QueryTermBase * queryTerm() const override { abort(); }
- const vespalib::string &attributeName() const override { abort(); }
-};
-
-} // namespace search::queryeval::<unnamed>
-
-void
-FakeSearch::is_attr(bool value)
-{
- if (value) {
- _ctx = std::make_unique<FakeContext>();
- } else {
- _ctx.reset();
- }
-}
-
void
FakeSearch::doSeek(uint32_t docid)
{
@@ -59,13 +33,20 @@ FakeSearch::doUnpack(uint32_t docid)
const Doc &doc = _result.inspect()[_offset];
assert(doc.docId == docid);
_tfmda[0]->reset(docid);
+ int32_t sum_weight = 0;
for (uint32_t i = 0; i < doc.elements.size(); ++i) {
- const Elem &elem =doc.elements[i];
- for (uint32_t j = 0; j < elem.positions.size(); ++j) {
- _tfmda[0]->appendPosition(PosCtx(elem.id, elem.positions[j],
- elem.weight, elem.length));
+ const Elem &elem = doc.elements[i];
+ sum_weight += elem.weight;
+ if (!is_attr()) {
+ for (uint32_t j = 0; j < elem.positions.size(); ++j) {
+ _tfmda[0]->appendPosition(PosCtx(elem.id, elem.positions[j],
+ elem.weight, elem.length));
+ }
}
}
+ if (is_attr()) {
+ _tfmda[0]->appendPosition(PosCtx(0, 0, sum_weight, 1));
+ }
}
void
diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_search.h b/searchlib/src/vespa/searchlib/queryeval/fake_search.h
index aa6df480a21..e629e849408 100644
--- a/searchlib/src/vespa/searchlib/queryeval/fake_search.h
+++ b/searchlib/src/vespa/searchlib/queryeval/fake_search.h
@@ -19,7 +19,7 @@ private:
FakeResult _result;
uint32_t _offset;
fef::TermFieldMatchDataArray _tfmda;
- std::unique_ptr<attribute::ISearchContext> _ctx;
+ const attribute::ISearchContext *_ctx;
bool valid() const { return _offset < _result.inspect().size(); }
uint32_t currId() const { return _result.inspect()[_offset].docId; }
@@ -32,16 +32,18 @@ public:
const FakeResult &res,
const fef::TermFieldMatchDataArray &tfmda)
: _tag(tag), _field(field), _term(term),
- _result(res), _offset(0), _tfmda(tfmda)
+ _result(res), _offset(0), _tfmda(tfmda),
+ _ctx(nullptr)
{
assert(_tfmda.size() == 1);
}
- void is_attr(bool value);
+ void attr_ctx(const attribute::ISearchContext *ctx) { _ctx = ctx; }
+ bool is_attr() const { return (_ctx != nullptr); }
void doSeek(uint32_t docid) override;
void doUnpack(uint32_t docid) override;
const PostingInfo *getPostingInfo() const override { return _result.postingInfo(); }
void visitMembers(vespalib::ObjectVisitor &visitor) const override;
- const attribute::ISearchContext *getAttributeSearchContext() const override { return _ctx.get(); }
+ const attribute::ISearchContext *getAttributeSearchContext() const override { return _ctx; }
};
} // namespace queryeval
diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_searchable.cpp b/searchlib/src/vespa/searchlib/queryeval/fake_searchable.cpp
index 997f9afc54f..4c678a9902f 100644
--- a/searchlib/src/vespa/searchlib/queryeval/fake_searchable.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/fake_searchable.cpp
@@ -21,7 +21,8 @@ namespace search::queryeval {
FakeSearchable::FakeSearchable()
: _tag("<undef>"),
- _map()
+ _map(),
+ _is_attr(false)
{
}
@@ -44,10 +45,11 @@ class LookupVisitor : public CreateBlueprintVisitorHelper
{
const Map &_map;
const vespalib::string _tag;
+ bool _is_attr;
public:
LookupVisitor(Searchable &searchable, const IRequestContext & requestContext,
- const Map &map, const vespalib::string &tag, const FieldSpec &field);
+ const Map &map, const vespalib::string &tag, bool is_attr, const FieldSpec &field);
~LookupVisitor();
template <class TermNode>
@@ -66,10 +68,11 @@ public:
template <class Map>
LookupVisitor<Map>::LookupVisitor(Searchable &searchable, const IRequestContext & requestContext,
- const Map &map, const vespalib::string &tag, const FieldSpec &field)
+ const Map &map, const vespalib::string &tag, bool is_attr, const FieldSpec &field)
: CreateBlueprintVisitorHelper(searchable, field, requestContext),
_map(map),
- _tag(tag)
+ _tag(tag),
+ _is_attr(is_attr)
{}
template <class Map>
@@ -86,8 +89,8 @@ LookupVisitor<Map>::visitTerm(TermNode &n) {
if (pos != _map.end()) {
result = pos->second;
}
- auto fake = std::make_unique<FakeBlueprint>(getField(), result);
- fake->tag(_tag).term(term_string);
+ auto fake = std::make_unique<FakeBlueprint>(getField(), result);
+ fake->tag(_tag).is_attr(_is_attr).term(term_string);
setResult(std::move(fake));
}
@@ -98,7 +101,7 @@ FakeSearchable::createBlueprint(const IRequestContext & requestContext,
const FieldSpec &field,
const search::query::Node &term)
{
- LookupVisitor<Map> visitor(*this, requestContext, _map, _tag, field);
+ LookupVisitor<Map> visitor(*this, requestContext, _map, _tag, _is_attr, field);
const_cast<Node &>(term).accept(visitor);
return visitor.getResult();
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/fake_searchable.h b/searchlib/src/vespa/searchlib/queryeval/fake_searchable.h
index 8f95c116bf5..a47ac18d88b 100644
--- a/searchlib/src/vespa/searchlib/queryeval/fake_searchable.h
+++ b/searchlib/src/vespa/searchlib/queryeval/fake_searchable.h
@@ -17,11 +17,11 @@ class FakeSearchable : public Searchable
{
private:
typedef std::pair<vespalib::string, vespalib::string> Key;
- typedef FakeResult Value;
- typedef std::map<Key, Value> Map;
+ typedef std::map<Key, FakeResult> Map;
vespalib::string _tag;
- Map _map;
+ Map _map;
+ bool _is_attr;
public:
/**
@@ -42,6 +42,16 @@ public:
}
/**
+ * Is this searchable searching attributes? Setting this to true
+ * will result in blueprints and search iterators exposing a
+ * mocked attribute search context interface.
+ **/
+ FakeSearchable &is_attr(bool value) {
+ _is_attr = value;
+ return *this;
+ }
+
+ /**
* Add a fake result to be returned for lookup on the given field
* and term combination.
*
diff --git a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp
index a140fb146d5..042de113a35 100644
--- a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.cpp
@@ -61,11 +61,46 @@ SimpleBlueprint::tag(const vespalib::string &t)
//-----------------------------------------------------------------------------
+namespace {
+
+struct FakeContext : attribute::ISearchContext {
+ const vespalib::string &name;
+ const FakeResult &result;
+ FakeContext(const vespalib::string &name_in, const FakeResult &result_in)
+ : name(name_in), result(result_in) {}
+ int32_t onFind(DocId docid, int32_t elemid, int32_t &weight) const override {
+ for (const auto &doc: result.inspect()) {
+ if (doc.docId == docid) {
+ for (const auto &elem: doc.elements) {
+ if (elem.id >= uint32_t(elemid)) {
+ weight = elem.weight;
+ return elem.id;
+ }
+ }
+ }
+ }
+ return -1;
+ }
+ int32_t onFind(DocId docid, int32_t elem) const override {
+ int32_t ignore_weight;
+ return onFind(docid, elem, ignore_weight);
+ }
+ unsigned int approximateHits() const override { return 0; }
+ std::unique_ptr<SearchIterator> createIterator(fef::TermFieldMatchData *, bool) override { abort(); }
+ void fetchPostings(bool) override { }
+ bool valid() const override { return true; }
+ search::Int64Range getAsIntegerTerm() const override { abort(); }
+ const search::QueryTermBase * queryTerm() const override { abort(); }
+ const vespalib::string &attributeName() const override { return name; }
+};
+
+}
+
SearchIterator::UP
FakeBlueprint::createLeafSearch(const fef::TermFieldMatchDataArray &tfmda, bool) const
{
auto result = std::make_unique<FakeSearch>(_tag, _field.getName(), _term, _result, tfmda);
- result->is_attr(_is_attr);
+ result->attr_ctx(_ctx.get());
return result;
}
@@ -75,11 +110,21 @@ FakeBlueprint::FakeBlueprint(const FieldSpec &field, const FakeResult &result)
_term("<term>"),
_field(field),
_result(result),
- _is_attr(false)
+ _ctx()
{
setEstimate(HitEstimate(result.inspect().size(), result.inspect().empty()));
}
FakeBlueprint::~FakeBlueprint() = default;
+FakeBlueprint &
+FakeBlueprint::is_attr(bool value) {
+ if (value) {
+ _ctx = std::make_unique<FakeContext>(_field.getName(), _result);
+ } else {
+ _ctx.reset();
+ }
+ return *this;
+}
+
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h
index 85d30aaf003..2dc2d938bb6 100644
--- a/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h
+++ b/searchlib/src/vespa/searchlib/queryeval/leaf_blueprints.h
@@ -51,7 +51,7 @@ private:
vespalib::string _term;
FieldSpec _field;
FakeResult _result;
- bool _is_attr;
+ std::unique_ptr<attribute::ISearchContext> _ctx;
protected:
SearchIterator::UP
@@ -67,16 +67,17 @@ public:
}
const vespalib::string &tag() const { return _tag; }
- FakeBlueprint &is_attr(bool value) {
- _is_attr = value;
- return *this;
- }
- bool is_attr() const { return _is_attr; }
+ FakeBlueprint &is_attr(bool value);
+ bool is_attr() const { return bool(_ctx); }
FakeBlueprint &term(const vespalib::string &t) {
_term = t;
return *this;
}
+
+ const attribute::ISearchContext *get_attribute_search_context() const override {
+ return _ctx.get();
+ }
};
//-----------------------------------------------------------------------------