From e215b71629f74101f8e7e11279ec95fb1bbec075 Mon Sep 17 00:00:00 2001 From: aziz-mu Date: Thu, 18 May 2023 12:44:41 -0400 Subject: [PATCH] Implemented undirected Rel for multi-labelled and unlabelled queries --- src/binder/bind/bind_graph_pattern.cpp | 26 +++++++++++++ .../parser/query/graph_pattern/node_pattern.h | 4 ++ test/test_files/demo_db/demo_db.test | 17 +++++++++ test/test_files/tinysnb/match/undirected.test | 38 +++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/src/binder/bind/bind_graph_pattern.cpp b/src/binder/bind/bind_graph_pattern.cpp index 47d3ba2411..acf85d9ad0 100644 --- a/src/binder/bind/bind_graph_pattern.cpp +++ b/src/binder/bind/bind_graph_pattern.cpp @@ -27,9 +27,35 @@ Binder::bindGraphPattern(const std::vector>& gra return std::make_pair(std::move(queryGraphCollection), std::move(propertyCollection)); } +// For undirected pattern (A)-[R]-(B), we need to match R in both FWD and BWD direction. +// Since computation always starts from one node, we need to rewrite the node table names to be +// the union of both node table names, i.e. (A|B)-[R]-(A|B) +void static rewriteNodeTableNameForUndirectedRel(const PatternElement& patternElement) { + auto leftNode = patternElement.getFirstNodePattern(); + for (auto i = 0u; i < patternElement.getNumPatternElementChains(); ++i) { + auto patternElementChain = patternElement.getPatternElementChain(i); + auto rightNode = patternElementChain->getNodePattern(); + if (patternElementChain->getRelPattern()->getDirection() == ArrowDirection::BOTH) { + std::vector tableNameUnion = {}; + auto leftTableNames = leftNode->getTableNames(); + auto rightTableNames = rightNode->getTableNames(); + if (!leftTableNames.empty() && !rightTableNames.empty()) { + tableNameUnion.insert( + tableNameUnion.end(), leftTableNames.begin(), leftTableNames.end()); + tableNameUnion.insert( + tableNameUnion.end(), rightTableNames.begin(), rightTableNames.end()); + } + leftNode->setTableNames(tableNameUnion); + rightNode->setTableNames(tableNameUnion); + } + leftNode = rightNode; + } +} + // Grammar ensures pattern element is always connected and thus can be bound as a query graph. std::unique_ptr Binder::bindPatternElement( const PatternElement& patternElement, PropertyKeyValCollection& collection) { + rewriteNodeTableNameForUndirectedRel(patternElement); auto queryGraph = std::make_unique(); auto leftNode = bindQueryNode(*patternElement.getFirstNodePattern(), *queryGraph, collection); for (auto i = 0u; i < patternElement.getNumPatternElementChains(); ++i) { diff --git a/src/include/parser/query/graph_pattern/node_pattern.h b/src/include/parser/query/graph_pattern/node_pattern.h index b65d37999b..08f3aa93d5 100644 --- a/src/include/parser/query/graph_pattern/node_pattern.h +++ b/src/include/parser/query/graph_pattern/node_pattern.h @@ -30,6 +30,10 @@ class NodePattern { propertyKeyValPairs[idx].first, propertyKeyValPairs[idx].second.get()); } + void setTableNames(std::vector otherTableNames) { + tableNames = std::move(otherTableNames); + } + protected: std::string variableName; std::vector tableNames; diff --git a/test/test_files/demo_db/demo_db.test b/test/test_files/demo_db/demo_db.test index e12ba5f9ed..f04caae461 100644 --- a/test/test_files/demo_db/demo_db.test +++ b/test/test_files/demo_db/demo_db.test @@ -234,3 +234,20 @@ Karissa|30 Zhang|30 Zhang|40 Noura|50 + +-NAME Undir2 +-QUERY MATCH (a:User)-[:LivesIn]-(c:City) RETURN a.name, c.name; +---- 8 +Adam|Waterloo +Karissa|Waterloo +Zhang|Kitchener +Noura|Guelph +Waterloo|Karissa +Waterloo|Adam +Kitchener|Zhang +Guelph|Noura + +-NAME Undir3 +-QUERY MATCH ()-[]-() RETURN COUNT(*); +---- 1 +16 diff --git a/test/test_files/tinysnb/match/undirected.test b/test/test_files/tinysnb/match/undirected.test index 2951322a09..47324d0e7a 100644 --- a/test/test_files/tinysnb/match/undirected.test +++ b/test/test_files/tinysnb/match/undirected.test @@ -19,3 +19,41 @@ Alice|Dan Carol|Dan Alice|Dan Carol|Dan + +-NAME UndirMultiLabel1 +-QUERY MATCH (a:person:organisation)-[:meets|:marries|:workAt]-(b:person:organisation) RETURN COUNT(*); +---- 1 +26 + +-NAME UndirMultiLabel2 +-QUERY MATCH (a:person)-[:studyAt|:meets]-(b:person:organisation) RETURN COUNT(*); +---- 1 +20 + +-NAME UndirMultiLabel3 +-QUERY MATCH (a:person)-[:meets|:marries|:knows]-(b:person)-[:knows|:meets]-(c:person) WHERE c.fName = "Farooq" AND a.fName <> "Farooq" RETURN a.fName, b.fName; +---- 13 +Carol|Elizabeth +Alice|Carol +Bob|Carol +Dan|Carol +Elizabeth|Carol +Greg|Carol +Greg|Elizabeth +Carol|Elizabeth +Alice|Carol +Bob|Carol +Dan|Carol +Elizabeth|Carol +Dan|Carol + +-NAME UndirUnlabelled +-QUERY MATCH (a:person)-[]-() RETURN COUNT(*); +---- 1 +60 + +-NAME UndirPattern +-QUERY MATCH ()-[:studyAt]-(a)-[:meets]-()-[:workAt]-() RETURN a.fName; +---- 2 +Farooq +Bob