From 0867cd45faf41ce20e0ee809b581ccd54391f74e Mon Sep 17 00:00:00 2001 From: jimingquan <mingquan.ji@vesoft.com> Date: Tue, 9 Mar 2021 10:36:26 +0800 Subject: [PATCH] Add LeftJoin & change DataJoin to InnerJoin (#758) * add LeftJoin & change DataJoin to InnerJoin * add more test case * rebase * rebase master --- src/executor/CMakeLists.txt | 4 +- src/executor/Executor.cpp | 10 +- src/executor/query/DataJoinExecutor.cpp | 123 ---- src/executor/query/DataJoinExecutor.h | 38 -- src/executor/query/InnerJoinExecutor.cpp | 90 +++ src/executor/query/InnerJoinExecutor.h | 35 ++ src/executor/query/JoinExecutor.cpp | 54 ++ src/executor/query/JoinExecutor.h | 29 + src/executor/query/LeftJoinExecutor.cpp | 88 +++ src/executor/query/LeftJoinExecutor.h | 35 ++ src/executor/test/CMakeLists.txt | 2 +- src/executor/test/DataJoinTest.cpp | 261 -------- src/executor/test/JoinTest.cpp | 567 ++++++++++++++++++ src/planner/PlanNode.cpp | 6 +- src/planner/PlanNode.h | 3 +- src/planner/Query.cpp | 15 +- src/planner/Query.h | 109 ++-- src/planner/match/InnerJoinStrategy.cpp | 2 +- src/validator/GoValidator.cpp | 8 +- src/validator/test/GroupByValidatorTest.cpp | 14 +- src/validator/test/MatchValidatorTest.cpp | 24 +- src/validator/test/QueryValidatorTest.cpp | 122 ++-- src/validator/test/SymbolsTest.cpp | 6 +- .../MergeGetNbrsDedupProjectRule.feature | 4 +- 24 files changed, 1091 insertions(+), 558 deletions(-) delete mode 100644 src/executor/query/DataJoinExecutor.cpp delete mode 100644 src/executor/query/DataJoinExecutor.h create mode 100644 src/executor/query/InnerJoinExecutor.cpp create mode 100644 src/executor/query/InnerJoinExecutor.h create mode 100644 src/executor/query/JoinExecutor.cpp create mode 100644 src/executor/query/JoinExecutor.h create mode 100644 src/executor/query/LeftJoinExecutor.cpp create mode 100644 src/executor/query/LeftJoinExecutor.h delete mode 100644 src/executor/test/DataJoinTest.cpp create mode 100644 src/executor/test/JoinTest.cpp diff --git a/src/executor/CMakeLists.txt b/src/executor/CMakeLists.txt index cd8d3bcd..719cc46c 100644 --- a/src/executor/CMakeLists.txt +++ b/src/executor/CMakeLists.txt @@ -28,7 +28,9 @@ nebula_add_library( query/UnionExecutor.cpp query/UnionAllVersionVarExecutor.cpp query/DataCollectExecutor.cpp - query/DataJoinExecutor.cpp + query/JoinExecutor.cpp + query/LeftJoinExecutor.cpp + query/InnerJoinExecutor.cpp query/IndexScanExecutor.cpp query/AssignExecutor.cpp algo/ConjunctPathExecutor.cpp diff --git a/src/executor/Executor.cpp b/src/executor/Executor.cpp index 6905e261..c0783770 100644 --- a/src/executor/Executor.cpp +++ b/src/executor/Executor.cpp @@ -63,7 +63,8 @@ #include "executor/mutate/UpdateExecutor.h" #include "executor/query/AggregateExecutor.h" #include "executor/query/DataCollectExecutor.h" -#include "executor/query/DataJoinExecutor.h" +#include "executor/query/LeftJoinExecutor.h" +#include "executor/query/InnerJoinExecutor.h" #include "executor/query/DedupExecutor.h" #include "executor/query/FilterExecutor.h" #include "executor/query/GetEdgesExecutor.h" @@ -327,8 +328,11 @@ Executor *Executor::makeExecutor(QueryContext *qctx, const PlanNode *node) { case PlanNode::Kind::kShowSnapshots: { return pool->add(new ShowSnapshotsExecutor(node, qctx)); } - case PlanNode::Kind::kDataJoin: { - return pool->add(new DataJoinExecutor(node, qctx)); + case PlanNode::Kind::kLeftJoin: { + return pool->add(new LeftJoinExecutor(node, qctx)); + } + case PlanNode::Kind::kInnerJoin: { + return pool->add(new InnerJoinExecutor(node, qctx)); } case PlanNode::Kind::kDeleteVertices: { return pool->add(new DeleteVerticesExecutor(node, qctx)); diff --git a/src/executor/query/DataJoinExecutor.cpp b/src/executor/query/DataJoinExecutor.cpp deleted file mode 100644 index cad741bf..00000000 --- a/src/executor/query/DataJoinExecutor.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License, - * attached with Common Clause Condition 1.0, found in the LICENSES directory. - */ - -#include "executor/query/DataJoinExecutor.h" - -#include "planner/Query.h" -#include "context/QueryExpressionContext.h" -#include "context/Iterator.h" -#include "util/ScopedTimer.h" - -namespace nebula { -namespace graph { -folly::Future<Status> DataJoinExecutor::execute() { - return doInnerJoin(); -} - -Status DataJoinExecutor::close() { - exchange_ = false; - hashTable_.clear(); - return Executor::close(); -} - -folly::Future<Status> DataJoinExecutor::doInnerJoin() { - SCOPED_TIMER(&execTime_); - - auto* dataJoin = asNode<DataJoin>(node()); - auto colNames = dataJoin->colNames(); - auto lhsIter = ectx_ - ->getVersionedResult(dataJoin->leftVar().first, - dataJoin->leftVar().second) - .iter(); - DCHECK(!!lhsIter); - if (lhsIter->isGetNeighborsIter() || lhsIter->isDefaultIter()) { - std::stringstream ss; - ss << "Join executor does not support " << lhsIter->kind(); - return error(Status::Error(ss.str())); - } - auto rhsIter = ectx_ - ->getVersionedResult(dataJoin->rightVar().first, - dataJoin->rightVar().second) - .iter(); - DCHECK(!!rhsIter); - if (lhsIter->isGetNeighborsIter() || lhsIter->isDefaultIter()) { - std::stringstream ss; - ss << "Join executor does not support " << lhsIter->kind(); - return error(Status::Error(ss.str())); - } - - auto resultIter = std::make_unique<JoinIter>(std::move(colNames)); - resultIter->joinIndex(lhsIter.get(), rhsIter.get()); - auto bucketSize = - lhsIter->size() > rhsIter->size() ? rhsIter->size() : lhsIter->size(); - hashTable_.reserve(bucketSize); - resultIter->reserve(lhsIter->size() > rhsIter->size() ? lhsIter->size() : rhsIter->size()); - - if (!(lhsIter->empty() || rhsIter->empty())) { - if (lhsIter->size() < rhsIter->size()) { - buildHashTable(dataJoin->hashKeys(), lhsIter.get()); - probe(dataJoin->probeKeys(), rhsIter.get(), resultIter.get()); - } else { - exchange_ = true; - buildHashTable(dataJoin->probeKeys(), rhsIter.get()); - probe(dataJoin->hashKeys(), lhsIter.get(), resultIter.get()); - } - } - return finish(ResultBuilder().iter(std::move(resultIter)).finish()); -} - -void DataJoinExecutor::buildHashTable(const std::vector<Expression*>& hashKeys, - Iterator* iter) { - QueryExpressionContext ctx(ectx_); - for (; iter->valid(); iter->next()) { - List list; - list.values.reserve(hashKeys.size()); - for (auto& col : hashKeys) { - Value val = col->eval(ctx(iter)); - list.values.emplace_back(std::move(val)); - } - - auto& vals = hashTable_[list]; - vals.emplace_back(iter->row()); - } -} - -void DataJoinExecutor::probe(const std::vector<Expression*>& probeKeys, - Iterator* probeIter, JoinIter* resultIter) { - QueryExpressionContext ctx(ectx_); - for (; probeIter->valid(); probeIter->next()) { - List list; - list.values.reserve(probeKeys.size()); - for (auto& col : probeKeys) { - Value val = col->eval(ctx(probeIter)); - list.values.emplace_back(std::move(val)); - } - - const auto& range = hashTable_.find(list); - if (range == hashTable_.end()) { - continue; - } - for (auto* row : range->second) { - std::vector<const Row*> values; - auto& lSegs = row->segments(); - auto& rSegs = probeIter->row()->segments(); - values.reserve(lSegs.size() + rSegs.size()); - if (exchange_) { - values.insert(values.end(), rSegs.begin(), rSegs.end()); - values.insert(values.end(), lSegs.begin(), lSegs.end()); - } else { - values.insert(values.end(), lSegs.begin(), lSegs.end()); - values.insert(values.end(), rSegs.begin(), rSegs.end()); - } - size_t size = row->size() + probeIter->row()->size(); - JoinIter::JoinLogicalRow newRow(std::move(values), size, - &resultIter->getColIdxIndices()); - resultIter->addRow(std::move(newRow)); - } - } -} -} // namespace graph -} // namespace nebula diff --git a/src/executor/query/DataJoinExecutor.h b/src/executor/query/DataJoinExecutor.h deleted file mode 100644 index 1332dbd1..00000000 --- a/src/executor/query/DataJoinExecutor.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License, - * attached with Common Clause Condition 1.0, found in the LICENSES directory. - */ - -#ifndef EXECUTOR_QUERY_DATAJOINEXECUTOR_H_ -#define EXECUTOR_QUERY_DATAJOINEXECUTOR_H_ - -#include "executor/Executor.h" - -namespace nebula { -namespace graph { - -class DataJoinExecutor final : public Executor { -public: - DataJoinExecutor(const PlanNode *node, QueryContext *qctx) - : Executor("DataJoinExecutor", node, qctx) {} - - folly::Future<Status> execute() override; - - Status close() override; - -private: - folly::Future<Status> doInnerJoin(); - - void buildHashTable(const std::vector<Expression*>& hashKeys, Iterator* iter); - - void probe(const std::vector<Expression*>& probeKeys, Iterator* probeiter, - JoinIter* resultIter); - -private: - bool exchange_{false}; - std::unordered_map<List, std::vector<const LogicalRow*>> hashTable_; -}; -} // namespace graph -} // namespace nebula -#endif diff --git a/src/executor/query/InnerJoinExecutor.cpp b/src/executor/query/InnerJoinExecutor.cpp new file mode 100644 index 00000000..429afce3 --- /dev/null +++ b/src/executor/query/InnerJoinExecutor.cpp @@ -0,0 +1,90 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "executor/query/InnerJoinExecutor.h" + +#include "context/Iterator.h" +#include "context/QueryExpressionContext.h" +#include "planner/Query.h" +#include "util/ScopedTimer.h" + +namespace nebula { +namespace graph { +folly::Future<Status> InnerJoinExecutor::execute() { + SCOPED_TIMER(&execTime_); + NG_RETURN_IF_ERROR(checkInputDataSets()); + return join(); +} + +Status InnerJoinExecutor::close() { + exchange_ = false; + hashTable_.clear(); + return Executor::close(); +} + +folly::Future<Status> InnerJoinExecutor::join() { + auto* join = asNode<Join>(node()); + auto lhsIter = ectx_->getVersionedResult(join->leftVar().first, join->leftVar().second).iter(); + auto rhsIter = + ectx_->getVersionedResult(join->rightVar().first, join->rightVar().second).iter(); + + auto resultIter = std::make_unique<JoinIter>(join->colNames()); + resultIter->joinIndex(lhsIter.get(), rhsIter.get()); + auto bucketSize = lhsIter->size() > rhsIter->size() ? rhsIter->size() : lhsIter->size(); + hashTable_.reserve(bucketSize); + resultIter->reserve(lhsIter->size() > rhsIter->size() ? lhsIter->size() : rhsIter->size()); + + if (!(lhsIter->empty() || rhsIter->empty())) { + if (lhsIter->size() < rhsIter->size()) { + buildHashTable(join->hashKeys(), lhsIter.get()); + probe(join->probeKeys(), rhsIter.get(), resultIter.get()); + } else { + exchange_ = true; + buildHashTable(join->probeKeys(), rhsIter.get()); + probe(join->hashKeys(), lhsIter.get(), resultIter.get()); + } + } + return finish(ResultBuilder().iter(std::move(resultIter)).finish()); +} + +void InnerJoinExecutor::probe(const std::vector<Expression*>& probeKeys, + Iterator* probeIter, + JoinIter* resultIter) { + QueryExpressionContext ctx(ectx_); + for (; probeIter->valid(); probeIter->next()) { + List list; + list.values.reserve(probeKeys.size()); + for (auto& col : probeKeys) { + Value val = col->eval(ctx(probeIter)); + list.values.emplace_back(std::move(val)); + } + + auto range = hashTable_.find(list); + if (range == hashTable_.end()) { + continue; + } + for (auto* row : range->second) { + std::vector<const Row*> values; + auto& lSegs = row->segments(); + auto& rSegs = probeIter->row()->segments(); + values.reserve(lSegs.size() + rSegs.size()); + if (exchange_) { + values.insert(values.end(), rSegs.begin(), rSegs.end()); + values.insert(values.end(), lSegs.begin(), lSegs.end()); + } else { + values.insert(values.end(), lSegs.begin(), lSegs.end()); + values.insert(values.end(), rSegs.begin(), rSegs.end()); + } + size_t size = row->size() + probeIter->row()->size(); + JoinIter::JoinLogicalRow newRow( + std::move(values), size, &resultIter->getColIdxIndices()); + VLOG(1) << node()->outputVar() << " : " << newRow; + resultIter->addRow(std::move(newRow)); + } + } +} +} // namespace graph +} // namespace nebula diff --git a/src/executor/query/InnerJoinExecutor.h b/src/executor/query/InnerJoinExecutor.h new file mode 100644 index 00000000..8651ca34 --- /dev/null +++ b/src/executor/query/InnerJoinExecutor.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef EXECUTOR_QUERY_INNERJOINEXECUTOR_H_ +#define EXECUTOR_QUERY_INNERJOINEXECUTOR_H_ + +#include "executor/query/JoinExecutor.h" + +namespace nebula { +namespace graph { + +class InnerJoinExecutor final : public JoinExecutor { +public: + InnerJoinExecutor(const PlanNode* node, QueryContext* qctx) + : JoinExecutor("InnerJoinExecutor", node, qctx) {} + + folly::Future<Status> execute() override; + + Status close() override; + +private: + folly::Future<Status> join(); + void probe(const std::vector<Expression*>& probeKeys, + Iterator* probeiter, + JoinIter* resultIter); + +private: + bool exchange_{false}; +}; +} // namespace graph +} // namespace nebula +#endif diff --git a/src/executor/query/JoinExecutor.cpp b/src/executor/query/JoinExecutor.cpp new file mode 100644 index 00000000..4395f4a9 --- /dev/null +++ b/src/executor/query/JoinExecutor.cpp @@ -0,0 +1,54 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "executor/query/JoinExecutor.h" + +#include "planner/Query.h" +#include "context/QueryExpressionContext.h" +#include "context/Iterator.h" + +namespace nebula { +namespace graph { + +Status JoinExecutor::checkInputDataSets() { + auto* join = asNode<Join>(node()); + auto lhsIter = ectx_->getVersionedResult(join->leftVar().first, join->leftVar().second).iter(); + DCHECK(!!lhsIter); + VLOG(1) << "lhs: " << join->leftVar().first << " " << lhsIter->size(); + if (lhsIter->isGetNeighborsIter() || lhsIter->isDefaultIter()) { + std::stringstream ss; + ss << "Join executor does not support " << lhsIter->kind(); + return Status::Error(ss.str()); + } + auto rhsIter = + ectx_->getVersionedResult(join->rightVar().first, join->rightVar().second).iter(); + DCHECK(!!rhsIter); + VLOG(1) << "rhs: " << join->rightVar().first << " " << rhsIter->size(); + if (rhsIter->isGetNeighborsIter() || rhsIter->isDefaultIter()) { + std::stringstream ss; + ss << "Join executor does not support " << rhsIter->kind(); + return Status::Error(ss.str()); + } + return Status::OK(); +} + +void JoinExecutor::buildHashTable(const std::vector<Expression*>& hashKeys, Iterator* iter) { + QueryExpressionContext ctx(ectx_); + for (; iter->valid(); iter->next()) { + List list; + list.values.reserve(hashKeys.size()); + for (auto& col : hashKeys) { + Value val = col->eval(ctx(iter)); + list.values.emplace_back(std::move(val)); + } + + auto& vals = hashTable_[list]; + vals.emplace_back(iter->row()); + } +} + +} // namespace graph +} // namespace nebula diff --git a/src/executor/query/JoinExecutor.h b/src/executor/query/JoinExecutor.h new file mode 100644 index 00000000..33e0eb9f --- /dev/null +++ b/src/executor/query/JoinExecutor.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef EXECUTOR_QUERY_JOINEXECUTOR_H_ +#define EXECUTOR_QUERY_JOINEXECUTOR_H_ + +#include "executor/Executor.h" + +namespace nebula { +namespace graph { + +class JoinExecutor : public Executor { +public: + JoinExecutor(const std::string& name, const PlanNode* node, QueryContext* qctx) + : Executor(name, node, qctx) {} + + Status checkInputDataSets(); + + void buildHashTable(const std::vector<Expression*>& hashKeys, Iterator* iter); + +protected: + std::unordered_map<List, std::vector<const LogicalRow*>> hashTable_; +}; +} // namespace graph +} // namespace nebula +#endif diff --git a/src/executor/query/LeftJoinExecutor.cpp b/src/executor/query/LeftJoinExecutor.cpp new file mode 100644 index 00000000..ed521a93 --- /dev/null +++ b/src/executor/query/LeftJoinExecutor.cpp @@ -0,0 +1,88 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "executor/query/LeftJoinExecutor.h" + +#include "context/Iterator.h" +#include "context/QueryExpressionContext.h" +#include "planner/Query.h" +#include "util/ScopedTimer.h" + +namespace nebula { +namespace graph { +folly::Future<Status> LeftJoinExecutor::execute() { + SCOPED_TIMER(&execTime_); + NG_RETURN_IF_ERROR(checkInputDataSets()); + return join(); +} + +Status LeftJoinExecutor::close() { + hashTable_.clear(); + return Executor::close(); +} + +folly::Future<Status> LeftJoinExecutor::join() { + auto* join = asNode<Join>(node()); + auto lhsIter = ectx_->getVersionedResult(join->leftVar().first, join->leftVar().second).iter(); + auto& rhsResult = ectx_->getVersionedResult(join->rightVar().first, join->rightVar().second); + rightColSize_ = rhsResult.valuePtr()->getDataSet().colNames.size(); + auto rhsIter = rhsResult.iter(); + + auto resultIter = std::make_unique<JoinIter>(join->colNames()); + resultIter->joinIndex(lhsIter.get(), rhsIter.get()); + hashTable_.reserve(rhsIter->size() == 0 ? 1 : rhsIter->size()); + resultIter->reserve(lhsIter->size()); + if (!lhsIter->empty()) { + buildHashTable(join->probeKeys(), rhsIter.get()); + probe(join->hashKeys(), lhsIter.get(), resultIter.get()); + } + return finish(ResultBuilder().iter(std::move(resultIter)).finish()); +} + +void LeftJoinExecutor::probe(const std::vector<Expression*>& probeKeys, + Iterator* probeIter, + JoinIter* resultIter) { + QueryExpressionContext ctx(ectx_); + for (; probeIter->valid(); probeIter->next()) { + List list; + list.values.reserve(probeKeys.size()); + for (auto& col : probeKeys) { + Value val = col->eval(ctx(probeIter)); + list.values.emplace_back(std::move(val)); + } + + auto range = hashTable_.find(list); + if (range == hashTable_.end()) { + std::vector<const Row*> values; + auto& lSegs = probeIter->row()->segments(); + values.reserve(lSegs.size() + 1); + values.insert(values.end(), lSegs.begin(), lSegs.end()); + Row* emptyRow = qctx_->objPool()->add(new List(std::vector<Value>(rightColSize_))); + values.insert(values.end(), emptyRow); + size_t size = probeIter->row()->size() + rightColSize_; + JoinIter::JoinLogicalRow newRow( + std::move(values), size, &resultIter->getColIdxIndices()); + VLOG(1) << node()->outputVar() << " : " << newRow; + resultIter->addRow(std::move(newRow)); + } else { + for (auto* row : range->second) { + std::vector<const Row*> values; + auto& lSegs = probeIter->row()->segments(); + auto& rSegs = row->segments(); + values.reserve(lSegs.size() + rSegs.size()); + values.insert(values.end(), lSegs.begin(), lSegs.end()); + values.insert(values.end(), rSegs.begin(), rSegs.end()); + size_t size = row->size() + probeIter->row()->size(); + JoinIter::JoinLogicalRow newRow( + std::move(values), size, &resultIter->getColIdxIndices()); + VLOG(1) << node()->outputVar() << " : " << newRow; + resultIter->addRow(std::move(newRow)); + } + } + } +} +} // namespace graph +} // namespace nebula diff --git a/src/executor/query/LeftJoinExecutor.h b/src/executor/query/LeftJoinExecutor.h new file mode 100644 index 00000000..c4245e34 --- /dev/null +++ b/src/executor/query/LeftJoinExecutor.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef EXECUTOR_QUERY_LEFTJOINEXECUTOR_H_ +#define EXECUTOR_QUERY_LEFTJOINEXECUTOR_H_ + +#include "executor/query/JoinExecutor.h" + +namespace nebula { +namespace graph { + +class LeftJoinExecutor final : public JoinExecutor { +public: + LeftJoinExecutor(const PlanNode *node, QueryContext *qctx) + : JoinExecutor("LeftJoinExecutor", node, qctx) {} + + folly::Future<Status> execute() override; + + Status close() override; + +private: + folly::Future<Status> join(); + + void probe(const std::vector<Expression*>& probeKeys, Iterator* probeiter, + JoinIter* resultIter); + +private: + size_t rightColSize_{0}; +}; +} // namespace graph +} // namespace nebula +#endif diff --git a/src/executor/test/CMakeLists.txt b/src/executor/test/CMakeLists.txt index 8eedd7e6..789a5f71 100644 --- a/src/executor/test/CMakeLists.txt +++ b/src/executor/test/CMakeLists.txt @@ -72,7 +72,7 @@ nebula_add_test( SortTest.cpp TopNTest.cpp AggregateTest.cpp - DataJoinTest.cpp + JoinTest.cpp BFSShortestTest.cpp ConjunctPathTest.cpp ProduceSemiShortestPathTest.cpp diff --git a/src/executor/test/DataJoinTest.cpp b/src/executor/test/DataJoinTest.cpp deleted file mode 100644 index 090144af..00000000 --- a/src/executor/test/DataJoinTest.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License, - * attached with Common Clause Condition 1.0, found in the LICENSES directory. - */ - -#include <gtest/gtest.h> - -#include "context/QueryContext.h" -#include "planner/Query.h" -#include "executor/query/DataJoinExecutor.h" -#include "executor/test/QueryTestBase.h" - -namespace nebula { -namespace graph { -class DataJoinTest : public QueryTestBase { -protected: - void SetUp() override { - qctx_ = std::make_unique<QueryContext>(); - { - DataSet ds; - ds.colNames = {kVid, "tag_prop", "edge_prop", kDst}; - for (auto i = 0; i < 10; ++i) { - Row row; - // _vid - row.values.emplace_back(folly::to<std::string>(i / 2)); - row.values.emplace_back(i); - row.values.emplace_back(i + 1); - // _dst - row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); - ds.rows.emplace_back(std::move(row)); - } - qctx_->symTable()->newVariable("var1"); - qctx_->ectx()->setResult( - "var1", - ResultBuilder().value(Value(std::move(ds))).finish()); - } - { - DataSet ds; - ds.colNames = {"src", "dst"}; - for (auto i = 0; i < 5; ++i) { - Row row; - row.values.emplace_back(folly::to<std::string>(i + 11)); - row.values.emplace_back(folly::to<std::string>(i)); - ds.rows.emplace_back(std::move(row)); - } - qctx_->symTable()->newVariable("var2"); - qctx_->ectx()->setResult( - "var2", ResultBuilder().value(Value(std::move(ds))).finish()); - } - { - DataSet ds; - ds.colNames = {"col1"}; - Row row; - row.values.emplace_back("11"); - ds.rows.emplace_back(std::move(row)); - qctx_->symTable()->newVariable("var3"); - qctx_->ectx()->setResult( - "var3", ResultBuilder().value(Value(std::move(ds))).finish()); - } - { - DataSet ds; - ds.colNames = {kVid, "tag_prop", "edge_prop", kDst}; - qctx_->symTable()->newVariable("empty_var1"); - qctx_->ectx()->setResult( - "empty_var1", - ResultBuilder().value(Value(std::move(ds))).finish()); - } - { - DataSet ds; - ds.colNames = {"src", "dst"}; - qctx_->symTable()->newVariable("empty_var2"); - qctx_->ectx()->setResult( - "empty_var2", - ResultBuilder().value(Value(std::move(ds))).finish()); - } - } - - void testJoin(std::string left, std::string right, DataSet& expected, int64_t line); - -protected: - std::unique_ptr<QueryContext> qctx_; -}; - -void DataJoinTest::testJoin(std::string left, std::string right, - DataSet& expected, int64_t line) { - VariablePropertyExpression key(new std::string(left), - new std::string("dst")); - std::vector<Expression*> hashKeys = {&key}; - VariablePropertyExpression probe(new std::string(right), - new std::string("_vid")); - std::vector<Expression*> probeKeys = {&probe}; - - auto* dataJoin = - DataJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), - std::move(probeKeys)); - dataJoin->setColNames(std::vector<std::string>{ - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}); - - auto dataJoinExe = - std::make_unique<DataJoinExecutor>(dataJoin, qctx_.get()); - auto future = dataJoinExe->execute(); - auto status = std::move(future).get(); - EXPECT_TRUE(status.ok()) << "LINE: " << line; - auto& result = qctx_->ectx()->getResult(dataJoin->outputVar()); - - DataSet resultDs; - resultDs.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; - auto iter = result.iter(); - for (; iter->valid(); iter->next()) { - const auto& cols = *iter->row(); - Row row; - for (size_t i = 0; i < cols.size(); ++i) { - Value col = cols[i]; - row.values.emplace_back(std::move(col)); - } - resultDs.rows.emplace_back(std::move(row)); - } - - EXPECT_EQ(resultDs, expected) << "LINE: " << line; - EXPECT_EQ(result.state(), Result::State::kSuccess) << "LINE: " << line; -} - -TEST_F(DataJoinTest, Join) { - DataSet expected; - expected.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; - for (auto i = 11; i < 16; ++i) { - Row row1; - row1.values.emplace_back(folly::to<std::string>(i)); - row1.values.emplace_back(folly::to<std::string>(i % 11)); - row1.values.emplace_back(folly::to<std::string>(i % 11)); - row1.values.emplace_back(i % 11 * 2); - row1.values.emplace_back(i % 11 * 2 + 1); - row1.values.emplace_back(folly::to<std::string>(i - 6)); - expected.rows.emplace_back(std::move(row1)); - - Row row2; - row2.values.emplace_back(folly::to<std::string>(i)); - row2.values.emplace_back(folly::to<std::string>(i % 11)); - row2.values.emplace_back(folly::to<std::string>(i % 11)); - row2.values.emplace_back(i % 11 * 2 + 1); - row2.values.emplace_back(i % 11 * 2 + 2); - row2.values.emplace_back(folly::to<std::string>(i - 5)); - expected.rows.emplace_back(std::move(row2)); - } - - // $var1 inner join $var2 on $var2.dst = $var1._vid - testJoin("var2", "var1", expected, __LINE__); -} - -TEST_F(DataJoinTest, JoinTwice) { - std::string join; - { - std::string left = "var2"; - std::string right = "var1"; - VariablePropertyExpression key(new std::string(left), - new std::string("dst")); - std::vector<Expression*> hashKeys = {&key}; - VariablePropertyExpression probe(new std::string(right), - new std::string("_vid")); - std::vector<Expression*> probeKeys = {&probe}; - - auto* dataJoin = - DataJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), - std::move(probeKeys)); - dataJoin->setColNames(std::vector<std::string>{ - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}); - - auto dataJoinExe = - std::make_unique<DataJoinExecutor>(dataJoin, qctx_.get()); - auto future = dataJoinExe->execute(); - - join = dataJoin->outputVar(); - } - - std::string left = join; - std::string right = "var3"; - VariablePropertyExpression key(new std::string(left), - new std::string("src")); - std::vector<Expression*> hashKeys = {&key}; - VariablePropertyExpression probe(new std::string(right), - new std::string("col1")); - std::vector<Expression*> probeKeys = {&probe}; - - auto* dataJoin = - DataJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), - std::move(probeKeys)); - dataJoin->setColNames(std::vector<std::string>{ - "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}); - - auto dataJoinExe = - std::make_unique<DataJoinExecutor>(dataJoin, qctx_.get()); - auto future = dataJoinExe->execute(); - auto status = std::move(future).get(); - EXPECT_TRUE(status.ok()); - auto& result = qctx_->ectx()->getResult(dataJoin->outputVar()); - - DataSet resultDs; - resultDs.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}; - auto iter = result.iter(); - for (; iter->valid(); iter->next()) { - const auto& cols = *iter->row(); - Row row; - for (size_t i = 0; i < cols.size(); ++i) { - Value col = cols[i]; - row.values.emplace_back(std::move(col)); - } - resultDs.rows.emplace_back(std::move(row)); - } - - DataSet expected; - expected.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}; - Row row1; - row1.values.emplace_back("11"); - row1.values.emplace_back("0"); - row1.values.emplace_back("0"); - row1.values.emplace_back(0); - row1.values.emplace_back(1); - row1.values.emplace_back("5"); - row1.values.emplace_back("11"); - expected.rows.emplace_back(row1); - row1.values[3] = 1; - row1.values[4] = 2; - row1.values[5] = "6"; - expected.rows.emplace_back(std::move(row1)); - - EXPECT_EQ(resultDs, expected); - EXPECT_EQ(result.state(), Result::State::kSuccess); -} - -TEST_F(DataJoinTest, JoinEmpty) { - { - DataSet expected; - expected.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; - - testJoin("var2", "empty_var1", expected, __LINE__); - } - - { - DataSet expected; - expected.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; - - testJoin("empty_var2", "var1", expected, __LINE__); - } - - { - DataSet expected; - expected.colNames = { - "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; - - testJoin("empty_var2", "empty_var1", expected, __LINE__); - } -} -} // namespace graph -} // namespace nebula diff --git a/src/executor/test/JoinTest.cpp b/src/executor/test/JoinTest.cpp new file mode 100644 index 00000000..af874353 --- /dev/null +++ b/src/executor/test/JoinTest.cpp @@ -0,0 +1,567 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include <gtest/gtest.h> + +#include "context/QueryContext.h" +#include "planner/Query.h" +#include "executor/query/InnerJoinExecutor.h" +#include "executor/query/LeftJoinExecutor.h" +#include "executor/test/QueryTestBase.h" + +namespace nebula { +namespace graph { +class JoinTest : public QueryTestBase { +protected: + void SetUp() override { + qctx_ = std::make_unique<QueryContext>(); + { + DataSet ds; + ds.colNames = {kVid, "tag_prop", "edge_prop", kDst}; + for (auto i = 0; i < 10; ++i) { + Row row; + // _vid + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + // _dst + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + ds.rows.emplace_back(std::move(row)); + } + qctx_->symTable()->newVariable("var1"); + qctx_->ectx()->setResult( + "var1", + ResultBuilder().value(Value(std::move(ds))).finish()); + } + { + DataSet ds; + ds.colNames = {"src", "dst"}; + for (auto i = 0; i < 5; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i + 11)); + row.values.emplace_back(folly::to<std::string>(i)); + ds.rows.emplace_back(std::move(row)); + } + qctx_->symTable()->newVariable("var2"); + qctx_->ectx()->setResult( + "var2", ResultBuilder().value(Value(std::move(ds))).finish()); + } + { + DataSet ds; + ds.colNames = {"col1"}; + Row row; + row.values.emplace_back("11"); + ds.rows.emplace_back(std::move(row)); + qctx_->symTable()->newVariable("var3"); + qctx_->ectx()->setResult( + "var3", ResultBuilder().value(Value(std::move(ds))).finish()); + } + { + DataSet ds; + ds.colNames = {kVid, "tag_prop", "edge_prop", kDst}; + qctx_->symTable()->newVariable("empty_var1"); + qctx_->ectx()->setResult( + "empty_var1", + ResultBuilder().value(Value(std::move(ds))).finish()); + } + { + DataSet ds; + ds.colNames = {"src", "dst"}; + qctx_->symTable()->newVariable("empty_var2"); + qctx_->ectx()->setResult( + "empty_var2", + ResultBuilder().value(Value(std::move(ds))).finish()); + } + } + + void testInnerJoin(std::string left, std::string right, DataSet& expected, int64_t line); + void testLeftJoin(std::string left, std::string right, DataSet& expected, int64_t line); + +protected: + std::unique_ptr<QueryContext> qctx_; +}; + +void JoinTest::testInnerJoin(std::string left, std::string right, + DataSet& expected, int64_t line) { + VariablePropertyExpression key(new std::string(left), + new std::string("dst")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), + new std::string("_vid")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = + InnerJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), + std::move(probeKeys)); + join->setColNames(std::vector<std::string>{ + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}); + + auto joinExe = + std::make_unique<InnerJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()) << "LINE: " << line; + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + EXPECT_EQ(resultDs, expected) << "LINE: " << line; + EXPECT_EQ(result.state(), Result::State::kSuccess) << "LINE: " << line; +} + +void JoinTest::testLeftJoin(std::string left, std::string right, + DataSet& expected, int64_t line) { + VariablePropertyExpression key(new std::string(left), + new std::string("_vid")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), + new std::string("dst")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = + LeftJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), + std::move(probeKeys)); + join->setColNames(std::vector<std::string>{ + kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}); + + auto joinExe = + std::make_unique<LeftJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()) << "LINE: " << line; + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = { + kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + EXPECT_EQ(resultDs, expected) << "LINE: " << line; + EXPECT_EQ(result.state(), Result::State::kSuccess) << "LINE: " << line; +} + +TEST_F(JoinTest, InnerJoin) { + DataSet expected; + expected.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; + for (auto i = 11; i < 16; ++i) { + Row row1; + row1.values.emplace_back(folly::to<std::string>(i)); + row1.values.emplace_back(folly::to<std::string>(i % 11)); + row1.values.emplace_back(folly::to<std::string>(i % 11)); + row1.values.emplace_back(i % 11 * 2); + row1.values.emplace_back(i % 11 * 2 + 1); + row1.values.emplace_back(folly::to<std::string>(i - 6)); + expected.rows.emplace_back(std::move(row1)); + + Row row2; + row2.values.emplace_back(folly::to<std::string>(i)); + row2.values.emplace_back(folly::to<std::string>(i % 11)); + row2.values.emplace_back(folly::to<std::string>(i % 11)); + row2.values.emplace_back(i % 11 * 2 + 1); + row2.values.emplace_back(i % 11 * 2 + 2); + row2.values.emplace_back(folly::to<std::string>(i - 5)); + expected.rows.emplace_back(std::move(row2)); + } + + // $var1 inner join $var2 on $var2.dst = $var1._vid + testInnerJoin("var2", "var1", expected, __LINE__); +} + +TEST_F(JoinTest, InnerJoinTwice) { + std::string joinOutput; + { + std::string left = "var2"; + std::string right = "var1"; + VariablePropertyExpression key(new std::string(left), + new std::string("dst")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), + new std::string("_vid")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = + InnerJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), + std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{"src", "dst", kVid, "tag_prop", "edge_prop", kDst}); + + auto joinExe = + std::make_unique<InnerJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + + joinOutput = join->outputVar(); + } + + std::string left = joinOutput; + std::string right = "var3"; + VariablePropertyExpression key(new std::string(left), + new std::string("src")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), + new std::string("col1")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = + InnerJoin::make(qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), + std::move(probeKeys)); + join->setColNames(std::vector<std::string>{ + "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}); + + auto joinExe = + std::make_unique<InnerJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()); + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + DataSet expected; + expected.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst, "col1"}; + Row row1; + row1.values.emplace_back("11"); + row1.values.emplace_back("0"); + row1.values.emplace_back("0"); + row1.values.emplace_back(0); + row1.values.emplace_back(1); + row1.values.emplace_back("5"); + row1.values.emplace_back("11"); + expected.rows.emplace_back(row1); + row1.values[3] = 1; + row1.values[4] = 2; + row1.values[5] = "6"; + expected.rows.emplace_back(std::move(row1)); + + EXPECT_EQ(resultDs, expected); + EXPECT_EQ(result.state(), Result::State::kSuccess); +} + +TEST_F(JoinTest, InnerJoinEmpty) { + { + DataSet expected; + expected.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; + + testInnerJoin("var2", "empty_var1", expected, __LINE__); + } + + { + DataSet expected; + expected.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; + + testInnerJoin("empty_var2", "var1", expected, __LINE__); + } + + { + DataSet expected; + expected.colNames = { + "src", "dst", kVid, "tag_prop", "edge_prop", kDst}; + + testInnerJoin("empty_var2", "empty_var1", expected, __LINE__); + } +} + +TEST_F(JoinTest, LeftJoin) { + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}; + for (auto i = 0; i < 10; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + row.values.emplace_back(folly::to<std::string>(i / 2 + 11)); + row.values.emplace_back(folly::to<std::string>(i / 2)); + expected.rows.emplace_back(std::move(row)); + } + + // $var1 left join $var2 on $var1._vid = $var2.dst + testLeftJoin("var1", "var2", expected, __LINE__); +} + +TEST_F(JoinTest, LeftJoinTwice) { + std::string joinOutput; + { + std::string left = "var1"; + std::string right = "var2"; + VariablePropertyExpression key(new std::string(left), new std::string("_vid")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("dst")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = LeftJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}); + + auto joinExe = std::make_unique<LeftJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + + joinOutput = join->outputVar(); + } + + std::string left = joinOutput; + std::string right = "var3"; + VariablePropertyExpression key(new std::string(left), new std::string("src")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("col1")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = LeftJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}); + + auto joinExe = std::make_unique<LeftJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()); + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + for (auto i = 0; i < 10; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + row.values.emplace_back(folly::to<std::string>(i / 2 + 11)); + row.values.emplace_back(folly::to<std::string>(i / 2)); + if (i < 2) { + row.values.emplace_back(folly::to<std::string>(11)); + } else { + row.values.emplace_back(Value::kEmpty); + } + expected.rows.emplace_back(std::move(row)); + } + EXPECT_EQ(resultDs, expected); + EXPECT_EQ(result.state(), Result::State::kSuccess); +} + +TEST_F(JoinTest, LeftJoinEmpty) { + { + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}; + for (auto i = 0; i < 10; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + row.values.emplace_back(Value::kEmpty); + row.values.emplace_back(Value::kEmpty); + expected.rows.emplace_back(std::move(row)); + } + testLeftJoin("var1", "empty_var2", expected, __LINE__); + } + + { + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}; + testLeftJoin("empty_var1", "var2", expected, __LINE__); + } + + { + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}; + testLeftJoin("empty_var1", "empty_var2", expected, __LINE__); + } +} + +TEST_F(JoinTest, LeftJoinAndInnerjoin) { + std::string joinOutput; + { + std::string left = "var1"; + std::string right = "var2"; + VariablePropertyExpression key(new std::string(left), new std::string("_vid")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("dst")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = LeftJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}); + + auto joinExe = std::make_unique<LeftJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + + joinOutput = join->outputVar(); + } + + std::string left = joinOutput; + std::string right = "var3"; + VariablePropertyExpression key(new std::string(left), new std::string("src")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("col1")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = InnerJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}); + + auto joinExe = std::make_unique<InnerJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()); + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + for (auto i = 0; i < 2; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + row.values.emplace_back(folly::to<std::string>(i / 2 + 11)); + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(folly::to<std::string>(11)); + expected.rows.emplace_back(std::move(row)); + } + EXPECT_EQ(resultDs, expected); + EXPECT_EQ(result.state(), Result::State::kSuccess); +} + +TEST_F(JoinTest, InnerJoinAndLeftjoin) { + std::string joinOutput; + { + std::string left = "var1"; + std::string right = "var2"; + VariablePropertyExpression key(new std::string(left), new std::string("_vid")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("dst")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = InnerJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst"}); + + auto joinExe = std::make_unique<InnerJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + + joinOutput = join->outputVar(); + } + + std::string left = joinOutput; + std::string right = "var3"; + VariablePropertyExpression key(new std::string(left), new std::string("src")); + std::vector<Expression*> hashKeys = {&key}; + VariablePropertyExpression probe(new std::string(right), new std::string("col1")); + std::vector<Expression*> probeKeys = {&probe}; + + auto* join = LeftJoin::make( + qctx_.get(), nullptr, {left, 0}, {right, 0}, std::move(hashKeys), std::move(probeKeys)); + join->setColNames( + std::vector<std::string>{kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}); + + auto joinExe = std::make_unique<LeftJoinExecutor>(join, qctx_.get()); + auto future = joinExe->execute(); + auto status = std::move(future).get(); + EXPECT_TRUE(status.ok()); + auto& result = qctx_->ectx()->getResult(join->outputVar()); + + DataSet resultDs; + resultDs.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + auto iter = result.iter(); + for (; iter->valid(); iter->next()) { + const auto& cols = *iter->row(); + Row row; + for (size_t i = 0; i < cols.size(); ++i) { + Value col = cols[i]; + row.values.emplace_back(std::move(col)); + } + resultDs.rows.emplace_back(std::move(row)); + } + + DataSet expected; + expected.colNames = {kVid, "tag_prop", "edge_prop", kDst, "src", "dst", "col1"}; + for (auto i = 0; i < 10; ++i) { + Row row; + row.values.emplace_back(folly::to<std::string>(i / 2)); + row.values.emplace_back(i); + row.values.emplace_back(i + 1); + row.values.emplace_back(folly::to<std::string>(i / 2 + 5 + i % 2)); + row.values.emplace_back(folly::to<std::string>(i / 2 + 11)); + row.values.emplace_back(folly::to<std::string>(i / 2)); + if (i < 2) { + row.values.emplace_back(folly::to<std::string>(11)); + } else { + row.values.emplace_back(Value::kEmpty); + } + expected.rows.emplace_back(std::move(row)); + } + EXPECT_EQ(resultDs, expected); + EXPECT_EQ(result.state(), Result::State::kSuccess); +} + +} // namespace graph +} // namespace nebula diff --git a/src/planner/PlanNode.cpp b/src/planner/PlanNode.cpp index edd18cb7..4d8b142b 100644 --- a/src/planner/PlanNode.cpp +++ b/src/planner/PlanNode.cpp @@ -179,8 +179,10 @@ const char* PlanNode::toString(PlanNode::Kind kind) { return "ShowBalance"; case Kind::kSubmitJob: return "SubmitJob"; - case Kind::kDataJoin: - return "DataJoin"; + case Kind::kLeftJoin: + return "LeftJoin"; + case Kind::kInnerJoin: + return "InnerJoin"; case Kind::kDeleteVertices: return "DeleteVertices"; case Kind::kDeleteEdges: diff --git a/src/planner/PlanNode.h b/src/planner/PlanNode.h index 4ca23852..14977c19 100644 --- a/src/planner/PlanNode.h +++ b/src/planner/PlanNode.h @@ -100,7 +100,8 @@ public: kCreateSnapshot, kDropSnapshot, kShowSnapshots, - kDataJoin, + kLeftJoin, + kInnerJoin, kDeleteVertices, kDeleteEdges, kUpdateVertex, diff --git a/src/planner/Query.cpp b/src/planner/Query.cpp index 3302bb97..4e80790d 100644 --- a/src/planner/Query.cpp +++ b/src/planner/Query.cpp @@ -271,7 +271,7 @@ std::unique_ptr<PlanNodeDescription> DataCollect::explain() const { return desc; } -std::unique_ptr<PlanNodeDescription> DataJoin::explain() const { +std::unique_ptr<PlanNodeDescription> LeftJoin::explain() const { auto desc = SingleDependencyNode::explain(); folly::dynamic inputVar = folly::dynamic::object(); inputVar.insert("leftVar", util::toJson(leftVar_)); @@ -279,6 +279,19 @@ std::unique_ptr<PlanNodeDescription> DataJoin::explain() const { addDescription("inputVar", folly::toJson(inputVar), desc.get()); addDescription("hashKeys", folly::toJson(util::toJson(hashKeys_)), desc.get()); addDescription("probeKeys", folly::toJson(util::toJson(probeKeys_)), desc.get()); + addDescription("kind", "LeftJoin", desc.get()); + return desc; +} + +std::unique_ptr<PlanNodeDescription> InnerJoin::explain() const { + auto desc = SingleDependencyNode::explain(); + folly::dynamic inputVar = folly::dynamic::object(); + inputVar.insert("leftVar", util::toJson(leftVar_)); + inputVar.insert("rightVar", util::toJson(rightVar_)); + addDescription("inputVar", folly::toJson(inputVar), desc.get()); + addDescription("hashKeys", folly::toJson(util::toJson(hashKeys_)), desc.get()); + addDescription("probeKeys", folly::toJson(util::toJson(probeKeys_)), desc.get()); + addDescription("kind", "InnerJoin", desc.get()); return desc; } diff --git a/src/planner/Query.h b/src/planner/Query.h index 24876819..8d9f8b99 100644 --- a/src/planner/Query.h +++ b/src/planner/Query.h @@ -962,23 +962,31 @@ private: bool distinct_{false}; }; -/** - * An implementation of inner join which join two given variable. - */ -class DataJoin final : public SingleDependencyNode { +class Join : public SingleDependencyNode { public: - static DataJoin* make(QueryContext* qctx, - PlanNode* input, - std::pair<std::string, int64_t> leftVar, - std::pair<std::string, int64_t> rightVar, - std::vector<Expression*> hashKeys, - std::vector<Expression*> probeKeys) { - return qctx->objPool()->add(new DataJoin(qctx, - input, - std::move(leftVar), - std::move(rightVar), - std::move(hashKeys), - std::move(probeKeys))); + Join(QueryContext* qctx, + Kind kind, + PlanNode* input, + std::pair<std::string, int64_t> leftVar, + std::pair<std::string, int64_t> rightVar, + std::vector<Expression*> hashKeys, + std::vector<Expression*> probeKeys) + : SingleDependencyNode(qctx, kind, input), + leftVar_(std::move(leftVar)), + rightVar_(std::move(rightVar)), + hashKeys_(std::move(hashKeys)), + probeKeys_(std::move(probeKeys)) { + inputVars_.clear(); + + auto* leftVarPtr = qctx_->symTable()->getVar(leftVar_.first); + DCHECK(leftVarPtr != nullptr); + inputVars_.emplace_back(leftVarPtr); + qctx_->symTable()->readBy(leftVarPtr->name, this); + + auto* rightVarPtr = qctx_->symTable()->getVar(rightVar_.first); + DCHECK(rightVarPtr != nullptr); + inputVars_.emplace_back(rightVarPtr); + qctx_->symTable()->readBy(rightVarPtr->name, this); } const std::pair<std::string, int64_t>& leftVar() const { @@ -997,39 +1005,66 @@ public: return probeKeys_; } +protected: + // var name, var version + std::pair<std::string, int64_t> leftVar_; + std::pair<std::string, int64_t> rightVar_; + std::vector<Expression*> hashKeys_; + std::vector<Expression*> probeKeys_; +}; + +/* + * left join + */ +class LeftJoin final : public Join { +public: + static LeftJoin* make(QueryContext* qctx, + PlanNode* input, + std::pair<std::string, int64_t> leftVar, + std::pair<std::string, int64_t> rightVar, + std::vector<Expression*> hashKeys, + std::vector<Expression*> probeKeys) { + return qctx->objPool()->add( + new LeftJoin(qctx, input, leftVar, rightVar, hashKeys, probeKeys)); + } + std::unique_ptr<PlanNodeDescription> explain() const override; private: - DataJoin(QueryContext* qctx, + LeftJoin(QueryContext* qctx, PlanNode* input, std::pair<std::string, int64_t> leftVar, std::pair<std::string, int64_t> rightVar, std::vector<Expression*> hashKeys, std::vector<Expression*> probeKeys) - : SingleDependencyNode(qctx, Kind::kDataJoin, input), - leftVar_(std::move(leftVar)), - rightVar_(std::move(rightVar)), - hashKeys_(std::move(hashKeys)), - probeKeys_(std::move(probeKeys)) { - inputVars_.clear(); - - auto* leftVarPtr = qctx_->symTable()->getVar(leftVar_.first); - DCHECK(leftVarPtr != nullptr); - inputVars_.emplace_back(leftVarPtr); - qctx_->symTable()->readBy(leftVarPtr->name, this); + : Join(qctx, Kind::kLeftJoin, input, leftVar, rightVar, hashKeys, probeKeys) {} +}; - auto* rightVarPtr = qctx_->symTable()->getVar(rightVar_.first); - DCHECK(rightVarPtr != nullptr); - inputVars_.emplace_back(rightVarPtr); - qctx_->symTable()->readBy(rightVarPtr->name, this); +/* + * inner join + */ +class InnerJoin final : public Join { +public: + static InnerJoin* make(QueryContext* qctx, + PlanNode* input, + std::pair<std::string, int64_t> leftVar, + std::pair<std::string, int64_t> rightVar, + std::vector<Expression*> hashKeys, + std::vector<Expression*> probeKeys) { + return qctx->objPool()->add( + new InnerJoin(qctx, input, leftVar, rightVar, hashKeys, probeKeys)); } + std::unique_ptr<PlanNodeDescription> explain() const override; + private: - // var name, var version - std::pair<std::string, int64_t> leftVar_; - std::pair<std::string, int64_t> rightVar_; - std::vector<Expression*> hashKeys_; - std::vector<Expression*> probeKeys_; + InnerJoin(QueryContext* qctx, + PlanNode* input, + std::pair<std::string, int64_t> leftVar, + std::pair<std::string, int64_t> rightVar, + std::vector<Expression*> hashKeys, + std::vector<Expression*> probeKeys) + : Join(qctx, Kind::kInnerJoin, input, leftVar, rightVar, hashKeys, probeKeys) {} }; /* diff --git a/src/planner/match/InnerJoinStrategy.cpp b/src/planner/match/InnerJoinStrategy.cpp index 9815301b..38e87c04 100644 --- a/src/planner/match/InnerJoinStrategy.cpp +++ b/src/planner/match/InnerJoinStrategy.cpp @@ -38,7 +38,7 @@ PlanNode* InnerJoinStrategy::joinDataSet(const PlanNode* left, const PlanNode* r qctx_->objPool()->add(buildExpr); qctx_->objPool()->add(probeExpr); - auto join = DataJoin::make(qctx_, + auto join = InnerJoin::make(qctx_, const_cast<PlanNode*>(right), {left->outputVar(), 0}, {right->outputVar(), 0}, diff --git a/src/validator/GoValidator.cpp b/src/validator/GoValidator.cpp index a49992e6..9dfc552b 100644 --- a/src/validator/GoValidator.cpp +++ b/src/validator/GoValidator.cpp @@ -473,7 +473,7 @@ PlanNode* GoValidator::buildJoinDstProps(PlanNode* projectSrcDstProps) { new std::string(joinDstVidColName_)); auto* probeKey = objPool->makeAndAdd<VariablePropertyExpression>( new std::string(project->outputVar()), new std::string(vidColName)); - auto joinDst = DataJoin::make(qctx_, project, + auto joinDst = InnerJoin::make(qctx_, project, {projectSrcDstProps->outputVar(), ExecutionContext::kLatestVersion}, {project->outputVar(), ExecutionContext::kLatestVersion}, {joinHashKey}, {probeKey}); @@ -499,7 +499,7 @@ PlanNode* GoValidator::buildJoinPipeOrVariableInput(PlanNode* projectFromJoin, auto* probeKey = pool->add(new VariablePropertyExpression( new std::string(projectFromJoin->outputVar()), new std::string(dstVidColName_))); auto* join = - DataJoin::make(qctx_, + InnerJoin::make(qctx_, dependencyForJoinInput, {dependencyForJoinInput->outputVar(), ExecutionContext::kLatestVersion}, {projectFromJoin->outputVar(), @@ -524,7 +524,7 @@ PlanNode* GoValidator::buildJoinPipeOrVariableInput(PlanNode* projectFromJoin, : kVid))); std::string varName = from_.fromType == kPipe ? inputVarName_ : from_.userDefinedVarName; auto* joinInput = - DataJoin::make(qctx_, dependencyForJoinInput, + InnerJoin::make(qctx_, dependencyForJoinInput, {dependencyForJoinInput->outputVar(), ExecutionContext::kLatestVersion}, {varName, @@ -555,7 +555,7 @@ PlanNode* GoValidator::traceToStartVid(PlanNode* projectLeftVarForJoin, auto probeKey = new VariablePropertyExpression( new std::string(dedupDstVids->outputVar()), new std::string(srcVidColName_)); pool->add(probeKey); - auto* join = DataJoin::make( + auto* join = InnerJoin::make( qctx_, dedupDstVids, {projectLeftVarForJoin->outputVar(), ExecutionContext::kLatestVersion}, diff --git a/src/validator/test/GroupByValidatorTest.cpp b/src/validator/test/GroupByValidatorTest.cpp index 501051d0..5eb16a49 100644 --- a/src/validator/test/GroupByValidatorTest.cpp +++ b/src/validator/test/GroupByValidatorTest.cpp @@ -73,7 +73,7 @@ TEST_F(GroupByValidatorTest, TestGroupBy) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -103,7 +103,7 @@ TEST_F(GroupByValidatorTest, TestGroupBy) { PK::kProject, PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -128,7 +128,7 @@ TEST_F(GroupByValidatorTest, TestGroupBy) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -154,7 +154,7 @@ TEST_F(GroupByValidatorTest, TestGroupBy) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -180,7 +180,7 @@ TEST_F(GroupByValidatorTest, TestGroupBy) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -217,7 +217,7 @@ TEST_F(GroupByValidatorTest, VariableTest) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -243,7 +243,7 @@ TEST_F(GroupByValidatorTest, VariableTest) { std::vector<PlanNode::Kind> expected = { PK::kAggregate, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, diff --git a/src/validator/test/MatchValidatorTest.cpp b/src/validator/test/MatchValidatorTest.cpp index 431a6980..4e0c0887 100644 --- a/src/validator/test/MatchValidatorTest.cpp +++ b/src/validator/test/MatchValidatorTest.cpp @@ -52,7 +52,7 @@ TEST_F(MatchValidatorTest, SeekByTagIndex) { std::vector<PlanNode::Kind> expected = {PlanNode::Kind::kProject, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kFilter, PlanNode::Kind::kGetVertices, @@ -183,7 +183,7 @@ TEST_F(MatchValidatorTest, groupby) { std::vector<PlanNode::Kind> expected = {PlanNode::Kind::kAggregate, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -211,7 +211,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kAggregate, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -240,7 +240,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -272,7 +272,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -303,7 +303,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -336,7 +336,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -372,7 +372,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -407,7 +407,7 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, @@ -443,12 +443,12 @@ TEST_F(MatchValidatorTest, groupby) { PlanNode::Kind::kFilter, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, PlanNode::Kind::kGetNeighbors, @@ -476,7 +476,7 @@ TEST_F(MatchValidatorTest, with) { PlanNode::Kind::kAggregate, PlanNode::Kind::kFilter, PlanNode::Kind::kProject, - PlanNode::Kind::kDataJoin, + PlanNode::Kind::kInnerJoin, PlanNode::Kind::kProject, PlanNode::Kind::kGetVertices, PlanNode::Kind::kDedup, diff --git a/src/validator/test/QueryValidatorTest.cpp b/src/validator/test/QueryValidatorTest.cpp index 8fee40e0..1e93d49b 100644 --- a/src/validator/test/QueryValidatorTest.cpp +++ b/src/validator/test/QueryValidatorTest.cpp @@ -60,7 +60,7 @@ TEST_F(QueryValidatorTest, GoZeroStep) { "| GO FROM $-.id OVER serve"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -155,8 +155,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "id | GO 2 STEPS FROM $-.id OVER like"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kLoop, @@ -165,7 +165,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, @@ -184,7 +184,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "| GO 1 STEPS FROM $-.id OVER like"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -204,7 +204,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { std::string query = "YIELD \"1\" AS id | GO FROM $-.id OVER like"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -219,7 +219,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "id | GO 1 STEPS FROM $-.id OVER like YIELD $-.id, like._dst"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -237,7 +237,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { std::vector<PlanNode::Kind> expected = { PK::kProject, PK::kFilter, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -257,7 +257,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDedup, PK::kProject, PK::kFilter, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -273,8 +273,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "id | GO 2 STEPS FROM $-.id OVER like YIELD $-.id, like._dst"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kLoop, @@ -283,7 +283,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, @@ -304,8 +304,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { std::vector<PlanNode::Kind> expected = { PK::kProject, PK::kFilter, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kLoop, @@ -314,7 +314,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, @@ -337,8 +337,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDedup, PK::kProject, PK::kFilter, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kLoop, @@ -347,7 +347,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, @@ -368,8 +368,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "$$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -379,7 +379,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -399,8 +399,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDataCollect, PK::kDedup, PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -410,7 +410,7 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -428,8 +428,8 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "YIELD $-.name, $^.person.name, $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -451,9 +451,9 @@ TEST_F(QueryValidatorTest, GoWithPipe) { "$$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -466,12 +466,12 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kDedup, PK::kProject, PK::kProject, @@ -495,9 +495,9 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kDataCollect, PK::kDedup, PK::kProject, - PK::kDataJoin, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -510,12 +510,12 @@ TEST_F(QueryValidatorTest, GoWithPipe) { PK::kProject, PK::kProject, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kDedup, PK::kProject, PK::kProject, @@ -552,8 +552,8 @@ TEST_F(QueryValidatorTest, GoWithVariable) { "YIELD $var.name, $^.person.name, $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, - PK::kDataJoin, + PK::kInnerJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -576,7 +576,7 @@ TEST_F(QueryValidatorTest, GoReversely) { "YIELD $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -592,7 +592,7 @@ TEST_F(QueryValidatorTest, GoReversely) { "YIELD $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -625,7 +625,7 @@ TEST_F(QueryValidatorTest, GoBidirectly) { "YIELD $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -690,7 +690,7 @@ TEST_F(QueryValidatorTest, GoOneStep) { "YIELD $$.person.name,$$.person.age"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -707,7 +707,7 @@ TEST_F(QueryValidatorTest, GoOneStep) { "$$.person.name, $$.person.age + 1"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -726,7 +726,7 @@ TEST_F(QueryValidatorTest, GoOneStep) { std::vector<PlanNode::Kind> expected = { PK::kProject, PK::kFilter, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -747,7 +747,7 @@ TEST_F(QueryValidatorTest, GoOneStep) { PK::kDedup, PK::kProject, PK::kFilter, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -805,7 +805,7 @@ TEST_F(QueryValidatorTest, GoOneStep) { "| GO FROM $-.id OVER like"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -851,7 +851,7 @@ TEST_F(QueryValidatorTest, GoOverAll) { std::string query = "GO FROM \"1\" OVER * YIELD $$.person.name"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -871,13 +871,13 @@ TEST_F(QueryValidatorTest, OutputToAPipe) { "| ( GO FROM $-.id OVER like YIELD like._dst as id | GO FROM $-.id OVER serve )"; std::vector<PlanNode::Kind> expected = { PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetNeighbors, PK::kDedup, @@ -933,7 +933,7 @@ TEST_F(QueryValidatorTest, GoMToN) { PK::kStart, PK::kDedup, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -1002,7 +1002,7 @@ TEST_F(QueryValidatorTest, GoMToN) { PK::kLoop, PK::kStart, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -1025,9 +1025,9 @@ TEST_F(QueryValidatorTest, GoMToN) { PK::kDedup, PK::kProject, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kDedup, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kProject, PK::kProject, @@ -1035,7 +1035,7 @@ TEST_F(QueryValidatorTest, GoMToN) { PK::kGetNeighbors, PK::kProject, PK::kStart, - PK::kDataJoin, + PK::kInnerJoin, PK::kDedup, PK::kProject, PK::kDedup, @@ -1287,7 +1287,7 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kProject, PK::kFilter, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -1312,12 +1312,12 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kProject, PK::kFilter, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kFilter, PK::kProject, PK::kGetNeighbors, @@ -1343,7 +1343,7 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kFilter, PK::kFilter, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -1366,7 +1366,7 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kFilter, PK::kFilter, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, @@ -1379,7 +1379,7 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kFilter, PK::kProject, PK::kGetNeighbors, - PK::kDataJoin, + PK::kInnerJoin, PK::kDedup, PK::kProject, PK::kProject, @@ -1398,7 +1398,7 @@ TEST_F(QueryValidatorTest, TestMatch) { PK::kProject, PK::kFilter, PK::kProject, - PK::kDataJoin, + PK::kInnerJoin, PK::kProject, PK::kGetVertices, PK::kDedup, diff --git a/src/validator/test/SymbolsTest.cpp b/src/validator/test/SymbolsTest.cpp index 02c73b90..efa1ed96 100644 --- a/src/validator/test/SymbolsTest.cpp +++ b/src/validator/test/SymbolsTest.cpp @@ -172,7 +172,7 @@ TEST_F(SymbolsTest, Variables) { EXPECT_TRUE(checkNodes(variable->writtenBy, {12})); } { - auto varName = "__DataJoin_13"; + auto varName = "__InnerJoin_13"; auto* variable = symTable->getVar(varName); EXPECT_NE(variable, nullptr); EXPECT_EQ(variable->name, varName); @@ -223,7 +223,7 @@ TEST_F(SymbolsTest, Variables) { EXPECT_TRUE(checkNodes(variable->writtenBy, {18})); } { - auto varName = "__DataJoin_19"; + auto varName = "__InnerJoin_19"; auto* variable = symTable->getVar(varName); EXPECT_NE(variable, nullptr); EXPECT_EQ(variable->name, varName); @@ -234,7 +234,7 @@ TEST_F(SymbolsTest, Variables) { EXPECT_TRUE(checkNodes(variable->writtenBy, {19})); } { - auto varName = "__DataJoin_20"; + auto varName = "__InnerJoin_20"; auto* variable = symTable->getVar(varName); EXPECT_NE(variable, nullptr); EXPECT_EQ(variable->name, varName); diff --git a/tests/tck/features/optimizer/MergeGetNbrsDedupProjectRule.feature b/tests/tck/features/optimizer/MergeGetNbrsDedupProjectRule.feature index 5f20cb22..edd4c48d 100644 --- a/tests/tck/features/optimizer/MergeGetNbrsDedupProjectRule.feature +++ b/tests/tck/features/optimizer/MergeGetNbrsDedupProjectRule.feature @@ -23,7 +23,7 @@ Feature: merge get neighbors, dedup and project rule | Project | 1 | | | Filter | 2 | | | Project | 3 | | - | DataJoin | 4 | | + | InnerJoin | 4 | | | Project | 5 | | | GetVertices | 6 | dedup: true | | Filter | 7 | | @@ -31,7 +31,7 @@ Feature: merge get neighbors, dedup and project rule | Loop | 15 | loopBody: 9 | | Filter | 10 | | | Project | 11 | | - | DataJoin | 12 | | + | InnerJoin | 12 | | | Project | 13 | | | GetNeighbors | 14 | dedup: true | | Start | | | -- GitLab