I just made SingleIterationStrategy a whole lot smarter. Not only is the code 
simpler with less checks, we now support out().count() -> out().id().count() 
and out().dedup().count() as out().id().dedup().count(). This will constrain 
numerous star local traversers from message passing in all GraphComputer 
implementations. Again, for Spark, this means we don't have to worry about 
caching the graph and save lots of clock cycles on many typical queries.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/1819e05a
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/1819e05a
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/1819e05a

Branch: refs/heads/TINKERPOP-1602
Commit: 1819e05aa1545f14ae97a78c3626d38b732ead9d
Parents: b2f2a9d
Author: Marko A. Rodriguez <okramma...@gmail.com>
Authored: Fri Jan 27 06:26:22 2017 -0700
Committer: Marko A. Rodriguez <okramma...@gmail.com>
Committed: Fri Jan 27 14:24:18 2017 -0700

----------------------------------------------------------------------
 .../optimization/SingleIterationStrategy.java   | 105 +++++++++++--------
 .../SingleIterationStrategyTest.java            |  38 ++++---
 .../SparkSingleIterationStrategyTest.java       |  20 ++--
 3 files changed, 97 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/1819e05a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
index 96a2a0a..6b509ef 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategy.java
@@ -21,7 +21,6 @@ package 
org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimiz
 
 import 
org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.TraversalVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.computer.util.EmptyMemory;
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
@@ -29,14 +28,18 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTrav
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
 import org.apache.tinkerpop.gremlin.process.traversal.step.LambdaHolder;
-import org.apache.tinkerpop.gremlin.process.traversal.step.SideEffectCapable;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.EdgeVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
-import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaFlatMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LambdaMapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.IdStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
+import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
@@ -45,7 +48,6 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.Inci
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.InlineFilterStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 
@@ -66,13 +68,6 @@ public final class SingleIterationStrategy extends 
AbstractTraversalStrategy<Tra
             FilterRankingStrategy.class,
             InlineFilterStrategy.class));
 
-    private static final Set<Class> MULTI_ITERATION_CLASSES = new 
HashSet<>(Arrays.asList(
-            EdgeVertexStep.class,
-            LambdaFlatMapStep.class,
-            LambdaMapStep.class
-    ));
-
-
     private SingleIterationStrategy() {
     }
 
@@ -81,48 +76,70 @@ public final class SingleIterationStrategy extends 
AbstractTraversalStrategy<Tra
         // only process the first traversal step in an OLAP chain
         
