diff --git a/src/optimizer/rule/IndexScanRule.cpp b/src/optimizer/rule/IndexScanRule.cpp
index 9aedb52f1f553434e8baa0376a00de33eb202f0e..78fffec7e53cc9577f9063f545ef3fb08ae456e4 100644
--- a/src/optimizer/rule/IndexScanRule.cpp
+++ b/src/optimizer/rule/IndexScanRule.cpp
@@ -31,15 +31,16 @@ StatusOr<OptRule::TransformResult> IndexScanRule::transform(graph::QueryContext*
const MatchedResult& matched) const {
auto groupNode = matched.node;
auto filter = filterExpr(groupNode);
+ IndexQueryCtx iqctx = std::make_unique<std::vector<IndexQueryContext>>();
if (filter == nullptr) {
- return Status::SemanticError("WHERE clause error");
+ // Only filter is nullptr when lookup on tagname
+ NG_RETURN_IF_ERROR(createIndexQueryCtx(iqctx, qctx, groupNode));
+ } else {
+ FilterItems items;
+ ScanKind kind;
+ NG_RETURN_IF_ERROR(analyzeExpression(filter.get(), &items, &kind, isEdge(groupNode)));
+ NG_RETURN_IF_ERROR(createIndexQueryCtx(iqctx, kind, items, qctx, groupNode));
}
- FilterItems items;
- ScanKind kind;
- NG_RETURN_IF_ERROR(analyzeExpression(filter.get(), &items, &kind, isEdge(groupNode)));
-
- IndexQueryCtx iqctx = std::make_unique<std::vector<IndexQueryContext>>();
- NG_RETURN_IF_ERROR(createIndexQueryCtx(iqctx, kind, items, qctx, groupNode));
auto newIN = static_cast<const IndexScan*>(groupNode->node())->clone(qctx);
newIN->setIndexQueryContext(std::move(iqctx));
@@ -68,6 +69,20 @@ Status IndexScanRule::createIndexQueryCtx(IndexQueryCtx &iqctx,
: createIQCWithLogicOR(iqctx, items, qctx, groupNode);
}
+Status IndexScanRule::createIndexQueryCtx(IndexQueryCtx &iqctx,
+ graph::QueryContext *qctx,
+ const OptGroupNode *groupNode) const {
+ auto index = findLightestIndex(qctx, groupNode);
+ if (index == nullptr) {
+ return Status::IndexNotFound("No valid index found");
+ }
+ auto ret = appendIQCtx(index, iqctx);
+ NG_RETURN_IF_ERROR(ret);
+
+ return Status::OK();
+}
+
+
Status IndexScanRule::createIQCWithLogicAnd(IndexQueryCtx &iqctx,
const FilterItems& items,
graph::QueryContext *qctx,
@@ -148,6 +163,15 @@ Status IndexScanRule::appendIQCtx(const IndexItem& index,
return Status::OK();
}
+Status IndexScanRule::appendIQCtx(const IndexItem& index,
+ IndexQueryCtx &iqctx) const {
+ IndexQueryContext ctx;
+ ctx.set_index_id(index->get_index_id());
+ ctx.set_filter("");
+ iqctx->emplace_back(std::move(ctx));
+ return Status::OK();
+}
+
#define CHECK_BOUND_VALUE(v, name) \
do { \
if (v == Value::kNullBadType) { \
@@ -277,8 +301,12 @@ std::unique_ptr<Expression>
IndexScanRule::filterExpr(const OptGroupNode *groupNode) const {
auto in = static_cast<const IndexScan *>(groupNode->node());
auto qct = in->queryContext();
- // The initial IndexScan plan node has only one queryContext.
+ // The initial IndexScan plan node has only zeor or one queryContext.
// TODO(yee): Move this condition to match interface
+ if (qct == nullptr) {
+ return nullptr;
+ }
+
if (qct->size() != 1) {
LOG(ERROR) << "Index Scan plan node error";
return nullptr;
@@ -406,6 +434,24 @@ IndexItem IndexScanRule::findOptimalIndex(graph::QueryContext *qctx,
return indexesRange[0];
}
+// Find the index with the fewest fields
+// Only use "lookup on tagname"
+IndexItem IndexScanRule::findLightestIndex(graph::QueryContext *qctx,
+ const OptGroupNode *groupNode) const {
+ auto indexes = allIndexesBySchema(qctx, groupNode);
+ if (indexes.empty()) {
+ return nullptr;
+ }
+
+ auto result = indexes[0];
+ for (size_t i = 1; i < indexes.size(); i++) {
+ if (result->get_fields().size() > indexes[i]->get_fields().size()) {
+ result = indexes[i];
+ }
+ }
+ return result;
+}
+
std::vector<IndexItem>
IndexScanRule::allIndexesBySchema(graph::QueryContext *qctx,
const OptGroupNode *groupNode) const {
diff --git a/src/optimizer/rule/IndexScanRule.h b/src/optimizer/rule/IndexScanRule.h
index 1fcffd8285dfbdc2e652f372e4719f9cdf76a01f..7581475192335eb244366c889d92ae5bd99615fb 100644
--- a/src/optimizer/rule/IndexScanRule.h
+++ b/src/optimizer/rule/IndexScanRule.h
@@ -108,6 +108,10 @@ private:
graph::QueryContext *qctx,
const OptGroupNode *groupNode) const;
+ Status createIndexQueryCtx(IndexQueryCtx &iqctx,
+ graph::QueryContext *qctx,
+ const OptGroupNode *groupNode) const;
+
Status createIQCWithLogicAnd(IndexQueryCtx &iqctx,
const FilterItems& items,
graph::QueryContext *qctx,
@@ -123,6 +127,9 @@ private:
IndexQueryCtx &iqctx,
const std::string& filter = "") const;
+ Status appendIQCtx(const IndexItem& index,
+ IndexQueryCtx &iqctx) const;
+
Status appendColHint(std::vector<IndexColumnHint>& hitns,
const FilterItems& items,
const meta::cpp2::ColumnDef& col) const;
@@ -155,6 +162,9 @@ private:
const OptGroupNode *groupNode,
const FilterItems& items) const;
+ IndexItem findLightestIndex(graph::QueryContext *qctx,
+ const OptGroupNode *groupNode) const;
+
std::vector<IndexItem>
allIndexesBySchema(graph::QueryContext *qctx, const OptGroupNode *groupNode) const;
diff --git a/src/validator/IndexScanValidator.cpp b/src/validator/IndexScanValidator.cpp
index 758093256a33878d2d0cb079d5f821f12ebe0ece..c814fb832c3f90f793cc15f78af1b266f96df52f 100644
--- a/src/validator/IndexScanValidator.cpp
+++ b/src/validator/IndexScanValidator.cpp
@@ -46,6 +46,12 @@ Status IndexScanValidator::prepareYield() {
if (sentence->yieldClause() == nullptr) {
return Status::OK();
}
+ // When whereClause is nullptr, yieldClause is not nullptr,
+ // only return vid for tag. return src, ranking, dst for edge
+ if (sentence->whereClause() == nullptr) {
+ return Status::SemanticError("Yield clauses are not supported "
+ "when WHERE clause does not exist");
+ }
auto columns = sentence->yieldClause()->columns();
auto schema = isEdge_
? qctx_->schemaMng()->getEdgeSchema(spaceId_, schemaId_)
@@ -82,6 +88,10 @@ Status IndexScanValidator::prepareYield() {
Status IndexScanValidator::prepareFilter() {
auto *sentence = static_cast<const LookupSentence *>(sentence_);
+ if (sentence->whereClause() == nullptr) {
+ return Status::OK();
+ }
+
auto *filter = sentence->whereClause()->filter();
auto ret = checkFilter(filter, *sentence->from());
NG_RETURN_IF_ERROR(ret);
diff --git a/src/validator/IndexScanValidator.h b/src/validator/IndexScanValidator.h
index a8e686ebcaee8dc37c7f4ffcb9dccadbea8e539a..4d27eed343260c62420601957b1a93297d699fa9 100644
--- a/src/validator/IndexScanValidator.h
+++ b/src/validator/IndexScanValidator.h
@@ -42,7 +42,7 @@ private:
private:
GraphSpaceID spaceId_{0};
- IndexScan::IndexQueryCtx contexts_{};
+ IndexScan::IndexQueryCtx contexts_{nullptr};
IndexScan::IndexReturnCols returnCols_{};
bool isEdge_{false};
int32_t schemaId_;