aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/vespa/searchcore/proton/matching/unpacking_iterators_optimizer.cpp
blob: 48c656984b0c32947ba2df21a3bf948e35bb17fa (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "unpacking_iterators_optimizer.h"

#include "querynodes.h"
#include <vespa/vespalib/util/classname.h>
#include <vespa/searchlib/query/tree/queryvisitor.h>
#include <vespa/searchlib/query/tree/templatetermvisitor.h>
#include <vespa/searchlib/query/tree/querytreecreator.h>

#include <vespa/log/log.h>
LOG_SETUP(".matching.unpacking_iterators_optimizer");

using namespace search::query;

namespace proton::matching {

namespace {

struct TermExpander : QueryVisitor {
    std::vector<Node::UP> terms;

    template <typename T>
    void expand(T &n) {
        n.set_expensive(true);
        for (Node *child: n.getChildren()) {
            Node::UP node = QueryTreeCreator<ProtonNodeTypes>::replicate(*child);
            if (Term *term = dynamic_cast<Term *>(node.get())) {
                term->setRanked(false);
                term->setPositionData(false);
                terms.push_back(std::move(node));
            } else {
                LOG(error, "Required a search::query::TermNode. Got %s", vespalib::getClassName(*node).c_str());
            }
        }
    }
    void visit(And &) override {}
    void visit(AndNot &) override {}
    void visit(Equiv &) override {}
    void visit(NumberTerm &) override {}
    void visit(LocationTerm &) override {}
    void visit(Near &) override {}
    void visit(ONear &) override {}
    void visit(Or &) override {}
    void visit(Phrase &n) override { expand(n); }
    void visit(SameElement &) override {
        // TODO expand(n) once we figure out to handle artificial terms in matched-elements-only;
    }
    void visit(PrefixTerm &) override {}
    void visit(RangeTerm &) override {}
    void visit(Rank &) override {}
    void visit(StringTerm &) override {}
    void visit(SubstringTerm &) override {}
    void visit(SuffixTerm &) override {}
    void visit(WeakAnd &) override {}
    void visit(WeightedSetTerm &) override {}
    void visit(DotProduct &) override {}
    void visit(WandTerm &) override {}
    void visit(PredicateQuery &) override {}
    void visit(RegExpTerm &) override {}
    void visit(NearestNeighborTerm &) override {}
    void visit(TrueQueryNode &) override {}
    void visit(FalseQueryNode &) override {}
    void visit(FuzzyTerm &) override {}

    void flush(Intermediate &parent) {
        for (Node::UP &term: terms) {
            parent.append(std::move(term));
        }
        terms.clear();
    }
};

struct NodeTraverser : TemplateTermVisitor<NodeTraverser, ProtonNodeTypes>
{
    bool split_unpacking_iterators;

    NodeTraverser(bool split_unpacking_iterators_in)
        : split_unpacking_iterators(split_unpacking_iterators_in) {}
    template <class TermNode> void visitTerm(TermNode &) {}
    void visit(ProtonNodeTypes::And &n) override {
        for (Node *child: n.getChildren()) {
            child->accept(*this);
        }
        if (split_unpacking_iterators) {
            TermExpander expander;
            for (Node *child: n.getChildren()) {
                child->accept(expander);
            }
            expander.flush(n);
        }
    }
};

} // namespace proton::matching::<unnamed>

search::query::Node::UP
UnpackingIteratorsOptimizer::optimize(search::query::Node::UP root,
                                      bool has_white_list,
                                      bool split_unpacking_iterators)
{
    if (split_unpacking_iterators) {
        NodeTraverser traverser(split_unpacking_iterators);
        root->accept(traverser);
    }
    if (has_white_list && split_unpacking_iterators) {
        TermExpander expander;
        root->accept(expander);
        if (!expander.terms.empty()) {
            Intermediate::UP and_node = std::make_unique<ProtonNodeTypes::And>();
            and_node->append(std::move(root));
            expander.flush(*and_node);
            root = std::move(and_node);
        }
    }
    return root;
}

} // namespace proton::matching