Skip to content

Except Retain Pattern

okram edited this page Jan 12, 2011 · 10 revisions

In many instances its desirable to traverse to only those elements that have not been seen in a previous step. Specific use cases are:

  • “Who are my friends friends that are not already my friends?”
  • “What is liked by the people that like the same things as me that I don’t already like?”

The solution to these types of problems is called the except pattern. Its opposite is the retain pattern—only traverse to those vertices that have been seen in a previous step.

gremlin> g.v(1).outE.inV
==>v[2]
==>v[3]
==>v[4]
gremlin> g.v(1).outE.inV.outE.inV
==>v[5]
==>v[3]

Both the first outE.inV and the second emit v[3]. To ensure that v[3] is not traversed to on the second step, its necessary to save the results seen after the first outE.inV.

gremlin> x = [] as Set
gremlin> g.v(1).outE.inV.gather._{x.addAll(it)}.scatter.outE.inV{!x.contains(it)} 
==>v[5]

The gather step aggregates all the results up to that stage in the pipeline. Those results are stored in x. The scatter step emits the gathered individual objects. The closure at the end checks to make sure the vertex is not contained in x.

Expressed in other ways.

gremlin> x = [] as Set
gremlin> g.v(1).outE.inV >> x; x._().outE.inV{!x.contains(it)}
==>v[5]
gremlin> x = [] as Set                                        
gremlin> (g.v(1).outE.inV >> x)._().outE.inV{!x.contains(it)} 
==>v[5]

Finally, this pattern is so common, that a high-level pipe called aggregate is provided. This pipe, in essence, accomplishes the behavior of gather._{x.addAll(it)}.scatter.

gremlin> x = [] as Set
gremlin> g.v(1).outE.inV.aggregate(x).outE.inV{!x.contains(it)}
==>v[5]