Results 1 to 10 of 10

Thread: SDN. What's wrong with my query Friends of Friends

  1. #1
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default SDN. What's wrong with my query Friends of Friends

    So here is my query in my repo

    Code:
    @Query("start user=node({0}) " +
                "match user-[:FRIEND]-friends-[:FRIEND]-friendsOfFriends, " +
                "user-[r?:FRIEND]-friendOfFriends " +
                "where r IS NULL " +
                "return friendsOfFriends " +
                "order by friendsOfFriends.lastName asc")
        public Page<User> findFriendsOfFriends(Long userId, Pageable pageable);
    When I have

    "user-[r?:FRIEND]-friendOfFriends " +
    "where r IS NULL " +

    I am not getting results back. I am expecting this to filter out friends of friends that are already friends of mine. But instead it ends up filtering everyone out, when it shouldn't.

    If I remove that part, then I get a list of all my friends of friends including ones that are already friends of mine.

    So I figure I did something wrong in that part, but can't figure out what. And if I am pretty sure that I tried that query in the shell and it worked as expected. But I can't be positive again.

    Thanks

    Mark

  2. #2
    Join Date
    May 2012
    Posts
    107

    Default

    Mark,

    It seems to work in the console with a couple of changes: http://console.neo4j.org/r/okf5h1

    Regards,

    Lasse

  3. #3
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Looking at the console, it looks like the data you added made both sides 7->8 and 8->7, whereas in my User object the User friend property is Direction.BOTH, so when I set a friend by calling the addFriend method in User, is will set one to be a friend of the other, and since Direction = BOTH it should automatically do 7->8 and 8->7, but my code only set 7->8

    Will

    match sam-[:FRIEND*2]->friendsOfFriends

    only return friendsOfFriends 2 levels down, or will it also include 1 level down from SAM? Although the second part of the match would remove those 1 level down anyway. I will try that out in my @Query and let you know how it goes.

    Thanks

    Mark

    Thanks

  4. #4
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Hmm, I reran your console adding the users then running your query and a couple times it returned correct results, but a couple times it returned incorrect results.

    I did it for Gamgee, and in the result set was Gamgee the user itself.
    I did it for Took and it returned only Gandalf and Baggins, but Baggins is a direct friend already.

    But if I did it for Meriadock, I got the correct friends of friends only.

    Hmm. OK, I am still putting it in my code to see if in my app it will work. But thanks again.

    Mark

  5. #5
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Bummer, changing the query with yours still produces the exact same results which is not correct. For instance I have a user Cathy, who is friends with everyone. If I go into a user Mark, which only has Cathy as a friend, then the query should return all of Cathy's Friends for Mark, but I get zero results. If I go to a user John who has one friend Tom. Tom has three friends John, Cathy and Mike. When I query for John's friends of friends I correctly get Cathy and Mike as results back.

    It must be that even if I have

    @RelatedTo(type = FRIEND, direction=Direction.BOTH)
    Set<User> friends;

    I have to add to both sides of the relationship?
    Thanks

    Mark

  6. #6
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    OK. I think the query is wrong, because I have found a pattern.

    So Cathy is friends with everyone. Meaning cathy.addFriend() got passed all the other users one at a time, not like tom.addFriend(cathy). but cathy.addFriend(tom) etc.

    So if those other users are friends only with Cathy and no others, then the query will return all of Cathy's friends for that user, which is what I would expect. However, if the other user is friends with Cathy and at least one more user, then I see none of Cathy's friends. So for example Tom is friends with Cathy and Bill only. Cathy is friends with Bill, Tom and 6 others. I would expect to see Tom's friends of friends to be those 6 others, but instead I get no results.

    Hope that helps clarify. So somehow by having anyone else as friends also will negate Cathy's friends from being friends of friends.

    Thanks

    Mark

  7. #7
    Join Date
    May 2012
    Posts
    107

    Default

    Mark,

    Right, now I am confused

    So on a high level, you are trying to find 1) everyone who is 2 degrees out from a user, or 2) everyone who is 2 degrees out from a user but not a friend already?

    So in set terms, are you looking for

    1) sam-[:FRIEND*1]->friends + sam-[:FRIEND*2]->friendsOfFriends

    or

    2) sam-[:FRIEND*2]->friendsOfFriends - sam-[:FRIEND*1]->friends

    Regards,

    Lasse

  8. #8
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    "2) everyone who is 2 degrees out from a user but not a friend already?"

    Exactly, what you thought.

    But when I run that query against my data, but that is not what I am getting when I run that query. It only works as long as the start User only has one friend. If it has two friends then nothing will ever get returned from the query. That is a bug, problem.

    So I have a User A who has one friend C, I also have a User B who is friends with C and D. Now C is friends with A, B, D, E, F, G, H, I, J.

    You would expect running the query with A you'd get back, B, D, E, F, G, H, I, J and that is exactly what I get back.
    You would expect running the query with B you'd get back A, E, F, G, H, I, J. Except, I get back nothing. 0 results back. And I figured it is because B has two friends instead of just one. That is what is happening in my database when I run that query. Could it be because I am running Neo4J Embedded?

    It is just frustrating because we both know that that query as written is correct and we should see the results we are expecting. But when it doesn't I just scratch my head.

    Thanks

    Mark

  9. #9
    Join Date
    May 2012
    Posts
    107

    Default

    Mark,

    Sorry for the delay. I have now convinced myself this must be some sort of user error (that took a while, I was getting similar problem to what you were reporting), with this test:

    Code:
        @Test
        public void shouldRecommendFriends() throws Exception {
            User a = users.save(new User("A"));
            User b = users.save(new User("B"));
            User c = users.save(new User("C"));
            User d = users.save(new User("D"));
            User e = users.save(new User("E"));
            User f = users.save(new User("F"));
            User g = users.save(new User("G"));
    
            a.add(c);
            b.add(c, d);
            c.add(d, e);
            d.add(f);
    
            users.save(a);
            users.save(b);
            users.save(c);
            users.save(d);
            users.save(e);
            users.save(f);
            users.save(g);
    
            assertFriendSuggestions(a, b, d, e);
            assertFriendSuggestions(b, a, e, f);
            assertFriendSuggestions(c, f);
            assertFriendSuggestions(d, a, e);
            assertFriendSuggestions(e, a, b, d);
            assertFriendSuggestions(f, b, c);
        }
    
        private void assertFriendSuggestions(User user, User... expectedFriendSuggestions) {
            List<User> actualFriendSuggestions = users.fofs(user.id, new PageRequest(0, 20)).getContent();
    
            assertThat(actualFriendSuggestions.size(), is(equalTo(expectedFriendSuggestions.length)));
    
            for (int i = 0; i < expectedFriendSuggestions.length; i++) {
                assertThat(actualFriendSuggestions.get(i).name, is(equalTo(expectedFriendSuggestions[i].name)));
            }
        }
    
    
    
    @NodeEntity
    public class User {
        @GraphId
        Long id;
    
        String name;
    
        @RelatedTo(type = "FRIEND")
        private Set<User> friends = new HashSet<User>();
    
        public User() {
    
        }
    
        public User(String name) {
            this.name = name;
        }
    
        public void add(User... users) {
            friends.addAll(asList(users));
        }
    }
    
    
    
    public interface UserRepositoryExtension extends GraphRepository<User> {
        @Query("start user=node({0})  match user-[:FRIEND*2..2]-friendsOfFriends, user-[r?:FRIEND]-friendsOfFriends  where r IS NULL and user <> friendsOfFriends return distinct friendsOfFriends  order by friendsOfFriends.name asc")
        Page<User> fofs(long id, Pageable pageable);
    }
    So, the query is the same as you had, in essence. I've added distinct results and used multi-step relationship match. I can't tell you what the problem was, but this version works. Also, it works with both unidirectional and bidirectional relationships.

    Hope this helps!

    Lasse

  10. #10
    Join Date
    Jan 2009
    Location
    Huntington Beach, CA
    Posts
    718

    Default

    Finally got a chance to test it out. Started a new contract this week.

    But that is perfect. The exact results that you would expect. THANKS SO MUCH Lasse.

    Mark

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •