You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2019/06/27 01:12:46 UTC

[tinkerpop] branch TINKERPOP-1553 created (now e25b523)

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a change to branch TINKERPOP-1553
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


      at e25b523  TINKERPOP-1553 Deprecate store(String) for aggregate(Scope,String)

This branch includes the following new commits:

     new e25b523  TINKERPOP-1553 Deprecate store(String) for aggregate(Scope,String)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[tinkerpop] 01/01: TINKERPOP-1553 Deprecate store(String) for aggregate(Scope, String)

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-1553
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit e25b5234540d700a9d5447610dac49a44b6230ac
Author: Stephen Mallette <sp...@genoprime.com>
AuthorDate: Wed Jun 26 21:11:03 2019 -0400

    TINKERPOP-1553 Deprecate store(String) for aggregate(Scope,String)
    
    store('x') can now be accomplished with aggregate(local,'x') and aggregate('x') is aggregate(global,'x').
---
 CHANGELOG.asciidoc                                 |   1 +
 docs/src/reference/the-traversal.asciidoc          |  70 ++++++------
 docs/src/upgrade/release-3.4.x.asciidoc            |  15 +++
 .../traversal/dsl/graph/GraphTraversal.java        |  24 ++++-
 .../gremlin/process/traversal/dsl/graph/__.java    |   9 ++
 .../Process/Traversal/GraphTraversal.cs            |   9 ++
 .../src/Gremlin.Net/Process/Traversal/__.cs        |   8 ++
 .../test/cucumber/feature-steps.js                 |   1 +
 gremlin-test/features/sideEffect/Aggregate.feature |  88 ++++++++++++++-
 .../traversal/step/sideEffect/AggregateTest.java   | 118 ++++++++++++++++++++-
 ...tractTinkerGraphGraphSONTranslatorProvider.java |   4 +
 11 files changed, 305 insertions(+), 42 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 1030310..471e2d4 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -27,6 +27,7 @@ This release also includes changes from <<release-3-3-8, 3.3.8>>.
 
 * Improved error messaging on timeouts returned to the console from `:>`.
 * Added a Docker command to start Gremlin Server with the standard GLV test configurations.
+* Added `aggregate(Scope,String)` and deprecated `store()` in favor of `aggregate(local)`.
 * Modified `NumberHelper` to better ignore `Double.NaN` in `min()` and `max()` comparisons.
 * Bump to Netty 4.1.36.
 * Bump to Groovy 2.5.7.
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 7eb4b23..8fa37fb 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -280,28 +280,32 @@ link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/grem
 link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/structure/VertexProperty.Cardinality.html++[`Cardinality`]
 
 [[aggregate-step]]
+[[store-step]]
 === Aggregate Step
 
 image::aggregate-step.png[width=800]
 
 The `aggregate()`-step (*sideEffect*) is used to aggregate all the objects at a particular point of traversal into a
-`Collection`. The step uses link:http://en.wikipedia.org/wiki/Eager_evaluation[eager evaluation] in that no objects
-continue on until all previous objects have been fully aggregated (as opposed to <<store-step,`store()`>> which
-link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazily] fills a collection). The eager evaluation nature is crucial
-in situations where everything at a particular point is required for future computation. An example is provided below.
+`Collection`. The step is uses `Scope` to help determine the aggregating behavior. For `global` scope this means that
+the step will use link:http://en.wikipedia.org/wiki/Eager_evaluation[eager evaluation] in that no objects continue on
+until all previous objects have been fully aggregated. The eager evaluation model is crucial in situations
+where everything at a particular point is required for future computation. By default, when the overload of
+`aggregate()` is called without a `Scope`, the default is `global`. An example is provided below.
 
 [gremlin-groovy,modern]
 ----
 g.V(1).out('created') <1>
 g.V(1).out('created').aggregate('x') <2>
-g.V(1).out('created').aggregate('x').in('created') <3>
-g.V(1).out('created').aggregate('x').in('created').out('created') <4>
+g.V(1).out('created').aggregate(global, 'x') <3>
+g.V(1).out('created').aggregate('x').in('created') <4>
+g.V(1).out('created').aggregate('x').in('created').out('created') <5>
 g.V(1).out('created').aggregate('x').in('created').out('created').
