aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Egge <Tor.Egge@online.no>2024-02-02 14:20:03 +0100
committerTor Egge <Tor.Egge@online.no>2024-02-02 14:20:03 +0100
commit41502ddacbfc64c2ef883f8be16b88d80a8f33c8 (patch)
tree393f8f3ede3ad501583ca1dbfa9464b632d00bfa
parentd005a092da0e5f352a9ede03ab48989a1d5dbb2b (diff)
Change parent class of search::streaming::PhraseQueryNode from
search::streaming::AndQueryNode to search::streaming::MultiTerm.
-rw-r--r--searchlib/src/tests/query/streaming/phrase_query_node_test.cpp1
-rw-r--r--searchlib/src/tests/query/streaming_query_test.cpp10
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.cpp11
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/hit_iterator_pack.h1
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.cpp62
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/phrase_query_node.h14
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/query.cpp2
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/querynode.cpp27
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/querynode.h1
-rw-r--r--searchlib/src/vespa/searchlib/query/streaming/queryterm.h2
-rw-r--r--streamingvisitors/src/vespa/searchvisitor/querywrapper.cpp9
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];
}