AND/OR trees queries in Neo4j - neo4j

I'm representing AND/OR trees in Neo4j as in the figure below (with AND and OR nodes and corresponding relationships). The tree's leaves are properties representing boolean values (green = true, red = false).
Now, I'm looking for an algorithm (or cypher query) to traverse each tree to know whether there is at least a valid path (a set of leaves that satisfies the AND/OR conditions) from the leaves or not to the tree's root. For example, in the figure there is such a path, thus the algorithm should return true (and perhaps also the nodes part of the path).
AND/OR tree in Neo4J
example data:
MERGE (a:ROOT_NODE{key:'a'})
MERGE (b:AND_NODE{key:'b'})
MERGE (c:OR_NODE{key:'c'})
MERGE (d:OR_NODE{key:'d'})
MERGE (e:AND_NODE{key:'e'})
MERGE (f:RED{key:'f'})
MERGE (g:GREEN{key:'g'})
MERGE (h:RED{key:'h'})
MERGE (i:RED{key:'i'})
MERGE (j:GREEN{key:'j'})
MERGE (k:GREEN{key:'k'})
MERGE (k)-[:AND]->(e)
MERGE (j)-[:AND]->(e)
MERGE (e)-[:OR]->(d)
MERGE (i)-[:OR]->(d)
MERGE (f)-[:OR]->(c)
MERGE (g)-[:OR]->(c)
MERGE (h)-[:OR]->(c)
MERGE (c)-[:AND]->(b)
MERGE (d)-[:AND]->(b)
MERGE (b)-[:OR]->(a)

Related

Neo4j create graph that some nodes have more than one relationships

Over my Neo4j I want to create this graph:
SO I tried to create some nodes and relationships with:
MERGE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})-[:LINKS]->(B:POINT {NAME:'b'})-[:LINKS]->(C:POINT {NAME:'c'})
But I cannot find out how I will create the relationships between D and B points also I cannot find out how I will link the A and C as well.
Do you have any Idea how to do that?
In order to avoid unintentionally creating duplicate nodes and/or relationships, you must invoke MERGE on individual nodes and relationships.
To quote the dev manual:
When using MERGE on full patterns, the behavior is that either the
whole pattern matches, or the whole pattern is created. MERGE will not
partially use existing patterns — it’s all or nothing. If partial
matches are needed, this can be accomplished by splitting a pattern up
into multiple MERGE clauses.
For example, to properly create your graph without any duplicate nodes or relationships:
MERGE (A:POINT {NAME:'a'})
MERGE (B:POINT {NAME:'b'})
MERGE (C:POINT {NAME:'c'})
MERGE (D:POINT {NAME:'d'})
MERGE (A)-[:LINKS]->(B)
MERGE (A)-[:LINKS]->(C)
MERGE (A)-[:LINKS]->(D)
MERGE (B)-[:LINKS]->(C)
MERGE (D)-[:LINKS]->(B)
CREATE seems to be the natural way to me for creating nodes and relationships.
CREATE (D:POINT {NAME:'d'})<-[:LINKS]-(A:POINT {NAME:'a'})
, (A)-[:LINKS]->(B:POINT {NAME:'b'})<-[:LINKS]-(D)
, (B)-[:LINKS]->(C:POINT {NAME:'c'})<-[:LINKS]-(A)
You can do it by doing a MATCH before a MERGE eg. FOR the relationship between A and D do:
MATCH (A:POINT {NAME:'a'}),(B:POINT {NAME:'d'}) MERGE (A)-[:LINKS]->(B)

Neo4j: How to speed up a query with multiple merges?

I have a query that creates a node, and relates a large number of nodes to it.
Example:
CREATE (target :x {index:'a'})
WITH target
MERGE (x1:x {index:'1'}) MERGE (x1)-[:r]->(target)
MERGE (x2:x {index:'2'}) MERGE (x2)-[:r]->(target)
MERGE (x3:x {index:'3'}) MERGE (x3)-[:r]->(target)
...
MERGE (x1000:x {index:'1000'}) MERGE (x1000)-[:r]->(target)
I have already set an indexes with CREATE CONSTRAINT ON (x:x) ASSERT x.index IS UNIQUE. However, this query is currently taking ~45 minutes to complete.
Is there anything I can do to speed it up? Is adding more CPU power the only option from here?
When you stack MERGE or MATCH statements like that, you can end up with performance issues (related to result rows). For a case like this, use an iterative loop:
CREATE (target :x {index:'a'})
WITH target
FOREACH(i IN RANGE(1, 1000)|
MERGE (a:x {index: toString(i)})
MERGE (a) - [:r] -> (target) )

