summaryrefslogtreecommitdiffstats
path: root/searchlib
diff options
context:
space:
mode:
authorGeir Storli <geirst@verizonmedia.com>2019-06-20 07:45:00 +0000
committerGeir Storli <geirst@verizonmedia.com>2019-06-21 11:30:50 +0000
commitb729f40270612be3074ecd1ae584a0b997a88b23 (patch)
treeec157e9efc4f6b57bb8f3c09db41e9ce6cc635ec /searchlib
parentfe4a0938e061aca61f9308481fa1aa6a5e1b9f92 (diff)
Prepare memory posting list iterators to handle interleaved features.
Diffstat (limited to 'searchlib')
-rw-r--r--searchlib/src/tests/memoryindex/field_index/field_index_iterator_test.cpp5
-rw-r--r--searchlib/src/tests/memoryindex/field_index/field_index_test.cpp214
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/field_index.cpp3
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/ordered_field_index_inserter.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/posting_iterator.cpp113
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/posting_iterator.h42
-rw-r--r--searchlib/src/vespa/searchlib/memoryindex/posting_list_entry.h48
-rw-r--r--searchlib/src/vespa/searchlib/test/fakedata/fakememtreeocc.cpp10
8 files changed, 264 insertions, 175 deletions
diff --git a/searchlib/src/tests/memoryindex/field_index/field_index_iterator_test.cpp b/searchlib/src/tests/memoryindex/field_index/field_index_iterator_test.cpp
index 36e9bde5c9f..4658707a1f3 100644
--- a/searchlib/src/tests/memoryindex/field_index/field_index_iterator_test.cpp
+++ b/searchlib/src/tests/memoryindex/field_index/field_index_iterator_test.cpp
@@ -19,7 +19,6 @@ using search::index::schema::DataType;
using search::test::SearchIteratorVerifier;
using FieldIndexType = FieldIndex<false>;
-using PostingIteratorType = PostingIterator<false>;
class Verifier : public SearchIteratorVerifier {
private:
@@ -44,8 +43,8 @@ public:
(void) strict;
TermFieldMatchDataArray match_data;
match_data.add(&_tfmd);
- return std::make_unique<PostingIteratorType>(_field_index.find("a"),
- _field_index.getFeatureStore(), 0, match_data);
+ return make_search_iterator<false>(_field_index.find("a"),
+ _field_index.getFeatureStore(), 0, match_data);
}
};
diff --git a/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp b/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp
index f2cc2580cd8..90e33714cac 100644
--- a/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp
+++ b/searchlib/src/tests/memoryindex/field_index/field_index_test.cpp
@@ -43,7 +43,6 @@ using test::WrapInserter;
using FieldIndexType = FieldIndex<false>;
using PostingList = FieldIndexType::PostingList;
using PostingConstItr = PostingList::ConstIterator;
-using PostingIteratorType = PostingIterator<false>;
class MyBuilder : public IndexBuilder {
private:
@@ -201,20 +200,20 @@ assertPostingList(std::vector<uint32_t> &exp, PostingConstItr itr)
FieldIndexType::PostingList::Iterator
find_in_field_index(const vespalib::stringref word,
- uint32_t fieldId,
+ uint32_t field_id,
const FieldIndexCollection& fic)
{
- auto* field_index = dynamic_cast<FieldIndexType*>(fic.getFieldIndex(fieldId));
+ auto* field_index = dynamic_cast<FieldIndexType*>(fic.getFieldIndex(field_id));
assert(field_index != nullptr);
return field_index->find(word);
}
FieldIndexType::PostingList::ConstIterator
find_frozen_in_field_index(const vespalib::stringref word,
- uint32_t fieldId,
+ uint32_t field_id,
const FieldIndexCollection& fic)
{
- auto* field_index = dynamic_cast<FieldIndexType*>(fic.getFieldIndex(fieldId));
+ auto* field_index = dynamic_cast<FieldIndexType*>(fic.getFieldIndex(field_id));
assert(field_index != nullptr);
return field_index->findFrozen(word);
}
@@ -495,6 +494,10 @@ struct FieldIndexTest : public ::testing::Test {
idx(schema, 0)
{
}
+ SearchIterator::UP search(const vespalib::stringref word,
+ const TermFieldMatchDataArray& match_data) {
+ return make_search_iterator<false>(idx.find(word), idx.getFeatureStore(), 0, match_data);
+ }
};
Schema
@@ -673,30 +676,26 @@ TEST_F(FieldIndexTest, require_that_posting_iterator_is_working)
TermFieldMatchDataArray matchData;
matchData.add(&tfmd);
{
- PostingIteratorType itr(idx.find("not"),
- idx.getFeatureStore(),
- 0, matchData);
- itr.initFullRange();
- EXPECT_TRUE(itr.isAtEnd());
+ auto itr = search("not", matchData);
+ itr->initFullRange();
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(idx.find("a"),
- idx.getFeatureStore(),
- 0, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("a", matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{4:0}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_EQ(30u, itr.getDocId());
- itr.unpack(30);
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_EQ(30u, itr->getDocId());
+ itr->unpack(30);
EXPECT_EQ("{6:0}", toString(tfmd.getIterator()));
- EXPECT_TRUE(itr.seek(40));
- EXPECT_EQ(40u, itr.getDocId());
- itr.unpack(40);
+ EXPECT_TRUE(itr->seek(40));
+ EXPECT_EQ(40u, itr->getDocId());
+ itr->unpack(40);
EXPECT_EQ("{7:0,1}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(41));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(41));
+ EXPECT_TRUE(itr->isAtEnd());
}
}
@@ -792,11 +791,16 @@ public:
_inv(_schema, _invertThreads, _pushThreads, _fic)
{
}
- PostingList::Iterator find(const vespalib::stringref word, uint32_t fieldId) const {
- return find_in_field_index(word, fieldId, _fic);
+ PostingList::Iterator find(const vespalib::stringref word, uint32_t field_id) const {
+ return find_in_field_index(word, field_id, _fic);
+ }
+ PostingList::ConstIterator findFrozen(const vespalib::stringref word, uint32_t field_id) const {
+ return find_frozen_in_field_index(word, field_id, _fic);
}
- PostingList::ConstIterator findFrozen(const vespalib::stringref word, uint32_t fieldId) const {
- return find_frozen_in_field_index(word, fieldId, _fic);
+ SearchIterator::UP search(const vespalib::stringref word, uint32_t field_id,
+ const TermFieldMatchDataArray& match_data) {
+ return make_search_iterator<false>(findFrozen(word, field_id), featureStoreRef(_fic, field_id),
+ field_id, match_data);
}
};
@@ -956,52 +960,52 @@ TEST_F(BasicInverterTest, require_that_inversion_is_working)
TermFieldMatchDataArray matchData;
matchData.add(&tfmd);
{
- PostingIteratorType itr(findFrozen("not", 0), featureStoreRef(_fic, 0), 0, matchData);
- itr.initFullRange();
- EXPECT_TRUE(itr.isAtEnd());
+ auto itr = search("not", 0, matchData);
+ itr->initFullRange();
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(findFrozen("a", 0), featureStoreRef(_fic, 0), 0, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("a", 0, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{4:0}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_EQ(30u, itr.getDocId());
- itr.unpack(30);
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_EQ(30u, itr->getDocId());
+ itr->unpack(30);
EXPECT_EQ("{6:0}", toString(tfmd.getIterator()));
- EXPECT_TRUE(itr.seek(40));
- EXPECT_EQ(40u, itr.getDocId());
- itr.unpack(40);
+ EXPECT_TRUE(itr->seek(40));
+ EXPECT_EQ(40u, itr->getDocId());
+ itr->unpack(40);
EXPECT_EQ("{7:0,1,4}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(41));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(41));
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(findFrozen("x", 0), featureStoreRef(_fic, 0), 0, matchData);
- itr.initFullRange();
- EXPECT_TRUE(itr.isAtEnd());
+ auto itr = search("x", 0, matchData);
+ itr->initFullRange();
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(findFrozen("x", 1), featureStoreRef(_fic, 1), 1, matchData);
- itr.initFullRange();
- EXPECT_EQ(30u, itr.getDocId());
- itr.unpack(30);
+ auto itr = search("x", 1, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(30u, itr->getDocId());
+ itr->unpack(30);
EXPECT_EQ("{6:2[e=0,w=1,l=6]}", toString(tfmd.getIterator(), true, true));
}
{
- PostingIteratorType itr(findFrozen("x", 2), featureStoreRef(_fic, 2), 2, matchData);
- itr.initFullRange();
- EXPECT_EQ(30u, itr.getDocId());
- itr.unpack(30);
+ auto itr = search("x", 2, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(30u, itr->getDocId());
+ itr->unpack(30);
// weight is hardcoded to 1 for new style il doc array field
EXPECT_EQ("{2:1[e=0,w=1,l=2]}", toString(tfmd.getIterator(), true, true));
}
{
- PostingIteratorType itr(findFrozen("x", 3), featureStoreRef(_fic, 3), 3, matchData);
- itr.initFullRange();
- EXPECT_EQ(30u, itr.getDocId());
- itr.unpack(30);
+ auto itr = search("x", 3, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(30u, itr->getDocId());
+ itr->unpack(30);
EXPECT_EQ("{2:1[e=0,w=6,l=2]}",
toString(tfmd.getIterator(), true, true));
}
@@ -1195,49 +1199,41 @@ TEST_F(UriInverterTest, require_that_uri_indexing_is_working)
matchData.add(&tfmd);
{
uint32_t fieldId = _schema.getIndexFieldId("iu");
- PostingIteratorType itr(findFrozen("not", fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_TRUE(itr.isAtEnd());
+ auto itr = search("not", fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_TRUE(itr->isAtEnd());
}
{
uint32_t fieldId = _schema.getIndexFieldId("iu");
- PostingIteratorType itr(findFrozen("example", fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("example", fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{9:2}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_TRUE(itr->isAtEnd());
}
{
uint32_t fieldId = _schema.getIndexFieldId("iau");
- PostingIteratorType itr(findFrozen("example", fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("example", fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{9:2[e=0,l=9]}",
toString(tfmd.getIterator(), true, false));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_TRUE(itr->isAtEnd());
}
{
uint32_t fieldId = _schema.getIndexFieldId("iwu");
- PostingIteratorType itr(findFrozen("example", fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("example", fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{9:2[e=0,w=4,l=9]}",
toString(tfmd.getIterator(), true, true));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_TRUE(itr->isAtEnd());
}
{
search::diskindex::IndexBuilder dib(_schema);
@@ -1281,37 +1277,31 @@ TEST_F(CjkInverterTest, require_that_cjk_indexing_is_working)
matchData.add(&tfmd);
uint32_t fieldId = _schema.getIndexFieldId("f0");
{
- PostingIteratorType itr(findFrozen("not", fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_TRUE(itr.isAtEnd());
+ auto itr = search("not", fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(findFrozen("我就"
- "是那个",
- fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("我就"
+ "是那个",
+ fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{2:0}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_TRUE(itr->isAtEnd());
}
{
- PostingIteratorType itr(findFrozen("大灰"
- "狼",
- fieldId),
- featureStoreRef(_fic, fieldId),
- fieldId, matchData);
- itr.initFullRange();
- EXPECT_EQ(10u, itr.getDocId());
- itr.unpack(10);
+ auto itr = search("大灰"
+ "狼",
+ fieldId, matchData);
+ itr->initFullRange();
+ EXPECT_EQ(10u, itr->getDocId());
+ itr->unpack(10);
EXPECT_EQ("{2:1}", toString(tfmd.getIterator()));
- EXPECT_TRUE(!itr.seek(25));
- EXPECT_TRUE(itr.isAtEnd());
+ EXPECT_TRUE(!itr->seek(25));
+ EXPECT_TRUE(itr->isAtEnd());
}
}
diff --git a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp
index a5dc921cfdf..37a558b17a3 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp
+++ b/searchlib/src/vespa/searchlib/memoryindex/field_index.cpp
@@ -266,8 +266,7 @@ public:
}
SearchIterator::UP createLeafSearch(const TermFieldMatchDataArray& tfmda, bool) const override {
- using PostingIteratorType = PostingIterator<interleaved_features>;
- auto result = std::make_unique<PostingIteratorType>(_posting_itr, _feature_store, _field_id, tfmda);
+ auto result = make_search_iterator<interleaved_features>(_posting_itr, _feature_store, _field_id, tfmda);
if (_use_bit_vector) {
LOG(debug, "Return BooleanMatchIteratorWrapper: field_id(%u), doc_count(%zu)",
_field_id, _posting_itr.size());
diff --git a/searchlib/src/vespa/searchlib/memoryindex/ordered_field_index_inserter.cpp b/searchlib/src/vespa/searchlib/memoryindex/ordered_field_index_inserter.cpp
index c6524a2fc64..0d2bb1f5371 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/ordered_field_index_inserter.cpp
+++ b/searchlib/src/vespa/searchlib/memoryindex/ordered_field_index_inserter.cpp
@@ -118,7 +118,9 @@ OrderedFieldIndexInserter<interleaved_features>::add(uint32_t docId,
assert(_prevDocId == noDocId || _prevDocId < docId ||
(_prevDocId == docId && !_prevAdd));
datastore::EntryRef featureRef = _fieldIndex.addFeatures(features);
- _adds.push_back(PostingListKeyDataType(docId, PostingListEntryType(featureRef)));
+ _adds.push_back(PostingListKeyDataType(docId, PostingListEntryType(featureRef,
+ features.num_occs(),
+ features.field_length())));
_listener.insert(_dItr.getKey()._wordRef, docId);
_prevDocId = docId;
_prevAdd = true;
diff --git a/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.cpp b/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.cpp
index 0e84c2b7968..7c6ceb26f31 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.cpp
+++ b/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.cpp
@@ -1,6 +1,7 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "posting_iterator.h"
+#include <vespa/searchlib/queryeval/iterators.h>
#include <vespa/vespalib/btree/btreeiterator.hpp>
#include <vespa/vespalib/btree/btreenode.hpp>
#include <vespa/vespalib/btree/btreenodeallocator.hpp>
@@ -13,25 +14,51 @@ LOG_SETUP(".searchlib.memoryindex.posting_iterator");
namespace search::memoryindex {
+/**
+ * Base search iterator over memory field index posting list.
+ *
+ * The template parameter specifies whether the wrapped posting list has interleaved features or not.
+ */
template <bool interleaved_features>
-PostingIterator<interleaved_features>::PostingIterator(PostingListIteratorType itr,
- const FeatureStore& featureStore,
- uint32_t packedIndex,
- const fef::TermFieldMatchDataArray& matchData) :
- queryeval::RankedSearchIteratorBase(matchData),
+class PostingIteratorBase : public queryeval::RankedSearchIteratorBase {
+protected:
+ using FieldIndexType = FieldIndex<interleaved_features>;
+ using PostingListIteratorType = typename FieldIndexType::PostingList::ConstIterator;
+ PostingListIteratorType _itr;
+ const FeatureStore& _feature_store;
+ FeatureStore::DecodeContextCooked _feature_decoder;
+
+public:
+ PostingIteratorBase(PostingListIteratorType itr,
+ const FeatureStore& feature_store,
+ uint32_t field_id,
+ const fef::TermFieldMatchDataArray& match_data);
+ ~PostingIteratorBase();
+
+ void doSeek(uint32_t docId) override;
+ void initRange(uint32_t begin, uint32_t end) override;
+ Trinary is_strict() const override { return Trinary::True; }
+};
+
+template <bool interleaved_features>
+PostingIteratorBase<interleaved_features>::PostingIteratorBase(PostingListIteratorType itr,
+ const FeatureStore& feature_store,
+ uint32_t field_id,
+ const fef::TermFieldMatchDataArray& match_data) :
+ queryeval::RankedSearchIteratorBase(match_data),
_itr(itr),
- _featureStore(featureStore),
- _featureDecoder(nullptr)
+ _feature_store(feature_store),
+ _feature_decoder(nullptr)
{
- _featureStore.setupForField(packedIndex, _featureDecoder);
+ _feature_store.setupForField(field_id, _feature_decoder);
}
template <bool interleaved_features>
-PostingIterator<interleaved_features>::~PostingIterator() = default;
+PostingIteratorBase<interleaved_features>::~PostingIteratorBase() = default;
template <bool interleaved_features>
void
-PostingIterator<interleaved_features>::initRange(uint32_t begin, uint32_t end)
+PostingIteratorBase<interleaved_features>::initRange(uint32_t begin, uint32_t end)
{
SearchIterator::initRange(begin, end);
_itr.lower_bound(begin);
@@ -45,7 +72,7 @@ PostingIterator<interleaved_features>::initRange(uint32_t begin, uint32_t end)
template <bool interleaved_features>
void
-PostingIterator<interleaved_features>::doSeek(uint32_t docId)
+PostingIteratorBase<interleaved_features>::doSeek(uint32_t docId)
{
if (getUnpacked()) {
clearUnpacked();
@@ -58,9 +85,34 @@ PostingIterator<interleaved_features>::doSeek(uint32_t docId)
}
}
-template <bool interleaved_features>
+/**
+ * Search iterator over memory field index posting list.
+ *
+ * Template parameters:
+ * - interleaved_features: specifies whether the wrapped posting list has interleaved features or not.
+ * - unpack_normal_features: specifies whether to unpack normal features or not.
+ * - unpack_interleaved_features: specifies whether to unpack interleaved features or not.
+ */
+template <bool interleaved_features, bool unpack_normal_features, bool unpack_interleaved_features>
+class PostingIterator : public PostingIteratorBase<interleaved_features> {
+public:
+ using ParentType = PostingIteratorBase<interleaved_features>;
+
+ using ParentType::ParentType;
+ using ParentType::_feature_decoder;
+ using ParentType::_feature_store;
+ using ParentType::_itr;
+ using ParentType::_matchData;
+ using ParentType::getDocId;
+ using ParentType::getUnpacked;
+ using ParentType::setUnpacked;
+
+ void doUnpack(uint32_t docId) override;
+};
+
+template <bool interleaved_features, bool unpack_normal_features, bool unpack_interleaved_features>
void
-PostingIterator<interleaved_features>::doUnpack(uint32_t docId)
+PostingIterator<interleaved_features, unpack_normal_features, unpack_interleaved_features>::doUnpack(uint32_t docId)
{
if (!_matchData.valid() || getUnpacked()) {
return;
@@ -68,14 +120,39 @@ PostingIterator<interleaved_features>::doUnpack(uint32_t docId)
assert(docId == getDocId());
assert(_itr.valid());
assert(docId == _itr.getKey());
- datastore::EntryRef featureRef(_itr.getData().get_features());
- _featureStore.setupForUnpackFeatures(featureRef, _featureDecoder);
- _featureDecoder.unpackFeatures(_matchData, docId);
- setUnpacked();
+ if (unpack_normal_features) {
+ datastore::EntryRef featureRef(_itr.getData().get_features());
+ _feature_store.setupForUnpackFeatures(featureRef, _feature_decoder);
+ _feature_decoder.unpackFeatures(_matchData, docId);
+ setUnpacked();
+ }
+ if (unpack_interleaved_features) {
+ // TODO: implement
+ }
+}
+
+template <bool interleaved_features>
+queryeval::SearchIterator::UP
+make_search_iterator(typename FieldIndex<interleaved_features>::PostingList::ConstIterator itr,
+ const FeatureStore& feature_store,
+ uint32_t field_id,
+ const fef::TermFieldMatchDataArray& match_data)
+{
+ assert(match_data.size() == 1);
+ return std::make_unique<PostingIterator<interleaved_features, true, false>>
+ (itr, feature_store, field_id, match_data);
}
template
-class PostingIterator<false>;
+queryeval::SearchIterator::UP
+make_search_iterator<false>(typename FieldIndex<false>::PostingList::ConstIterator,
+ const FeatureStore&,
+ uint32_t,
+ const fef::TermFieldMatchDataArray&);
+
+template class PostingIteratorBase<false>;
+
+template class PostingIterator<false, true, false>;
}
diff --git a/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.h b/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.h
index f029c837cf7..056cad90c85 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.h
+++ b/searchlib/src/vespa/searchlib/memoryindex/posting_iterator.h
@@ -3,44 +3,26 @@
#pragma once
#include "field_index.h"
-#include <vespa/searchlib/queryeval/iterators.h>
+#include <vespa/searchlib/queryeval/searchiterator.h>
namespace search::memoryindex {
/**
- * Search iterator for memory field index posting list.
+ * Factory for creating search iterator over memory field index posting list.
*
* The template parameter specifies whether the wrapped posting list has interleaved features or not.
+ *
+ * @param itr the posting list iterator to base the search iterator upon.
+ * @param feature_store reference to store for features.
+ * @param field_id the id of the field searched.
+ * @param match_data the match data to unpack features into.
*/
template <bool interleaved_features>
-class PostingIterator : public queryeval::RankedSearchIteratorBase {
-private:
- using FieldIndexType = FieldIndex<interleaved_features>;
- using PostingListIteratorType = typename FieldIndexType::PostingList::ConstIterator;
- PostingListIteratorType _itr;
- const FeatureStore &_featureStore;
- FeatureStore::DecodeContextCooked _featureDecoder;
-
-public:
- /**
- * Creates a search iterator for the given posting list iterator.
- *
- * @param itr the posting list iterator to base the search iterator upon.
- * @param featureStore reference to store for features.
- * @param packedIndex the field or field collection owning features.
- * @param matchData the match data to unpack features into.
- **/
- PostingIterator(PostingListIteratorType itr,
- const FeatureStore &featureStore,
- uint32_t packedIndex,
- const fef::TermFieldMatchDataArray &matchData);
- ~PostingIterator();
-
- void doSeek(uint32_t docId) override;
- void doUnpack(uint32_t docId) override;
- void initRange(uint32_t begin, uint32_t end) override;
- Trinary is_strict() const override { return Trinary::True; }
-};
+queryeval::SearchIterator::UP
+make_search_iterator(typename FieldIndex<interleaved_features>::PostingList::ConstIterator itr,
+ const FeatureStore& feature_store,
+ uint32_t field_id,
+ const fef::TermFieldMatchDataArray& match_data);
}
diff --git a/searchlib/src/vespa/searchlib/memoryindex/posting_list_entry.h b/searchlib/src/vespa/searchlib/memoryindex/posting_list_entry.h
index 373de21e836..33cfda32843 100644
--- a/searchlib/src/vespa/searchlib/memoryindex/posting_list_entry.h
+++ b/searchlib/src/vespa/searchlib/memoryindex/posting_list_entry.h
@@ -7,20 +7,60 @@
namespace search::memoryindex {
/**
+ * Class storing interleaved features for a posting list entry.
+ */
+class InterleavedFeatures {
+protected:
+ uint16_t _num_occs;
+ uint16_t _field_length;
+
+public:
+ InterleavedFeatures()
+ : _num_occs(0),
+ _field_length(1)
+ {
+ }
+ InterleavedFeatures(uint16_t num_occs, uint16_t field_length)
+ : _num_occs(num_occs),
+ _field_length(field_length)
+ {
+ }
+ uint16_t get_num_occs() const { return _num_occs; }
+ uint16_t get_field_length() const { return _field_length; }
+};
+
+/**
+ * Empty class used when posting list entry does not have interleaved features.
+ */
+class NoInterleavedFeatures {
+public:
+ NoInterleavedFeatures() {}
+ NoInterleavedFeatures(uint16_t num_occs, uint16_t field_length) {
+ (void) num_occs;
+ (void) field_length;
+ }
+ uint16_t get_num_occs() const { return 0; }
+ uint16_t get_field_length() const { return 1; }
+};
+
+/**
* Entry per document in memory index posting list.
*/
template <bool interleaved_features>
-class PostingListEntry {
+class PostingListEntry : public std::conditional_t<interleaved_features, InterleavedFeatures, NoInterleavedFeatures> {
+ using ParentType = std::conditional_t<interleaved_features, InterleavedFeatures, NoInterleavedFeatures>;
mutable datastore::EntryRef _features; // reference to compressed features
public:
- explicit PostingListEntry(datastore::EntryRef features)
- : _features(features)
+ explicit PostingListEntry(datastore::EntryRef features, uint16_t num_occs, uint16_t field_length)
+ : ParentType(num_occs, field_length),
+ _features(features)
{
}
PostingListEntry()
- : _features()
+ : ParentType(),
+ _features()
{
}
diff --git a/searchlib/src/vespa/searchlib/test/fakedata/fakememtreeocc.cpp b/searchlib/src/vespa/searchlib/test/fakedata/fakememtreeocc.cpp
index a4996c931e2..b7d444a0fca 100644
--- a/searchlib/src/vespa/searchlib/test/fakedata/fakememtreeocc.cpp
+++ b/searchlib/src/vespa/searchlib/test/fakedata/fakememtreeocc.cpp
@@ -129,10 +129,10 @@ search::queryeval::SearchIterator *
FakeMemTreeOcc::
createIterator(const fef::TermFieldMatchDataArray &matchData) const
{
- return new search::memoryindex::PostingIterator<false>(_tree.begin(_allocator),
- _mgr._featureStore,
- _packedIndex,
- matchData);
+ return memoryindex::make_search_iterator<false>(_tree.begin(_allocator),
+ _mgr._featureStore,
+ _packedIndex,
+ matchData).release();
}
@@ -267,7 +267,7 @@ FakeMemTreeOccMgr::flush()
}
} else {
if (!itr.valid() || docId < itr.getKey()) {
- tree.insert(itr, docId, PostingListEntryType(i->getFeatureRef()));
+ tree.insert(itr, docId, PostingListEntryType(i->getFeatureRef(), 0, 1));
}
}
}