diff options
Diffstat (limited to 'searchlib')
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)); } } } |