summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
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();
+ }
};
//-----------------------------------------------------------------------------