forked from vesoft-inc/nebula
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOptimizerUtils.h
186 lines (161 loc) · 7.56 KB
/
OptimizerUtils.h
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
/* Copyright (c) 2020 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/
#ifndef NEBULA_GRAPH_UTIL_OPTIMIZERUTILS_H_
#define NEBULA_GRAPH_UTIL_OPTIMIZERUTILS_H_
#include "graph/util/SchemaUtil.h"
namespace nebula {
class Expression;
namespace meta {
namespace cpp2 {
class ColumnDef;
class IndexItem;
} // namespace cpp2
} // namespace meta
namespace storage {
namespace cpp2 {
class IndexQueryContext;
} // namespace cpp2
} // namespace storage
namespace graph {
class IndexScan;
class OptimizerUtils {
public:
OptimizerUtils() = delete;
// Compare `a` and `b`, if `a`>`b` then swap a and b.That means `b`>=`a` after call this function.
static Status compareAndSwapBound(std::pair<Value, bool> &a, std::pair<Value, bool> &b);
static void eraseInvalidIndexItems(
int32_t schemaId, std::vector<std::shared_ptr<nebula::meta::cpp2::IndexItem>> *indexItems);
// Find optimal index according to filter expression and all valid indexes.
//
// For relational condition expression:
// 1. iterate all indexes
// 2. select the best column hint for each index
// 2.1. generate column hint according to the first field of index
//
// For logical condition expression(only logical `AND' expression):
// 1. same steps as above 1, 2
// 2. for multiple columns combined index:
// * iterate each field of index
// * iterate each operand expression of filter condition
// * collect all column hints generated by operand expression for each index field
// * process collected column hints, for example, merge the begin and end values of
// range scan
// 3. sort all index results generated by each index
// 4. select the largest score index result
// 5. process the selected index result:
// * find the first not prefix column hint and ignore all followed hints except first
// range hint
// * check whether filter conditions are used, if not, place the unused expression parts
// into column hint filter
//
// For logical `OR' condition expression, use above steps to generate
// different `IndexQueryContext' for each operand of filter condition, nebula
// storage will union all results of multiple index contexts
static bool findOptimalIndex(
const Expression *condition,
const std::vector<std::shared_ptr<nebula::meta::cpp2::IndexItem>> &indexItems,
bool *isPrefixScan,
nebula::storage::cpp2::IndexQueryContext *ictx);
static bool relExprHasIndex(
const Expression *expr,
const std::vector<std::shared_ptr<nebula::meta::cpp2::IndexItem>> &indexItems);
static void copyIndexScanData(const nebula::graph::IndexScan *from,
nebula::graph::IndexScan *to,
QueryContext *qctx);
//---------------------------------------------------------------
using IndexItemPtr = std::shared_ptr<meta::cpp2::IndexItem>;
using IndexQueryContextList = std::vector<storage::cpp2::IndexQueryContext>;
struct ScanKind {
enum class Kind {
kUnknown = 0,
kMultipleScan,
kSingleScan,
};
private:
Kind kind_;
public:
ScanKind() {
kind_ = Kind::kUnknown;
}
void setKind(Kind k) {
kind_ = k;
}
Kind getKind() {
return kind_;
}
bool isSingleScan() {
return kind_ == Kind::kSingleScan;
}
};
// col_ : index column name
// relOP_ : Relational operator , for example c1 > 1 , the relOP_ == kRelGT
// 1 > c1 , the relOP_ == kRelLT
// value_ : Constant value. from ConstantExpression.
struct FilterItem {
std::string col_;
Expression::Kind relOP_;
Value value_;
FilterItem(const std::string &col, RelationalExpression::Kind relOP, const Value &value)
: col_(col), relOP_(relOP), value_(value) {}
};
static Status createIndexQueryCtx(Expression *filter,
QueryContext *qctx,
const IndexScan *node,
IndexQueryContextList &iqctx);
static Status createIndexQueryCtx(IndexQueryContextList &iqctx,
QueryContext *qctx,
const IndexScan *node);
static Status createIndexQueryCtx(IndexQueryContextList &iqctx,
ScanKind kind,
const std::vector<FilterItem> &items,
graph::QueryContext *qctx,
const IndexScan *node);
static IndexItemPtr findLightestIndex(graph::QueryContext *qctx, const IndexScan *node);
static Status createMultipleIQC(IndexQueryContextList &iqctx,
const std::vector<FilterItem> &items,
graph::QueryContext *qctx,
const IndexScan *node);
static Status createSingleIQC(IndexQueryContextList &iqctx,
const std::vector<FilterItem> &items,
graph::QueryContext *qctx,
const IndexScan *node);
static Status appendIQCtx(const IndexItemPtr &index,
const std::vector<FilterItem> &items,
IndexQueryContextList &iqctx,
const Expression *filter = nullptr);
static Status appendIQCtx(const IndexItemPtr &index, IndexQueryContextList &iqctx);
static Status appendColHint(std::vector<storage::cpp2::IndexColumnHint> &hints,
const std::vector<FilterItem> &items,
const meta::cpp2::ColumnDef &col);
static bool verifyType(const Value &val);
static size_t hintCount(const std::vector<FilterItem> &items);
static IndexItemPtr findOptimalIndex(graph::QueryContext *qctx,
const IndexScan *node,
const std::vector<FilterItem> &items);
static std::vector<IndexItemPtr> findIndexForRangeScan(const std::vector<IndexItemPtr> &indexes,
const std::vector<FilterItem> &items);
static std::vector<IndexItemPtr> findIndexForEqualScan(const std::vector<IndexItemPtr> &indexes,
const std::vector<FilterItem> &items);
static std::vector<IndexItemPtr> findValidIndex(graph::QueryContext *qctx,
const IndexScan *node,
const std::vector<FilterItem> &items);
static std::vector<IndexItemPtr> allIndexesBySchema(graph::QueryContext *qctx,
const IndexScan *node);
static Status analyzeExpression(Expression *expr,
std::vector<FilterItem> *items,
ScanKind *kind,
bool isEdge,
QueryContext *qctx);
template <typename E,
typename = std::enable_if_t<std::is_same<E, EdgePropertyExpression>::value ||
std::is_same<E, LabelTagPropertyExpression>::value ||
std::is_same<E, TagPropertyExpression>::value>>
static Status addFilterItem(RelationalExpression *expr,
std::vector<FilterItem> *items,
QueryContext *qctx);
};
} // namespace graph
} // namespace nebula
#endif // NEBULA_GRAPH_UTIL_OPTIMIZERUTILS_H_