Peter Halverson
Peter Halverson

Reputation: 419

Traverse implied edge through property match?

I'm trying to create edges between vertices based on matching the value of a property in each vertex, making what is currently an implied relationship into an explicit relationship. I've been unsuccessful in writing a gremlin traversal that will match up related vertices.

Specifically, given the following graph:

g = TinkerGraph.open().traversal()
g.addV('person').property('name','alice')
g.addV('person').property('name','bob').property('spouse','carol')
g.addV('person').property('name','carol')
g.addV('person').property('name','dave').property('spouse', 'alice')

I was hoping I could create a spouse_of relation using the following

> g.V().has('spouse').as('x')
   .V().has('name', select('x').by('spouse'))
       .addE('spouse_of').from('x')

but instead of creating one edge from bob to carol and another edge from dave to alice, bob and dave each end up with spouse_of edges to all of the vertices (including themselves):

> g.V().out('spouse_of').path().by('name')
  ==>[bob,alice]
  ==>[bob,bob]
  ==>[bob,carol]
  ==>[bob,dave]
  ==>[dave,carol]
  ==>[dave,dave]
  ==>[dave,alice]
  ==>[dave,bob]

It almost seems as if the has filter isn't being applied, or, to use RDBMS terms, as if I'm ending up with an "outer join" instead of the "inner join" I'd intended.

Any suggestions? Am I overlooking something trivial or profound (local vs global scope, perhaps)? Is there any way of accomplishing this in a single traversal query, or do I have to iterate through g.has('spouse') and create edges individually?

Upvotes: 0

Views: 168

Answers (1)

stephen mallette
stephen mallette

Reputation: 46216

You can make this happen in a single traversal, but has() is not meant to work quite that way. The pattern for this is type of traversal is described in the Traversal Induced Values section of the Gremlin Recipes tutorial, but you can see it in action here:

gremlin> g.V().hasLabel('person').has('spouse').as('s').
......1>   V().hasLabel('person').as('x').
......2>   where('x', eq('s')).
......3>     by('name').
......4>     by('spouse').
......5>   addE('spouse_of').from('s').to('x')
==>e[10][2-spouse_of->5]
==>e[11][7-spouse_of->0]
gremlin> g.E().project('x','y').by(outV().values('name')).by(inV().values('name'))
==>[x:bob,y:carol]
==>[x:dave,y:alice]

While this can be done in a single traversal note that depending on the size of your data this could be an expensive traversal as I'm not sure that either call to V() will be optimized by any graph. While it's neat to use this form, you may find that it's faster to take approaches that ensure that a use of an index is in place which might mean issuing multiple queries to solve the problem.

Upvotes: 2

Related Questions