0

I want to retrieve all vertexes and for each one I want to count the number of 'Like' edges pointing at it.

How do I write this kind of query in Gremlin?

In SQL it could be something like....

SELECT *, (SELECT Count(*) FROM tbl_like l WHERE l.id = b.id) AS LikeCount
FROM tbl_blah b
Ian Warburton
  • 15,170
  • 23
  • 107
  • 189

3 Answers3

1

E.g. use sideEffect to put the counts in a map (m)

m=[:];g.V.sideEffect{m[it]=it.inE.has('label','like').count()}

An alternative which omits vertices with 0 likes:

m=[:];g.V.inE('like').groupCount(m){it.inV.next()}

EDIT

Finally the smart solution:

 m=[:];g.V.groupCount(m){it}{it.a.inE('like').count()}

The first closure of groupCount determines the key to update in the map and the second closure the value to the key. Seems like it.a in the second closure gives the current input value to groupCount (here a vertex) and it.b the previous value in the map for the input object. Haven't really found a documentation that explains this, maybe one of the TinkerPop guys can elaborate on the exact usage of the groupCount closures.

Faber
  • 1,504
  • 2
  • 13
  • 21
  • You're right, the `b` is the previous value returned from the closure. In that way you can increment `b` over each item that passes through the `groupCount`. In this case, that isn't necessary, because the edge count is all you want. – stephen mallette Nov 04 '14 at 14:03
  • Where is the documentation for the map declaration? I can't see it here... http://gremlindocs.com/ – Ian Warburton Nov 06 '14 at 15:22
  • Your first solution works good but it took me a while to find a way of returning the info. This works, what do you think....? m=[:];g.V().sideEffect({m[it] = it.in().has('type').count()}).transform{[it, m[it]]} – Ian Warburton Nov 07 '14 at 15:59
  • How can I return a map in order to give the values names? – Ian Warburton Nov 07 '14 at 16:09
1

I would consider:

m = g.E.has('label','like').groupBy{it.inV.next()}{1}{it.sum()}.cap.next()

Iterate all edges and filter by label, group on the inV of each "like" edge and add a 1 to that Map of results. That much takes you to the second to last closure of the groupBy. At that point you will have a Map like:

[v1:[1,1,1]
 v2:[1,1]]

which basically is a vertex with a 1 representing each "like" edge. Going back to the Gremlin above, the final closure to groupBy is a reduce operation that occurs on the values in the Map. In this case, we use the Groovy sum function (though I suppose size would work here too - but sum seems easier for readability) to add up the number of edges. Finally, we use cap to extract the Map side-effect from the pipeline and next it out into a var.

I suppose the downside here is that it doesn't yield a result for vertices with no "like" edges. If you need that, then the solution provided by @Faber is a better way to go. You might even pick and choose a bit from both solutions to ultimately get at what you are looking for.

stephen mallette
  • 45,298
  • 5
  • 67
  • 135
  • Finally I understand `cap`. From the doc: "`cap` emits the value of the previous step (here the map resulting from `groupBy`) and not the values that flow through it (here edges that flow through `groupBy`)"! Thx! But hence `cap` behaves like `gather` in that it collects all objects up to the `cap` step, correct? – Faber Nov 04 '14 at 14:25
  • 2
    I'm not sure I'd go that far. `cap` simply extracts the side-effect from the previous step, whereas `gather` works on objects in the pipeline itself, grabbing all items in the pipeline to a list. One works with pipeline objects and one grabs side-effects....it's an important distinction. – stephen mallette Nov 04 '14 at 14:57
0

No need for a side effect...

g.V().transform{[it, it.in('likes').count()]}
Ian Warburton
  • 15,170
  • 23
  • 107
  • 189