Friends of Friends Gremlin query with FramedGraph

376 views
Skip to first unread message

bytor...@gmail.com

unread,
Mar 31, 2015, 7:33:50 PM3/31/15
to aureliu...@googlegroups.com
OK, we have a very very simple Node and Relationships. We have PlayerPresenceGraphTitan Java objects representing our Nodes, and the relationships between those objects are friends, friend invites, friend rejections. So just friends. I added a method in the PlayerPresenceGraphTitan object to get friends of friends with a gremlin query. (Gremlin confuses me a lot so I can never get it right)

This is what I have.

@GremlinGroovy("it.as('x').both('playerActive').as('f').both('playerActive').except('x').except('f')")
public Iterable<PlayerPresenceGraphTitan> getFriendsOfFriends();

'playerActive' is just another word for friends.

And we have to make sure it doesn't return those that are already friends and ourselves.

Right now it is returning all friends and friends of friends, and I can't seem to get rid of the friends. (Heck I feel the same in real life too)

What am I missing, besides the original font I started typing this in?

Thanks

Mark

bytor...@gmail.com

unread,
Mar 31, 2015, 8:08:59 PM3/31/15
to aureliu...@googlegroups.com
Changed it to

GremlinGroovy("it.as('x').both('playerActive').as('f').out('playerActive').except('x').except('f')")

And it got real close. Issue I had this time is that there is a friend of a friend that is currently a friend that was also added. 

I have a workaround where I then use Groovy to deleteAll {} comparing to my friends. But requires two queries to Titan, one for the above gremlin query and one to return the user, then grab their friends. Actually I think that is three calls to the db. I'll use that for now till something better comes along.

Thank Mark

bytor...@gmail.com

unread,
Mar 31, 2015, 8:20:11 PM3/31/15
to aureliu...@googlegroups.com
OK, I know I am getting closer and just need one more method to add to get rid of duplicates.

This is what works except for a duplicate friend of a friend. 

@GremlinGroovy("it.as('x').both('playerActive').as('f').both('playerActive').except('f','x')")

Thanks

Mark

Nick DeYoung

unread,
Mar 31, 2015, 8:34:26 PM3/31/15
to aureliu...@googlegroups.com
can't use dedup() ? 

--
You received this message because you are subscribed to the Google Groups "Aurelius" group.
To unsubscribe from this group and stop receiving emails from it, send an email to aureliusgraph...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/aureliusgraphs/a8417003-ee47-45b0-8d41-2b50c032947d%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
// ndy 

bytor...@gmail.com

unread,
Mar 31, 2015, 10:39:44 PM3/31/15
to aureliu...@googlegroups.com
Didn't help anyway. I kept getting incorrect results. I know how to write it in Cypher, but Gremlin is giving me fits. It should be really easy, give me all nodes via Both(friends) and then from there both(friends) removing first friends list. 

Thanks

Mark

Nick DeYoung

unread,
Apr 1, 2015, 12:58:05 AM4/1/15
to aureliu...@googlegroups.com
what do you want from your graph? it's not very clear from your post. 

you have this notion of friends which you define as any vertex with an out edge or in edge with a label of 'playerActive'

So to get friends would be g.V().both('playerActive')

But is seems like you don't want friends, but rather the friends of all friends. Which I think you define as any vertex to or from a friend (as defined above) via an edge with the label 'playerActive'. Which would just be your start set of Friends again. 

Does Directionality matter to you? 

I would think that to only get the friends of friends you would want 

g.V().both('playerActive').outE('playerActive') 

//ndy






For more options, visit https://groups.google.com/d/optout.



--
// ndy 

bytor...@gmail.com

unread,
Apr 1, 2015, 1:21:42 PM4/1/15
to aureliu...@googlegroups.com
Thanks Nick. While that is the easy part. The problem with that query is it includes friends of friends that are already your friend. You only want those that are two away and not those two away down one path that is also one away on another path. You have to remove the direct friends from the friends of friends list. It is a very very common graph query. People you might know that aren't your friends already.

Also I am using Gremlin String directly in an annotation, I have tried code directly like g().V() and it never works in my code, so the Gremlin String in the annotation with TinkerPop TitanGraph is much easier to write and for me understand.

Thanks

Mark

bytor...@gmail.com

unread,
Apr 1, 2015, 1:26:22 PM4/1/15
to aureliu...@googlegroups.com
Nick. Right now I am using that query, and then have to remove all the direct friends from the results in code. But I would love to be able to get the correct results in just one gremlin query.

Mark

Nick DeYoung

unread,
Apr 1, 2015, 1:35:22 PM4/1/15
to aureliu...@googlegroups.com
try attached 

On Wed, Apr 1, 2015 at 10:26 AM, <bytor...@gmail.com> wrote:
Nick. Right now I am using that query, and then have to remove all the direct friends from the results in code. But I would love to be able to get the correct results in just one gremlin query.

Mark

--
You received this message because you are subscribed to the Google Groups "Aurelius" group.
To unsubscribe from this group and stop receiving emails from it, send an email to aureliusgraph...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
// ndy 
img-150401103252-0001 (1).pdf

bytor...@gmail.com

unread,
Apr 1, 2015, 2:25:38 PM4/1/15
to aureliu...@googlegroups.com
Wow thanks Nick. Will give that a try and let you know.

Mark

Daniel Kuppitz

unread,
Apr 1, 2015, 2:58:17 PM4/1/15
to aureliu...@googlegroups.com
Actually you'll need two queries (1 per depth). A DFS query can't do what you want.

This is the query you're looking for:

v = g.v(1); x = [] as Set; v.both('playerActive').fill(x)._().both('playerActive').except(x + v)

