Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Family Tree Questions #748

Open
dandago opened this issue Nov 17, 2019 · 6 comments
Open

Family Tree Questions #748

dandago opened this issue Nov 17, 2019 · 6 comments
Labels

Comments

@dandago
Copy link

@dandago dandago commented Nov 17, 2019

Hi,

I've just gone through an exercise where I attempted to model a family tree using RedisGraph. I have just published this as my second RedisGraph article, Family Tree with RedisGraph.

As a result of this exercise, I have a few questions on things that I wasn't sure how to do.

First, is it possible to get a mixed tree (i.e. ancestors and descendants) in a single query as opposed to separate queries for ancestors and descendants?

Secondly, given two people, is it possible to identify their relationship (e.g. sibling, cousin, uncle, parent, etc) based on the path between then, or would one need to run separate queries for each relationship type?

Finally, what would be a good query to identify cousins? I'm not convinced with the one I'm using (below) as it should exclude the family where the person queried lies.

MATCH (x)-[:childOf*2]->(p)<-[:childOf*2]-(c) WHERE x.name = 'Donald' AND c.name <> 'Donald' RETURN c.name

I was thinking of a solution along the lines of having another MATCH clause to get the queried person's parents in order to exclude their children later in the WHERE, but there might be a more elegant way.

@swilly22

This comment has been minimized.

Copy link
Collaborator

@swilly22 swilly22 commented Nov 17, 2019

Hi @dandago,
Thank you for the tutorials! I must say I enjoy reading them.

I hope you'll find my answers below useful

  1. Ancestors and descendants, "MATCH (ancestor:Person)-[:childOf*1..]->(p:Person)-[:childOf*1..]->(descendant:Person) WHERE p.name = 'Donald' RETURN ancestor, descendant"

  2. Using the type function on an edge will return the relationship type of that edge: "MATCH ()-[e]->() RETURN type(e)"

  3. Identify cousins:

MATCH (x)-[:childOf]-(parent:Person) WHERE x.name = 'Donald' WITH x as x, parent as parent
MATCH (x)-[:childOf*2]->(grandParent:Person)<-[:childOf]-(uncle:Person)<-[:childOf]-(c:Person) WHERE uncle != parent RETURN c.name

RedisGraph will not avoid revisiting visited nodes.

@swilly22 swilly22 added the question label Nov 17, 2019
@dandago

This comment has been minimized.

Copy link
Author

@dandago dandago commented Nov 17, 2019

Hi @swilly22,

Thanks for your kind words and for your answers. Let's go through them:

  1. Ancestors and descendants: The query you provided gives pairs of ascendants and descendants. I'm sorry, I probably didn't explain myself clearly. I this case I'd like to get a single list consisting of both ancestors and descendants of the individual. Pretty much what I'm doing separately for ancestors and descendants, but I was hoping to do it in a single query. Now that I look at the docs again, it looks like I should be able to do this with a UNION.

  2. Relationships: the result of the query you provided gives:

1) 1) "type(e)"
2)  1) 1) "married"
    2) 1) "childOf"
    3) 1) "childOf"
    4) 1) "married"
    5) 1) "childOf"
    6) 1) "childOf"
    7) 1) "married"
    8) 1) "married"
    9) 1) "childOf"
   10) 1) "childOf"
   11) 1) "childOf"
   12) 1) "childOf"
   13) 1) "childOf"
   14) 1) "childOf"
   15) 1) "married"
   16) 1) "childOf"
   17) 1) "childOf"
   18) 1) "childOf"
   19) 1) "childOf"
3) 1) "Query internal execution time: 1.256898 milliseconds"

That's interesting, as I can see the relationship. However what I'd like is to be able to give it two individuals (e.g. Donald and Antoinette) and identify the family relationship (e.g. aunt). I'm not sure whether that's possible with a single query.

  1. Cousins: I've slightly modified your query as follows:
