Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining depth- and breadth-first traversals in a single cypher query

Tags:

neo4j

cypher

My graph is a tree structure with root and end nodes, and a line of nodes between them with [:NEXT]-> relationships from one to the next. Some nodes along that path also have [:BRANCH]-> relationships to other root nodes, and through them to other lines of nodes.

What Cypher query will return an ordered list of the nodes on the path from beginning to end, with any BRANCH relationships being included with the records for the nodes that have them?

EDIT: It's not a technical diagram, but the basic structure looks like this:

enter image description here

with each node depicted as a black circle. In this case, I would would want every node depicted here.

like image 321
drew moore Avatar asked Feb 11 '14 07:02

drew moore


3 Answers

How about

MATCH p=(root)-[:NEXT*0..]->(leaf)
OPTIONAL MATCH (leaf)-[:BRANCH]->(branched)
RETURN leaf, branched, length(p) as l
ORDER BY l ASC

see also this graph-gist: http://gist.neo4j.org/?9042990

like image 123
Michael Hunger Avatar answered Oct 31 '22 14:10

Michael Hunger


This query - a bit slow - should work (I guess):

START n=node(startID), child=node(*)
MATCH (n)-[rels*]-(child)
WHERE all(r in rels WHERE type(r) IN ["NEXT", "BRANCH"])
RETURN *

That is based on Neo4j 2.0.x Cypher syntax.
Technically this query will stop at the end of the tree started from startID: that is because the end in the diagram above belongs to a single path, but not the end of all the branches. I would also recommend to limit the cardinality of the relationships - [rels*1..n] - to prevent the query to go away...

like image 39
MarcoL Avatar answered Oct 31 '22 14:10

MarcoL


You wont be able to control the order in which the nodes are returned as per the depth first or breadth first algo unless you have a variable to save previous element or kind of recursive call which I dont think is not possible using only Cypher.

What you can do

MATCH p =(n)-[:NEXT*]->(end) 
WITH collect(p) as node_paths
MATCH (n1)-[:NEXT]->(m)-[:BRANCH]->(n2)
WITH collect(m) as branch_nodes , node_paths
RETURN branch_nodes,node_paths

Now node_paths consists of all the paths with pattern (node)-[:NEXT]->(node)-[:NEXT]->...(node) . Now you have the paths and branch Nodes(starting point of basically all the paths in the node_paths except the one which will be emerging from root node) , you can arrange the output order accordingly.

like image 37
Sumeet Sharma Avatar answered Oct 31 '22 16:10

Sumeet Sharma