diff --git a/src/graph/optimizer/rule/IndexScanRule.cpp b/src/graph/optimizer/rule/IndexScanRule.cpp index 399a4987ee1..466a076e78b 100644 --- a/src/graph/optimizer/rule/IndexScanRule.cpp +++ b/src/graph/optimizer/rule/IndexScanRule.cpp @@ -66,7 +66,10 @@ StatusOr IndexScanRule::transform(OptContext* ctx, FilterItems items; ScanKind kind; NG_RETURN_IF_ERROR(analyzeExpression(filter, &items, &kind, isEdge(groupNode))); - NG_RETURN_IF_ERROR(createIndexQueryCtx(iqctx, kind, items, qctx, groupNode)); + auto status = createIndexQueryCtx(iqctx, kind, items, qctx, groupNode); + if (!status.ok()) { + NG_RETURN_IF_ERROR(createIndexQueryCtx(iqctx, qctx, groupNode)); + } } const auto* oldIN = groupNode->node(); @@ -481,20 +484,15 @@ std::vector IndexScanRule::findValidIndex(graph::QueryContext* qctx, std::vector validIndexes; // Find indexes for match all fields by where condition. for (const auto& index : indexes) { - bool allColsHint = true; const auto& fields = index->get_fields(); for (const auto& item : items.items) { auto it = std::find_if(fields.begin(), fields.end(), [item](const auto& field) { return field.get_name() == item.col_; }); - if (it == fields.end()) { - allColsHint = false; - break; + if (it != fields.end()) { + validIndexes.emplace_back(index); } } - if (allColsHint) { - validIndexes.emplace_back(index); - } } // If the first field of the index does not match any condition, the index is // invalid. remove it from validIndexes. diff --git a/tests/tck/features/match/Index.feature b/tests/tck/features/match/Index.feature new file mode 100644 index 00000000000..0a221383c51 --- /dev/null +++ b/tests/tck/features/match/Index.feature @@ -0,0 +1,109 @@ +# Copyright (c) 2021 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License. +Feature: Index selecting for match statement + + Background: Prepare a new space + Given an empty graph + And create a space with following options: + | partition_num | 9 | + | replica_factor | 1 | + | vid_type | FIXED_STRING(30) | + | charset | utf8 | + | collate | utf8_bin | + And having executed: + """ + CREATE tag player(name string, age int, score int, gender bool); + """ + And having executed: + """ + INSERT VERTEX player(name, age, score, gender) VALUES "Tim Duncan":("Tim Duncan", 42, 28, true),"Yao Ming":("Yao Ming", 38, 23, true),"Nneka Ogwumike":("Nneka Ogwumike", 35, 13, false); + """ + And having executed: + """ + create tag index player_index on player(); + create tag index player_name_index on player(name(8)); + create tag index player_age_name_index on player(age,name(8)); + """ + And wait 3 seconds + + Scenario: Test Index selecting + When submit a job: + """ + rebuild tag index player_index; + """ + Then wait the job to finish + When submit a job: + """ + rebuild tag index player_name_index; + """ + Then wait the job to finish + When submit a job: + """ + rebuild tag index player_age_name_index; + """ + Then wait the job to finish + # Prefix Index + When profiling query: + """ + MATCH (v:player {name: "Yao Ming"}) RETURN v.name AS name + """ + Then the result should be, in any order, with relax comparison: + | name | + | "Yao Ming" | + And the execution plan should be: + | id | name | dependencies | operator info | + | 9 | Project | 8 | | + | 8 | Filter | 7 | | + | 7 | Project | 6 | | + | 6 | Project | 5 | | + | 5 | Filter | 14 | | + | 14 | GetVertices | 10 | | + | 10 | IndexScan | 0 | {"indexCtx": {"columnHints":{"scanType":"PREFIX"}}} | + | 0 | Start | | | + # Range Index + When profiling query: + """ + MATCH (v:player) WHERE v.name > "Tim" and v.name < "Zom" RETURN v.name AS name + """ + Then the result should be, in any order, with relax comparison: + | name | + | "Yao Ming" | + | "Tim Duncan" | + And the execution plan should be: + | id | name | dependencies | operator info | + | 10 | Project | 13 | | + | 13 | Filter | 7 | | + | 7 | Project | 6 | | + | 6 | Project | 5 | | + | 5 | Filter | 16 | | + | 16 | GetVertices | 11 | | + | 11 | IndexScan | 0 | {"indexCtx": {"columnHints":{"scanType":"RANGE"}}} | + | 0 | Start | | | + # Degeneration to FullScan Index + When executing query: + """ + MATCH (v:player) WHERE v.score < 20 RETURN v.name AS name + """ + Then the result should be, in any order, with relax comparison: + | name | + | "Nneka Ogwumike" | + # Degeneration to Prefix Index + When profiling query: + """ + MATCH (v:player) WHERE v.name == "Tim Duncan" and v.score == 28 RETURN v.name AS name + """ + Then the result should be, in any order, with relax comparison: + | name | + | "Tim Duncan" | + And the execution plan should be: + | id | name | dependencies | operator info | + | 10 | Project | 13 | | + | 13 | Filter | 7 | | + | 7 | Project | 6 | | + | 6 | Project | 5 | | + | 5 | Filter | 16 | | + | 16 | GetVertices | 11 | | + | 11 | IndexScan | 0 | {"indexCtx": {"columnHints":{"scanType":"PREFIX"}}} | + | 0 | Start | | | + Then drop the used space