We know that we can get the shortest path between nodes by the following statement
MATCH p=allShortestPaths((a)-[*]->(b))
Is there any way to search for the second shortest path without exhaustive search?
There's no way to specify something like second shortest path via shortestPath() or allShortestPaths(). However: You could search for all paths, ordered by path length, and just limit the depth and number of items returned. For example:
MATCH p =(a)-[*2..5]-(b)
RETURN p, length(p)
order by length(p)
LIMIT 5;
You'd have to fine-tune this based on your knowledge of the domain (such as min # and max # of relationship hops). And you can further optimize with the addition of labels and relationship types.
You could find the shortest path in a subquery first and then find the paths that are longer than the shorter path.
CALL
{MATCH p=shortestPath((a)-[*]->(b))
RETURN length(p) as `shortPathLength`}
MATCH p=shortestPath((a)-[*]->(b))
WHERE length(p) > `shortPathLength`
RETURN p
Using SKIP or LIMIT and hardcoding a number to skip the first shortest path is likely to fetch undesired results in your use case if there are multiple shortest paths with the smallest number of hops.
Related
I am trying to work with ShortestPath in Neo4j.
I want to find, for each node, its shortest path to any node with a given property.
In other words, for any node n1 I want the smallest length of the shortest paths to any node n2, n2 having a specific property.
I currently use the following query but I believe it is inefficient as it would have to compute all shortest path between n1 and n2. A smarter way would be to stop looking as soon as we find a path such that length(path)==1.
MATCH path = shortestpath((n1:Node {has_ppt: False})-[:KNOWS]-(n2:Node {has_ppt: True}))
RETURN n1,n2,length(path)
LIMIT 5
Does anyone know how to do it differently ? Thanks
Your -[:KNOWS]- pattern does not specify a variable length path (like -[:KNOWS*..5]-), so your shortestpath query is currently only trying to find paths of length 1. This is probably not what you intended.
You may want to try an iterative approach to finding a single instance of the shortest path. That is, repeatedly perform the following query (while incrementing the number in the [:KNOWS*1] pattern, to increment the desired path length) until you get a result:
MATCH path = (n1:Node {has_ppt: False})-[:KNOWS*1]-(n2:Node {has_ppt: True})
RETURN n1,n2,length(path)
LIMIT 1;
Actually i'm modelling TEI-encoded XML-Text in a graph (words as a chain of nodes) and i want to find shortestPaths and only the very shortest path in a graph.
My query looks like
MATCH (w0:XmlWord)-[:NEXT*..6]->(n:XmlTag {_name:'lb'})-[:NEXT*..6]->(w1:XmlWord)
RETURN id(w0), id(w1);
And I need only the shortest possible path but neo4j gives me all possibilities until to the 6th step. The result should be the nodes Vorträge, über, des, and Freiherrn
Neo4j gives me back all possible combinations until to the 6th step.
If someone needs access to a sample-database just let me know.
This is a little tough when you're using multiple variable-length relationships in the same path. You can however order the results by path length and filter for the ones with the minimum length.
MATCH path = (:XmlWord)-[:NEXT*..6]->(:XmlTag {_name:'lb'})-[:NEXT*..6]->(:XmlWord)
WITH length(path) as length, collect(path) as paths
ORDER BY length ASC
LIMIT 1
UNWIND paths as path
WITH head(nodes(path)) as first, last(nodes(path)) as last
RETURN id(first), id(last);
I'm trying to find the closest node with a specific label to a node which i have his id.
MATCH (object{id:'1489751911095'}), (apiUser:ApiUser) ,
p = allShortestPaths((object) - [*] - (apiUser)) return p limit 1
For some reason, it doesn't stops in the first encounter of the node apiUser:ApiUser, but is continuing further on.
The allShortestPaths feature enumerates all shortest paths between two nodes. So, for your query, it takes all possible pairs of object and apiUser nodes and enumerates all shortest paths between each pair. So how do we stop that from happening?
First, you might want to simplify your original query like this:
MATCH p=allShortestPaths((object {id:'1489751911095'})-[*]-(apiUser:ApiUser))
RETURN p
LIMIT 1
Second, if you only need one path, why not use the shortestPath feature?
MATCH p=shortestPath((object {id:'1489751911095'})-[*]-(apiUser:ApiUser))
RETURN p
LIMIT 1
This will still calculate a shortest path for each apiUser, so you'd want to order the results based on the length of the path:
MATCH p=shortestPath((object {id:'1489751911095'})-[*]-(apiUser:ApiUser))
RETURN p
ORDER BY length(p) DESC
LIMIT 1
This is not the most efficient solution, as Neo4j will still calculate the shortest path for each apiUser - whether the solution is applicable to your use case depends on the number of apiUsers in your database.
When matching from a single node, a variable-length match with LIMIT 1 should work:
MATCH (object{id:'1489751911095'})-[*]-(p:ApiUser)
RETURN p limit 1
It's recommended to have a label in your match when looking up a node by property, and an index or unique constraint on the label+property so it's a fast match.
If you are unsure if there will be a node of that type close by, you may want to add an upper bound to your variable length match.
below Shortestpath query returns many paths instead of one path.
MATCH PATHS=shortestPath((a:Endpoint{ nodeName: 'BRS-PE-SR7-X03B' }) -[*]-(b:Endpoint{ nodeName: 'LDN-PE-SR7-X03C' }) RETURN PATHS
Can anybody explain how iternally it calculates the paths and return the shortest path for the below scenarios.
My understanding is it should return ONLY one path.Am I right?
The SHORTESTPATH function finds the single shortest path between two specific nodes.
If multiple Endpoint nodes can have the same nodeName value, this can explain why you are getting multiple shortest paths.
If this is the reason for your results, at least one of the 2 counts returned by this query should exceed 1:
MATCH
(a:Endpoint{ nodeName: 'BRS-PE-SR7-X03B' }),
(b:Endpoint{ nodeName: 'LDN-PE-SR7-X03C' })
RETURN COUNT(DISTINCT a), COUNT(DISTINCT b);
The shortest path algorithm as provided by the REST API provides ALL SHORTEST PATHS between two nodes. This implies that if the minimum number of hops are same in more than one path, then you will get all of those shortest paths.
(https://neo4j.com/docs/rest-docs/current/#rest-api-find-all-shortest-paths).
I created a Neo4j database with the cypher statement here:https://gist.github.com/neoecos/8748091
i want to know : how to get :
1.less Transfer Paths (order by transfer)
2.the Shortest Path (order by path length)
3.the optimal Path (less Transfer and the Shortest Path)
please give the corresponding query.
And do you think that is the best way to create a Bus inquiry system?
Thanks a lot.
The shortest path is pretty easy:
MATCH path=shortestPath((station_44:STATION {id:44})-[*0..10]-(station_46:STATION {id:46}))
RETURN path
As far as counting transfers you can do something like this:
MATCH path=allShortestPaths((station_44:STATION {id:44})-[rels*0..10]-(station_46:STATION {id:46}))
RETURN length(path) AS stop_count, length(FILTER(index IN RANGE(1, length(rels)-1) WHERE (rels[index]).bus <> (rels[index - 1]).bus)) AS transfer_count
Once you have those two variables you can calculate / sort however you like. For example:
MATCH path=(station_44:STATION {id:44})-[rels*0..4]-(station_46:STATION {id:46})
WITH length(path) AS stop_count, length(FILTER(index IN RANGE(1, length(rels)-1) WHERE (rels[index]).bus <> (rels[index - 1]).bus)) AS transfer_count
RETURN stop_count, transfer_count
ORDER BY (stop_count * 0.5) + (transfer_count * 2.0) DESC
Here I removed the allShortestPaths call so that you get different lengths of paths. The ORDER BY uses weights on the two metrics. Unfortunately, at least in my DB, if you go beyond a path length of four it starts to get really slow. You might be able to improve that by introducing a direction arrow in the path, if that makes sense in your case.