0

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.

Ryan Kauk
  • 63
  • 1
  • 1
  • 4
  • I'm not familiar with wordnets, but the [wikipedia article](https://en.wikipedia.org/wiki/Hyponymy_and_hypernymy) 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 Oct 08 '17 at 04:56
  • 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 Oct 08 '17 at 05:31
  • 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 Oct 08 '17 at 06:10

2 Answers2

1

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.

Antimony
  • 2,230
  • 3
  • 28
  • 38
  • I think I'll be using this one, however do you know how to speed this query up? At best this kind of query took 3606 ms. – Ryan Kauk Oct 10 '17 at 17:28
  • If you can just fix the syntax error in yours I'll make yours the answer. The arrow to the immediate right of the ancestor node should just be a dash not an arrow. "(ancestor:node) - [:RELATIONSHIP*1..] -> (child2:node)" – Ryan Kauk Oct 10 '17 at 19:52
  • Oops, yes, fixed that! And no, sorry, I don't know how to speed this up. – Antimony Oct 10 '17 at 20:11
  • Just a question I'm trying to expand this to more than two nodes now, do you have any idea how to change your original query to allow this? – Ryan Kauk Oct 12 '17 at 19:46
  • Something like this could work: `MATCH (child1:node) <- [:RELATIONSHIP*1..] - (ancestor:node) - [:RELATIONSHIP*1..] -> (child2:node), (ancestor:node - [:RELATIONSHIP*1..]->(child3:node)` but I'm not sure. It may take prohibitively long too. – Antimony Oct 13 '17 at 16:45
0

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

Gabor Szarnyas
  • 4,410
  • 3
  • 18
  • 42