Announcement Announcement Module
Collapse
No announcement yet.
SDN. What's wrong with my query Friends of Friends Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    Mark,

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

    Regards,

    Lasse

    Comment


    • #3
      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

      Comment


      • #4
        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

        Comment


        • #5
          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

          Comment


          • #6
            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

            Comment


            • #7
              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

              Comment


              • #8
                "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

                Comment


                • #9
                  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

                  Comment


                  • #10
                    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

                    Comment

                    Working...
                    X