aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/query/streaming/equiv_query_node.cpp
blob: 8878c8c5cdc2bfd83239725e03c6257bd1b3e948 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "equiv_query_node.h"
#include "phrase_query_node.h"
#include "queryterm.hpp"

using search::fef::TermFieldMatchData;
using search::fef::TermFieldMatchDataPosition;
using search::fef::ITermFieldData;

namespace search::streaming {

namespace {

class HitWithFieldLength : public Hit
{
    uint32_t _field_length;
public:
    HitWithFieldLength(const Hit& hit, uint32_t field_length) noexcept
        : Hit(hit),
          _field_length(field_length)
    {
    }
    uint32_t get_field_length() const noexcept { return _field_length; }
};

template <typename HitType>
void merge_hits_from_children(std::vector<HitType>& hl, const MultiTerm& mt)
{
    HitList sub_hl_store;
    for (auto& subterm : mt.get_terms()) {
        auto *phrase = dynamic_cast<PhraseQueryNode*>(subterm.get());
        QueryTerm& fl_term = (phrase == nullptr) ? *subterm : *phrase->get_terms().front();
        auto& sub_hl = subterm->evaluateHits(sub_hl_store);
        for (auto& h : sub_hl) {
            if constexpr (std::is_same_v<Hit,HitType>) {
                hl.emplace_back(h);
            } else {
                hl.emplace_back(h, extract_field_length(fl_term, h.field_id()));
            }
        }
    }
    std::sort(hl.begin(), hl.end());
    auto last = std::unique(hl.begin(), hl.end(), [](auto& lhs, auto &rhs) noexcept { return lhs.at_same_pos(rhs); });
    hl.erase(last, hl.end());
}

}

EquivQueryNode::EquivQueryNode(std::unique_ptr<QueryNodeResultBase> result_base, uint32_t num_terms)
    : MultiTerm(std::move(result_base), "", num_terms)
{
}

EquivQueryNode::~EquivQueryNode() = default;

bool
EquivQueryNode::evaluate() const
{
    for (auto& subterm : get_terms()) {
        if (subterm->evaluate()) {
            return true;
        }
    }
    return false;
}

const HitList &
EquivQueryNode::evaluateHits(HitList & hl) const
{
    hl.clear();
    merge_hits_from_children(hl, *this);
    return hl;
}

void
EquivQueryNode::unpack_match_data(uint32_t docid, const fef::ITermData& td, fef::MatchData& match_data, const fef::IIndexEnvironment& index_env)
{
    std::vector<HitWithFieldLength> hit_list;
    merge_hits_from_children(hit_list, *this);
    unpack_match_data_helper(docid, td, match_data, hit_list, *this, is_filter(), index_env);
}

bool
EquivQueryNode::multi_index_terms() const noexcept
{
    return true;
}

const EquivQueryNode*
EquivQueryNode::as_equiv_query_node() const noexcept
{
    return this;
}

std::vector<std::unique_ptr<QueryTerm>>
EquivQueryNode::steal_terms()
{
    return std::move(_terms);
}

}