1
votes

I would like to match certain paths in my graph. These good paths should not contain certain subpaths, e.g. avoiding certain nodes. For example, given the graph

a->b->c->d
a->avoid1->b
c->avoid2->d

NB: There could be many more nodes in between the edges I specified, e.g. a->t0->t1->b or a->avoid1->t2->b.

Now I would like to get all paths from a to d which do not contain certain subpaths, to be precise, those subpaths going from a over avoid1 to b and from c over avoid2 to d.

My current (insufficient) approach is to MATCH the entire path I am looking for and then specifying the node I want to avoid:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT (avoid1 IN nodes(p))

This is not working out for me because I actually need to "filter out" subpaths and not nodes.

I need something like this:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(avoid1)->[:CF*]->(b) IN p) AND NOT ( (c)-[:CF*]->(avoid2)->[:CF*]->(d) )

This does not work, I know but it could help to explain what I need: a way to filter out paths based on the fact if they contain certain subpaths.

EDIT:

Here are the commands:

MERGE (a:MYTYPE { label:'a' })
MERGE (b:MYTYPE { label:'b' })
MERGE (c:MYTYPE { label:'c' })
MERGE (d:MYTYPE { label:'d' })
MERGE (avoid1:MYTYPE { label:'avoid1' })
MERGE (avoid2:MYTYPE { label:'avoid2' })

CREATE (a)-[:CF]->(b)
CREATE (b)-[:CF]->(c)
CREATE (c)-[:CF]->(d)

CREATE (a)-[:CF]->(avoid1)
CREATE (avoid1)-[:CF]->(b)
CREATE (c)-[:CF]->(avoid2)
CREATE (avoid2)-[:CF]->(d)

and my current try (as suggested by dave's answer):

MATCH (a:MYTYPE { label:'a' })
MATCH (b:MYTYPE { label:'b' })
MATCH (c:MYTYPE { label:'c' })
MATCH (d:MYTYPE { label:'d' })
MATCH (avoid1:MYTYPE { label:'avoid1' })
MATCH (avoid2:MYTYPE { label:'avoid2' })

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(avoid1 {label:'avoid1'})-[:CF*]->(b) ) 

RETURN p

Yet, this gives me "(no rows)".

1
Hello @gogo_gorila, have you reach to a solution on this? I have a similar problem and I would like to see your approach - bmalbusca
@bmalbusca No, haven't worked on the topic for quite a long time. - gogo_gorilla
Ok, I found a solution for this type of problems. The first thing to do is excluding the possible paths that ends on the source node variable and, exclude the forward paths that uses the end node variable. Then, use apoc.path.combine() to combine subpaths - bmalbusca

1 Answers

1
votes

This query should allow you to filter on paths:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->()-[:CF*]->(b)) 
AND NOT ( (c)-[:CF*]->()-[:CF*]->(d) )
return p;`

You could also specify a label/property for the node that you want to filter on:

MATCH p=(a)-[:CF*]->(b)-[:CF*]->(c)-[:CF*]->(d)
WHERE NOT ( (a)-[:CF*]->(:Person {name:'Dave'})-[:CF*]->(b)) AND NOT ( (c)-[:CF*]->()-[:CF*]->(d) )
return p;