aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/query/streaming/query.h
blob: 75388d564ee31f5898620b32ecc71e1f1fe8d75e (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include "queryterm.h"
#include <vespa/searchlib/parsequery/parse.h>
#include <vespa/searchlib/query/base.h>

namespace search::streaming {

/**
   Base class for all N-ary query operators.
   Implements the width, depth, print, and collect all leafs operators(terms).
*/
class QueryConnector : public QueryNode
{
public:
    QueryConnector(const char * opName);
    ~QueryConnector();
    const HitList & evaluateHits(HitList & hl) const override;
    void reset() override;
    void getLeafs(QueryTermList & tl) override;
    void getLeafs(ConstQueryTermList & tl) const override;
    void getPhrases(QueryNodeRefList & tl) override;
    void getPhrases(ConstQueryNodeRefList & tl) const override;
    size_t depth() const override;
    size_t width() const override;
    virtual void visitMembers(vespalib::ObjectVisitor &visitor) const;
    void setIndex(const vespalib::string & index) override { _index = index; }
    const vespalib::string & getIndex() const override { return _index; }
    static std::unique_ptr<QueryConnector> create(ParseItem::ItemType type);
    virtual bool isFlattenable(ParseItem::ItemType type) const { (void) type; return false; }
    const QueryNodeList & getChildren() const { return _children; }
    virtual void addChild(QueryNode::UP child);
    size_t size() const { return _children.size(); }
    const QueryNode::UP & operator [](size_t index) const { return _children[index]; }
private:
    vespalib::string _opName;
    vespalib::string _index;
    QueryNodeList _children;
};

/**
   True operator. Matches everything.
*/
class TrueNode : public QueryConnector
{
public:
    TrueNode() : QueryConnector("AND") { }
    bool evaluate() const override;
};

/**
   N-ary Or operator that simply ANDs all the nodes together.
*/
class AndQueryNode : public QueryConnector
{
public:
    AndQueryNode() : QueryConnector("AND") { }
    AndQueryNode(const char * opName) : QueryConnector(opName) { }
    bool evaluate() const override;
    bool isFlattenable(ParseItem::ItemType type) const override { return type == ParseItem::ITEM_AND; }
};

/**
   N-ary special AndNot operator. n[0] & !n[1] & !n[2] .. & !n[j].
*/
class AndNotQueryNode : public QueryConnector
{
public:
    AndNotQueryNode() : QueryConnector("ANDNOT") { }
    bool evaluate() const override;
    bool isFlattenable(ParseItem::ItemType type) const override { return type == ParseItem::ITEM_NOT; }
};

/**
   N-ary Or operator that simply ORs all the nodes together.
*/
class OrQueryNode : public QueryConnector
{
public:
    OrQueryNode() : QueryConnector("OR") { }
    OrQueryNode(const char * opName) : QueryConnector(opName) { }
    bool evaluate() const override;
    bool isFlattenable(ParseItem::ItemType type) const override {
        return (type == ParseItem::ITEM_OR) ||
               (type == ParseItem::ITEM_DOT_PRODUCT) ||
               (type == ParseItem::ITEM_WAND) ||
               (type == ParseItem::ITEM_WEAK_AND);
    }
};

/**
   N-ary "EQUIV" operator that merges terms from nodes below.
*/
class EquivQueryNode : public OrQueryNode
{
public:
    EquivQueryNode() : OrQueryNode("EQUIV") { }
    bool evaluate() const override;
    bool isFlattenable(ParseItem::ItemType type) const override {
        return (type == ParseItem::ITEM_EQUIV) ||
               (type == ParseItem::ITEM_WEIGHTED_SET);
    }
};

/**
   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
{
public:
    PhraseQueryNode() : AndQueryNode("PHRASE"), _fieldInfo(32) { }
    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 type) const override { return type == ParseItem::ITEM_NOT; }
    void addChild(QueryNode::UP child) override;
private:
    mutable std::vector<QueryTerm::FieldInfo> _fieldInfo;
    void updateFieldInfo(size_t fid, size_t offset, size_t fieldLength) const;
#if WE_EVER_NEED_TO_CACHE_THIS_WE_MIGHT_WANT_SOME_CODE_HERE
    HitList _cachedHitList;
    bool    _evaluated;
#endif
};

class SameElementQueryNode : public AndQueryNode
{
public:
    SameElementQueryNode() : AndQueryNode("SAME_ELEMENT") { }
    bool evaluate() const override;
    const HitList & evaluateHits(HitList & hl) const override;
    bool isFlattenable(ParseItem::ItemType type) const override { return type == ParseItem::ITEM_NOT; }
    void addChild(QueryNode::UP child) override;
};

/**
   N-ary Near operator. All terms must be within the given distance.
*/
class NearQueryNode : public AndQueryNode
{
public:
    NearQueryNode() : AndQueryNode("NEAR"), _distance(0) { }
    NearQueryNode(const char * opName) : AndQueryNode(opName), _distance(0) { }
    bool evaluate() const override;
    void distance(size_t dist)       { _distance = dist; }
    size_t distance()          const { return _distance; }
    void visitMembers(vespalib::ObjectVisitor &visitor) const override;
    bool isFlattenable(ParseItem::ItemType type) const override { return type == ParseItem::ITEM_NOT; }
private:
    size_t _distance;
};

/**
   N-ary Ordered near operator. The terms must be in order and the distance between
   the first and last must not exceed the given distance.
*/
class ONearQueryNode : public NearQueryNode
{
public:
    ONearQueryNode() : NearQueryNode("ONEAR") { }
    ~ONearQueryNode() { }
    bool evaluate() const override;
};

/**
   Query packages the query tree. The usage pattern is like this.
   Construct the tree with the correct tree description.
   Get the leaf nodes and populate them with the term occurences.
   Then evaluate the query. This is repeated for each document or chunk that
   you want to process. The tree can also be printed. And you can read the
   width and depth properties.
*/
class Query
{
public:
    Query();
    Query(const QueryNodeResultFactory & factory, const QueryPacketT & queryRep);
    /// Will build the query tree
    bool build(const QueryNodeResultFactory & factory, const QueryPacketT & queryRep);
    /// Will clear the results from the querytree.
    void reset();
    /// Will get all leafnodes.
    void getLeafs(QueryTermList & tl);
    void getLeafs(ConstQueryTermList & tl) const;
    /// Gives you all phrases of this tree.
    void getPhrases(QueryNodeRefList & tl);
    void getPhrases(ConstQueryNodeRefList & tl) const;
    bool evaluate() const;
    size_t depth() const;
    size_t width() const;
    bool valid() const { return _root.get() != NULL; }
    const QueryNode & getRoot() const { return *_root; }
    QueryNode & getRoot() { return *_root; }
    static QueryNode::UP steal(Query && query) { return std::move(query._root); }
private:
    QueryNode::UP _root;
};

}