// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once #include "array_iterator.h" #include "postinglisttraits.h" #include #include #include namespace search { namespace fef { class TermFieldMatchData; class TermFieldMatchDataPosition; } /** * Abstract superclass for all attribute iterators with convenience function * for getting the type of the iterator (used for testing). **/ class AttributeIteratorBase : public queryeval::SearchIterator { protected: template void and_hits_into(const SC & sc, BitVector & result, uint32_t begin_id) const; template void or_hits_into(const SC & sc, BitVector & result, uint32_t begin_id) const; template std::unique_ptr get_hits(const SC & sc, uint32_t begin_id) const; void visitMembers(vespalib::ObjectVisitor &visitor) const override; const attribute::ISearchContext & _baseSearchCtx; fef::TermFieldMatchData * _matchData; fef::TermFieldMatchDataPosition * _matchPosition; public: AttributeIteratorBase(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData) : _baseSearchCtx(baseSearchCtx), _matchData(matchData), _matchPosition(_matchData->populate_fixed()) { } Trinary is_strict() const override { return Trinary::False; } }; /** * This class acts as an iterator over documents that are results for * the subquery represented by the search context object associated * with this iterator. The search context object contains an * attribute vector that does not use posting lists. * * @param SC the specialized search context type associated with this iterator */ class AttributeIterator : public AttributeIteratorBase { public: AttributeIterator(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData) : AttributeIteratorBase(baseSearchCtx, matchData), _weight(1) { } protected: void visitMembers(vespalib::ObjectVisitor &visitor) const override; void doUnpack(uint32_t docId) override; int32_t _weight; }; class FilterAttributeIterator : public AttributeIteratorBase { public: FilterAttributeIterator(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData) : AttributeIteratorBase(baseSearchCtx, matchData) { _matchPosition->setElementWeight(1); } protected: void doUnpack(uint32_t docId) override; }; template class AttributeIteratorT : public AttributeIterator { private: void doSeek(uint32_t docId) override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void and_hits_into(BitVector & result, uint32_t begin_id) override; void or_hits_into(BitVector & result, uint32_t begin_id) override; std::unique_ptr get_hits(uint32_t begin_id) override; protected: bool matches(uint32_t docId, int32_t &weight) const { return attribute::ISearchContext::matches(_concreteSearchCtx, docId, weight); } bool matches(uint32_t doc) const { return _concreteSearchCtx.find(doc, 0) >= 0; } const SC &_concreteSearchCtx; public: AttributeIteratorT(const SC &concreteSearchCtx, fef::TermFieldMatchData *matchData); bool seekFast(uint32_t docId) const { return matches(docId); } }; template class FilterAttributeIteratorT : public FilterAttributeIterator { private: void doSeek(uint32_t docId) override; void visitMembers(vespalib::ObjectVisitor &visitor) const override; void and_hits_into(BitVector & result, uint32_t begin_id) override; void or_hits_into(BitVector & result, uint32_t begin_id) override; std::unique_ptr get_hits(uint32_t begin_id) override; protected: bool matches(uint32_t doc) const { return _concreteSearchCtx.find(doc, 0) >= 0; } const SC &_concreteSearchCtx; public: FilterAttributeIteratorT(const SC &concreteSearchCtx, fef::TermFieldMatchData *matchData); bool seekFast(uint32_t docId) const { return matches(docId); } }; /** * This class acts as a strict iterator over documents that are * results for the subquery represented by the search context object * associated with this iterator. The search context object contains * an attribute vector that does not use posting lists. * * @param SC the specialized search context type associated with this iterator */ template class AttributeIteratorStrict : public AttributeIteratorT { private: using AttributeIteratorT::_concreteSearchCtx; using AttributeIteratorT::setDocId; using AttributeIteratorT::setAtEnd; using AttributeIteratorT::isAtEnd; using AttributeIteratorT::_weight; using Trinary=vespalib::Trinary; void doSeek(uint32_t docId) override; Trinary is_strict() const override { return Trinary::True; } public: AttributeIteratorStrict(const SC &concreteSearchCtx, fef::TermFieldMatchData * matchData) : AttributeIteratorT(concreteSearchCtx, matchData) { } }; template class FilterAttributeIteratorStrict : public FilterAttributeIteratorT { private: using FilterAttributeIteratorT::_concreteSearchCtx; using FilterAttributeIteratorT::setDocId; using FilterAttributeIteratorT::setAtEnd; using FilterAttributeIteratorT::isAtEnd; using Trinary=vespalib::Trinary; void doSeek(uint32_t docId) override; Trinary is_strict() const override { return Trinary::True; } public: FilterAttributeIteratorStrict(const SC &concreteSearchCtx, fef::TermFieldMatchData *matchData) : FilterAttributeIteratorT(concreteSearchCtx, matchData) { } }; /** * This class acts as an iterator over documents that are results for * the subquery represented by the search context object associated * with this iterator. The search context object contains an * attribute vector that uses underlying posting lists, and the search * context will setup a posting list iterator which is used by this * class. This iterator is always strict. * * @param PL the posting list iterator type to work as an iterator over */ class AttributePostingListIterator : public AttributeIteratorBase { public: AttributePostingListIterator(const attribute::ISearchContext &baseSearchCtx, bool hasWeight, fef::TermFieldMatchData *matchData) : AttributeIteratorBase(baseSearchCtx, matchData), _hasWeight(hasWeight) {} Trinary is_strict() const override { return Trinary::True; } protected: bool _hasWeight; }; class FilterAttributePostingListIterator : public AttributeIteratorBase { public: FilterAttributePostingListIterator(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData) : AttributeIteratorBase(baseSearchCtx, matchData) {} Trinary is_strict() const override { return Trinary::True; } }; using InnerAttributePostingListIterator = attribute::PostingListTraits::const_iterator; using WeightedInnerAttributePostingListIterator = attribute::PostingListTraits::const_iterator; template class AttributePostingListIteratorT : public AttributePostingListIterator { private: PL _iterator; queryeval::MinMaxPostingInfo _postingInfo; bool _postingInfoValid; void doSeek(uint32_t docId) override; void doUnpack(uint32_t docId) override; void setupPostingInfo() { } int32_t getWeight() { return _iterator.getData(); } const queryeval::PostingInfo * getPostingInfo() const override { return _postingInfoValid ? &_postingInfo : nullptr; } void initRange(uint32_t begin, uint32_t end) override; std::unique_ptr get_hits(uint32_t begin_id) override; void or_hits_into(BitVector &result, uint32_t begin_id) override; void and_hits_into(BitVector &result, uint32_t begin_id) override; public: template AttributePostingListIteratorT(const attribute::ISearchContext &baseSearchCtx, bool hasWeight, fef::TermFieldMatchData *matchData, Args &&... args); }; template class FilterAttributePostingListIteratorT : public FilterAttributePostingListIterator { private: PL _iterator; public: std::unique_ptr get_hits(uint32_t begin_id) override; void or_hits_into(BitVector &result, uint32_t begin_id) override; void and_hits_into(BitVector &result, uint32_t begin_id) override; private: queryeval::MinMaxPostingInfo _postingInfo; bool _postingInfoValid; void doSeek(uint32_t docId) override; void doUnpack(uint32_t docId) override; void setupPostingInfo() { } const queryeval::PostingInfo * getPostingInfo() const override { return _postingInfoValid ? &_postingInfo : nullptr; } void initRange(uint32_t begin, uint32_t end) override; public: template FilterAttributePostingListIteratorT(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData, Args &&... args); }; template <> inline int32_t AttributePostingListIteratorT:: getWeight() { return 1; // default weight 1 for single value attributes } template <> void AttributePostingListIteratorT:: doUnpack(uint32_t docId); template <> void AttributePostingListIteratorT:: doUnpack(uint32_t docId); template <> void AttributePostingListIteratorT::setupPostingInfo(); template <> void AttributePostingListIteratorT::setupPostingInfo(); template <> void AttributePostingListIteratorT >::setupPostingInfo(); template <> void AttributePostingListIteratorT >::setupPostingInfo(); template <> void FilterAttributePostingListIteratorT::setupPostingInfo(); template <> void FilterAttributePostingListIteratorT::setupPostingInfo(); template <> void FilterAttributePostingListIteratorT >::setupPostingInfo(); /** * This class acts as an iterator over a flag attribute. */ class FlagAttributeIterator : public AttributeIteratorBase { public: FlagAttributeIterator(const attribute::ISearchContext &baseSearchCtx, fef::TermFieldMatchData *matchData) : AttributeIteratorBase(baseSearchCtx, matchData) { } protected: void doUnpack(uint32_t docId) override; }; template class FlagAttributeIteratorT : public FlagAttributeIterator { private: void doSeek(uint32_t docId) override; protected: const SC &_concreteSearchCtx; void or_hits_into(BitVector &result, uint32_t begin_id) override; void and_hits_into(BitVector &result, uint32_t begin_id) override; std::unique_ptr get_hits(uint32_t begin_id) override; public: FlagAttributeIteratorT(const SC &concreteSearchCtx, fef::TermFieldMatchData *matchData) : FlagAttributeIterator(concreteSearchCtx, matchData), _concreteSearchCtx(concreteSearchCtx) { } void initRange(uint32_t begin, uint32_t end) override { FlagAttributeIterator::initRange(begin, end); if ( _concreteSearchCtx._zeroHits ) { setAtEnd(); } } }; template class FlagAttributeIteratorStrict : public FlagAttributeIteratorT { private: using FlagAttributeIteratorT::_concreteSearchCtx; using FlagAttributeIteratorT::setDocId; using FlagAttributeIteratorT::setAtEnd; using FlagAttributeIteratorT::isAtEnd; using Trinary=vespalib::Trinary; void doSeek(uint32_t docId) override; Trinary is_strict() const override { return Trinary::True; } public: FlagAttributeIteratorStrict(const SC &concreteSearchCtx, fef::TermFieldMatchData *matchData) : FlagAttributeIteratorT(concreteSearchCtx, matchData) { } }; }