Neo4J find shortest path using all nodes (unordered) cypher - neo4j

I'm not sure if this can be done in any efficient way, but i'm hoping it can be.
I am getting a set of data with data on it that allows me to find very specific nodes. However this data is not ordered in any way in terms of how the nodes are connected.
What I am trying to do is to be able to find all the nodes in neo4J (up to 7) and then say with these 7 nodes, find the path that connects them all.
These given nodes will be the only nodes connected in the desired path.
basically i'm trying to get a set that looks like
1,2,3,4,5,6,7
and to be able to find
2->7->6->3<-5<-1->4
any help or direction would be greatly appreciated

the way I would do it is the following:
You need a starting node from where on you will query the next 7 nodes. To be able to find the very first 7 nodes I would introduce a starting root node. Lets call it simply :Root .
MATCH (:Root)-[r:NEXT*1..7]->(x)<-[]-(y) RETURN x, y
or even simpler:
MATCH (:Root)-[r:NEXT*..7]->(x)<-[]-(y) RETURN x, y
:Root of course could be any other node in your set, to get the next seven nodes from there on.
Is this what you want?
Take a further look at the following neo4j cheat sheet, which has some great tips:
http://assets.neo4j.org/download/Neo4j_CheatSheet_v3.pdf
Regards
EDIT
Ok sorry, I misunderstood you.
Maybe this brings you further:
MATCH (n:Node) where n.refId in [1,2,3,4,5,6,7]
MATCH (n2:Node) where n2.refId in [1,2,3,4,5,6,7]
MATCH p=shortestPath((q)-[:NEXT*]-(q2))
return collect(distinct p)
or if those numbers are node IDs than like this:
MATCH (n:Node) where id(n) in [1,2,3,4,5,6,7]
MATCH (n2:Node) where id(n2) in [1,2,3,4,5,6,7]
MATCH p=shortestPath((q)-[:NEXT*]-(q2))
return collect(distinct p)
This actually returns all the paths between the given nodes as a collection.
So it doesn't return a single path for all those nodes.
I am not aware of a function doing that.
However the neo4j browser displays just a single path between all those nodes desired, because of it's auto complete function. So I think you would have to build your own logic in code, if you want to connect those paths to a single one.
Maybe this is at least a starting point for the problem

Related

How to get all connected nodes in neo4j

