0
votes

I am just starting out with neo4j and cypher. I am building a database to store names and synonyms for different chemicals. The way I currently do this is something like this:

CREATE CONSTRAINT ON (flow:Flow) ASSERT flow.name IS UNIQUE;
CREATE (a:Flow {name: "Ethene"})-[:synonym]->(b:Flow {name: "Ethylene"});

(The --> syntax is required by cypher syntax even though synonym is a bidirectional relationship).

Now-- say I want to add a new flow which is a synonym to both,

CREATE (c:Flow {name: "C2H4"})-[:synonym]->(b:Flow {name: "Ethylene"})

After that, I will have 3 nodes in a linear relationship (a)-[:synonym]->(b)<-[:synonym]-(c). But synonymy is transitive, so the graph of synonyms should really be complete (the a-[:synonym]-c relationship is missing)

Is there a way to automatically create a :synonym relationship to a node and all that node's synonyms?

The following seems to work, except it feels clumsy and also is not idempotent (if it's run again, it creates a c-->c relationship):

// create a new synonym to 'Ethylene' with the name 'C2H04'
MATCH (j:Flow {name:"Ethylene"})-[:synonym]-(k)
WITH j,k
MERGE (c:Flow {name:"C2H04"})-[:synonym]->(j)
MERGE (c)-[:synonym]->(k)

Is there a better way to create these relationships? Alternately, is there a way to collapse all the synonym relationships so that a query will return all synonyms of a node even if they are not directly connected?

2

2 Answers

2
votes

I recommend to change the model. Let's add an intermediate node such as "synonym" to connects all synonyms:

(S:Synonym)
(A1:Flow {name: "Ethene"})-[:synonym]->(S)
(A2:Flow {name: "Ethylene"})-[:synonym]->(S)
(A3:Flow {name: "C2H4"})-[:synonym]->(S)

Example query for creating:

MERGE (A1:Flow {name: "Ethene"})
MERGE (A2:Flow {name: "Ethylene"})
MERGE (A3:Flow {name: "C2H4"})
MERGE (A1)-[:synonym]->(S:Synonym)
MERGE (A2)-[:synonym]->(S)
MERGE (A3)-[:synonym]->(S)

MERGE (A11:Flow {name: "Ferrum"})
MERGE (A12:Flow {name: "Iron"})
MERGE (A13:Flow {name: "Fe"})
MERGE (A11)-[:synonym]->(S2:Synonym)
MERGE (A12)-[:synonym]->(S2)
MERGE (A13)-[:synonym]->(S2)

Sample query for get all group of synonyms:

MATCH (S:Synonym) WITH S
MATCH (S)<-[:synonym]-(F:Flow)
WITH S, collect(F) as synonyms
RETURN synonyms

Sample query for get all synonyms for chemical:

MATCH (A:Flow {name:'Ethene'})
OPTIONAL MATCH (A)-[:synonym]->(S:Synonym)<-[:synonym]-(F:Flow)
RETURN A as chemical, collect(F) as synonyms

Add new chemical as synonym to exist chemical:

MATCH (A:Flow {name:'C2H4'})
  MERGE (A)-[:synonym]->(S:Synonym)
  MERGE (New:Flow {name:'Aethylen'})
  MERGE (New)-[:synonym]->(S)

Update:

If you do not want to change your model, you can use a query with a variable path length to get all synonyms for chemical:

MATCH (A:Flow {name: "Ethylene"})
OPTIONAL MATCH (A)-[:synonym*]-(F:Flow)
RETURN A as chemical, collect(F) as synonyms
1
votes

It would be much simpler overall if all the synonyms for the same chemical resided within a single node. For example:

(:Flow {names: ["Ethylene", "Ethene", "C2H4"]})