in src/search/passes/index_selection.h [183:318]
std::unique_ptr<PlanOperator> VisitExprImpl(Expr *node) {
struct AggregatedNodes {
std::set<Node *> nodes;
IntervalSet intervals;
};
std::map<const FieldInfo *, AggregatedNodes> agg_nodes;
std::vector<std::variant<QueryExpr *, const FieldInfo *>> rest_nodes;
for (const auto &n : node->inners) {
IntervalSet is;
const FieldInfo *field = nullptr;
if (auto iter = intervals.find(n.get()); iter != intervals.end()) {
field = iter->second.field_info;
is = iter->second.intervals;
} else if (auto expr = dynamic_cast<NumericCompareExpr *>(n.get()); expr && expr->op != NumericCompareExpr::NE) {
field = expr->field->info;
is = IntervalSet(expr->op, expr->num->val);
} else {
rest_nodes.emplace_back(n.get());
continue;
}
if (!field->HasIndex()) {
rest_nodes.emplace_back(n.get());
continue;
}
if (auto jter = agg_nodes.find(field); jter != agg_nodes.end()) {
jter->second.nodes.emplace(n.get());
if constexpr (std::is_same_v<Expr, AndExpr>) {
jter->second.intervals = jter->second.intervals & is;
} else {
jter->second.intervals = jter->second.intervals | is;
}
} else {
rest_nodes.emplace_back(field);
agg_nodes.emplace(field, AggregatedNodes{std::set<Node *>{n.get()}, is});
}
}
if constexpr (std::is_same_v<Expr, AndExpr>) {
struct SelectionInfo {
std::unique_ptr<PlanOperator> plan;
std::set<Node *> selected_nodes;
size_t cost;
SelectionInfo(std::unique_ptr<PlanOperator> &&plan, std::set<Node *> nodes)
: plan(std::move(plan)), selected_nodes(std::move(nodes)), cost(CostModel::Transform(this->plan.get())) {}
};
std::vector<SelectionInfo> available_plans;
available_plans.emplace_back(std::make_unique<FullIndexScan>(index->CloneAs<IndexRef>()), std::set<Node *>{});
for (auto v : rest_nodes) {
if (std::holds_alternative<QueryExpr *>(v)) {
auto n = std::get<QueryExpr *>(v);
auto op = TransformExpr(n);
available_plans.emplace_back(std::move(op), std::set<Node *>{n});
} else {
auto n = std::get<const FieldInfo *>(v);
const auto &agg_info = agg_nodes.at(n);
auto field_ref = std::make_unique<FieldRef>(n->name, n);
available_plans.emplace_back(PlanFromInterval(agg_info.intervals, field_ref.get(), SortByClause::ASC),
agg_info.nodes);
}
}
auto &best_plan = *std::min_element(available_plans.begin(), available_plans.end(),
[](const auto &l, const auto &r) { return l.cost < r.cost; });
std::vector<std::unique_ptr<QueryExpr>> filter_nodes;
for (const auto &n : node->inners) {
if (best_plan.selected_nodes.count(n.get()) == 0) filter_nodes.push_back(n->template CloneAs<QueryExpr>());
}
if (filter_nodes.empty()) {
return std::move(best_plan.plan);
} else if (filter_nodes.size() == 1) {
return std::make_unique<Filter>(std::move(best_plan.plan), std::move(filter_nodes.front()));
} else {
return std::make_unique<Filter>(std::move(best_plan.plan), std::make_unique<AndExpr>(std::move(filter_nodes)));
}
} else {
auto full_scan_plan = MakeFullIndexFilter(node);
std::vector<std::unique_ptr<PlanOperator>> merged_elems;
std::vector<std::unique_ptr<QueryExpr>> elem_filter;
auto add_filter = [&elem_filter](std::unique_ptr<PlanOperator> op) {
if (!elem_filter.empty()) {
std::unique_ptr<QueryExpr> filter = std::make_unique<NotExpr>(OrExpr::Create(CloneExprs(elem_filter)));
PushDownNotExpr pdne;
filter = Node::MustAs<QueryExpr>(pdne.Transform(std::move(filter)));
SimplifyAndOrExpr saoe;
filter = Node::MustAs<QueryExpr>(saoe.Transform(std::move(filter)));
op = std::make_unique<Filter>(std::move(op), std::move(filter));
}
return op;
};
for (auto v : rest_nodes) {
if (std::holds_alternative<QueryExpr *>(v)) {
auto n = std::get<QueryExpr *>(v);
auto op = add_filter(TransformExpr(n));
merged_elems.push_back(std::move(op));
elem_filter.push_back(n->CloneAs<QueryExpr>());
} else {
auto n = std::get<const FieldInfo *>(v);
const auto &agg_info = agg_nodes.at(n);
auto field_ref = std::make_unique<FieldRef>(n->name, n);
auto elem = PlanFromInterval(agg_info.intervals, field_ref.get(), SortByClause::ASC);
elem = add_filter(std::move(elem));
merged_elems.push_back(std::move(elem));
for (auto nn : agg_info.nodes) {
elem_filter.push_back(nn->template CloneAs<QueryExpr>());
}
}
}
auto merge_plan = Merge::Create(std::move(merged_elems));
auto &best_plan = const_cast<std::unique_ptr<PlanOperator> &>(std::min(
full_scan_plan, merge_plan,
[](const auto &l, const auto &r) { return CostModel::Transform(l.get()) < CostModel::Transform(r.get()); }));
return std::move(best_plan);
}
}