cancel
Showing results for 
Search instead for 
Did you mean: 

Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.

Return +2nd degree connections

Hi all,

I'm new to neo4j so apologies in advance if I'm not explaining myself correctly. I'm starting to build a recommendation system from scratch. For the moment I'm making my query tests with a dummy DB:
2X_0_012c0366fa7a33cfad10568cd40e5747c3f731f3.png
It represents a network of players that played a match together (that's why relationships are reciprocal).

I'm trying to find 2nd (or more) degree connections for each player:

  • P1 > P5
  • P2 > P3, P4, P5
  • P3 > P2, P4, P5
  • P4 > P2, P3, P5
  • P5 > P1, P2, P3

Let's say I want to look at the recommendations for P5. I tried with the following query:

MATCH (originalplayer:Player{playerId:"P5"})-[*2..5]->(recommended:Player)
WHERE recommended.playerId<>"P5"
RETURN DISTINCT recommended.playerId

Which results in this:
2X_4_4c174e458e76f117b71eda92055970fb82ecad44.png

I think I understand why is returning P4. Basically because my graph is bidirectional, correct?

But then, what should I do?
Should I build the relationships differently?
Should I exclude direct connections? I haven't learned how to do that yet but not sure if that solution would be optimal when trying to return all users and its recommendations in a single query

Many thanks!
Raul.

1 ACCEPTED SOLUTION

Since a :played_with relationship always implies reciprocality in your graph (if the relationship is present in one direction, then it is present in the other direction), then you should only use single relationships for these between nodes, not one in each direction.

This will simplify your graph structure, and it will allow your queries to work as you expect. You will want to omit the relationship direction in your MATCH pattern however, since you're just interested in the presence of a relationship in the pattern.

Cypher matches have a type of uniqueness behavior such that, per path, a relationship may only be traversed once. Once you refactor your graph to only have single relationships between nodes, the query will only allow those relationships to be matched once per path per MATCH, so once a relationship is traversed, it can't be used to backtrack in the path.

View solution in original post

3 REPLIES 3

Since a :played_with relationship always implies reciprocality in your graph (if the relationship is present in one direction, then it is present in the other direction), then you should only use single relationships for these between nodes, not one in each direction.

This will simplify your graph structure, and it will allow your queries to work as you expect. You will want to omit the relationship direction in your MATCH pattern however, since you're just interested in the presence of a relationship in the pattern.

Cypher matches have a type of uniqueness behavior such that, per path, a relationship may only be traversed once. Once you refactor your graph to only have single relationships between nodes, the query will only allow those relationships to be matched once per path per MATCH, so once a relationship is traversed, it can't be used to backtrack in the path.

Thank you Andrew!
it works perfectly!
Silly me, I thought it was essential to create reciprocal relationships but as long as I don't indicate direction on my match query it will work as I wanted it to work.

MATCH (p1:Player)-[:played_with*2..5]-(p2:Player)
RETURN distinct p1.playerId, p2.playerId

2X_9_916be1982950b66026fcfea3a2d94ac5e0a99443.png

thanks again.

Just a quick note on that last query, you will get mirrored results (same nodes, but switching variables) which may not be what you want. You can add a restriction on the graph ids of the nodes to ensure you don't get the mirrored version:

MATCH (p1:Player)-[:played_with*2..5]-(p2:Player)
WHERE id(p1) < id(p2)
RETURN distinct p1.playerId, p2.playerId