Search code examples
filterneo4jpathvariable-length

How to filter by pattern in a variable length Cypher query


I have a very simple graph with 5 nodes (named n1 - n5), 1 node type (:Node) and 2 relationship types (:r1, :r2). The nodes and relationships are arranged as follows (apologies for the ascii art):

(n1)-[:r1]->(n2)-[:r1]->(n3)
(n1)-[:r2]->(n4)-[:r2]->(n3)
(n1)-[:r1]->(n5)-[:r2]->(n3)

I have a query using a variable length path. I expected to be able restrict the paths returned by describing a specific pattern in the WHERE clause:

MATCH p = (n:Node {name: 'n1'})-[*..2]->()
WHERE (n)-[:r1]->()-[:r1]->()
RETURN p

The problem is that the response returns all possible paths. My question; is it possible to filter the returned paths when specifying a variable length path in a query?


Solution

  • If all relationships or nodes have to adhere to the same predicate, this is easy. You'll need a variable for the path, and you'll need to use all() (or none()) in your WHERE clause to apply the predicate for all relationships or nodes in your path:

    MATCH p = (n:Node {name: 'n1'})-[*..2]->()
    WHERE all(rel in relationships(p) WHERE type(rel) = 'r1')
    RETURN p
    

    That said, when all you want is for all relationships in the var-length path to be of the same type (or types, if you want multiple), that's best done in the pattern itself:

    MATCH p = (n:Node {name: 'n1'})-[:r1*..2]->()
    RETURN p
    

    For more complicated cases, such as multiple relationship types (where the order of those types matters in the path), or repeating sequences of types or node labels in the path, then alternate approaches are needed. APOC path expanders may help.

    EDIT

    You mentioned in the comments that your case deals with sequences of relationships of varying lengths. While the APOC path expanders may help, it there are a few restrictions:

    1. The path expanders currently operate on node labels and relationship types, but not properties, so if your expansions rely on predicates on properties, the path expanders won't be able to handle that for you during expansion, that would have to be done by filtering the path expander results after.

    2. There are limits to the relationship sequence support for path expanders. We can define sequences of any length, and can accept multiple relationship types at each step in the sequence, but we don't currently support diverging sequences ((r1 then r2 then r3) or (r2 then r5 then r6)).

    If we wanted to do a 3-step sequence of r1 (incoming), r2 (outgoing), then r3 or r4 (with r3 in either direction and r4 outgoing), repeating the sequence up to 3 times we could do so like this:

    MATCH (n:Node {name: 'n1'})
    CALL apoc.path.expandConfig(n, {relationshipFilter:'<r1, r2>, r3 | r4>', minLevel:1, maxLevel:9) YIELD path
    RETURN path
    

    Note that we can provide differing directions per relationship in the filter, or leave off the arrow entirely if we don't care about the direction.

    Label filtering is more complex, but I didn't see any need for that present in the examples so far.