I have a graph of Airports, Routes between them and Airlines that carry it. I created routes as separate nodes, rather than just a relationship, so that I can connect each with an Airline, and other nodes.
Each Route node has an IS_FROM relationship with the origin airport and an IS_TO relationship with the destination. It also has an IS_BY relationship with its airline:
I am trying to traverse this tree, n times, for routes between two airports. For example, if n = 3, I want to get all the routes, that will lead from LAX to LHR, with 3 or fewer connections.
So basically, my result would be a union of the following:
No Connecting Airports:
MATCH (a1:Airport {iata : 'LAX'})<-[:IS_FROM]-(r:Route)-[:IS_TO]->(a2:Airport {iata : 'LHR'}), (r)-[:IS_BY]->(ai:Airline) return a1 , r , a2 , ai;
1 Connecting airports:
MATCH (a1:Airport {iata : 'LAX'})<-[:IS_FROM]-(r:Route)-[:IS_TO]->(a2:Airport)<-[IS_FROM]-(r2:Route)-[:IS_TO]->(a3:Airport {iata: 'LHR'}), (r2)-[:IS_BY]->(ai:Airline) return a1 , r , a2 , a3 , r2 , ai;
and so on.
So the query should dynamically traverse the (:Airport)<-[:IS_FROM]-(:Route)-[:IS_TO]->(:Airport) pattern n times, and return the nodes (I am more interested in returning the Airlines that connect to those routes.
You can first extract all the paths between Airports that are 3 or less hops away, and then use OPTIONAL MATCH to see which of the nodes in the path are Routes, and which Airlines are offering them.
MATCH path = (:Airport {iata:$start_airport})-[*2..6]-(:Airport {iata:$end_airport})
WITH path,nodes(path) as path_airports_and_connecting_routes
UNWIND path_airports_and_connecting_routes as node
OPTIONAL MATCH (node)-[:IS_BY]-(airline:Airline)
WITH collect(node) as airports_and_routes,airline
RETURN airports_and_routes + [airline]
Caveat: Variable-length paths don't allow passing parameters, so you can't do something like [*2..2*n].
I don't know if i got your question right. To me your problem could be solved this way:
MATCH (a1:Airport {iata : 'LAX'})<-[r1:IS_FROM]-(r:Route)-[r2:IS_TO]->(a2:Airport{iata : 'LHR'})
OPTIONAL MATCH (r)-[r3:IS_BY]->(ai:Airline)
RETURN a1,r1,r,r2,a2,r3,ai
Related
Env - Neo4j 4.0 enterprise
Plugins - GDS and apoc
I have a data in neo4j like below -
CREATE (a:hotel {hotel_id:'A'}),
(b:hotel {hotel_id:'B'}),
(c:hotel {hotel_id:'C'}),
(d:hotel {hotel_id:'D'}),
(e:hotel {hotel_id:'E'}),
(f:hotel {hotel_id:'F'}),
(g:hotel {hotel_id:'G'}),
(h:hotel {hotel_id:'H'}),
(i:hotel {hotel_id:'I'}),
(a)-[:HAS]->(b),
(b)-[:HAS]->(c),
(c)-[:HAS]->(d),
(d)-[:HAS]->(e),
(e)-[:HAS]->(f),
(f)-[:HAS]->(g),
(g)-[:HAS]->(h),
(h)-[:HAS]->(i),
(ap:hotel_loc {loc_id:'pp1A'}),
(bp:hotel_loc {loc_id:'pp1B'}),
(cp:hotel_loc {loc_id:'pp1C'}),
(dp:hotel_loc {loc_id:'pp1D'}),
(ep:hotel_loc {loc_id:'pp1E'}),
(fp:hotel_loc {loc_id:'pp1F'}),
(gp:hotel_loc {loc_id:'pp1G'}),
(hp:hotel_loc {loc_id:'pp1H'}),
(ip:hotel_loc {loc_id:'pp1I'}),
(a)-[:HAS_JUNC]->(ap),
(b)-[:HAS_JUNC]->(bp),
(c)-[:HAS_JUNC]->(cp),
(d)-[:HAS_JUNC]->(dp),
(e)-[:HAS_JUNC]->(ep),
(f)-[:HAS_JUNC]->(fp),
(g)-[:HAS_JUNC]->(gp),
(h)-[:HAS_JUNC]->(hp),
(i)-[:HAS_JUNC]->(ip);
2 scenerios
1. List of the all node starting from
given a loc_id (example pp1F), i need to get all the nodes(hotel) and their associated :HAS_JUNC nodes.
f,pp1F
g,pp1G
h,pp1H
i,pp1I
List of all until the end.
given a loc_id (example pp1C), i need to all the nodes until pp1C
a,pp1A
b,pp1B
c,pp1C
I tried this query, but no results -
MATCH s= (h1:hotel)-[:HAS_PROPERTY]->(start:hotel_propert {property_id:"pp1A"}),
e= (h2:hotel)-[:HAS_PROPERTY]->(end:hotel_propert {property_id:"pp1C"})
WITH h1, h2, s,e match p=(h1)-[:HAS*]->(h2) RETURN s,p,e
Any help is highly appreciated.
To get the hotels that have a direct HAS_JUNC relationship to a specific hotel_loc (whose id is assumed to be in the loc_id parameter) :
MATCH (a:hotel)-[:HAS_JUNC]->(ap)
WHERE ap.loc_id = $loc_id
RETURN ap, COLLECT(a) AS directly_connected_hotels
To get all the hotels connected to a specific hotel_loc:
MATCH (a:hotel)-[:HAS *0..]->()-[:HAS_JUNC]->(ap)
WHERE ap.loc_id = $loc_id
RETURN ap, COLLECT(a) AS connected_hotels
In the variable-length relationship pattern [:HAS *0..], the 0 lower bound means that the pattern is allowed to match paths in which the HAS relationship does not exist.
I have a huge database of size 260GB, which is storing a ton of transaction information. It has Agent, Customer,Phone,ID_Card as the nodes. Relationships are as follows:
Agent_Send, Customer_Send,Customer_at_Agent, Customer_used_Phone,Customer_used_ID.
A single agent is connected to many customers .And hence hitting the agent node while querying a path is not feasible. Below is my query:
match p=((ph: Phone {Phone_ID : "3851308.0"})-[r:Customer_Send
| Customer_used_ID | Customer_used_Phone *1..5]-(n2))
with nodes(p) as ns
return extract (node in ns | Labels(node) ) as Labels
I am starting with a phone number and trying to extract a big "Customer" network. I am intentionally not touching the "Customer_at_Agent" relationship in the above networked query as it is not optimal as far as performance is concerned.
So, the idea is to extract all the "Customer" labeled nodes from the path and match it with [Customer_at_Agent] relationship.
For instance , something like:
match p=((ph: Phone {Phone_ID : "3851308.0"})-[r:Customer_Send
| Customer_used_ID | Customer_used_Phone *1..5]-(n2))
with nodes(p) as ns
return extract (node in ns | Labels(node) ) as Labels
of "type customer as c "
optional match (c)-[r1:Customer_at_Agent]-(n3)
return distinct p,r1
I am still new to neo4j and cypher and I am not able to figure out a hack to extract only "customer" nodes from the path and use that in the optional match.
Thanks in advance.
Use filter notation instead of extract and you can drop any nodes that aren't labelled right. Try out this query instead:
MATCH p = (ph:Phone {Phone_ID : "3851308.0"}) - [:Customer_Send|:Customer_used_ID|:Customer_used_Phone*1..5] - ()
WITH ph, [node IN NODES(p) WHERE node:Customer] AS customer_nodes
UNWIND customer_nodes AS c_node
OPTIONAL MATCH (c_node) - [r1:Customer_at_Agent] - ()
RETURN ph, COLLECT(DISTINCT r1)
So the second line takes the phone number and the path generated and gives you a list of nodes that have the Customer label as customer_nodes. You then unwind this list so you have individual nodes you can use in path matching. Line 4 performs your optional match and finds the r1 you're interested in, then line 5 will return the phone number node you started with and a collection of all of the r1 relationships that you found on customer nodes hooked up to that phone number.
UPDATE: I added some modifications to clean up your first query line as well. If you aren't going to use an alias (like r or n2 in the first line), then don't assign them in the first place; they can affect performance and cause confusion. Empty nodes and relationships are totally fine if you don't actually have any restrictions to place on them. You also don't need parentheses to mark off a path; they are used as a core part of Cypher's ASCII art to signify nodes, so I find they are more confusing than helpful.
I'm struggling with a problem despite having read a lot of documentation... I'm trying to find my graph root node (or nodes, they may be several top nodes) and counting their immediate children (all relations are typed :BELONGS_TO)
My graph looks like this (cf. attached screenshot). I have been trying the following query which works as long as the root node only has ONE incomming relationship, and it doesn not when it has more than one. (i'm not realy familiar with the cyhper language yet).
MATCH (n:Somelabel) WHERE NOT (()-[:BELONGS_TO]->(n:Somelabel)) RETURN n
Any help would be much appreciated ! (i haven't even tried to count the root nodes immediate children yet...which would be "2" according to my graph)
Correct query was given by cybersam
MATCH (n:Somelabel) WHERE NOT (n)-[:BELONGS_TO]->() RETURN n;
MATCH (n:Somelabel)<-[:BELONGS_TO]-(c:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->() RETURN n, count(c);
Based on your diagram, it looks like you are actually looking for "leaf" nodes. This query will search for all Somelabel nodes that have no outgoing relationships, and return each such node along with a count of the number of distinct nodes that have a relationship pointing to that node.
MATCH (n:Somelabel)
WHERE NOT (n)-[:BELONGS_TO]->()
OPTIONAL MATCH (m)-[:BELONGS_TO]->(n)
RETURN n, COUNT(DISTINCT m);
If you are actually looking for all "root" nodes, your original query would have worked.
As a sanity check, if you have a specific node that you believe is a "leaf" node (let's say it has an id value of 123), this query should return a single row with null values for r and m. If you get non-null results, then you actually have outgoing relationships.
MATCH (n {id:123})
OPTIONAL MATCH (n)-[r]->(m)
RETURN r, m
I have created a graph db in Neo4j and want to use it for generalization purposes.
There are about 500,000 nodes (20 distinct labels) and 2.5 million relations (50 distinct types) between them.
In an example path : a -> b -> c-> d -> e
I want to find out the node without any incoming relations (which is 'a').
And I should do this for all the nodes (finding the nodes at the beginning of all possible paths that have no incoming relations).
I have tried several Cypher codes without any success:
match (a:type_A)-[r:is_a]->(b:type_A)
with a,count (r) as count
where count = 0
set a.isFirst = 'true'
or
match (a:type_A), (b:type_A)
where not (a)<-[:is_a*..]-(b)
set a.isFirst = 'true'
Where is the problem?!
Also, I have to create this code in neo4jClient, too.
Your first query will only match paths where there is a relationship [r:is_a], so counting r can never be 0. Your second query will return any arbitrary pair of nodes labeled :typeA that aren't transitively related by [:is_a]. What you want is to filter on a path predicate. For the general case try
MATCH (a)
WHERE NOT ()-->a
This translates roughly "any node that does not have incoming relationships". You can specify the pattern with types, properties or labels as needed, for instance
MATCH (a:type_A)
WHERE NOT ()-[:is_a]->a
If you want to find all nodes that have no incoming relationships, you can find them using OPTIONAL MATCH:
START n=node(*)
OPTIONAL MATCH n<-[r]-()
WITH n,r
WHERE r IS NULL
RETURN n
I have a scenario where I have more than 2 random nodes.
I need to get all possible paths connecting all three nodes. I do not know the direction of relation and the relationship type.
Example : I have in the graph database with three nodes person->Purchase->Product.
I need to get the path connecting these three nodes. But I do not know the order in which I need to query, for example if I give the query as person-Product-Purchase, it will return no rows as the order is incorrect.
So in this case how should I frame the query?
In a nutshell I need to find the path between more than two nodes where the match clause may be mentioned in what ever order the user knows.
You could list all of the nodes in multiple bound identifiers in the start, and then your match would find the ones that match, in any order. And you could do this for N items, if needed. For example, here is a query for 3 items:
start a=node:node_auto_index('name:(person product purchase)'),
b=node:node_auto_index('name:(person product purchase)'),
c=node:node_auto_index('name:(person product purchase)')
match p=a-->b-->c
return p;
http://console.neo4j.org/r/tbwu2d
I actually just made a blog post about how start works, which might help:
http://wes.skeweredrook.com/cypher-it-all-starts-with-the-start/
Wouldn't be acceptable to make several queries ? In your case you'd automatically generate 6 queries with all the possible combinations (factorial on the number of variables)
A possible solution would be to first get three sets of nodes (s,m,e). These sets may be the same as in the question (or contain partially or completely different nodes). The sets are important, because starting, middle and end node are not fixed.
Here is the code for the Matrix example with added nodes.
match (s) where s.name in ["Oracle", "Neo", "Cypher"]
match (m) where m.name in ["Oracle", "Neo", "Cypher"] and s <> m
match (e) where e.name in ["Oracle", "Neo", "Cypher"] and s <> e and m <> e
match rel=(s)-[r1*1..]-(m)-[r2*1..]-(e)
return s, r1, m, r2, e, rel;
The additional where clause makes sure the same node is not used twice in one result row.
The relations are matched with one or more edges (*1..) or hops between the nodes s and m or m and e respectively and disregarding the directions.
Note that cypher 3 syntax is used here.