Neo4j: Multiple Relationships Merge Issue

I've a neo4j schema in which I've 3 nodes. e.g. p,b,c
I want to write a Merge query such that
MERGE (p)-[:has_b]->(b),
MERGE (p)-[:has_c]->(c1),
MERGE (p)-[:has_c]->(c2)
where c1 and c2 are instance of c node having different property values.
i.e. Merge on all three relationships.
If any of 3 merge queries creates a new node, all relationships should use newly created p node.
I can achieve this if I had only two relationships using
(c)<-[:has_c]-MERGE (p)-[:has_b]->(b)
Any suggestions how to do it for 3 relationships as in my case?
FYI, I'm using py2neo which isn't helping at all.
Nodes don't have instances. A node is a node and it has a label.
You can MERGE your nodes first to make sure they exist and that all relationships use the same p:
MERGE (p:LabelA {k: "v"})
MERGE (b:LabelB {k: "v"})
MERGE (c1:LabelC {k: "v"})
MERGE (c2:LabelC {k: "v"})
MERGE (p)-[:has_b]->(b)
MERGE (p)-[:has_c]->(c1)
MERGE (p)-[:has_c]->(c2)
This will create the nodes and relationships only once.

Neo4j merge nodes with relationships

I have got a question how I can merge the nodes for Documents (Doc1, Doc2 and Doc3), to get nice 3 start schemas.
for index, row in import_ds.iterrows():
ind = ind+1
graph.cypher.execute("MERGE (Document:Document"+str(fnum)+" {Document:\"Doc"+str(fnum)+"\"})")
graph.cypher.execute("MERGE (Type:Type {Type:\""+str(row['type'])+"\"})<-[:HAS_TYPE]-(Word:Word {Word:\""+str(row['token_low'])+"\"})-[:IS_IN]->(Document:Document"+str(fnum)+" {Document:\"Doc"+str(fnum)+"\"})")
(WordType)<-[:HAS_TYPE]-(Word)-[:IS_IN]->(Document) http://www.yottalabs.co.uk/ss.png
[code output - Neo4j browser][1]
you should use parameters, not string substitution
merge tries to find the whole path, if it doesn't it creates the whole path
Usually you would merge the nodes first then the rels:
MERGE (type:Type {Type: {type}})
MERGE (word:Word {Word:{token_low}})
MERGE (document:Document {Document:{doc}})
MERGE (type)<-[:HAS_TYPE]-(word)
MERGE (word)-[:IS_IN]->(document)
Merge data on document node
MERGE (document:Document {Document:{doc}})
SET document.foo = {new_data}.foo, document.bar = {param_bar}

Is it better to make one MERGE request for multiple nodes / edges creation in Neo4J Cypher 2.0 or to split it into transactions?

I have a long Cypher query (the new Neo4J 2.0 version), which creates multiple nodes and connections using the MERGE command.
The question is: do you think I'm better off splitting it into different parts and submitting it as a transaction (for robustness) or should I keep the long single one (for speed)?
Here's the query:
MATCH (u:User {name: "User"}) MERGE (tag1:Hashtag {name:"tag1"}) MERGE (tag2:Hashtag
{name:"tag2"}) MERGE (tag3:Hashtag {name:"tag3"}) MERGE (tag4:Hashtag {name:"tag4"})
MERGE tag1-[:BY]->u MERGE tag2-[:BY]->u MERGE tag3-[:BY]->u MERGE tag4-[:BY]->u;
(I purposefully made the request shorter, imagine that there are like 50 tags (nodes) and even more edges for example)
As long as your query statement is not hundreds of lines and your data created doesn't exceed 50k elements, I'd stick with one query.
But you should use parameters instead.
I would also rewrite your query with foreach and parameters
MATCH (u:User {name: {userName})
FOREACH (tagName in {tags} |
MERGE (tag:Hashtag {name:tagName})
MERGE (tag)-[:BY]->(u)
)
params:
{userName:"User", tags: ["tag1",...,"tagN"]}

Resources