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}
Related
I have nodes that represent documents, and nodes that represent entities. Entities can be referenced in document, if so, they are linked together with a relationship like that :
(doc)<-[:IS_REFERENCED_IN]-(entity)
The same entity can be referenced in several documents, and a document can reference several entities.
I'd like to delete, for a given document, every entity that are referenced in this given document only.
I thought of two different ways to do this.
The first one uses java to make a foreach and would basically be something like that :
List<Entity> entities = MATCH (d:Document {id:0})<-[:IS_REFERENCED_IN]-(e:Entity) return e
for (Entity entity : entities){
MATCH (e:Entity)-[r:IS_REFERENCED_IN]->(d:Document) WITH *, count(r) as nb_document_linked WHERE nb_document_linked = 1 DELETE e
}
This method would work but i'd like not to use a foreach or java code to make it. I'd like to do it in one cypher query.
The second one uses only one cypher query but doesn't work. It's something like that :
MATCH (d:Document {id:0})<-[:IS_REFERENCED_IN]-(e:Entity)-[r:IS_REFERENCED_IN]->(d:Document) WITH *, count(r) as nb_document_linked WHERE nb_document_linked = 1 DELETE e
The problem here is that nb_document_linked is not unique for every entity, it is a unique variable for all the entities, which mean it'll count every relationship of every entity, which i don't want.
So how could I make a kind of a foreach in my cypher query to make it work?
Sorry for my english, I hope the question is clear, if you need any information please ask me.
You can do something like:
MATCH (d:Document{key:1})<-[:IS_REFERENCED_IN]-(e:Entity)
WITH e
MATCH (d:Document)<-[:IS_REFERENCED_IN]-(e)
WITH COUNT (d) AS countD, e
WHERE countD=1
DETACH DELETE e
Which you can see working on this sample data:
MERGE (a:Document {key: 1})
MERGE (b:Document {key: 2})
MERGE (c:Document {key: 3})
MERGE (d:Entity{key: 4})
MERGE (e:Entity{key: 5})
MERGE (f:Entity{key: 6})
MERGE (g:Entity{key: 7})
MERGE (h:Entity{key: 8})
MERGE (i:Entity{key: 9})
MERGE (j:Entity{key: 10})
MERGE (k:Entity{key: 11})
MERGE (l:Entity{key: 12})
MERGE (m:Entity{key: 13})
MERGE (d)-[:IS_REFERENCED_IN]-(a)
MERGE (e)-[:IS_REFERENCED_IN]-(a)
MERGE (f)-[:IS_REFERENCED_IN]-(a)
MERGE (g)-[:IS_REFERENCED_IN]-(a)
MERGE (d)-[:IS_REFERENCED_IN]-(b)
MERGE (e)-[:IS_REFERENCED_IN]-(b)
MERGE (f)-[:IS_REFERENCED_IN]-(c)
MERGE (g)-[:IS_REFERENCED_IN]-(c)
MERGE (j)-[:IS_REFERENCED_IN]-(a)
MERGE (h)-[:IS_REFERENCED_IN]-(a)
MERGE (i)-[:IS_REFERENCED_IN]-(a)
MERGE (g)-[:IS_REFERENCED_IN]-(c)
MERGE (k)-[:IS_REFERENCED_IN]-(c)
MERGE (l)-[:IS_REFERENCED_IN]-(c)
MERGE (m)-[:IS_REFERENCED_IN]-(c)
On which it removes 3 Entities.
The first MATCH finds the entities that are attached to your input doc, and the second MATCH finds the number of documents that each of these entities is connected to.
In other words, is there a way to find a path between N1 and N2 that includes max steps > 1, but only one node of a specific label:X in it?
I have a grpah with nodes of 3 labels: A, B, C, looking like this (A labels are numbered for the sake of clarity):
A1->B->B->C->B->A2->B->B->B->C->B->A3->B->B->B->B->A4
| ^
V |
B->B->B->B-B->C->B-----------------+
I want to find all pairs of A's that the path between them includes only one Node with label:C (but allow 2-15 B's)
So my wanted results are:
A1-A2, A2-A3, A3-A4, A2-A4, but not A1-A3, or A1-A4
I started with this:
MATCH(a: A)-[]->(:B)-[*..14]->(:C)-[*..14]->(:B)-[]->(b:A)
RETURN DISTINCT a.key, b.key
But this returns also paths with 2 nodes with label C in it (A1-A3, A1-A4)
Looking at APOC, I tried using apoc.path.expandConfig, but as far as I understand sequence is not relevant for an unknown number of steps in the pattern.
So I tried using terminatorNodes, for example:
MATCH(n:A)
CALL apoc.path.expandConfig(n, {terminatorNodes:[n]})
YIELD path
RETURN apoc.convert.toJson(path)
But got no relevant results.
Please advise
P.S: I think the case of exactly one node with label:C is solvable, but what if cases with no C's in the path are allowed, or if I would allow cases with exactly two nodes of label:C in the path...
my data:
MERGE (a1:A {key:1})
MERGE (a2:A {key:2})
MERGE (a3:A {key:3})
MERGE (a4:A {key:4})
MERGE (b5 :B {key:5})
MERGE (b6 :B {key:6})
MERGE (b7 :B {key:7})
MERGE (b8 :B {key:8})
MERGE (b9 :B {key:9})
MERGE (b10:B {key:10})
MERGE (b11:B {key:11})
MERGE (b12:B {key:12})
MERGE (b13:B {key:13})
MERGE (b14:B {key:14})
MERGE (b15:B {key:15})
MERGE (b16:B {key:16})
MERGE (b17:B {key:17})
MERGE (b18:B {key:18})
MERGE (b19:B {key:19})
MERGE (b20:B {key:20})
MERGE (c21:C {key:21})
MERGE (c22:C {key:22})
MERGE (c23:C {key:23})
MERGE (c24:C {key:24})
MERGE (a1 )-[:POINTS]-(b5 )
MERGE (b5 )-[:POINTS]-(b6 )
MERGE (b6 )-[:POINTS]-(c21)
MERGE (c21)-[:POINTS]-(b7 )
MERGE (b7 )-[:POINTS]-(a2 )
MERGE (a2 )-[:POINTS]-(b8 )
MERGE (b8 )-[:POINTS]-(b9)
MERGE (b9 )-[:POINTS]-(b10)
MERGE (b10)-[:POINTS]-(c22)
MERGE (c22)-[:POINTS]-(b11)
MERGE (b11)-[:POINTS]-(a3 )
MERGE (a3 )-[:POINTS]-(b12)
MERGE (b12)-[:POINTS]-(c23)
MERGE (c23)-[:POINTS]-(b13)
MERGE (b13)-[:POINTS]-(b14)
MERGE (b14)-[:POINTS]-(a4 )
MERGE (a2 )-[:POINTS]-(b15)
MERGE (b15)-[:POINTS]-(b16)
MERGE (b16)-[:POINTS]-(b17)
MERGE (b17)-[:POINTS]-(b18)
MERGE (b18)-[:POINTS]-(b19)
MERGE (b19)-[:POINTS]-(c24)
MERGE (c24)-[:POINTS]-(b20)
MERGE (b20)-[:POINTS]-(a4 )
Thank you for your help
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)
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)
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.