Add Unique Nodes and relationship between them from Existing Setup in Neo4j - neo4j

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

Related

Is there a way to return data according to properties in Neo4j?

In each of my nodes I have a selection of properties like education_id , work_id, locale etc etc. All these properties can have one or more than one values of the sort of education_id:112 or education_id:165 i.e. Node A might have education_id:112 and Node B might have education_id:165 and again Node C might have education_id:112 and so on.
I want a cypher query that return all nodes for a particular value of the property and I don't care about the value of the property beforehand.
To put it into perspective, in the example I have provided, it must return Node A and Node C under education_id:112 and Node B under education_id:165
Note: I am not providing multiple cypher queries specifying the values of properties each time. The whole output must be dynamic.
The output to the query should be something like
education_id:112 Node A, Node C
education_id:165 Node B
These are the results of a single query statement.
Not quite sure I understand your question, but based on the expected output:
MATCH (n) RETURN n.education_id,collect(n)
will group nodes by distinct values of education_id
You should probably take a look at the cypher refcard. What you are looking for is the WHEREclause:
Match (a) WHERE a.education_id = 112 return a
You can also specify property directly in the MATCH clause.
Match (a{education_id: 112}) RETURN a

Neo4j and Cypher: Create relationships to nodes that have similar property keys

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

Grouping nodes by their relationship

I've built a simple graph of one node type and two relationship types: IS and ISNOT. IS relationships means that the node pair belongs to the same group, and obviouslly ISNOT represents the not belonging rel.
When I have to get the groups of related nodes I run the following query:
"MATCH (a:Item)-[r1:IS*1..20]-(b:Item) RETURN a,b"
So this returns a lot of a is b results and I added some code to group them after.
What I'd like is to group them modifying the query above, but given my rookie level I haven't yet figured it out. What I'd like is to get one row per group like:
(node1, node3, node5)
(node2,node4,node6)
(node7,node8)
I assume what you call groups are nodes present in a path where all these nodes are connected with a :IS relationship.
I think this query is what you want :
MATCH p=(a:Item)-[r1:IS*1..20]-(b:Item)
RETURN nodes(p) as nodes
Where p is a path describing your pattern, then you return all the nodes present in the path in a collection.
Note that, a simple graph (http://console.neo4j.org/r/ukblc0) :
(item1)-[:IS]-(item2)-[:IS]-(item3)
will return already 6 paths, because you use undericted relationships in the pattern, so there are two possible paths between item1 and item2 for eg.

Keep track of Changes in Neo4j - Achieve functionality like a "flag" variable in standard programming

Initial setup of the sample database is provided link to console
There are various cases and within each case, there are performers(with properties id and name). This is the continuation of problems defined problem statement and solution to unique node creation
The solution in the second link is (credits to Christophe Willemsen
)
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
This solution achieved what was asked for.
But I need to achieve something like this.
foreach (Case.id in the database)
{
foreach(distinct value of r.Length)
{
//update value property of node normal
normal.value=normal.value+0.5^(r.Length-2)
//create new nodes and add the result as their relationship or merge it to existing one
MATCH (nn1:NewUniqueNode {name:startNode(r).name})
MATCH (nn2:NewUniqueNode {name:endNode(r).name})
MERGE (nn1)-[rf:FINAL_RESULT]->(nn2)
//
rf.strength=rf.strength + r.value*0.5^(r.Length-2);
}
}
The problem is to track the change in the case and then the r.Length property. How can it be achieved in Cypher?
I will not redo the last part, where setting strengths.
One thing though, in your console link, there is only one Normal node, so why do you need to iterate over each case, you can just match distinct relationships lengths.
By the way for the first part :
MATCH (n:Case)
MATCH (n)-[:RELATES]->()-[r:RELATES_TO]->()<-[:RELATES]-(n)
WITH collect(DISTINCT (r.length)) AS lengths
MATCH (normal:Normal)
UNWIND lengths AS l
SET normal.value = normal.value +(0.5^l)
RETURN normal.value
Explanations :
Match the cases
Foreach case, match the RELATES_TO relationships of Performers for that Case
collect distinct lengths
Match the Normal node, iterate the the distinct lengths collection and setting the proper value on the normal node

How do I get all relationships between nodes on a path

I am trying to follow a certain relationship type and return all the nodes and (other) relationships on that path but not to follow paths through nodes that are not part of the path.
Below is the live query that I have set up to demonstrate.
http://console.neo4j.org/?id=b6sxoh
In the example I do not want the relationship through B->E->C to be included in the results because there is no 'depends_on' relationship between them.
Below is one of my many attempts... (also in the console).
START me=node:node_auto_index(name='A')
MATCH p=me-[d:depends_on*]->others
WITH me,others
MATCH p=me-[r*]-others
RETURN DISTINCT relationships(p);
I would love some help please!
One way to do this is to iterate through each pair of nodes on the matched path for the pattern "p=me-[d:depends_on*]->others", and find any other relationships between them.
START me=node:node_auto_index(name='A')
MATCH me-[:depends_on*0..]->(previous)-[:depends_on]->last
With previous, last
Match previous-[r]-last
Where type(r) <> 'depends_on'
Return r
Since each matched path for the pattern "me-[d:depends_on*]->others" is augmented with a new relationship as the last relationship, to iterate through all the relationships on the matched path is to iterate through each last relationship on the matched paths. So for each matched path, we capture the start node and the end node of the last relationship as "previous" and "last" and then find the relationships "r" between them, filter "r" with the "Where" clause based on the type of the relationship r, return only those relationships r that are not of the type "depends_on".

Resources