0
votes

I'm using neo4j with wordnet to be able to calculate the similarity between words. However I'm not too good with cypher yet.

What I want is to be able to get the path between two nodes in a hierarchal pattern, but I need to know the ancestor in the middle of them. So if you consider this graph and assume each block is a word and we have the c node and b node already and want to get the path and for it to be able to return the ancestor node, a.

The query i was trying with was MATCH (synset:wdo#Synset {id:"wn/100015568-n"}), (synset1:wdo#Synset {id:"wn/113957498-n"}), path = shortestPath((synset)-[:wdo#hyponym|wdo#hypernym*]-(synset1)) return path

which got me the path but I can't get the shared ancestor from it. Any help would be appreciated thank you.

2
I'm not familiar with wordnets, but the wikipedia article tells me that the hyponym and hypernym relationships are opposites of each other. Is that correct? If the data is modelled with a mix of these edges, that will make finding the common root of the tree more difficult. - Gabor Szarnyas
By the way, is your graph always a tree? If it is (and only uses single edges between nodes) then you can omit shortestPath and use a plain path instead. - Gabor Szarnyas
Hey yea, they are opposite of each other, so it's essentially bidirectional, hypernym is the parent node and hyponym is the child. With this query specifically it will always be using node types wdo#Synset and relation either one of the two. I tried doing a query like this MATCH path = (synset:wdo#Synset {id:"wn/100015568-n"})-[:wdo#hyponym|wdo#hypernym]->(middle:wdo#Synset)<-[:wdo#hyponym|wdo#hypernym]-(synset1:wdo#Synset {id:"wn/113957498-n"}) return synset But it seemed like it wasn't even going to ever finish the query. The shortestPath was almost instant. - Ryan Kauk

2 Answers

1
votes

You probably want something that recursively goes down relationships, like in this StackOverflow answer.

In your case, to get the common ancestor, you could try

MATCH (child1:node) <- [:RELATIONSHIP*1..] - (ancestor:node) - [:RELATIONSHIP*1..] -> (child2:node)
WHERE child1.id = c
AND ancestor.id = a
AND child2.id = b
RETURN a

The code is untested, and you'll need to fill in the right kind of node labels and relationships for your case.

0
votes

You could take all consequent (x, y, z) node triples in the path and check if y is an ancestor of x and z:

MATCH ...
WITH nodes(path) AS np
UNWIND range(1, length(np)) AS i
WITH np[i-1] AS x, np[i] AS y, np[i+1] AS z
WHERE ((x)-[:hypernym]->(y) OR (x)<-[:hyponym]->(y))
  AND ((z)-[:hypernym]->(y) OR (z)<-[:hyponym]->(y))
RETURN y

(The query is untested and may require some tuning. Also, please check my comments on data modeling.)