Given the following nodes:
create(:ABC{id:'1', a:'axle',b:'bat'})
create(:ABC{id:'2', a:'ant',b:'ball',c:'clown'})
create(:ABC{id:'3', e:'elk',f:'fog',g:'gaff'})
create(:ABC{id:'4', a:'ax',c:'car',z:'zink'})
Using cypher, how would one create edges between nodes that share 1 or more property keys (regardless of their property value and with an unknown set of properties)? I'm fairly certain I could iterate thru nodes individually via python and create edges, but I have tried without success to do this in cypher.
Here is a query that creates a SHARES_KEYS_WITH relationship between every pair of nodes that share at least one property with the same name (ignoring the id property, which all your example nodes have).
MATCH (m),(n)
WHERE (ID(m) > ID(n)) AND ANY (k IN KEYS(m)
WHERE k <> 'id' AND k IN KEYS(n))
CREATE (m)-[:SHARES_KEYS_WITH]->(n)
RETURN m, n;
The ID(m) > ID(n) test ensures that we only evaluate each pair of distinct nodes just once. (Note that the ID() function returns the neo4j-generated internal identifier -- with is not the same as your id property.)
Related
I have a graph of nodes with a relationship NEXT with 2 properties sequence (s) and position (p). For example:
N1-[NEXT{s:1, p:2}]-> N2-[NEXT{s:1, p:3}]-> N3-[NEXT{s:1, p:4}]-> N4
A node N might have multiple outgoing Next relationships with different property values.
Given a list of node names, e.g. [N2,N3,N4] representing a sequential path, I want to check if the graph contains the nodes and that the nodes are connected with relationship Next in order.
For example, if the list contains [N2,N3,N4], then check if there is a relationship Next between nodes N2,N3 and between N3,N4.
In addition, I want to make sure that the nodes are part of the same sequence, thus the property s is the same for each relationship Next. To ensure that the order maintained, I need to verify if the property p is incremental. Meaning, the value of p in the relationship between N2 -> N3 is 3 and the value p between N3->N4 is (3+1) = 4 and so on.
I tried using APOC to retrieve the possible paths from an initial node N using python (library: neo4jrestclient) and then process the paths manually to check if a sequence exists using the following query:
q = "MATCH (n:Node) WHERE n.name = 'N' CALL apoc.path.expandConfig(n {relationshipFilter:'NEXT>', maxLevel:4}) YIELD path RETURN path"
results = db.query(q,data_contents=True)
However, running the query took some time that I eventually stopped the query. Any ideas?
This one is a bit tough.
First, pre-match to the nodes in the path. We can use the collected nodes here to be a whitelist for nodes in the path
Assuming the start node is included in the list, a query might go like:
UNWIND $names as name
MATCH (n:Node {name:name})
WITH collect(n) as nodes
WITH nodes, nodes[0] as start, tail(nodes) as tail, size(nodes)-1 as depth
CALL apoc.path.expandConfig(start, {whitelistNodes:nodes, minLevel:depth, maxLevel:depth, relationshipFilter:'NEXT>'}) YIELD path
WHERE all(index in range(0, size(nodes)-1) WHERE nodes[index] = nodes(path)[index])
// we now have only paths with the given nodes in order
WITH path, relationships(path)[0].s as sequence
WHERE all(rel in tail(relationships(path)) WHERE rel.s = sequence)
// now each path only has relationships of common sequence
WITH path, apoc.coll.pairsMin([rel in relationships(path) | rel.p]) as pairs
WHERE all(pair in pairs WHERE pair[0] + 1 = pair[1])
RETURN path
I have a database where each node is connected to all other nodes with a relationship, and each relationship has a weight. I need a query where given a weight w and a number of nodes n, I want all n nodes where each pair of relationship has a weight greater than w.
Any help on this would be great
It depends on what you would like your result set to look like. Something as simple as this query would return all paths that fall under your criteria:
MATCH p=()-[r:my_rel]->() WHERE r.weight > w RETURN p;
This would return all such paths.
If you would like the two nodes only (and not the entire pattern's results), you can return only those two nodes:
MATCH (n1)-[r:my_rel]->(n2) WHERE r.weight > w RETURN n1,n2;
Do note that due to Neo4J's storage internals, performing a search based on the properties of a relationship tends to not perform as well as those based on properties of a node.
I have 3 labels, A, B, and Z. A & B both have a relationship to Z. I want to find all the A nodes that do not have share any of nodes Z in common with B
Currently, doing a normal query where the relationship DOES exist, works.
MATCH (a:A)-[:rel1]->(z:Z)<-[:rel2]-(b:B { uuid: {<SOME ID>} })
RETURN DISTINCT a
But when I do
MATCH (a:A)
WHERE NOT (a)-[:rel1]->(z:Z)<-[:rel2]-(b:B { uuid: {<SOME ID>} }))
RETURN DISTINCT a
It throws an error
Neo4j::Server::CypherResponse::ResponseError: z not defined
Not sure if the syntax for this is incorrect, I tried WHERE NOT EXIST() but no luck.
The query is part of a larger one called through a rails app using neo4jrb / (Neo4j::Session.query)
This is a problem to do with the scope of your query. When you describe a node in a MATCH clause like the below
MATCH (n:SomeLabel)
You're telling cypher to look for a node with the label SomeLabel, and assign it to the variable n in the rest of the query, and at the end of the query, you can return the values stored in this node using RETURN n (unless you drop n by not including it in a WITH clause).
Later on in you query, if you want to MATCH another node, you can do it in reference to n, so for example:
MATCH (m:SomeOtherLabel)-[:SOME_RELATIONSHIP]-(n)
Will match a variable connected (in any direction) to the node n, with a label SomeOtherLabel, and assign it to the variable m for the rest of the query.
You can only assign nodes to variables like this in MATCH, OPTIONAL MATCH, MERGE, CREATE and (sort of) in WITH and UNWIND clauses (someone correct me here if I've missed one, I suppose you also do this in list comprehensions and FOREACH clauses).
In your second query, you are trying to find a node with the label A, which is not connected to a node with the label Z. However, the way you have written the query means that you are actually saying find a node with label A which is not connected via a rel1 relationship to the node stored as z. This will fail (and as shown, neo complains that z is not defined), because you can't create a new variable like this in the WHERE clause.
To correct your error, you need to remove the reference to the variable z, and ensure you have also defined the variable b containing your node before the WHERE clause. Now, you keep the label in the query, like the below.
MATCH (a:A)
MATCH (b:B { uuid: {<SOME ID>} })
WHERE NOT (a)-[:rel1]->(:Z)<-[:rel2]-(b) // changed this line
RETURN DISTINCT a
And with a bit of luck, this will now work.
You get the error because z is the identifier of a node that you are using in a where clause that you have not yet identified.
Since you know b already I would match it first and then use it in your where clause. You don't need to assign :Z an identifier, simply using the node label will suffice.
MATCH (b:B { uuid: {<SOME ID>} })
WITH b
MATCH (a:A)
WHERE NOT (a)-[:rel1]->(:Z)<-[:rel2]-(b)
RETURN DISTINCT a
This is in continuation of the problem defined here
Query case-specific nodes in Neo4j
So the situation looks like the image below(please bear with the crappy image)
The blue links denotes the [:RELATES_TO] relationship with the number in black boxes denoting the value of Length property. Similar values also exists for all such other [:RELATES_TO] relationship which is not shown here.
Now I would like to find and create unique Nodes based on 'Name' property of Performer Nodes. Continuing with the example in the link there will be only 4 New Unique Nodes [A,B,C,D]. Lets Call them NewUniqueNodes with name as a property.
Then I would like to query each case in turn. Within each case, I need to query [:RELATES_TO] relationship in increasing order of Length property. For any such pair of nodes (x,y) I need to add a relationship [:FINALRESULT{strength:0}] from NewUniqueNode(Name:x) to NewUniqueNode(name:y) with strength being updated to (strength + value). The value is the number associated with value property of [:RELATES_TO] for the pair of nodes(x,y).
[Example and Expected Output]
In case1, the order of visiting nodes will be
Node(ID:3) to Node(ID:4)
Node(ID:1) to Node(ID:2)
Node(ID:1) to Node(ID:3)
On processing these nodes, the result would be
NewUniqueNode(name:A)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:D)
NewUniqueNode(name:A)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:B)
NewUniqueNode(name:B)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:A)
On processing the full set of cases(case1 + case2 + case3), the result would be something like
NewUniqueNode(name:A)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:D)
NewUniqueNode(name:A)-[:FINALRESULT{strength: 3}]-NewUniqueNode(name:B)
NewUniqueNode(name:B)-[:FINALRESULT{strength: 2}]-NewUniqueNode(name:A)
NewUniqueNode(name:C)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:B)
NewUniqueNode(name:A)-[:FINALRESULT{strength: 1}]-NewUniqueNode(name:A)
According to this Neo4j console setup, based on the previous question http://console.neo4j.org/r/vci9yd
I have the following query :
MATCH (n:Performer)
WITH collect(DISTINCT (n.name)) AS names
UNWIND names as name
MERGE (nn:NewUniqueNode {name:name})
WITH names
MATCH (c:Case)
MATCH (p1)-[r:RELATES_TO]->(p2)<-[:RELATES]-(c)-[:RELATES]->(p1)
WITH r
ORDER BY r.length
MATCH (nn1:NewUniqueNode {name:startNode(r).name})
MATCH (nn2:NewUniqueNode {name:endNode(r).name})
MERGE (nn1)-[rf:FINAL_RESULT]->(nn2)
SET rf.strength = CASE WHEN rf.strength IS NULL THEN r.value ELSE rf.strength + r.value END
Explanations :
First we match all performer nodes and collect the distinct name values in the names variable.
Secondly, we iterate the names with the UNWIND clause, creating a NewUniqueNode for each name in the names collection
Then we match all cases, within each case we look for the :RELATES_TO relationships that are inside this case and ordering them by the relationship length value
Then for each relationship found, we match the NewUniqueNode corresponding to the startNode name value, and same for the NewUniqueNode corresponding to the endNode name value
Lastly we merge the :FINAL RESULT relationship between those two unique nodes, we then set the strength property on the relationship depending of the :RELATES_TO relationship length value, for this part I guess you could do the same with ON CREATE and ON MATCH on the MERGE
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