shortestPath relationship does not reflect the correct direction - neo4j

I am new to Neo4j and is developing a small site.
I have setup the nodes and relationships between them. For most of the paired nodes, I created a mutual link. For example:
Zeus - FATHER -> Apollo
Appollo - SON -> Zeus
I used shortestPath to find the possible shortest path between these two:
MATCH (o1 { name: 'Apollo' }),(o2 { name: 'Zeus' }), p = shortestPath((o1)-[*..6]-(o2)) RETURN nodes(p), relationships(p)
The result is that it returns "FATHER" instead of "SON".
If I change the query to [*..6]->(o2), "SON" is returned.
But I need to consider the search may make o1 a node with no outgoing relationship, in which case, the above-modified query fails.
So:
The original query can cope with nodes with no outgoing relationship, but may return wrong relationship.
The modified query can return right relationship (so far) but can't cope with "no out relation" nodes.
I can of course change every node to have at least one outgoing relation to fix Issue 2 but that will be too redundant.
Hope to get your advice.

It's a bad practice to create bidirectional relationships like you do, specially when it's a bijection.
You are duplicating some data in the database (it's obvious that if Zeus is the father of Apollo, Apollo is the son of Zeus).
This query :
MATCH
(o1 { name: 'Apollo' }),
(o2 { name: 'Zeus' }),
p = shortestPath((o1)-[*..6]-(o2))
RETURN nodes(p), relationships(p)
search only one shortestpath. But due to the duplication, there is in fact two shortestpaths. You can replace the shortestpath function by the allshortestpaths to find all. So youwill have the son and father result.
Or you can also give to the shortestpath function, a list of relationship type thath it can traverse like this:
MATCH
(o1 { name: 'Apollo' }),
(o2 { name: 'Zeus' }),
p = shortestPath((o1)-[:FATHER*..6]-(o2))
RETURN nodes(p), relationships(p)

Related

Checking every relationship of a path triggers way too many dbhits

I am running a query to find the path from a user to a permission node in neo4j and I want to make sure it doesn't traverse some relationships. Therefore I've used the following cypher :
PROFILE
MATCH path = (u:user { _id: 'ea6b17e0-3b9e-11ea-b206-e7610aa23593' })-[r:accessRole|isMemberOf*1..5]->(n:PermissionSet { name: 'project'})
WHERE all(x IN r WHERE NOT (:PermissionSet)-[x]->(:user))
RETURN path
I didn't expect the where clause to trigger so many hits. I believe I'm not writing my test correctly.
(2000 nodes/ 3500 rels => 350,000 hits for "(:PermissionSet)-[x]->(:user)"
any advice?
Not sure this is the correct answer, but I added a WITH statement
PROFILE
MATCH path = (u:user { _id: 'ea6b17e0-3b9e-11ea-b206-e7610aa23593' })-[r:accessRole|isMemberOf*1..5]->(n:PermissionSet { name: 'project'})
WITH path,r
WHERE all(x IN r WHERE NOT (:PermissionSet)-[x]->(:user))
RETURN path
And the dbhits for "(:PermissionSet)-[x]->(:user)" went down to 2800 hits.
I can guess why it does that, but I'd love some more experts explanations, and is there a better way to do it? (this way is fine with me performance-wise)

Cypher query fails with variable length paths when trying to find all paths with unique node occurences

I have a highly interconnected graph where starting from a specific node
i want to find all nodes connected to it regardless of the relation type, direction or length. What i am trying to do is to filter out paths that include a node more than 1 times. But what i get is a
Neo.DatabaseError.General.UnknownError: key not found: UNNAMED27
I have managed to create a much simpler database
in neo4j sandbox and get the same message again using the following data:
CREATE (n1:Person { pid:1, name: 'User1'}),
(n2:Person { pid:2, name: 'User2'}),
(n3:Person { pid:3, name: 'User3'}),
(n4:Person { pid:4, name: 'User4'}),
(n5:Person { pid:5, name: 'User5'})
With the following relationships:
MATCH (n1{pid:1}),(n2{pid:2}),(n3{pid:3}),(n4{pid:4}),(n5{pid:5})
CREATE (n1)-[r1:RELATION]->(n2),
(n5)-[r2:RELATION]->(n2),
(n1)-[r3:RELATION]->(n3),
(n4)-[r4:RELATION]->(n3)
The Cypher Query that causes this issue in the above model is
MATCH p= (n:Person{pid:1})-[*0..]-(m)
WHERE ALL(c IN nodes(p) WHERE 1=size(filter(d in nodes(p) where c.pid = d.pid)) )
return m
Can anybody see what is wrong with this query?
The error seems like a bug to me. There is a closed neo4j issue that seems similar, but it was supposed to be fixed in version 3.2.1. You should probably create a new issue for it, since your comments state you are using 3.2.5.
Meanwhile, this query should get the results you seem to want:
MATCH p=(:Person{pid:1})-[*0..]-(m)
WITH m, NODES(p) AS ns
UNWIND ns AS n
WITH m, ns, COUNT(DISTINCT n) AS cns
WHERE SIZE(ns) = cns
return m
You should strongly consider putting a reasonable upper bound on your variable-length path search, though. If you do not do so, then with any reasonable DB size your query is likely to take a very long time and/or run out of memory.
When finding paths, Cypher will never visit the same node twice in a single path. So MATCH (a:Start)-[*]-(b) RETURN DISTINCT b will return all nodes connected to a. (DISTINCT here is redundant, but it can affect query performance. Use PROFILE on your version of Neo4j to see if it cares and which is better)
NOTE: This works starting with Neo4j 3.2 Cypher planner. For previous versions of
the Cypher planner, the only performant way to do this is with APOC, or add a -[:connected_to]-> relation from start node to all children so that path doesn't have to be explored.)

py2Neo.ogm shortestPath search not turning up results

I have implemented py2neo with ogm, however I cannot get the search functionality to work like it should. Below I have my cypher query (directly to the Neo4j db) with 'rpt_id' and 'country_code' as GraphObjects in the graph with those as the primary keys of the graph. The relationship between them is PART_OF.
MATCH (m:Column {name: '{rpt_id}'}), (n:Column {name:'{country_code}'}),
p = shortestPath((m)-[:PART_OF*..4]-(n))
RETURN p
I expect a response of the Tables (another ogm node) to go through to get to country_code, however, nothing is being returned.
If nodes definitely exist that match rpt_id and country_code I expect the problem is the use of ticks around your parameters. I would re-write the query as follows:
MATCH (m:Column {name: {rpt_id} }), (n:Column {name: {country_code} }), p = shortestPath((m)-[:PART_OF*..4]-(n))
RETURN p

Limiting ShortestPath in Cypher to nodes with specific properties

I am trying to figure out how to limit a shortest path query in cypher so that it only connects "Person" nodes containing a specific property.
Here is my query:
MATCH p = shortestPath( (from:Person {id: 1})-[*]-(to:Person {id: 2})) RETURN p
I would like to limit it so that when it connects from one Person node to another Person node, the Person node has to contain a property called "job" and a value of "engineer."
Could you help me construct the query? Thanks!
Your requirements are not very clear, but if you simply want one of the people to have an id of 1 and the other person to be an engineer, you would use this:
MATCH p = shortestPath( (from:Person {id: 1})-[*]-(to:Person {job: "engineer"}))
RETURN p;
This kind query should be much faster if you also created indexes for the id and job properties of Person.

How to get nodes from relationships with any depth including relation filter

I'm using a query similar to this one:
(n)-[*]->(m)
Any depth.
But I cannot filter the relation name in such a query like this:
(n)-[*:DOES]->(m)
Any depth.
I need to filter the relation name since there are different relations on the related path. If it helps, here is my graph:
CREATE (Computer { name:'Computer' }),(Programming { name:'Programming' }),(Java { name:'Java' }),(GUI { name:'GUI' }),(Button { name:'Button' }), Computer<-[:IS]-Programming, Programming<-[:IS]-Java, Java<-[:IS]-GUI, GUI<-[:IS]-Button, (Ekin { name:'Ekin' }), (Gunes { name:'Gunes' }), (Ilker {name:'Ilker'}), Ekin-[:DOES]->Programming, Ilker-[:DOES]->Java, Ilker-[:DOES]->Button, Gunes-[:DOES]->Java
I'd like to get the names (Ekin, Ilker and Gunes) which have "DOES" relationship connected to "Programming" with any depth.
Edit:
I'm able to get the values I want by merging two different queries' results (think 13 is the top node that I want to reach):
START n=node(13)
MATCH p-[:DOES]->()-[*]->(n)
RETURN DISTINCT p
START n=node(13)
MATCH p-[:DOES]->(n)
RETURN DISTINCT p
I want to do it in a single query.
Change the matching pattern to "p-[:DOES]->()-[*0..]->n",
Match p-[:DOES]->()-[*0..]->n
Return distinct p.name
The variable length relationship "[*]" means 1..*. You need 0..* length relationships on the path.
Just to update the answer with Neo4j 3.0.
MATCH p-[:DOES*0..]->(n)
RETURN DISTINCT(p.name)
It returns the same result as the accepted answer.

Resources