How to find a path in cypher the ungreedy way - neo4j

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);

Related

Find The shortest Path between Given multiple Nodes

I am trying to find the Shortest Path between given Multiple Nodes.
Like I have an Array of locations Node and then there is a location for the user. I want to find the Nearest Location to that user between these given nodes.
I have tried this query
UNWIND
["93049","67069","90762","86156","01067","18069","52146","04356"," 42329","53113","76131","40549","50670","50678","85774","80339"] AS plz
MATCH p=Shortestpath(
(a:plzNodes {plz: plz})-[*..14]-(b:plzNodes {plz: "88400"})
) RETURN plz,collect(p);
You can use the path expander procs from APOC Procedures for this, collecting the possible end nodes, and then using the path expander from the start node to those end nodes with a limit of 1: the path to the first node encountered (which will be the shortest path, due to breadth first expansion) will be returned.
WITH ["93049","67069","90762","86156","01067","18069","52146","04356"," 42329","53113","76131","40549","50670","50678","85774","80339"] AS plzes
MATCH (a:plzNodes)
WHERE a.plz in plzes
WITH collect(a) as plzNodes
MATCH (b:plzNodes {plz: "88400"})
CALL apoc.path.subgraphNodes(b, {endNodes:plzNodes, limit:1, maxLevel:14}) YIELD node as closest
RETURN closest

Neo4j ShortestPath to any node with a given property

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;

Neo4j - get shortest path between a specific node with id to a node with a label

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.

Neo4j search for second shortest path

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.

how can i get Shortest Path cypher query?

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.

Resources