cancel
Showing results for 
Search instead for 
Did you mean: 

Variable multihop traversal constrained by what a relationship is not

BrianS
Node

Greetings All,

I'm new to the community and still wrapping my head around Cypher.

I'm playing with a sample dataset in the desktop app, and I want to match all nodes that are a certain distance away from a point, but I do not want to traverse over specific relationship types.

My attempted query is this:

MATCH (p:Program {name: 'Initial Program'})-[x*1..4]-(n)
WHERE NOT x.name = 'IMPLEMENTED_BY' OR x.name = 'CREATED_BY'
RETURN p, n

The CLI gives me this error:

Type mismatch: expected Map, Node, Relationship, Point, Duration, Date, Time, LocalTime, LocalDateTime or DateTime but was List<Relationship> (line 2, column 11 (offset: 67))
"WHERE NOT x.name = 'IMPLEMENTED_BY' OR x.name = 'CREATED_BY'"

I glean from this that the variable x is not an instance of every relationship traversed, but a set of relationships needed to connect each set of matched nodes. This leads to a few different questions:

  1. How do I logically represent that I never want a single relationship to be of a single type?
  2. How do I optimize the query? For example - I may have a relationship I want to not traverse on the root node. If this relationship leads to a large set of nodes, the memory usage would be much larger if the traversal engine first matches all nodes, then filters nodes based on the set of relationships associated with each node versus understand the relationship constraint, testing it on each hop.

I spent time in Chapter 3 of the neo4j cypher manual, however I couldn't find an example of filtering off of relationships in a variable multiple traversal scenario.

Thanks ahead of time for patience with a beginner.

1 REPLY 1

Joel
Ninja
Ninja

There are a number of ways to do this. If this was a one hop relationship you could just do this,

MATCH (p:Program {name: 'Initial Program'})-[x]-(n)
WHERE type(x)<> 'IMPLEMENTED_BY' AND type(x)<>'CREATED_BY'
RETURN p, n

However in this case x is a LIST (of relationships)

Here are two ways,

You can specify the relationships you want to explore (instead of the list you want to avoid). for example, this would find all paths of BOUGHT_BY and OWNED_BY relationships, and NOT any other relationship types

MATCH (p:Program {name: 'Initial Program'})-[:BOUGHT_BY|OWNED_BY*1..4]-(n)
RETURN p, n

relationship types are accessed with type(), so you could also write

WITH ['IMPLEMENTED_BY','CREATED_BY'] AS list
MATCH t=(p:Program {name: 'Initial Program'})-[*1..4]-(n)
WHERE none(r in relationships(t) WHERE type(r) in list)
return p, n 

Note: t contains each path, you can also access the nodes in a given path with nodes(t)

a few additional notes, food for thought: Your query explores relationships in both directions, and (when possible and it might not be here) it is more efficient to use directed relationships... I would suggest adding a LIMIT statement at the end when developing a query of this kind just to insure it comes back if it finds thousands or millions of paths... or return a count() first just to get a sense of how big the result set is.