-       where(without('x')).values('name') <5>
+       where(without('x')).values('name') <6>
 ----
 
 <1> What has marko created?
 <2> Aggregate all his creations.
+<3> Identical to the previous line.
 <3> Who are marko's collaborators?
 <4> What have marko's collaborators created?
 <5> What have marko's collaborators created that he hasn't created?
@@ -318,9 +322,31 @@ g.V().out('knows').aggregate('x').cap('x')
 g.V().out('knows').aggregate('x').by('name').cap('x')
 ----
 
+For `local` scope the aggregation will occur in a link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy] fashion.
+
+NOTE: Prior to 3.4.3, `local` aggregation (i.e. lazy) evaluation was handled by `store()`-step.
+
+[gremlin-groovy,modern]
+----
+g.V().aggregate(global, 'x').limit(1).cap('x')
+g.V().aggregate(local, 'x').limit(1).cap('x')
+g.withoutStrategies(EarlyLimitStrategy).V().aggregate(local,'x').limit(1).cap('x')
+----
+
+It is important to note that `EarlyLimitStrategy` introduced in 3.3.5 alters the behavior of `aggregate(local)`.
+Without that strategy (which is installed by default), there are two results in the `aggregate()` side-effect even
+though the interval selection is for 1 object. Realize that when the second object is on its way to the `range()`
+filter (i.e. `[0..1]`), it passes through `aggregate()` and thus, stored before filtered.
+
+[gremlin-groovy,modern]
+----
+g.E().store('x').by('weight').cap('x')
+----
+
 *Additional References*
 
-link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate-java.lang.String-++[`aggregate(String)`]
+link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate-java.lang.String-++[`aggregate(String)`],
+++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate-org.apache.tinkerpop.gremlin.process.traversal.Scope,java.lang.String-++[`aggregate(Scope,String)`]
 
 [[and-step]]
 === And Step
@@ -2901,34 +2927,6 @@ link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/grem
 link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#skip-org.apache.tinkerpop.gremlin.process.traversal.Scope-long-++[`skip(Scope,long)`],
 link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Scope.html++[`Scope`]
 
-[[store-step]]
-=== Store Step
-
-When link:http://en.wikipedia.org/wiki/Lazy_evaluation[lazy] aggregation is needed, `store()`-step (*sideEffect*)
-should be used over <<aggregate-step,`aggregate()`>>. The two steps differ in that `store()` does not block and only
-stores objects in its side-effect collection as they pass through.
-
-[gremlin-groovy,modern]
-----
-g.V().aggregate('x').limit(1).cap('x')                               
-g.V().store('x').limit(1).cap('x')
-g.withoutStrategies(EarlyLimitStrategy).V().store('x').limit(1).cap('x')
-----
-
-It is important to note that `EarlyLimitStrategy` introduced in 3.3.5 alters the behavior of `store()`. Without that
-strategy (which is installed by default), there are two results in the `store()` side-effect even though the interval
-selection is for 1 object. Realize that when the second object is on its way to the `range()` filter (i.e. `[0..1]`),
-it passes through `store()` and thus, stored before filtered.
-
-[gremlin-groovy,modern]
-----
-g.E().store('x').by('weight').cap('x')
-----
-
-*Additional References*
-
-link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#store-java.lang.String-++[`store(String)`]
-
 [[subgraph-step]]
 === Subgraph Step
 
diff --git a/docs/src/upgrade/release-3.4.x.asciidoc b/docs/src/upgrade/release-3.4.x.asciidoc
index cd575d6..295ba5c 100644
--- a/docs/src/upgrade/release-3.4.x.asciidoc
+++ b/docs/src/upgrade/release-3.4.x.asciidoc
@@ -27,6 +27,21 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 Please see the link:https://github.com/apache/tinkerpop/blob/3.4.3/CHANGELOG.asciidoc#release-3-4-3[changelog] for a complete list of all the modifications that are part of this release.
 
+=== Upgrading for Users
+
+==== Deprecated store()
+
+The `store()`-step and `aggregate()`-step do the same thing in different ways, where the former is lazy and the latter
+is eager in the side-effect collection of objects from the traversal. The different behaviors can be thought of as
+differing applications of `Scope` where `global` is eager and `local` is lazy. As a result, there is no need for both
+steps when one will do.
+
+As of 3.4.3, `store(String)` is now deprecated in favor of `aggregate(Scope, String)` where the `Scope` should be set
+to `local` to ensure the same functionality as `store()`. Note that `aggregate('x')` is the same as
+`aggregate(global,'x')`.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1553[TINKERPOP-1553]
+
 === Upgrading for Providers
 
 ==== Graph Driver Providers
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 204cc37..ce445c4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -1972,7 +1972,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
-     * Eagerly collects objects up to this step into a side-effect.
+     * Eagerly collects objects up to this step into a side-effect. Same as calling {@link #aggregate(Scope, String)}
+     * with a {@link Scope#local}.
      *
      * @param sideEffectKey the name of the side-effect key that will hold the aggregated objects
      * @return the traversal with an appended {@link AggregateStep}
@@ -1985,6 +1986,21 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
+     * Collects objects in a list using the {@link Scope} argument to determine whether it should be lazy
+     * {@link Scope#local} or eager ({@link Scope#global} while gathering those objects.
+     *
+     * @param sideEffectKey the name of the side-effect key that will hold the aggregated objects
+     * @return the traversal with an appended {@link AggregateStep}
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#aggregate-step" target="_blank">Reference Documentation - Aggregate Step</a>
+     * @since 3.4.3
+     */
+    public default GraphTraversal<S, E> aggregate(final Scope scope, final String sideEffectKey) {
+        this.asAdmin().getBytecode().addStep(Symbols.aggregate, scope, sideEffectKey);
+        return this.asAdmin().addStep(scope == Scope.global ?
+                new AggregateStep<>(this.asAdmin(), sideEffectKey) : new StoreStep<>(this.asAdmin(), sideEffectKey));
+    }
+
+    /**
      * Organize objects in the stream into a {@code Map}. Calls to {@code group()} are typically accompanied with
      * {@link #by()} modulators which help specify how the grouping should occur.
      *
@@ -2045,6 +2061,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      * @return the traversal with an appended {@link StoreStep}
      * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#store-step" target="_blank">Reference Documentation - Store Step</a>
      * @since 3.0.0-incubating
+     * @deprecated As of release 3.4.3, replaced by {@link #aggregate(Scope, String)} using {@link Scope#local}.
      */
     public default GraphTraversal<S, E> store(final String sideEffectKey) {
         this.asAdmin().getBytecode().addStep(Symbols.store, sideEffectKey);
@@ -2984,6 +3001,11 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         public static final String sideEffect = "sideEffect";
         public static final String cap = "cap";
         public static final String property = "property";
+
+        /**
+         * @deprecated As of release 3.4.3, replaced by {@link Symbols#aggregate} with a {@link Scope#local}.
+         */
+        @Deprecated
         public static final String store = "store";
         public static final String aggregate = "aggregate";
         public static final String subgraph = "subgraph";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index f991e80..ab98930 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -898,6 +898,13 @@ public class __ {
     }
 
     /**
+     * @see GraphTraversal#aggregate(Scope, String)
+     */
+    public static <A> GraphTraversal<A, A> aggregate(final Scope scope, final String sideEffectKey) {
+        return __.<A>start().aggregate(scope, sideEffectKey);
+    }
+
+    /**
      * @see GraphTraversal#group(String)
      */
     public static <A> GraphTraversal<A, A> group(final String sideEffectKey) {
@@ -934,7 +941,9 @@ public class __ {
 
     /**
      * @see GraphTraversal#store(String)
+     * @deprecated As of release 3.4.3, replaced by {@link #aggregate(Scope, String)} using {@link Scope#local}.
      */
+    @Deprecated
     public static <A> GraphTraversal<A, A> store(final String sideEffectKey) {
         return __.<A>start().store(sideEffectKey);
     }
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
index e1cfd64..f22ee8c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs
@@ -122,6 +122,15 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Adds the aggregate step to this <see cref="GraphTraversal{SType, EType}" />.
         /// </summary>
+        public GraphTraversal<S, E> Aggregate (Scope scope, string sideEffectKey)
+        {
+            Bytecode.AddStep("aggregate", scope, sideEffectKey);
+            return Wrap<S, E>(this);
+        }
+
+        /// <summary>
+        ///     Adds the aggregate step to this <see cref="GraphTraversal{SType, EType}" />.
+        /// </summary>
         public GraphTraversal<S, E> Aggregate (string sideEffectKey)
         {
             Bytecode.AddStep("aggregate", sideEffectKey);
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
index daea514..af31d1b 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs
@@ -93,6 +93,14 @@ namespace Gremlin.Net.Process.Traversal
         /// <summary>
         ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the aggregate step to that traversal.
         /// </summary>
+        public static GraphTraversal<object, object> Aggregate(Scope scope, string sideEffectKey)
+        {
+            return new GraphTraversal<object, object>().Aggregate(scope, sideEffectKey);            
+        }
+
+        /// <summary>
+        ///     Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the aggregate step to that traversal.
+        /// </summary>
         public static GraphTraversal<object, object> Aggregate(string sideEffectKey)
         {
             return new GraphTraversal<object, object>().Aggregate(sideEffectKey);            
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
index d6ca98c..22cbe6b 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/feature-steps.js
@@ -97,6 +97,7 @@ const ignoredScenarios = {
   'g_V_hasXname_markoX_shortestPath_maxDistanceX1X': new IgnoreError(ignoreReason.computerNotSupported),
   'g_V_hasXname_vadasX_shortestPath_distanceXweightX_maxDistanceX1_3X': new IgnoreError(ignoreReason.computerNotSupported),
   'g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX': new IgnoreError(ignoreReason.setNotSupported),
+  'g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX': new IgnoreError(ignoreReason.setNotSupported),
   'g_V_both_groupCountXaX_out_capXaX_selectXkeysX_unfold_both_groupCountXaX_capXaX': new IgnoreError(ignoreReason.needsFurtherInvestigation),
   'g_V_group_byXoutE_countX_byXnameX': new IgnoreError(ignoreReason.needsFurtherInvestigation),
 };
diff --git a/gremlin-test/features/sideEffect/Aggregate.feature b/gremlin-test/features/sideEffect/Aggregate.feature
index 2ab35ef..2e80990 100644
--- a/gremlin-test/features/sideEffect/Aggregate.feature
+++ b/gremlin-test/features/sideEffect/Aggregate.feature
@@ -33,6 +33,22 @@ Feature: Step - aggregate()
       | vadas |
       | ripple |
 
+  Scenario: g_V_valueXnameX_aggregateXglobal_xX_capXxX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().values("name").aggregate(Scope.global,"x").cap("x")
+      """
+    When iterated next
+    Then the result should be unordered
+      | result |
+      | marko |
+      | josh |
+      | peter |
+      | lop |
+      | vadas |
+      | ripple |
+
   Scenario: g_V_aggregateXxX_byXnameX_capXxX
     Given the modern graph
     And the traversal of
@@ -77,4 +93,74 @@ Feature: Step - aggregate()
       | d[29].i |
       | d[27].i |
       | d[32].i |
-      | d[35].i |
\ No newline at end of file
+      | d[35].i |
+
+  Scenario: g_V_aggregateXlocal_a_nameX_out_capXaX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().aggregate(Scope.local,"a").by("name").out().cap("a")
+      """
+    When iterated next
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | lop |
+      | josh |
+      | ripple |
+      | peter  |
+
+  Scenario: g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX
+    Given the modern graph
+    And using the parameter v1Id defined as "v[marko].id"
+    And the traversal of
+      """
+      g.V(v1Id).aggregate(Scope.local,"a").by("name").out().aggregate(Scope.local,"a").by("name").values("name").cap("a")
+      """
+    When iterated next
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | lop |
+      | josh |
+
+  Scenario: g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX
+    Given the modern graph
+    And using the parameter initial defined as "s[]"
+    And the traversal of
+      """
+      g.withSideEffect("a", initial).V().both().values("name").aggregate(Scope.local,"a").cap("a")
+      """
+    When iterated next
+    Then the result should be unordered
+      | result |
+      | marko |
+      | vadas |
+      | lop |
+      | josh |
+      | ripple |
+      | peter  |
+
+  Scenario: g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().aggregate(Scope.local,"a").
+             by(__.outE("created").count()).
+        out().out().aggregate(Scope.local,"a").
+                      by(__.inE("created").values("weight").sum()).
+        cap("a")
+      """
+    When iterated next
+    Then the result should be unordered
+      | result |
+      | d[1].l |
+      | d[1].l |
+      | d[0].l |
+      | d[0].l |
+      | d[0].l |
+      | d[2].l |
+      | d[1.0].d |
+      | d[1.0].d |
\ No newline at end of file
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
index 23dff26..f780046 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateTest.java
@@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.MapHelper;
@@ -31,10 +32,14 @@ import org.junit.runner.RunWith;
 
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertEquals;
@@ -50,6 +55,10 @@ import static org.junit.Assume.assumeThat;
 @RunWith(GremlinProcessRunner.class)
 public abstract class AggregateTest extends AbstractGremlinProcessTest {
 
+    ////// global
+
+    public abstract Traversal<Vertex, List<String>> get_g_V_name_aggregateXglobal_xX_capXxX();
+
     public abstract Traversal<Vertex, List<String>> get_g_V_name_aggregateXxX_capXxX();
 
     public abstract Traversal<Vertex, List<String>> get_g_V_aggregateXxX_byXnameX_capXxX();
@@ -58,7 +67,25 @@ public abstract class AggregateTest extends AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, Collection<Integer>> get_g_V_hasLabelXpersonX_aggregateXxX_byXageX_capXxX_asXyX_selectXyX();
 
-    //public abstract Traversal<Vertex, Path> get_g_v1_asXxX_bothE_asXeX_valueXweightX_exceptXwX_aggregateXwX_backXeX_otherV_jumpXx_true_trueX_path(final Object v1Id);
+    ////// local
+
+    public abstract Traversal<Vertex, Collection> get_g_V_aggregateXlocal_aX_byXnameX_out_capXaX();
+
+    public abstract Traversal<Vertex, Collection> get_g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX(final Object v1Id);
+
+    public abstract Traversal<Vertex, Set<String>> get_g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX();
+
+    public abstract Traversal<Vertex, Collection> get_g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX_capXaX();
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_valueXnameX_aggregateXglobal_xX_capXxX() {
+        final Traversal<Vertex, List<String>> traversal = get_g_V_name_aggregateXglobal_xX_capXxX();
+        printTraversalForm(traversal);
+        final Collection<String> names = traversal.next();
+        assertFalse(traversal.hasNext());
+        checkListOfNames(names);
+    }
 
     @Test
     @LoadGraphWith(MODERN)
@@ -139,9 +166,76 @@ public abstract class AggregateTest extends AbstractGremlinProcessTest {
         assertFalse(traversal.hasNext());
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_aggregateXlocal_a_nameX_out_capXaX() {
+        final Traversal<Vertex, Collection> traversal = get_g_V_aggregateXlocal_aX_byXnameX_out_capXaX();
+        printTraversalForm(traversal);
+        final Collection names = traversal.next();
+        assertEquals(6, names.size());
+        assertTrue(names.contains("marko"));
+        assertTrue(names.contains("josh"));
+        assertTrue(names.contains("peter"));
+        assertTrue(names.contains("lop"));
+        assertTrue(names.contains("ripple"));
+        assertTrue(names.contains("vadas"));
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX() {
+        final Traversal<Vertex, Collection> traversal = get_g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX(convertToVertexId("marko"));
+        printTraversalForm(traversal);
+        final Collection names = traversal.next();
+        assertEquals(4, names.size());
+        assertTrue(names.contains("marko"));
+        assertTrue(names.contains("josh"));
+        assertTrue(names.contains("vadas"));
+        assertTrue(names.contains("lop"));
+        assertFalse(traversal.hasNext());
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX() {
+        final Traversal<Vertex, Set<String>> traversal = get_g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX();
+        printTraversalForm(traversal);
+        final Set<String> names = traversal.next();
+        assertFalse(traversal.hasNext());
+        assertEquals(6, names.size());
+        assertTrue(names.contains("marko"));
+        assertTrue(names.contains("vadas"));
+        assertTrue(names.contains("josh"));
+        assertTrue(names.contains("lop"));
+        assertTrue(names.contains("ripple"));
+        assertTrue(names.contains("peter"));
+    }
+
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX() {
+        final Traversal<Vertex, Collection> traversal = get_g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX_capXaX();
+        printTraversalForm(traversal);
+        assertTrue(traversal.hasNext());
+        final Collection store = traversal.next();
+        assertFalse(traversal.hasNext());
+        assertEquals(8, store.size());
+        assertTrue(store.contains(0L));
+        assertTrue(store.contains(1L));
+        assertTrue(store.contains(2L));
+        assertTrue(store.contains(1.0d));
+        assertFalse(store.isEmpty());
+    }
+
     public static class Traversals extends AggregateTest {
 
         @Override
+        public Traversal<Vertex, List<String>> get_g_V_name_aggregateXglobal_xX_capXxX() {
+            return g.V().values("name").aggregate(Scope.global, "x").cap("x");
+        }
+
+        @Override
         public Traversal<Vertex, List<String>> get_g_V_name_aggregateXxX_capXxX() {
             return g.V().values("name").aggregate("x").cap("x");
         }
@@ -161,8 +255,24 @@ public abstract class AggregateTest extends AbstractGremlinProcessTest {
             return g.V().hasLabel("person").aggregate("x").by("age").cap("x").as("y").select("y");
         }
 
-        /*public Traversal<Vertex, Path> get_g_v1_asXxX_bothE_asXeX_valueXweightX_exceptXwX_aggregateXwX_backXeX_otherV_jumpXx_true_trueX_path(final Object v1Id) {
-            return g.V(1).as("x").bothE().as("e").value("weight").except("w").aggregate("w").back("e").otherV().jump("x", t -> true, t -> true).path();
-        }*/
+        @Override
+        public Traversal<Vertex, Collection> get_g_V_aggregateXlocal_aX_byXnameX_out_capXaX() {
+            return g.V().aggregate(Scope.local, "a").by("name").out().cap("a");
+        }
+
+        @Override
+        public Traversal<Vertex, Collection> get_g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX(final Object v1Id) {
+            return g.V(v1Id).aggregate(Scope.local, "a").by("name").out().aggregate(Scope.local, "a").by("name").values("name").cap("a");
+        }
+
+        @Override
+        public Traversal<Vertex, Set<String>> get_g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX() {
+            return g.withSideEffect("a", new HashSet()).V().both().<String>values("name").aggregate(Scope.local, "a").cap("a");
+        }
+
+        @Override
+        public Traversal<Vertex, Collection> get_g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX_capXaX() {
+            return g.V().aggregate(Scope.local, "a").by(outE("created").count()).out().out().aggregate(Scope.local, "a").by(inE("created").values("weight").sum()).cap("a");
+        }
     }
 }
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
index 66fa0f9..4d4ee00 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/io/graphson/AbstractTinkerGraphGraphSONTranslatorProvider.java
@@ -228,6 +228,10 @@ import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComp
         test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StoreTest",
         method = "g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX",
         reason = "This test returns BulkSet which isn't supported in GraphSON 3.0 until 3.4.0.")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateTest",
+        method = "g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX",
+        reason = "This test returns BulkSet which isn't supported in GraphSON 3.0 until 3.4.0.")
 public abstract class AbstractTinkerGraphGraphSONTranslatorProvider extends TinkerGraphProvider {
 
     private final GraphSONVersion version;