However, I suspect this won't help you with your FramedGraph code. A slow solution that would work with a single DFS query is:

v.both('playerActive').both('playerActive').except([v]).filter {!it.both('playerActive').retain([v]).hasNext()}

Cheers,
Daniel


bytor...@gmail.com

unread,
Apr 1, 2015, 3:19:27 PM4/1/15
to aureliu...@googlegroups.com
Nick. That query doesn't work. I have 8 nodes. starting at node 3, it is friends with node 2 and 4. 2 is friends with 1, 4, 5, 6, 7. So 4 is a friend of 3 and also a friend of 2, hence a friend of a friend that is already a friend. (Attached drawing) When I run your query, it only returns node 1.

RESULTS: friend name: UserName1, ID: UUIDForAccount1

Here is our mapping with my query, which is returning 1, 4, 5, 6, 7. So I have to filter out 4 in Groovy code directly.

//friends
@Adjacency(label=PLAYER_ACTIVE, direction=Direction.BOTH)
public Iterable<PlayerPresenceGraphTitan> getActiveFriends();

@Adjacency(label=PLAYER_ACTIVE, direction=Direction.OUT)
public Iterable<PlayerPresenceGraphTitan> addFriend(PlayerPresenceGraphTitan player);

@Adjacency(label=PLAYER_ACTIVE, direction=Direction.OUT)
public Iterable<PlayerPresenceGraphTitan> removeFriend(PlayerPresenceGraphTitan player);

@GremlinGroovy("it.as('x').both('playerActive').as('y').out('playerActive').as('z').except('y').except('x').dedup()")
public Iterable<PlayerPresenceGraphTitan> getFriendsOfFriends();


This is similar to Daniel's approach, except the "second" query is just a Groovy Collections removeAll (Closure) call to remove the friends of friends that are already out friends. 

data.removeAll {PlayerPresenceGraphTitan toRemove ->
  user
.activeFriends.contains(toRemove)
}


I really appreciate all your help Nick and Daniel. I am just going to stick with what we now have that is working as we want.

Thanks again

Mark
IMG_0402.JPG

bytor...@gmail.com

unread,
Apr 1, 2015, 3:24:31 PM4/1/15
to aureliu...@googlegroups.com
One last quick comment. Nick, I did learn something from you that really helped. I changed the query to use more descriptive names.

@GremlinGroovy("it.as('me').both('playerActive').as('firstDegree').out('playerActive').as('secondDegree').except('firstDegree').except('me')")

Thanks

Mark

bytor...@gmail.com

unread,
Apr 1, 2015, 3:46:23 PM4/1/15
to aureliu...@googlegroups.com
OK one more. More for the laugh. So typical here, they change what they want. So now they are ok with seeing friends of friends that are already your friend. I still need to loop through code, just so I can notate that they are already a friend, so that the invite button won't be next to those.

Mark

Nick DeYoung

unread,
Apr 1, 2015, 5:37:02 PM4/1/15
to aureliu...@googlegroups.com
g = TinkerGraph.open()

g.addVertex("person")
g.addVertex("person")
g.addVertex("person")
g.addVertex("person")
g.addVertex("person")
g.addVertex("person")
g.addVertex("person")
g.addVertex("person")

v0 = g.v(0L)
v1 = g.v(1L)
v2 = g.v(2L)
v3 = g.v(3L)
v4 = g.v(4L)
v5 = g.v(5L)
v6 = g.v(6L)
v7 = g.v(7L)

// per your email
v3.addEdge("playerActive", v2 )
v3.addEdge("playerActive", v4 )

// per your email 
v2.addEdge("playerActive", v1)
v2.addEdge("playerActive", v4)
v2.addEdge("playerActive", v5)
v2.addEdge("playerActive", v6)
v2.addEdge("playerActive", v7)

g.v(3L).both("playerActive").both().simplePath().both("playerActive").simplePath()


--
You received this message because you are subscribed to the Google Groups "Aurelius" group.
To unsubscribe from this group and stop receiving emails from it, send an email to aureliusgraph...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
// ndy 
friends of friends that aren't my friends.mp4

Charlie Harrison

unread,
Apr 24, 2015, 9:35:02 AM4/24/15
to aureliu...@googlegroups.com
Although that query produces the correct result for this particular graph, it is not actually correct for the general problem.  Consider what happens if you remove node 4: you would still want the same result set (nodes 1, 5, 6, and 7), but with your query you would get no results, because there are no third degree paths without repeated nodes.  

Daniel's query above is correct:

v = g.v(1)
x = [] as Set
v.both('playerActive').fill(x)._().both('playerActive').except(x + v)

It seems odd that such a classic graph query as friend-of-a-friend doesn't have a more elegant solution in Gremlin.

Also, I don't really understand why Nick's first solution - something like

v3.both().as("first").both().except("first")

doesn't actually remove the first order friends.  Anyone?

Cheers,

Charlie

Daniel Kuppitz

unread,
Apr 24, 2015, 11:27:42 AM4/24/15
to aureliu...@googlegroups.com
Hi Charlie,

Also, I don't really understand why Nick's first solution - something like
v3.both().as("first").both().except("first")
doesn't actually remove the first order friends.  Anyone?

because a standard Gremlin traversal is executed in DFS mode. That means "first" is not a reference to all first order friends, but a reference to the one first order friend on the current path.


Cheers,
Daniel


Charlie Harrison

unread,
Apr 24, 2015, 12:57:51 PM4/24/15
to aureliu...@googlegroups.com
Thanks Daniel!

Cheers,

Charlie
Reply all
Reply to author
Forward
0 new messages