From d0fb4d724214ab258a704dd3a0fc2436af243ba7 Mon Sep 17 00:00:00 2001 From: florijan <florijan@memgraph.io> Date: Fri, 6 Oct 2017 09:33:12 +0200 Subject: [PATCH] BFS - lower bound support Summary: This is not a very important functionality, but it turned out simple to do, so let's add it to have a consistent query support. Reviewers: buda, teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D862 --- docs/user_technical/open-cypher.md | 6 ++---- src/query/frontend/ast/cypher_main_visitor.cpp | 2 -- src/query/plan/operator.cpp | 12 ++++++++++-- .../memgraph_V1/features/memgraph_bfs.feature | 17 ++++++++++++++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/docs/user_technical/open-cypher.md b/docs/user_technical/open-cypher.md index 695e04128..373b41cb9 100644 --- a/docs/user_technical/open-cypher.md +++ b/docs/user_technical/open-cypher.md @@ -436,10 +436,8 @@ destination node. Furthermore, it's possible to find multiple paths to multiple nodes regardless of their length. Also, it is possible to simply go through a node's neighbourhood in breadth-first manner. -It is fair to say there are a few drawbacks too. Currently, it isn't possible to get -all shortest paths to a single node using Memgraph's breadth-first expansion. Also -property maps (in curly brackets) are not supported with a BFS. These features will -most likely be included in subsequent Memgraph releases. +Currently, it isn't possible to get all shortest paths to a single node using +Memgraph's breadth-first expansion. #### UNWIND diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp index 8c4aa285e..88ff750ed 100644 --- a/src/query/frontend/ast/cypher_main_visitor.cpp +++ b/src/query/frontend/ast/cypher_main_visitor.cpp @@ -570,8 +570,6 @@ antlrcpp::Any CypherMainVisitor::visitVariableExpansion( upper = ctx->expression()[1]->accept(this); } - if (is_bfs && lower) - throw SemanticException("BFS does not support lower bounds"); return std::make_tuple(is_bfs, lower, upper); } diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index b6dea0846..1ece0799d 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -927,6 +927,10 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor { SwitchAccessor(vertex, self_.graph_view_); processed_.emplace(vertex, std::experimental::nullopt); expand_from_vertex(vertex); + lower_bound_ = self_.lower_bound_ + ? EvaluateInt(evaluator, self_.lower_bound_, + "Min depth in breadth-first expansion") + : 1; upper_bound_ = self_.upper_bound_ ? EvaluateInt(evaluator, self_.upper_bound_, "Max depth in breadth-first expansion") @@ -963,6 +967,9 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor { if (static_cast<int>(edge_list.size()) < upper_bound_) expand_from_vertex(expansion.second); + if (static_cast<int64_t>(edge_list.size()) < lower_bound_) + continue; + // place destination node on the frame, handle existence flag if (self_.existing_node_) { TypedValue &node = frame[self_.node_symbol_]; @@ -990,8 +997,9 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor { GraphDbAccessor &db_; const std::unique_ptr<query::plan::Cursor> input_cursor_; - // maximum depth of the expansion. calculated on each pull - // from the input, the initial value is irrelevant. + // Depth bounds. Calculated on each pull from the input, the initial value is + // irrelevant. + int lower_bound_{-1}; int upper_bound_{-1}; // maps vertices to the edge they got expanded from. it is an optional diff --git a/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature b/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature index f6c6a457b..8c4e21607 100644 --- a/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature +++ b/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature @@ -1,6 +1,6 @@ Feature: Bfs - Scenario: Test match BFS depth blocked + Scenario: Test match BFS upper bound Given an empty graph And having executed: """ @@ -15,6 +15,21 @@ Feature: Bfs | '0' | '1.1' | | '0' | '1.2' | + Scenario: Test match BFS lower bound + Given an empty graph + And having executed: + """ + CREATE (n {a:'0'})-[:r]->({a:'1.1'})-[:r]->({a:'2.1'})-[:r]->({a:'3.1'}) + """ + When executing query: + """ + MATCH (n {a:'0'})-[*bfs 2..]->(m) RETURN n.a, m.a + """ + Then the result should be: + | n.a | m.a | + | '0' | '2.1' | + | '0' | '3.1' | + Scenario: Test match BFS filtered Given an empty graph And having executed: