Hello purple people eaters,

I did some benchmarking of GroupStep vs. GroupStepV3d0. The general themes:

        1. GroupStep is slightly faster than GroupV3d0Step (GOOD).
        2. GroupStep uses less memory if there is a reducer at the end of the 
valueTraversal (e.g. max(), min(), count(), sum(), etc.). (GOOD)
                - This is because every "X" inserts its processes the 
traversers thus far and reduces them.
        
------------------

The first query produces 2 keys but lots of values for each key. (actually 3 
keys -- we have a data bug in the GratefulDead graph :|).

        
g.V().both("followedBy").both("followedBy").group().by("songType").by(count())
        
g.V().both("followedBy").both("followedBy").groupV3d0().by("songType").by().by(count(local))

Both produce the answer:
         {cover=368579, =160968, original=771317}

**** The empty key! is a bunch of songs with a blank string for songType. Crap. 
Data bug. ****

Runtime group (ms): 420.1875169
Runtime groupV3d0 (ms): 461.91872409999996

Now, without the reducer -- thus, just a big old fold() at the end.

Runtime group (ms): 422.8069872
Runtime groupV3d0 (ms): 458.80180110000003

------------------

The second query produces 338 keys with each key having less values than the 
first.

        
g.V().both("followedBy").both("followedBy").group().by("name").by(count())
        
g.V().both("followedBy").both("followedBy").groupV3d0().by("name").by().by(count(local))

Runtime group (ms): 428.6962979
Runtime groupV3d0 (ms): 440.7029265

Now, without the reducer -- thus, just a big old fold() at the end.

Runtime group (ms): 442.3166115
Runtime groupV3d0 (ms): 444.6889403

Thus, I think this is a good move as we don't have to worry about OME with 
group() and we are getting slightly faster runtimes. I haven't spent much time 
optimizing the code either so I suspect we can get GroupStep even faster!

Enjoy,
Marko.

http://markorodriguez.com

On Oct 7, 2015, at 11:52 AM, Marko Rodriguez <[email protected]> wrote:

> Hi everyone,
> 
> I was soooooo close to having group() be backwards compatible. However, I 
> found a corner case that makes it break.
> 
> If you do something like:
> 
> g.V.group.by('name').by(outE.weight).by(max(local))
> 
> If you did this, I would know you were using "the old way" as your provided a 
> reduce by()-modulator. I would simply make your valueTraversal be 
> "outE.weight.fold." Easy peasy. In fact, all the test cases passed.
> 
> What about if you don't add a reduceTraversal and you want "the old way?" 
> 
> gremlin> g.V.group.by('name').by(outE.weight) // old way
> ==>[marko:[0.4,0.5,0.1]
>       
> gremlin> g.V.group.by('name').by(outE.weight) // new way
> ==>[marko:0.4]
> 
> Now, I was thinking, well we can say that if the valueTraversal doesn't end 
> with a reducing barrier step, then we add fold() and tada, they are the same. 
> However, what about this situation:
> 
> 
> 
> g.V.group.by('name').by(constant(1))
> old way would return a List[1,1,1,1,1,1,1]
> new way returns 1
> now, if you provided a reducer, I would be like: "Ah! you are using the old 
> way, let me make it constant(1).fold()"
> but if you don't provide a reducer, then we don't know if you are using old 
> or new version.
> 
> http://markorodriguez.com
> 
> On Oct 7, 2015, at 7:28 AM, Marko Rodriguez <[email protected]> wrote:
> 
>> Hi,
>> 
>>> - Don't keep the old GropupStep at all, and have the new GroupStep "concat"
>>> the second and third 'by' traversals if they exist.
>> 
>> This is not possible. In fact, I messed up my original examples. They should 
>> be:
>> 
>> g.V.group.by('name').by(outE.weight).by(max(local)) // old way
>> g.V.group.by('name').by(outE.weight.max()) // new way
>> 
>> Notice the semantics of the reduce in the old way. Its looking for a 
>> collection, not a stream. You can argue, well introspect and flatten/etc. 
>> That is easy for max(), sum(), etc, but what about lambdas? What about 
>> complex group().by()s people are using I don't even know about and mess up 
>> the reasoning on?
>> 
>>> - Leave the GroupStep as-is, and add the mapValues step for whoever wants a
>>> better implementation:
>> 
>> mapValues() is already step in use.
>>      
>> http://tinkerpop.incubator.apache.org/docs/3.1.0-SNAPSHOT/#mapvalues-step
>> 
>>> g.V().group().by(keyTraversal).mapValues(valueTraversal).
>>> No deprecation needed.
>> 
>> Can't do it cause of mapValues() and we need to keep modulators consistent, 
>> hence by()-modulation. I don't want to introduce a new modulator just for 
>> this situation as it makes the language start to look hackish. "Oh 
>> mapValues() isn't a step, its a modulator like by() as as() but only works 
>> for group() as the second modulator?!" Right now we have as() and by() as 
>> our "special" modulating steps.
>> 
>> Finally, to your notion of group(traversal). We have group(String) which 
>> uses GroupSideEffectStep. Furthermore, all step(traversal) are used 
>> exclusively for nesting and not for modulation (e.g. local(), repeat(), 
>> etc.). Using a traversal parameter in this way would ruin the consistency of 
>> the language.
>> 
>> Thank you for your thoughts,
>> Marko.
>> 
>> http://markorodriguez.com
>> 
>> 
>>> 
>>> On Wed, 7 Oct 2015 at 14:42 Ran Magen <[email protected]> wrote:
>>> 
>>>> My point is that group().by('key').by('value/reduce') seems kind of weird
>>>> anyway. The equivalent sql would be "select 'value/reduce' ... group by
>>>> 'key' ".
>>>> 
>>>> A few alternative options:
>>>> g.V().group().by(keyTraversal).mapValues(valueTraversal) //As Marko
>>>> pointed out this doesn't address the old GroupStep deprecation
>>>> 
>>>> g.V().group(keyTraversal).mapValues(valueTraversal) // group() is
>>>> @Deprecated
>>>> 
>>>> g.V().group(valueTraversal).by(keyTraversal) // group() is @Deprecated
>>>> 
>>>> g.V().group(keyTraversal, valueTraversal) // group() is @Deprecated
>>>> 
>>>> 
>>>> On Wed, 7 Oct 2015 at 01:42 Marko Rodriguez <[email protected]> wrote:
>>>> 
>>>>> Uh…. First select() is already taken and by() is always a
>>>>> by()-modulator…… :/ Even with that, we still can't fix the backwards
>>>>> compatibility issue as we can't deprecate out the second by(). How do you
>>>>> say "if the second by() is applied, its Deprecated?" Perhaps Logger.WARN 
>>>>> or
>>>>> something.. Dunno, sorta odd.
>>>>> 
>>>>> Marko.
>>>>> 
>>>>> http://markorodriguez.com
>>>>> 
>>>>> On Oct 6, 2015, at 3:26 PM, Ran Magen <[email protected]> wrote:
>>>>> 
>>>>>> How about changing the second 'by' to a more indicative name (could
>>>>>> 'select' work?)?
>>>>>> 
>>>>>> That way we could improve on the name (which always had me confused),
>>>>> and
>>>>>> leave the second+third 'by's as an indication to use the old
>>>>>> implementation...
>>>>>> 
>>>>>> On יום ד׳, 7 באוק׳ 2015 at 0:18 Marko Rodriguez <[email protected]>
>>>>>> wrote:
>>>>>> 
>>>>>>> Hello everyone (and the NSA -- Kuppitz did it),
>>>>>>> 
>>>>>>> This is regarding this ticket:
>>>>>>>       https://issues.apache.org/jira/browse/TINKERPOP3-866
>>>>>>> 
>>>>>>> In group_step_2/ branch we have a new implementation of GroupStep.
>>>>> Here is
>>>>>>> an example:
>>>>>>> 
>>>>>>> g.V.group.by('name').by(outE.weight).by(max()) // old way
>>>>>>> g.V.group.by('name').by(outE.weight.max()) // new way
>>>>>>> 
>>>>>>> What is the difference, there is only two by()-modulators that can be
>>>>>>> passed to group(): keyTraversal and valueTraversal. What happened to
>>>>>>> reduceTraversal? Well, valueTraversal is that. If you want to reduce on
>>>>>>> your values, well, add a reducing barrier step -- e.g. max, min, sum,
>>>>>>> count, fold, mean, etc. In the old way, we would put all your values
>>>>> into a
>>>>>>> Collection<V> and then when the step was complete, we would feed those
>>>>> into
>>>>>>> the reduceTraversal. Now -- we can dynamically reduce on the fly. This
>>>>> will
>>>>>>> greatly improve speed and memory usage as we don't have to create a
>>>>> big old
>>>>>>> Collection<V> and instead, can reduce as new traversers are fed into
>>>>>>> valueTraversal.
>>>>>>> 
>>>>>>> So this is great and no would object. What sucks is that this is NOT
>>>>>>> backwards compatible. What Stephen and I came up with (in the ticket)
>>>>> is to
>>>>>>> make:
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>> https://github.com/apache/incubator-tinkerpop/blob/group_step_2/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java#L637-L639
>>>>>>> 
>>>>>>> This new step groupV3d0() is a deprecated step that is what the "old
>>>>> way"
>>>>>>> was. Note the naming convention that Stephen used for Kryo is now used
>>>>> here
>>>>>>> -- V3d0 (version 3<dot>0). Thus, for users moving forward, they will
>>>>> have
>>>>>>> to do a "replace all" on their queries and rename "group()" to
>>>>>>> "groupV3d0()". Then slowly, over time, convert their traversal to use
>>>>> the
>>>>>>> new group() step and its respective semantics.
>>>>>>> 
>>>>>>> Note that in the past we have been able to do backwards compatibility
>>>>> via
>>>>>>> having the new step (e.g. AddVertexStep) simulate the behavior of the
>>>>> old
>>>>>>> step and have respective @Deprecates in there to say that particular
>>>>>>> GraphTraversal methods will go away. However, in this situation, the
>>>>> best
>>>>>>> we can do is groupV3d0().
>>>>>>> 
>>>>>>> Anywho. That is that. If people have any better ideas on how to solve
>>>>> this
>>>>>>> backwards compatibility issue, I'm all (deaf) ears.
>>>>>>> 
>>>>>>> Thanks,
>>>>>>> Marko.
>>>>>>> 
>>>>>>> http://markorodriguez.com
>>>>>>> 
>>>>>>> 
>>>>> 
>>>>> 
>> 
> 

Reply via email to