diff options
author | Tor Egge <Tor.Egge@online.no> | 2024-02-02 14:20:03 +0100 |
---|---|---|
committer | Tor Egge <Tor.Egge@online.no> | 2024-02-02 14:20:03 +0100 |
commit | 41502ddacbfc64c2ef883f8be16b88d80a8f33c8 (patch) | |
tree | 393f8f3ede3ad501583ca1dbfa9464b632d00bfa | |
parent | d005a092da0e5f352a9ede03ab48989a1d5dbb2b (diff) |
Change parent class of search::streaming::PhraseQueryNode from
search::streaming::AndQueryNode to search::streaming::MultiTerm.
11 files changed, 111 insertions, 29 deletions
diff --git a/searchlib/src/tests/query/streaming/phrase_query_node_test.cpp b/searchlib/src/tests/query/streaming/phrase_query_node_test.cpp index 5caae8d6e97..ff4734a3846 100644 --- a/searchlib/src/tests/query/streaming/phrase_query_node_test.cpp +++ b/searchlib/src/tests/query/streaming/phrase_query_node_test.cpp @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include <vespa/searchlib/query/streaming/phrase_query_node.h> +#include <vespa/searchlib/query/streaming/query.h> #include <vespa/searchlib/query/streaming/queryterm.h> #include <vespa/searchlib/query/tree/querybuilder.h> #include <vespa/searchlib/query/tree/simplequery.h> diff --git a/searchlib/src/tests/query/streaming_query_test.cpp b/searchlib/src/tests/query/streaming_query_test.cpp index d2be1d453a2..cf72b71d6ad 100644 --- a/searchlib/src/tests/query/streaming_query_test.cpp +++ b/searchlib/src/tests/query/streaming_query_test.cpp @@ -363,17 +363,15 @@ TEST(StreamingQueryTest, onedot0e_is_rewritten_if_allowed_too) EXPECT_TRUE(dynamic_cast<const PhraseQueryNode *>(equiv[1].get()) != nullptr); { const auto & phrase = static_cast<const PhraseQueryNode &>(*equiv[1]); - EXPECT_EQ(2u, phrase.size()); - EXPECT_TRUE(dynamic_cast<const QueryTerm *>(phrase[0].get()) != nullptr); - { - const auto & qt = static_cast<const QueryTerm &>(*phrase[0]); + EXPECT_EQ(2u, phrase.get_terms().size()); + { + const auto & qt = *phrase.get_terms()[0]; EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("1"), qt.getTerm()); EXPECT_EQ(0u, qt.uniqueId()); } - EXPECT_TRUE(dynamic_cast<const QueryTerm *>(phrase[1].get()) != nullptr); { - const auto & qt = static_cast<const QueryTerm &>(*phrase[1]); + const auto & qt = *phrase.get_terms()[1]; EXPECT_EQ("c", qt.index()); EXPECT_EQ(vespalib::stringref("0e"), qt.getTerm()); EXPECT_EQ(0u, qt.uniqueId()); diff --git a/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.cpp b/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.cpp index fabd992c379..ab32cd32e29 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.cpp +++ b/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.cpp @@ -17,6 +17,17 @@ HitIteratorPack::HitIteratorPack(const QueryNodeList& children) } } +HitIteratorPack::HitIteratorPack(const std::vector<std::unique_ptr<QueryTerm>>& children) + : _iterators(), + _field_element(std::make_pair(0, 0)) +{ + auto num_children = children.size(); + _iterators.reserve(num_children); + for (auto& child : children) { + _iterators.emplace_back(child->getHitList()); + } +} + HitIteratorPack::~HitIteratorPack() = default; bool diff --git a/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.h b/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.h index 200d579930a..ad9d15f719a 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.h +++ b/searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.h @@ -19,6 +19,7 @@ class HitIteratorPack FieldElement _field_element; public: explicit HitIteratorPack(const QueryNodeList& children); + explicit HitIteratorPack(const std::vector<std::unique_ptr<QueryTerm>>& children); ~HitIteratorPack(); FieldElement& get_field_element_ref() noexcept { return _field_element; } HitIterator& front() noexcept { return _iterators.front(); } diff --git a/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.cpp b/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.cpp index 2d2778417fa..0020089ef62 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.cpp +++ b/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.cpp @@ -6,6 +6,14 @@ namespace search::streaming { +PhraseQueryNode::PhraseQueryNode(std::unique_ptr<QueryNodeResultBase> result_base, const string& index, uint32_t num_terms) + : MultiTerm(std::move(result_base), index, num_terms), + _fieldInfo(32) +{ +} + +PhraseQueryNode::~PhraseQueryNode() = default; + bool PhraseQueryNode::evaluate() const { @@ -13,13 +21,44 @@ PhraseQueryNode::evaluate() const return ! evaluateHits(hl).empty(); } -void PhraseQueryNode::getPhrases(QueryNodeRefList & tl) { tl.push_back(this); } -void PhraseQueryNode::getPhrases(ConstQueryNodeRefList & tl) const { tl.push_back(this); } +void +PhraseQueryNode::getPhrases(QueryNodeRefList & tl) +{ + tl.push_back(this); +} + +void +PhraseQueryNode::getPhrases(ConstQueryNodeRefList & tl) const +{ + tl.push_back(this); +} + +void +PhraseQueryNode::getLeaves(QueryTermList & tl) +{ + for (const auto& node : get_terms()) { + node->getLeaves(tl); + } +} void -PhraseQueryNode::addChild(QueryNode::UP child) { - assert(dynamic_cast<const QueryTerm *>(child.get()) != nullptr); - AndQueryNode::addChild(std::move(child)); +PhraseQueryNode::getLeaves(ConstQueryTermList & tl) const +{ + for (const auto& node : get_terms()) { + node->getLeaves(tl); + } +} + +size_t +PhraseQueryNode::width() const +{ + return get_terms().size(); +} + +MultiTerm* +PhraseQueryNode::as_multi_term() noexcept +{ + return nullptr; } const HitList & @@ -27,11 +66,12 @@ PhraseQueryNode::evaluateHits(HitList & hl) const { hl.clear(); _fieldInfo.clear(); - HitIteratorPack itr_pack(getChildren()); + auto& terms = get_terms(); + HitIteratorPack itr_pack(terms); if (!itr_pack.all_valid()) { return hl; } - auto& last_child = dynamic_cast<const QueryTerm&>(*(*this)[size() - 1]); + auto& last_child = dynamic_cast<const QueryTerm&>(*terms.back()); while (itr_pack.seek_to_matching_field_element()) { uint32_t first_position = itr_pack.front()->position(); bool retry_element = true; @@ -79,4 +119,12 @@ PhraseQueryNode::updateFieldInfo(size_t fid, size_t offset, size_t fieldLength) fi.setHitCount(fi.getHitCount() + 1); } +void +PhraseQueryNode::unpack_match_data(uint32_t docid, const fef::ITermData& td, fef::MatchData& match_data) +{ + (void) docid; + (void) td; + (void) match_data; +} + } diff --git a/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.h b/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.h index b137f813150..594eab3deba 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.h +++ b/searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.h @@ -2,7 +2,7 @@ #pragma once -#include "query.h" +#include "multi_term.h" namespace search::streaming { @@ -10,18 +10,22 @@ namespace search::streaming { N-ary phrase operator. All terms must be satisfied and have the correct order with distance to next term equal to 1. */ -class PhraseQueryNode : public AndQueryNode +class PhraseQueryNode : public MultiTerm { public: - PhraseQueryNode() noexcept : AndQueryNode("PHRASE"), _fieldInfo(32) { } + PhraseQueryNode(std::unique_ptr<QueryNodeResultBase> result_base, const string& index, uint32_t num_terms); + ~PhraseQueryNode() override; bool evaluate() const override; const HitList & evaluateHits(HitList & hl) const override; void getPhrases(QueryNodeRefList & tl) override; void getPhrases(ConstQueryNodeRefList & tl) const override; const QueryTerm::FieldInfo & getFieldInfo(size_t fid) const { return _fieldInfo[fid]; } size_t getFieldInfoSize() const { return _fieldInfo.size(); } - bool isFlattenable(ParseItem::ItemType) const override { return false; } - void addChild(QueryNode::UP child) override; + void unpack_match_data(uint32_t docid, const fef::ITermData& td, fef::MatchData& match_data) override; + void getLeaves(QueryTermList & tl) override; + void getLeaves(ConstQueryTermList & tl) const override; + size_t width() const override; + MultiTerm* as_multi_term() noexcept override; private: mutable std::vector<QueryTerm::FieldInfo> _fieldInfo; void updateFieldInfo(size_t fid, size_t offset, size_t fieldLength) const; diff --git a/searchlib/src/vespa/searchlib/query/streaming/query.cpp b/searchlib/src/vespa/searchlib/query/streaming/query.cpp index 5b0076a30c5..f1b3a804c50 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/query.cpp +++ b/searchlib/src/vespa/searchlib/query/streaming/query.cpp @@ -2,7 +2,6 @@ #include "query.h" #include "near_query_node.h" #include "onear_query_node.h" -#include "phrase_query_node.h" #include "same_element_query_node.h" #include <vespa/searchlib/parsequery/stackdumpiterator.h> #include <vespa/vespalib/objects/visit.hpp> @@ -113,7 +112,6 @@ QueryConnector::create(ParseItem::ItemType type) case search::ParseItem::ITEM_WEAK_AND: return std::make_unique<OrQueryNode>(); case search::ParseItem::ITEM_EQUIV: return std::make_unique<EquivQueryNode>(); case search::ParseItem::ITEM_NOT: return std::make_unique<AndNotQueryNode>(); - case search::ParseItem::ITEM_PHRASE: return std::make_unique<PhraseQueryNode>(); case search::ParseItem::ITEM_SAME_ELEMENT: return std::make_unique<SameElementQueryNode>(); case search::ParseItem::ITEM_NEAR: return std::make_unique<NearQueryNode>(); case search::ParseItem::ITEM_ONEAR: return std::make_unique<ONearQueryNode>(); diff --git a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp index 32e3ec16b16..69fe77d3fd5 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp +++ b/searchlib/src/vespa/searchlib/query/streaming/querynode.cpp @@ -47,7 +47,6 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor case ParseItem::ITEM_WEAK_AND: case ParseItem::ITEM_EQUIV: case ParseItem::ITEM_NOT: - case ParseItem::ITEM_PHRASE: case ParseItem::ITEM_SAME_ELEMENT: case ParseItem::ITEM_NEAR: case ParseItem::ITEM_ONEAR: @@ -163,10 +162,10 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor qt->setWeight(queryRep.GetWeight()); qt->setUniqueId(queryRep.getUniqueId()); if (allowRewrite && possibleFloat(*qt, ssTerm) && factory.allow_float_terms_rewrite(ssIndex)) { - auto phrase = std::make_unique<PhraseQueryNode>(); + auto phrase = std::make_unique<PhraseQueryNode>(factory.create(), ssIndex, arity); auto dotPos = ssTerm.find('.'); - phrase->addChild(std::make_unique<QueryTerm>(factory.create(), ssTerm.substr(0, dotPos), ssIndex, TermType::WORD, normalize_mode)); - phrase->addChild(std::make_unique<QueryTerm>(factory.create(), ssTerm.substr(dotPos + 1), ssIndex, TermType::WORD, normalize_mode)); + phrase->add_term(std::make_unique<QueryTerm>(factory.create(), ssTerm.substr(0, dotPos), ssIndex, TermType::WORD, normalize_mode)); + phrase->add_term(std::make_unique<QueryTerm>(factory.create(), ssTerm.substr(dotPos + 1), ssIndex, TermType::WORD, normalize_mode)); auto orqn = std::make_unique<EquivQueryNode>(); orqn->addChild(std::move(qt)); orqn->addChild(std::move(phrase)); @@ -193,6 +192,9 @@ QueryNode::Build(const QueryNode * parent, const QueryNodeResultFactory & factor case ParseItem::ITEM_WEIGHTED_SET: qn = build_weighted_set_term(factory, queryRep); break; + case ParseItem::ITEM_PHRASE: + qn = build_phrase_term(factory, queryRep); + break; default: skip_unknown(queryRep); break; @@ -281,6 +283,23 @@ QueryNode::build_weighted_set_term(const QueryNodeResultFactory& factory, Simple return ws; } +std::unique_ptr<QueryNode> +QueryNode::build_phrase_term(const QueryNodeResultFactory& factory, SimpleQueryStackDumpIterator& queryRep) +{ + auto phrase = std::make_unique<PhraseQueryNode>(factory.create(), queryRep.getIndexName(), queryRep.getArity()); + auto arity = queryRep.getArity(); + for (size_t i = 0; i < arity; ++i) { + queryRep.next(); + auto qn = Build(phrase.get(), factory, queryRep, false); + auto qtp = dynamic_cast<QueryTerm*>(qn.get()); + assert(qtp != nullptr); + qn.release(); + std::unique_ptr<QueryTerm> qt(qtp); + phrase->add_term(std::move(qt)); + } + return phrase; +} + void QueryNode::skip_unknown(SimpleQueryStackDumpIterator& queryRep) { diff --git a/searchlib/src/vespa/searchlib/query/streaming/querynode.h b/searchlib/src/vespa/searchlib/query/streaming/querynode.h index 454932c0a68..01974c70843 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/querynode.h +++ b/searchlib/src/vespa/searchlib/query/streaming/querynode.h @@ -33,6 +33,7 @@ class QueryNode static std::unique_ptr<QueryNode> build_dot_product_term(const QueryNodeResultFactory& factory, SimpleQueryStackDumpIterator& queryRep); static std::unique_ptr<QueryNode> build_wand_term(const QueryNodeResultFactory& factory, SimpleQueryStackDumpIterator& queryRep); static std::unique_ptr<QueryNode> build_weighted_set_term(const QueryNodeResultFactory& factory, SimpleQueryStackDumpIterator& queryRep); + static std::unique_ptr<QueryNode> build_phrase_term(const QueryNodeResultFactory& factory, SimpleQueryStackDumpIterator& queryRep); static void skip_unknown(SimpleQueryStackDumpIterator& queryRep); public: using UP = std::unique_ptr<QueryNode>; diff --git a/searchlib/src/vespa/searchlib/query/streaming/queryterm.h b/searchlib/src/vespa/searchlib/query/streaming/queryterm.h index 504b94de747..108cc1c148d 100644 --- a/searchlib/src/vespa/searchlib/query/streaming/queryterm.h +++ b/searchlib/src/vespa/searchlib/query/streaming/queryterm.h @@ -65,7 +65,7 @@ public: QueryTerm & operator = (QueryTerm &&) = delete; ~QueryTerm() override; bool evaluate() const override; - const HitList & evaluateHits(HitList & hl) const final override; + const HitList & evaluateHits(HitList & hl) const override; void reset() override; void getLeaves(QueryTermList & tl) override; void getLeaves(ConstQueryTermList & tl) const override; diff --git a/streamingvisitors/src/vespa/searchvisitor/querywrapper.cpp b/streamingvisitors/src/vespa/searchvisitor/querywrapper.cpp index c1311a80c7a..78229f401ad 100644 --- a/streamingvisitors/src/vespa/searchvisitor/querywrapper.cpp +++ b/streamingvisitors/src/vespa/searchvisitor/querywrapper.cpp @@ -6,8 +6,8 @@ using namespace search::streaming; namespace streaming { -QueryWrapper::PhraseList::PhraseList(Query & query) : - _phrases() +QueryWrapper::PhraseList::PhraseList(Query & query) + : _phrases() { QueryNodeRefList phrases; query.getPhrases(phrases); @@ -20,8 +20,9 @@ PhraseQueryNode * QueryWrapper::PhraseList::findPhrase(QueryTerm * term, size_t & index) { for (size_t i = 0; i < _phrases.size(); ++i) { - for (size_t j = 0; j < _phrases[i]->size(); ++j) { - if ((*_phrases[i])[j].get() == term) { + auto& terms = _phrases[i]->get_terms(); + for (size_t j = 0; j < terms.size(); ++j) { + if (terms[j].get() == term) { index = j; return _phrases[i]; } |