GRAPH.QUERY FamilyTree "MATCH (x)-[:childOf]->(parent:Person) WHERE x.name = 'Donald' WITH x as x, parent as parent MATCH (x)-[:childOf*2]->(grandParent:Person)<-[:childOf]-(uncle:Person)<-[:childOf]-(c:Person) WHERE uncle <> parent RETURN c.name"

I fixed an indirected relation in the first MATCH, changed != to <>, and added a DISTINCT.

I got this:

1) 1) "c.name"
2) 1) 1) "Donald"
   2) 1) "Anthony"
   3) 1) "George"
   4) 1) "Bernard"
   5) 1) "Fiona"

Unfortunately this isn't quite right because although it does return the cousins (Bernard and Fiona), it also returns Donald (the person whose cousins we want) and his children (Anthony and George).

I'll see if I can play with this a little and get to a working solution.

Thanks very much!

@DvirDukhan

This comment has been minimized.

Copy link
Contributor

@DvirDukhan DvirDukhan commented Nov 18, 2019

hi @dandago

  1. Try to play with this query results graph.query FamilyTree "match p=(:Person)-[:childOf*0..]->(:Person {name:'John'})-[:childOf*0..]->(:Person) return nodes(p)". This will return EVERY path from John's ancestors to his decedents. You will get partial paths that are part of longer paths that return in this query, but I believe that it is a start in the direction you want.
  2. Regarding your second question: In your graph Persons can have only childOf ormarried relationships with each other, and that's it. I think that given two people, you will have to work really hard and write a very complex query just to have the answer "aunt" or any answer Inferring their family hierarchy.
  3. More general approach for cousins: graph.query FamilyTree "MATCH (c1:Person)-[:childOf]->(p1:Person)-[:childOf]->(:Person)<-[:childOf]-(p2:Person)<-[:childOf]-(c2:Person) WHERE p1 <> p2 return c1, c2"
@DvirDukhan DvirDukhan added the cypher label Nov 18, 2019
@dandago

This comment has been minimized.

Copy link
Author

@dandago dandago commented Nov 18, 2019

Hi @DvirDukhan,

Thanks for your answers!

The approach you took for No. 1 is interesting to say the least. I had no idea you could get paths like that. It's a shame that UNION is not supported, as it would have been a lot easier.

For No. 2, is there a way to get the shortest path between the two given nodes? Because I could identify the type of family relationship by analysing the relationships in the path. Which I guess is pretty much what I'd do in an actual Cypher query, except that like this I can run a single query instead of one for each type of family relationship.

For No. 3, that's pretty good! I modified it slightly to focus on a specific person, and it works perfectly:

graph.query FamilyTree "MATCH (c1:Person)-[:childOf]->(p1:Person)-[:childOf]->(:Person)<-[:childOf]-(p2:Person)<-[:childOf]-(c2:Person) WHERE p1 <> p2 AND c1.name = 'Donald' return c2.name"
1) 1) "c2.name"
2) 1) 1) "Bernard"
   2) 1) "Fiona"
3) 1) "Query internal execution time: 1.903291 milliseconds"
@swilly22

This comment has been minimized.

Copy link
Collaborator

@swilly22 swilly22 commented Nov 18, 2019

@dandago UNION is supported.

@dandago

This comment has been minimized.

Copy link
Author

@dandago dandago commented Nov 18, 2019

Yes, I just clarified that in #753. A working query for the ancestors & descendants is thus:

GRAPH.QUERY FamilyTree "MATCH (c)-[:childOf*1..]->(p) WHERE c.name = 'Donald' RETURN p.name AS name UNION MATCH (c)-[:childOf*1..]->(p) WHERE p.name = 'Donald' RETURN c.name AS name"
1) 1) "name"
2) 1) 1) "Christina"
   2) 1) "Joseph"
   3) 1) "Victoria"
   4) 1) "John"
   5) 1) "George"
   6) 1) "Anthony"
3) 1) "Query internal execution time: 50.751127 milliseconds"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.