I want to get list of all connected nodes starting from node 0 as shown in the diagram
Based on your comment:
I want to get a list of all the connected nodes. For example in the
above case when I search for connected nodes for 0, it should return
nodes- 1,2,3
This query will do what you want:
MATCH ({id : 0})-[*]-(connected)
RETURN connected
The above query will return all nodes connected with a node with id=0 (I'm considering that the numbers inside the nodes are values of an id property) in any depth, both directions and considering any relationship type. Take a look in the section Relationships in depth of the docs.
While this will work fine for small graphs note that this is a very expensive operation. It will go through the entire graph starting from the start point ({id : 0}) considering any relationship type. This is really not a good idea for production environments.
If you wish to match the nodes that have a relationship to another node, you can use this:
MATCH (n) MATCH (n)-[r]-() RETURN n,r
It will return you all the nodes that have a relationship to another node or nodes, irrespective of the direction of the relationship.
If you wish to add a constraint you can do it this way:
MATCH (n:Label {id:"id"}) MATCH (n)-[r]-() RETURN n,r
For larger or more heavily interconnected graphs, APOC Procedures offers a more efficient means of traversal that returns all nodes in a subgraph.
As others have already mentioned, it's best to use labels on your nodes, and add either an index or a unique constraint on the label+property for fast lookup of your starting node.
Using a label of "Label", and a parameter of idParam, a query to get nodes of the subgraph with APOC would be:
MATCH (n:Label {id:$idParam})
CALL apoc.path.subgraphNodes(n, {minLevel:1}) YIELD node
RETURN node
Nodes will be distinct, and the starting node will not be returned with the rest.
EDIT
There's currently a restriction preventing usage of minLevel in subgraphNodes(), you can use either filter out the starting node yourself, or use apoc.path.expandConfig() using uniqueness:'NODE_GLOBAL' to get the same effect.

neo4j query to exclude nodes related to nodes with certain properties

I am trying to write a neo4j query where I only want to present nodes that are have no relation to nodes with a specific property. One way to think of it is where two separate graphs exist where one node has the property I want to exclude. I should get a result that only contains the graph of the set of nodes not connected to the node that has the property I want to exclude. This is what the graph looks like before my query
match (n) where not (n{property:'valueIWishToExclude'})--() return n
This is what the result of the query looks like
I only want to have the four connected nodes in my results. How can I set up a query that excludes the nodes that are not connected to the node with the property I wish to exclude?
In fact you need those nodes from which there is no path to the node that should be excluded. You can use the shortestPath function and ALL predicate:
match (ex) where n.property = 'valueIWishToExclude'
with collect(ex) as exn
match (n) where (not n.property = 'valueIWishToExclude') and
ALL(e in exn where not shortestPath( (n)-[*]-(e) ) is null)
return n
You are almost there, just add in the relationship in your query to only get the nodes that are related to each other
MATCH (n:label) -[:RELATED]->() where n.property<>'exclude'
RETURN n
That should return only the nodes connected to each other, as the other nodes do not have that relationship.
Let me know if that worked for you.
You may want to alter your wording a bit, what you're asking for in this question, and what you really want, are not the same thing.
In Neo4j (and most graph databases), the phrase "nodes that have no relation to..." means nodes that are not connected by a relationship to the node in question.
In that context, in your right graph (assuming the one node selected is the node marked as excluded), one node would fit the criteria and be returned as a possible result, the topmost node, since it doesn't have a relationship to the node you want to exclude; It is however two relationships removed from the excluded node.
You seem to be asking for something else, though. You seem to want nodes that are not in the same subgraph as the node to exclude. Or, alternately, nodes that have no path to the excluded node.
Make sure on future queries you're clear about what you're asking, or you'll get answers that have no relevance to what you really want.
One approach that will work is to first find all nodes within the subgraph of the excluded node, and then return all nodes that are not in those subgraph nodes.
You'll want to install APOC Procedures so you can make use of a fast means of obtaining nodes within the subgraph.
You'll also want to use labels in your graph, and maybe put an index on the property you're searching for as this will make your search fast. As it is now, your query must examine every node in your entire database to find nodes with the property in question, and that will become slower and slower as your graph grows.
Your query might look like this (using 'Label' as a stand-in for the node label):
MATCH (n:Label{propertyToExclude:'valueToExclude'})
CALL apoc.path.expandConfig(n, {bfs:true, uniqueness:"NODE_GLOBAL"}) YIELD path
WITH COLLECT(DISTINCT LAST(NODES(path))) as subgraph
MATCH (n)
WHERE NOT n in subgraph
RETURN n

How to filter results by node label in neo4j cypher?

I have a graph database that maps out connections between buildings and bus stations, where the graph contains other connecting pieces like roads and intersections (among many node types).
What I'm trying to figure out is how to filter a path down to only return specific node types. I have two related questions that I'm currently struggling with.
Question 1: How do I return the labels of nodes along a path?
It seems like a logical first step is to determine what type of nodes occur along the path.
I have tried the following:
MATCH p=(a:Building)­-[:CONNECTED_TO*..5]­-(b:Bus)
WITH nodes(p) AS nodes
RETURN DISTINCT labels(nodes);
However, I'm getting a type exception error that labels() expects data of type node and not Collection. I'd like to dynamically know what types of nodes are on my paths so that I can eventually filter my paths.
Question 2: How can I return a subset of the nodes in a path that match a label I identified in the first step?
Say I found that that between (a:Building) and (d1:Bus) and (d2:Bus) I can expect to find (:Intersection) nodes and (:Street) nodes.
This is a simplified model of my graph:
(a:Building)­­--(:Street)­--­(:Street)--­­(b1:Bus)
\­­(:Street)--­­(:Intersection)­­--(:Street)--­­(b2:Bus)
I've written a MATCH statement that would look for all possible paths between (:Building) and (:Bus) nodes. What would I need to do next to filter to selectively return the Street nodes?
MATCH p=(a:Building)-[r:CONNECTED_TO*]-(b:Bus)
// Insert logic to only return (:Street) nodes from p
Any guidance on this would be greatly appreciated!
To get the distinct labels along matching paths:
MATCH p=(a:Building)-[:CONNECTED_TO*..5]-(b:Bus)
WITH NODES(p) AS nodes
UNWIND nodes AS n
WITH LABELS(n) AS ls
UNWIND ls AS label
RETURN DISTINCT label;
To return the nodes that have the Street label.
MATCH p=(a:Building)-[r:CONNECTED_TO*]-(b:Bus)
WITH NODES(p) AS nodes
UNWIND nodes AS n
WITH n
WHERE 'Street' IN LABELS(n)
RETURN n;
Cybersam's answers are good, but their output is simply a column of labels...you lose the path information completely. So if there are multiple paths from a :Building to a :Bus, the first query will only output all labels in all nodes in all patterns, and you can't tell how many paths exist, and since you lose path information, you cannot tell what labels are in some paths but not others, or common between some paths.
Likewise, the second query loses path information, so if there are multiple paths using different streets to get from a :Building to a :Bus, cybersam's query will return all streets involved in all paths. It is possible for it to output all streets in your graph, which doesn't seem very useful.
You need queries that preserve path information.
For 1, finding the distinct labels on nodes on each path I would offer this query:
MATCH p=(:Building)-[:CONNECTED_TO*..5]-(:Bus)
WITH NODES(p) AS nodes
WITH REDUCE(myLabels = [], node in nodes | myLabels + labels(node)) as myLabels
RETURN DISTINCT myLabels
For 2, this query preserves path information:
MATCH p=(:Building)-[:CONNECTED_TO*..5]-(:Bus)
WITH NODES(p) AS nodes
WITH FILTER(node in nodes WHERE (node:Street)) as pathStreets
RETURN pathStreets
Note that these are both expensive operations, as they perform a cartesian product of all buildings and all busses, as in the queries in your description. I highly recommend narrowing down the buildings and busses you're matching upon, hopefully to very few or specific buildings at least.
I also encourage limiting how deep you're looking in your pattern. I get the idea that many, if not most, of your nodes in your graph are connected by :CONNECTED_TO relationships, and if we don't cap that to a reasonable amount, your query could be finding every single path through your entire graph, no matter how long or convoluted or nonsensical, and I don't think that's what you want.

Matching subtree recursively in Neo4j

I'm using Neo4j, and I consider myself quite a newbie, and I don't really understand how I can select a subtree of my graph. I've found solutions using the shortestPath and allShortestPaths but that's not really the same thing as selecting a whole subtree by variable and all its children.
What I want to do is e.g. match MATCH (n {name: "Sovrum"})-[r:CHILDOF]->(child) return n, child but that only gives me the directly related nodes.
Instead I want to select the whole subtree.
Is there any good way of doing this or am I missing some vital point in how stuff works?
It's quite easy with variable length paths, you start at the root and tell Cypher to match CHILD_OF all the way down until it doesn't go further.
Please make sure to use labels in your query to allow Neo4j (with an index) to find your starting point quickly.
You can also assign the pattern matched to a path and return that path
MATCH path = (n:Node {name: "Sovrum"})-[:CHILDOF*]->(child)
RETURN path

Get all Routes between two nodes neo4j

I'm working on a project where I have to deal with graphs...
I'm using a graph to get routes by bus and bike between two stops.
The fact is,all my relationship contains the time needed to go from the start point of the relationship and the end.
In order to get the shortest path between to node, I'm using the shortest path function of cypher. But something, the shortest path is not the fastest....
Is there a way to get all paths between two nodes not linked by a relationship?
Thanks
EDIT:
In fact I change my graph, to make it easier.
So I still have all my nodes. Now the relationship type correspond to the time needed to go from a node to another.
The shortestPath function of cypher give the path which contains less relationship. I would like that it returns the path where the addition of all Type (the time) is the smallest..
Is that possible?
Thanks
In cypher, to get all paths between two nodes not linked by a relationship, and sort by a total in a weight, you can use the reduce function introduced in 1.9:
start a=node(...), b=node(...) // get your start nodes
match p=a-[r*2..5]->b // match paths (best to provide maximum lengths to prevent queries from running away)
where not(a-->b) // where a is not directly connected to b
with p, relationships(p) as rcoll // just for readability, alias rcoll
return p, reduce(totalTime=0, x in rcoll: totalTime + x.time) as totalTime
order by totalTime
You can throw a limit 1 at the end, if you need only the shortest.
You can use the Dijkstra/Astar algorithm, which seems to be a perfect fit for you. Take a look at http://api.neo4j.org/1.8.1/org/neo4j/graphalgo/GraphAlgoFactory.html
Unfortunately you cannot use those from Cypher.

Resources