TraversalHelper.getFirstStepOfAssignableClass(TraversalVertexProgramStep.class, 
traversal).ifPresent(step -> {
             final Graph graph = 
traversal.getGraph().orElse(EmptyGraph.instance()); // best guess at what the 
graph will be as its dynamically determined
-            final Traversal.Admin<?, ?> computerTraversal = 
step.generateProgram(graph, 
EmptyMemory.instance()).getTraversal().get().clone();
-            // does the traversal as it is message pass?
-            boolean doesMessagePass = 
TraversalHelper.hasStepOfAssignableClassRecursively(Scope.global, 
MULTI_ITERATION_CLASSES, computerTraversal);
-            if (!doesMessagePass) {
-                for (final VertexStep vertexStep : 
TraversalHelper.getStepsOfAssignableClassRecursively(Scope.global, 
VertexStep.class, computerTraversal)) {
-                    if (vertexStep.returnsVertex() || 
!vertexStep.getDirection().equals(Direction.OUT)) { // in-edges require message 
pass in OLAP
-                        doesMessagePass = true;
-                        break;
-                    }
-                }
-            }
-            if (doesMessagePass &&                                             
                                                     // if the traversal 
doesn't message pass, then don't try and localize it as its just wasted 
computation
-                    TraversalHelper.isLocalStarGraph(computerTraversal) &&     
                                                     // if we move beyond the 
star graph, then localization is not possible.
-                    computerTraversal.getStartStep() instanceof GraphStep &&   
                                                     // while GraphComputer 
requires GraphStep starts, this is just a precaution when inject() starts are 
supported
-                    !(computerTraversal.getStartStep().getNextStep() 
instanceof EmptyStep) &&                                       // if its just a 
g.V()/E(), then don't localize
-                    !(computerTraversal.getStartStep().getNextStep() 
instanceof LocalStep) &&                                       // removes the 
potential for the infinite recursive application of the traversal
-                    !(computerTraversal.getStartStep().getNextStep() 
instanceof Barrier) &&                                         // if the second 
step is a barrier, no point in trying to localize anything
-                    
!computerTraversal.getTraverserRequirements().contains(TraverserRequirement.LABELED_PATH)
 &&                    // this is to alleviate issues with DetachedElement in 
paths (TODO: when detachment is dynamic, remove this)
-                    
!computerTraversal.getTraverserRequirements().contains(TraverserRequirement.PATH)
 &&                            // this is to alleviate issues with 
DetachedElement in paths (TODO: when detachment is dynamic, remove this)
-                    
!TraversalHelper.hasStepOfAssignableClassRecursively(LambdaHolder.class, 
computerTraversal) &&                  // this is because we might be accessing 
data on an adjacent vertex and that is bad
-                    
!TraversalHelper.hasStepOfAssignableClassRecursively(SideEffectCapable.class, 
computerTraversal) &&             // this is to alleviate issues with 
DetachedElement in paths (TODO: when detachment is dynamic, remove this)
-                    
!(TraversalHelper.getStepsOfAssignableClass(TraversalParent.class, 
computerTraversal).                          // this is a strict precaution 
that could be loosed with deeper logic on barriers in global children
+            final Traversal.Admin<?, ?> compiledComputerTraversal = 
step.generateProgram(graph, 
EmptyMemory.instance()).getTraversal().get().clone();
+            if (!compiledComputerTraversal.isLocked())
+                compiledComputerTraversal.applyStrategies();
+            if 
(!TraversalHelper.hasStepOfAssignableClassRecursively(Arrays.asList(LocalStep.class,
 LambdaHolder.class), compiledComputerTraversal) &&
+                    
!compiledComputerTraversal.getTraverserRequirements().contains(TraverserRequirement.PATH)
 &&            // when dynamic detachment is provided in 3.3.0, remove this 
(TODO)
+                    
!compiledComputerTraversal.getTraverserRequirements().contains(TraverserRequirement.LABELED_PATH)
 &&    // when dynamic detachment is provided in 3.3.0, remove this (TODO)
+                    
!(TraversalHelper.getStepsOfAssignableClass(TraversalParent.class, 
compiledComputerTraversal).          // this is a strict precaution that could 
be loosed with deeper logic on barriers in global children
                             stream().
                             filter(parent -> 
!parent.getGlobalChildren().isEmpty()).findAny().isPresent())) {
-                final Traversal.Admin<?, ?> newComputerTraversal = 
step.computerTraversal.getPure();
-                final Traversal.Admin localTraversal = new 
DefaultGraphTraversal<>();
-                final Step barrier = (Step) 
TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, 
newComputerTraversal).orElse(null);
-                if (null == barrier || !(barrier instanceof TraversalParent && 
(barrier.getPreviousStep() instanceof VertexStep || barrier.getPreviousStep() 
instanceof EdgeVertexStep))) {
-                    
TraversalHelper.removeToTraversal(newComputerTraversal.getStartStep().getNextStep(),
 null == barrier ? EmptyStep.instance() : barrier, localTraversal);
-                    assert !localTraversal.getSteps().isEmpty(); // given the 
if() constraints, this is impossible
-                    if (localTraversal.getSteps().size() > 1) {  // if its 
just a single step, a local wrap will not alter its locus of computation
+                final Traversal.Admin<?, ?> computerTraversal = 
step.computerTraversal.getPure();
+                if (computerTraversal.getSteps().size() > 1 &&
+                        !(computerTraversal.getStartStep().getNextStep() 
instanceof Barrier) &&
+                        
TraversalHelper.hasStepOfAssignableClassRecursively(Arrays.asList(VertexStep.class,
 EdgeVertexStep.class), computerTraversal) &&
+                        TraversalHelper.isLocalStarGraph(computerTraversal)) {
+                    final Traversal.Admin newChildTraversal = new 
DefaultGraphTraversal<>();
+                    final Step barrier = (Step) 
TraversalHelper.getFirstStepOfAssignableClass(Barrier.class, 
computerTraversal).orElse(null);
+                    if (SingleIterationStrategy.insertElementId(barrier)) // 
out().count() -> out().id().count()
+                        TraversalHelper.insertBeforeStep(new 
IdStep(computerTraversal), barrier, computerTraversal);
+                    if (!(SingleIterationStrategy.endsWithElement(null == 
barrier ? computerTraversal.getEndStep() : barrier.getPreviousStep()))) {
+                        
TraversalHelper.removeToTraversal(computerTraversal.getStartStep() instanceof 
GraphStep ?
+                                computerTraversal.getStartStep().getNextStep() 
:
+                                (Step) computerTraversal.getStartStep(), null 
== barrier ?
+                                EmptyStep.instance() :
+                                barrier, newChildTraversal);
                         if (null == barrier)
-                            TraversalHelper.insertTraversal(0, 
(Traversal.Admin) __.local(localTraversal), newComputerTraversal);
+                            TraversalHelper.insertTraversal(0, 
(Traversal.Admin) __.local(newChildTraversal), computerTraversal);
                         else
-                            
TraversalHelper.insertTraversal(barrier.getPreviousStep(), (Traversal.Admin) 
__.local(localTraversal), newComputerTraversal);
-                        step.setComputerTraversal(newComputerTraversal);
+                            
TraversalHelper.insertTraversal(barrier.getPreviousStep(), (Traversal.Admin) 
__.local(newChildTraversal), computerTraversal);
                     }
                 }
+                step.setComputerTraversal(computerTraversal);
             }
         });
     }
 
+    private static boolean insertElementId(final Step<?, ?> barrier) {
+        if (!(barrier instanceof Barrier))
+            return false;
+        else if (!endsWithElement(barrier.getPreviousStep()))
+            return false;
+        else if (barrier instanceof CountGlobalStep)
+            return true;
+        else if (barrier instanceof DedupGlobalStep &&
+                ((DedupGlobalStep) barrier).getScopeKeys().isEmpty() &&
+                ((DedupGlobalStep) barrier).getLocalChildren().isEmpty() &&
+                barrier.getNextStep() instanceof CountGlobalStep)
+            return true;
+        else
+            return false;
+    }
+
+    private static boolean endsWithElement(Step<?, ?> currentStep) {
+        while (!(currentStep instanceof EmptyStep)) {
+            if (currentStep instanceof VertexStep || currentStep instanceof 
EdgeVertexStep) // TODO: add GraphStep but only if its mid-traversal V()/E()
+                return true;
+            else if (currentStep instanceof TraversalFlatMapStep || 
currentStep instanceof TraversalMapStep)
+                return endsWithElement(((TraversalParent) 
currentStep).getLocalChildren().get(0).getEndStep());
+            else if (!(currentStep instanceof FilterStep || currentStep 
instanceof SideEffectStep))
+                return false;
+            currentStep = currentStep.getPreviousStep();
+        }
+        return false;
+    }
+
     @Override
     public Set<Class<? extends OptimizationStrategy>> applyPrior() {
         return PRIORS;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/1819e05a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
index 09887f3..081a541 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/optimization/SingleIterationStrategyTest.java
@@ -23,11 +23,14 @@ import 
org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.Traversa
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy;
 import 
org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Column;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -35,10 +38,13 @@ import org.junit.runners.Parameterized;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.function.Function;
 
+import static 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.bothE;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.inE;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
 import static org.apache.tinkerpop.gremlin.structure.Column.keys;
 import static org.junit.Assert.assertEquals;
 
@@ -76,29 +82,29 @@ public class SingleIterationStrategyTest {
 
     @Parameterized.Parameters(name = "{0}")
     public static Iterable<Object[]> generateTestParameters() {
-
+        final Function<Traverser<Vertex>,Vertex> mapFunction = t -> 
t.get().vertices(Direction.OUT).next();
         return Arrays.asList(new Object[][]{
-                {__.V().out().count(), __.V().outE().count(), 
Collections.singletonList(AdjacentToIncidentStrategy.instance())},
+                {__.V().out().count(), __.V().local(out().id()).count(), 
Collections.singletonList(AdjacentToIncidentStrategy.instance())}, // TODO
                 {__.V().id(), __.V().id(), Collections.emptyList()},
-                {__.V().out().count(), __.V().out().count(), 
Collections.emptyList()},
+                {__.V().out().count(), __.V().local(out().id()).count(), 
Collections.emptyList()},
                 {__.V().out().label().count(), __.V().out().label().count(), 
Collections.emptyList()},
                 {__.V().in().id(), __.V().local(in().id()), 
Collections.emptyList()},
-                {in().id(), in().id(), Collections.emptyList()}, // test inject
+                {in().id(), __.local(in().id()), Collections.emptyList()}, // 
test inject
                 {__.V().out().id(), __.V().local(out().id()), 
Collections.emptyList()},
                 {__.V().both().id(), __.V().local(__.both().id()), 
Collections.emptyList()},
-                {__.V().outE().inV().id().count(), 
__.V().local(__.outE().inV().id()).count(), Collections.emptyList()},
-                {__.V().map(__.outE().inV()).count(), 
__.V().map(__.outE().inV()).count(), Collections.emptyList()},
-                {__.V().out().map(__.outE().inV()).count(), 
__.V().out().map(__.outE().inV()).count(), Collections.emptyList()},
-                {__.V().outE().map(__.inV()).id().count(), 
__.V().outE().map(__.inV()).id().count(), Collections.emptyList()},
-                {__.V().outE().map(__.inV()).count(), 
__.V().outE().map(__.inV()).count(), Collections.emptyList()},
+                {__.V().outE().inV().id().count(), 
__.V().local(outE().inV().id()).count(), Collections.emptyList()},
+                {__.V().map(outE().inV()).count(), 
__.V().local(__.map(outE().inV()).id()).count(), Collections.emptyList()},
+                {__.V().out().map(outE().inV()).count(), 
__.V().out().map(outE().inV()).count(), Collections.emptyList()},
+                {__.V().outE().map(__.inV()).id().count(), 
__.V().local(__.outE().map(__.inV()).id()).count(), Collections.emptyList()},
+                {__.V().outE().map(__.inV()).count(), 
__.V().local(outE().map(__.inV()).id()).count(), Collections.emptyList()},
                 {__.V().outE().map(__.inV()).values("name").count(), 
__.V().outE().map(__.inV()).values("name").count(), Collections.emptyList()},
-                {__.V().outE().inV().count(), 
__.V().local(__.outE().inV()).count(), Collections.emptyList()},
+                {__.V().outE().inV().count(), 
__.V().local(outE().inV().id()).count(), Collections.emptyList()},
                 {__.V().out().id().count(), __.V().local(out().id()).count(), 
Collections.emptyList()},
                 {__.V().in().id().count(), __.V().local(in().id()).count(), 
Collections.emptyList()},
                 {__.V().in().id().select("id-map").dedup().count(), 
__.V().local(in().id().select("id-map")).dedup().count(), 
Collections.emptyList()},
                 
{__.V().in().id().groupCount().select(keys).unfold().dedup().count(), 
__.V().local(in().id()).groupCount().select(keys).unfold().dedup().count(), 
Collections.emptyList()},
-                {__.V().outE().values("weight"), 
__.V().outE().values("weight"), Collections.emptyList()},
-                {__.V().outE().values("weight").sum(), 
__.V().outE().values("weight").sum(), Collections.emptyList()},
+                {__.V().outE().hasLabel("knows").values("weight"), 
__.V().local(outE().hasLabel("knows").values("weight")), 
Collections.emptyList()},
+                {__.V().outE().values("weight").sum(), 
__.V().local(outE().values("weight")).sum(), Collections.emptyList()},
                 {__.V().inE().values("weight"), 
__.V().local(inE().values("weight")), Collections.emptyList()},
                 {__.V().inE().values("weight").sum(), 
__.V().local(inE().values("weight")).sum(), Collections.emptyList()},
                 {__.V().inE().values("weight").sum().dedup().count(), 
__.V().local(inE().values("weight")).sum().dedup().count(), 
Collections.emptyList()},
@@ -110,7 +116,13 @@ public class SingleIterationStrategyTest {
                 {__.V().inE().id().groupCount(), 
__.V().local(inE().id()).groupCount(), Collections.emptyList()},
                 {__.V().inE().values("weight").groupCount(), 
__.V().local(inE().values("weight")).groupCount(), Collections.emptyList()},
                 {__.V().outE().inV().tree(), __.V().outE().inV().tree(), 
Collections.emptyList()},
-                {__.V().in().values("name").groupCount(), 
__.V().in().values("name").groupCount(), Collections.emptyList()}
+                {__.V().in().values("name").groupCount(), 
__.V().in().values("name").groupCount(), Collections.emptyList()},
+                {__.V().outE().inV().groupCount("x"), 
__.V().outE().inV().groupCount("x"), Collections.emptyList()},
+                {__.V().in().dedup().count(), 
__.V().local(in().id()).dedup().count(), Collections.emptyList()},
+                {__.V().bothE().dedup().count(), 
__.V().local(bothE().id()).dedup().count(), Collections.emptyList()},
+                {__.V().bothE().dedup().by("name").count(), 
__.V().bothE().dedup().by("name").count(), Collections.emptyList()},
+                {__.V().map(mapFunction).inV().count(), 
__.V().map(mapFunction).inV().count(), Collections.emptyList()},
+                
{__.V().groupCount().by(__.out().count()),__.V().groupCount().by(__.out().count()),Collections.emptyList()}
         });
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/1819e05a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
----------------------------------------------------------------------
diff --git 
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
 
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
index b055eb8..4297649 100644
--- 
a/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
+++ 
b/spark-gremlin/src/test/java/org/apache/tinkerpop/gremlin/spark/process/computer/traversal/strategy/optimization/SparkSingleIterationStrategyTest.java
@@ -139,22 +139,23 @@ public class SparkSingleIterationStrategyTest extends 
AbstractSparkTest {
         test(true, g.V().outE().groupCount().by("weight"));
         test(true, g.V().inE().id().groupCount());
         test(true, g.V().inE().values("weight").groupCount());
+        test(true, 6L, g.V().outE().outV().count());
+        test(true, g.V().out().id().groupCount("x"));
+        test(true, g.V().inE().values("weight").groupCount("x"));
+        test(true, 6L, g.V().in().count());
+        test(true, 12L, g.V().both().count());
+        test(true, 6L, g.V().flatMap(__.in()).count());
+        test(true, 4L, g.V().map(__.in()).count());
+        test(true, 6L, g.V().inE().count());
+        test(true, 4L, g.V().outE().inV().dedup().count());
         /////
         test(false, 6L, g.V().as("a").outE().inV().as("b").id().dedup("a", 
"b").by(T.id).count());
         test(false, 6L, g.V().local(__.inE()).count());
-        test(false, 6L, g.V().outE().outV().count()); // todo: low probability 
traversal, but none the less could be optimized for
-        test(false, g.V().out().id().groupCount("x")); // todo: low 
probability traversal, but none the less could be optimized for
-        test(false, g.V().inE().values("weight").groupCount("x")); // todo: 
low probability traversal, but none the less could be optimized for
-        test(false, 6L, g.V().in().count());
-        test(false, 6L, g.V().flatMap(__.in()).count());
-        test(false, 4L, g.V().map(__.in()).count());
+        test(false, 4L, g.V().outE().inV().dedup().by("name").count());
         test(false, 6L, g.V().local(__.in()).count());
-        test(false, 6L, g.V().inE().count());
         test(false, g.V().outE().inV());
         test(false, g.V().both());
-        test(false, 12L, g.V().both().count());
         test(false, g.V().outE().inV().dedup());
-        test(false, 4L, g.V().outE().inV().dedup().count());
         test(false, 2L, g.V().out().out().count());
         test(false, 6L, g.V().as("a").map(__.both()).select("a").count());
         test(false, g.V().out().values("name"));
@@ -168,6 +169,7 @@ public class SparkSingleIterationStrategyTest extends 
AbstractSparkTest {
         test(false, g.V().outE().inV().groupCount());
         test(false, g.V().outE().inV().groupCount().by("name"));
         test(false, g.V().outE().inV().tree());
+        test(false, g.V().outE().inV().id().tree());
         test(false, g.V().inE().groupCount());
         test(false, g.V().inE().groupCount().by("weight"));
         test(false, g.V().in().values("name").groupCount());

Reply via email to