diff --git a/src/graph/executor/query/ExpandAllExecutor.cpp b/src/graph/executor/query/ExpandAllExecutor.cpp index dd85469bbb4..396ddc97c7d 100644 --- a/src/graph/executor/query/ExpandAllExecutor.cpp +++ b/src/graph/executor/query/ExpandAllExecutor.cpp @@ -11,6 +11,7 @@ using nebula::storage::StorageClient; using nebula::storage::StorageRpcResponse; +using nebula::storage::cpp2::GetDstBySrcResponse; using nebula::storage::cpp2::GetNeighborsResponse; namespace nebula { @@ -60,9 +61,78 @@ folly::Future ExpandAllExecutor::execute() { if (nextStepVids_.empty()) { return finish(ResultBuilder().value(Value(std::move(result_))).build()); } + if (vertexColumns_ == nullptr && edgeColumns_ == nullptr) { + return GetDstBySrc(); + } return getNeighbors(); } +folly::Future ExpandAllExecutor::GetDstBySrc() { + currentStep_++; + time::Duration getDstTime; + StorageClient* storageClient = qctx_->getStorageClient(); + StorageClient::CommonRequestParam param(expand_->space(), + qctx_->rctx()->session()->id(), + qctx_->plan()->id(), + qctx_->plan()->isProfileEnabled()); + std::vector vids(nextStepVids_.size()); + std::move(nextStepVids_.begin(), nextStepVids_.end(), vids.begin()); + return storageClient->getDstBySrc(param, std::move(vids), expand_->edgeTypes()) + .via(runner()) + .ensure([this, getDstTime]() { + SCOPED_TIMER(&execTime_); + otherStats_.emplace("total_rpc_time", folly::sformat("{}(us)", getDstTime.elapsedInUSec())); + }) + .thenValue([this](StorageRpcResponse&& resps) { + memory::MemoryCheckGuard guard; + nextStepVids_.clear(); + SCOPED_TIMER(&execTime_); + auto& hostLatency = resps.hostLatency(); + for (size_t i = 0; i < hostLatency.size(); ++i) { + size_t size = 0u; + auto& result = resps.responses()[i]; + if (result.dsts_ref().has_value()) { + size = (*result.dsts_ref()).size(); + } + auto info = util::collectRespProfileData(result.result, hostLatency[i], size); + otherStats_.emplace(folly::sformat("step{} resp [{}]", currentStep_, i), + folly::toPrettyJson(info)); + } + auto result = handleCompleteness(resps, FLAGS_accept_partial_success); + if (!result.ok()) { + return folly::makeFuture(result.status()); + } + auto& responses = resps.responses(); + if (currentStep_ <= maxSteps_) { + for (auto& resp : responses) { + auto* dataset = resp.get_dsts(); + if (dataset == nullptr) continue; + for (auto& row : dataset->rows) { + nextStepVids_.insert(row.values.begin(), row.values.end()); + // add the dataset of each step to result_ + result_.rows.emplace_back(row); + } + } + if (nextStepVids_.empty()) { + finish(ResultBuilder().value(Value(std::move(result_))).build()); + return folly::makeFuture(Status::OK()); + } + return GetDstBySrc(); + } else { + for (auto& resp : responses) { + auto* dataset = resp.get_dsts(); + if (dataset == nullptr) continue; + for (auto& row : dataset->rows) { + // add the dataset of each step to result_ + result_.rows.emplace_back(row); + } + } + finish(ResultBuilder().value(Value(std::move(result_))).build()); + return folly::makeFuture(Status::OK()); + } + }); +} + folly::Future ExpandAllExecutor::getNeighbors() { currentStep_++; StorageClient* storageClient = qctx_->getStorageClient(); diff --git a/src/graph/executor/query/ExpandAllExecutor.h b/src/graph/executor/query/ExpandAllExecutor.h index 6f5388b6eac..388d434925b 100644 --- a/src/graph/executor/query/ExpandAllExecutor.h +++ b/src/graph/executor/query/ExpandAllExecutor.h @@ -59,6 +59,8 @@ class ExpandAllExecutor final : public StorageAccessExecutor { folly::Future getNeighbors(); + folly::Future GetDstBySrc(); + void getNeighborsFromCache(std::unordered_map>& dst2VidsMap, std::unordered_set& visitedVids, std::vector& samples); diff --git a/src/graph/planner/ngql/GoPlanner.cpp b/src/graph/planner/ngql/GoPlanner.cpp index d99dbdb1c06..e3b1c5dc8e8 100644 --- a/src/graph/planner/ngql/GoPlanner.cpp +++ b/src/graph/planner/ngql/GoPlanner.cpp @@ -144,18 +144,42 @@ PlanNode* GoPlanner::buildJoinDstPlan(PlanNode* dep) { SubPlan GoPlanner::doSimplePlan() { auto qctx = goCtx_->qctx; - size_t step = goCtx_->steps.mSteps(); + size_t minStep = goCtx_->steps.mSteps(); + size_t maxStep = goCtx_->steps.nSteps(); + size_t steps = minStep; + if (minStep != maxStep) { + steps = minStep == 0 ? minStep : minStep - 1; + } + auto* expand = Expand::make(qctx, startNode_, goCtx_->space.id, false, // random - step, + steps, buildEdgeProps(true)); expand->setEdgeTypes(buildEdgeTypes()); expand->setColNames({"_expand_vid"}); expand->setInputVar(goCtx_->vidsVar); - auto* dedup = Dedup::make(qctx, expand); + auto dep = expand; + if (minStep != maxStep) { + // simple m to n case + // go m to n steps from 'xxx' over edge yield distinct edge._dst + dep = ExpandAll::make(qctx, + dep, + goCtx_->space.id, + false, // random + minStep, + maxStep, + buildEdgeProps(true), + nullptr, + nullptr, + nullptr); + dep->setEdgeTypes(buildEdgeTypes()); + dep->setColNames({"_expandall_vid"}); + } + + auto* dedup = Dedup::make(qctx, dep); auto pool = qctx->objPool(); auto* newYieldExpr = pool->makeAndAdd(); diff --git a/src/graph/validator/GoValidator.cpp b/src/graph/validator/GoValidator.cpp index 84eccb6fc0f..e2b8da5923e 100644 --- a/src/graph/validator/GoValidator.cpp +++ b/src/graph/validator/GoValidator.cpp @@ -284,7 +284,7 @@ bool GoValidator::checkDstPropOrVertexExist(const Expression* expr) { } bool GoValidator::isSimpleCase() { - if (!goCtx_->limits.empty() || !goCtx_->distinct || goCtx_->filter || goCtx_->steps.isMToN() || + if (!goCtx_->limits.empty() || !goCtx_->distinct || goCtx_->filter || goCtx_->from.fromType != FromType::kInstantExpr) { return false; } diff --git a/src/graph/validator/test/QueryValidatorTest.cpp b/src/graph/validator/test/QueryValidatorTest.cpp index 4412d3b3091..a9d58f0e310 100644 --- a/src/graph/validator/test/QueryValidatorTest.cpp +++ b/src/graph/validator/test/QueryValidatorTest.cpp @@ -671,13 +671,13 @@ TEST_F(QueryValidatorTest, GoMToN) { { std::string query = "GO 1 TO 2 STEPS FROM '1' OVER like YIELD DISTINCT like._dst"; std::vector expected = { - PK::kDedup, PK::kProject, PK::kExpandAll, PK::kExpand, PK::kStart}; + PK::kProject, PK::kDedup, PK::kExpandAll, PK::kExpand, PK::kStart}; EXPECT_TRUE(checkResult(query, expected)); } { std::string query = "GO 0 TO 2 STEPS FROM '1' OVER like YIELD DISTINCT like._dst"; std::vector expected = { - PK::kDedup, PK::kProject, PK::kExpandAll, PK::kExpand, PK::kStart}; + PK::kProject, PK::kDedup, PK::kExpandAll, PK::kExpand, PK::kStart}; EXPECT_TRUE(checkResult(query, expected)); } { @@ -698,13 +698,13 @@ TEST_F(QueryValidatorTest, GoMToN) { { std::string query = "GO 1 TO 2 STEPS FROM '1' OVER like REVERSELY YIELD DISTINCT like._dst"; std::vector expected = { - PK::kDedup, PK::kProject, PK::kExpandAll, PK::kExpand, PK::kStart}; + PK::kProject, PK::kDedup, PK::kExpandAll, PK::kExpand, PK::kStart}; EXPECT_TRUE(checkResult(query, expected)); } { std::string query = "GO 1 TO 2 STEPS FROM '1' OVER like BIDIRECT YIELD DISTINCT like._dst"; std::vector expected = { - PK::kDedup, PK::kProject, PK::kExpandAll, PK::kExpand, PK::kStart}; + PK::kProject, PK::kDedup, PK::kExpandAll, PK::kExpand, PK::kStart}; EXPECT_TRUE(checkResult(query, expected)); } { diff --git a/tests/tck/features/go/SimpleCase.feature b/tests/tck/features/go/SimpleCase.feature index 625670d2899..addcb1107ba 100644 --- a/tests/tck/features/go/SimpleCase.feature +++ b/tests/tck/features/go/SimpleCase.feature @@ -266,11 +266,11 @@ Feature: Simple case And the execution plan should be: | id | name | dependencies | operator info | | 6 | Aggregate | 5 | | - | 5 | Dedup | 4 | | - | 4 | Project | 3 | | + | 5 | Project | 4 | | + | 4 | Dedup | 3 | | | 3 | ExpandAll | 2 | | - | 2 | Expand | 1 | | - | 1 | Start | | | + | 2 | Expand | 0 | | + | 0 | Start | | | When profiling query: """ GO 1 to 3 STEP FROM "Tony Parker" OVER like WHERE $$.player.age > 40 YIELD DISTINCT id($$), $$.player.age as age, $$.player.name | ORDER BY $-.age @@ -374,11 +374,11 @@ Feature: Simple case | 12 | Dedup | 11 | | | 11 | Project | 10 | | | 10 | HashInnerJoin | 5,9 | | - | 5 | Dedup | 4 | | - | 4 | Project | 3 | | + | 5 | Project | 4 | | + | 4 | Dedup | 3 | | | 3 | ExpandAll | 2 | | - | 2 | Expand | 1 | | - | 1 | Start | | | + | 2 | Expand | 0 | | + | 0 | Start | | | | 9 | ExpandAll | 8 | | | 8 | Expand | 7 | | | 7 | Argument | | |