You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2015/06/18 16:38:26 UTC

[1/3] incubator-tinkerpop git commit: Removed MatchStep and replaced it with XMatchStep. Renamed XMatchStep, MatchStep. All the tests are passing for OLTP and OLAP except one in OLAP that makes sense why it doesnt pass, but the pattern should be caught b

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master e2116901c -> 2f8026341


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
index c68d4f3..1916379 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
@@ -168,45 +168,45 @@ public class TinkerGraphTest {
                 /*() -> g.V().xmatch("a",
                         as("a").in("sungBy").as("b"),
                         not(as("a").in("writtenBy").as("b"))).select().by("name"),*/
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").in("sungBy").as("b"),
                         as("a").in("writtenBy").as("b")).select().by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").out("followedBy").as("b"),
                         as("b").out("followedBy").as("a")).select().by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").out("followedBy").count().as("b"),
                         as("a").in("followedBy").count().as("b"),
                         as("b").is(P.gt(10))).select("a").by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").in("sungBy").count().as("b"),
                         as("a").in("sungBy").as("c"),
                         as("c").out("followedBy").as("d"),
                         as("d").out("sungBy").as("e"),
                         as("e").in("sungBy").count().as("b"),
                         where("a",P.neq("e"))).select("a","e").by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").in("followedBy").as("b"),
                         as("a").out("sungBy").as("c"),
                         as("a").out("writtenBy").as("d")).select().by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").in("followedBy").as("b"),
                         as("a").out("sungBy").as("c"),
                         as("a").out("writtenBy").as("d"),
                         where("c", P.neq("d"))).select().by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").in("sungBy").as("b"),
                         as("a").in("writtenBy").as("b"),
                         as("b").out("followedBy").as("c"),
                         as("c").out("sungBy").as("a"),
                         as("c").out("writtenBy").as("a")).select().by("name"),
-                () -> g.V().xmatch("a",
+                () -> g.V().match("a",
                         as("a").has("name", "Garcia"),
                         as("a").in("writtenBy").as("b"),
                         as("b").out("followedBy").as("c"),
                         as("c").out("writtenBy").as("d"),
                         as("d").where(P.neq("a"))).select().by("name"),
-                () -> g.V().as("a").out("followedBy").as("b").xmatch(
+                () -> g.V().as("a").out("followedBy").as("b").match(
                         as("a").and(has(T.label,"song"),has("performances",P.gt(10))),
                         as("a").out("writtenBy").as("c"),
                         as("b").out("writtenBy").as("c")).select().by("name"));
@@ -238,7 +238,7 @@ public class TinkerGraphTest {
                 .select().by("name");*/
 
         final Supplier<Traversal<?, ?>> traversal = () ->
-                g.V().xmatch("a",
+                g.V().match("a",
                         where("a", P.neq("c")),
                         as("a").out("created").as("b"),
                         or(
@@ -287,7 +287,7 @@ public class TinkerGraphTest {
             });
         });
         graph.vertices(50).next().addEdge("uncle", graph.vertices(70).next());
-        System.out.println(TimeUtil.clockWithResult(500, () -> g.V().xmatch("a", as("a").out("knows").as("b"), as("a").out("uncle").as("b")).toList()));
+        System.out.println(TimeUtil.clockWithResult(500, () -> g.V().match("a", as("a").out("knows").as("b"), as("a").out("uncle").as("b")).toList()));
     }
 
     @Test


[3/3] incubator-tinkerpop git commit: Removed MatchStep and replaced it with XMatchStep. Renamed XMatchStep, MatchStep. All the tests are passing for OLTP and OLAP except one in OLAP that makes sense why it doesnt pass, but the pattern should be caught b

Posted by ok...@apache.org.
Removed MatchStep and replaced it with XMatchStep. Renamed XMatchStep, MatchStep. All the tests are passing for OLTP and OLAP except one in OLAP that makes sense why it doesnt pass, but the pattern should be caught by ComputerVerificationStrategy. Testing model in MatchTest revamped using AbstractGremlinProcessTest.checkResults() model which automagically tests Map streams.


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

Branch: refs/heads/master
Commit: 2f8026341803c3b8bfc924ff189f09ab02e3aa5f
Parents: e211690
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu Jun 18 08:38:20 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu Jun 18 08:38:20 2015 -0600

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   1 +
 .../traversal/dsl/graph/GraphTraversal.java     |  20 +-
 .../gremlin/process/traversal/dsl/graph/__.java |  19 +-
 .../traversal/step/filter/exp/XMatchStep.java   | 486 --------------
 .../process/traversal/step/map/MatchStep.java   | 485 ++++++++++++++
 .../traversal/step/map/match/Bindings.java      |  87 ---
 .../step/map/match/CrossJoinEnumerator.java     |  96 ---
 .../traversal/step/map/match/Enumerator.java    |  46 --
 .../step/map/match/InnerJoinEnumerator.java     | 129 ----
 .../step/map/match/IteratorEnumerator.java      |  67 --
 .../traversal/step/map/match/MatchStep.java     | 596 -----------------
 .../step/map/match/SerialEnumerator.java        | 119 ----
 .../step/map/match/SimpleEnumerator.java        |  66 --
 .../optimization/MatchWhereStrategy.java        |  17 +-
 .../ComputerVerificationStrategy.java           |   5 +-
 .../traversal/step/map/GroovyMatchTest.groovy   |  10 +-
 .../process/AbstractGremlinProcessTest.java     |   7 +-
 .../process/traversal/step/map/MatchTest.java   | 642 +++----------------
 .../tinkergraph/structure/TinkerGraphTest.java  |  22 +-
 19 files changed, 633 insertions(+), 2287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 6c26abe..1e16282 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::http://www.tinkerpop.com/docs/current/images/gremlin-hindu.png[width=225]
 TinkerPop 3.0.0.GA (NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Rewrote `MatchStep` where it now works on `GraphComputer`, solves more patterns, provides plugable execution plans, supports nested AND/OR, etc.
 * Renamed `Graphs` in Gremlin Server to `GraphManager`.
 * Arrow keys for cycling through command history now work in Gremlin Console when being used on Windows.
 * Added `NotStep` and `not(traversal)` for not'ing a traversal (integrates like `ConjunctionStep`).

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
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 86b7d1f..4dfc82c 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
@@ -58,7 +58,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TailGlobalStep
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TimeLimitStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TraversalFilterStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.exp.XMatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.CoalesceStep;
@@ -75,6 +74,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.IdStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.LabelStep;
 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.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxLocalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanGlobalStep;
@@ -101,7 +101,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.TreeStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.match.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AddPropertyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupCountSideEffectStep;
@@ -476,9 +475,12 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         return this.asAdmin().addStep(new PathStep<>(this.asAdmin()));
     }
 
-    public default <E2> GraphTraversal<S, Map<String, E2>> match(final String startLabel, final Traversal<?, ?>... traversals) {
-        return (GraphTraversal) this.asAdmin().addStep(new MatchStep<E, Map<String, E2>>(this.asAdmin(), startLabel, traversals));
-        //return this.asAdmin().addStep(new XMatchStep<>(this.asAdmin(), startLabel, XMatchStep.Conjunction.AND, traversals));
+    public default <E2> GraphTraversal<S, Map<String, E2>> match(final String startKey, final Traversal<?, ?>... andTraversals) {
+        return this.asAdmin().addStep(new MatchStep<>(this.asAdmin(), startKey, MatchStep.Conjunction.AND, andTraversals));
+    }
+
+    public default <E2> GraphTraversal<S, Map<String, E2>> match(final Traversal<?, ?>... andTraversals) {
+        return this.match(null, andTraversals);
     }
 
     /**
@@ -1036,14 +1038,6 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
     ////
 
-    public default <E2> GraphTraversal<S, Map<String, E2>> xmatch(final String startKey, final Traversal<?, ?>... andTraversals) {
-        return this.asAdmin().addStep(new XMatchStep<>(this.asAdmin(), startKey, XMatchStep.Conjunction.AND, andTraversals));
-    }
-
-    public default <E2> GraphTraversal<S, Map<String, E2>> xmatch(final Traversal<?, ?>... andTraversals) {
-        return this.xmatch(null, andTraversals);
-    }
-
     @Override
     public default GraphTraversal<S, E> iterate() {
         Traversal.super.iterate();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
----------------------------------------------------------------------
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 16117f5..be14115 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
@@ -275,8 +275,15 @@ public class __ {
     /**
      * @see {@link GraphTraversal#match(String, Traversal[])}
      */
-    public static <A, B> GraphTraversal<A, Map<String, B>> match(final String startLabel, final Traversal<?, ?>... traversals) {
-        return __.<A>start().match(startLabel, traversals);
+    public static <A, B> GraphTraversal<A, Map<String, B>> match(final String startKey, final Traversal<?, ?>... andTraversals) {
+        return __.<A>start().match(startKey, andTraversals);
+    }
+
+    /**
+     * @see {@link GraphTraversal#match(Traversal[])}
+     */
+    public static <A, B> GraphTraversal<A, Map<String, B>> match(final Traversal<?, ?>... andTraversals) {
+        return __.<A>start().match(andTraversals);
     }
 
     /**
@@ -794,12 +801,4 @@ public class __ {
         return __.<A>start().barrier(maxBarrierSize);
     }
 
-    public static <A, B> GraphTraversal<A, Map<String, B>> xmatch(final String startKey, final Traversal<?, ?>... andTraversals) {
-        return __.<A>start().xmatch(startKey, andTraversals);
-    }
-
-    public static <A, B> GraphTraversal<A, Map<String, B>> xmatch(final Traversal<?, ?>... andTraversals) {
-        return __.<A>start().xmatch(andTraversals);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
deleted file mode 100644
index e3384fa..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- *
- *  * Licensed to the Apache Software Foundation (ASF) under one
- *  * or more contributor license agreements.  See the NOTICE file
- *  * distributed with this work for additional information
- *  * regarding copyright ownership.  The ASF licenses this file
- *  * to you under the Apache License, Version 2.0 (the
- *  * "License"); you may not use this file except in compliance
- *  * with the License.  You may obtain a copy of the License at
- *  *
- *  * http://www.apache.org/licenses/LICENSE-2.0
- *  *
- *  * Unless required by applicable law or agreed to in writing,
- *  * software distributed under the License is distributed on an
- *  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  * KIND, either express or implied.  See the License for the
- *  * specific language governing permissions and limitations
- *  * under the License.
- *
- */
-
-package org.apache.tinkerpop.gremlin.process.traversal.step.filter.exp;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
-import org.apache.tinkerpop.gremlin.process.traversal.Pop;
-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.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ConjunctionStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.ReducingBarrierStep;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConjunctionStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public final class XMatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>> implements TraversalParent, Scoping {
-
-    public enum Conjunction {AND, OR}
-
-    private List<Traversal.Admin<Object, Object>> conjunctionTraversals = new ArrayList<>();
-    private boolean first = true;
-    private Set<String> matchStartLabels = new HashSet<>();
-    private Set<String> matchEndLabels = new HashSet<>();
-    private Set<String> scopeKeys = null;
-    private final Conjunction conjunction;
-    private final String startKey;
-    private final MatchAlgorithm matchAlgorithm = new GreedyMatchAlgorithm();
-
-    public XMatchStep(final Traversal.Admin traversal, final String startKey, final Conjunction conjunction, final Traversal... conjunctionTraversals) {
-        super(traversal);
-        this.conjunction = conjunction;
-        this.startKey = startKey;
-        if (null != this.startKey) {
-            if (this.traversal.getEndStep() instanceof StartStep)  // in case a match() is after the start step
-                this.traversal.addStep(new IdentityStep<>(this.traversal));
-            this.traversal.getEndStep().addLabel(this.startKey);
-        }
-        this.conjunctionTraversals = (List) Stream.of(conjunctionTraversals).map(Traversal::asAdmin).collect(Collectors.toList());
-        this.conjunctionTraversals.forEach(this::configureStartAndEndSteps); // recursively convert to XMatchStep, XMatchStartStep, or XMatchEndStep
-        this.conjunctionTraversals.forEach(this::integrateChild);
-    }
-
-    private void configureStartAndEndSteps(final Traversal.Admin<?, ?> conjunctionTraversal) {
-        ConjunctionStrategy.instance().apply(conjunctionTraversal);
-        // START STEP to XMatchStep OR XMatchStartStep
-        final Step<?, ?> startStep = conjunctionTraversal.getStartStep();
-        if (startStep instanceof ConjunctionStep) {
-            final XMatchStep xMatchStep = new XMatchStep(conjunctionTraversal, this.startKey,
-                    startStep instanceof AndStep ? XMatchStep.Conjunction.AND : XMatchStep.Conjunction.OR,
-                    ((ConjunctionStep<?>) startStep).getLocalChildren().toArray(new Traversal[((ConjunctionStep<?>) startStep).getLocalChildren().size()]));
-            TraversalHelper.replaceStep(startStep, xMatchStep, conjunctionTraversal);
-            this.matchStartLabels.addAll(xMatchStep.matchStartLabels);
-            this.matchEndLabels.addAll(xMatchStep.matchEndLabels);
-        } else if (startStep instanceof StartStep) {
-            if (startStep.getLabels().size() != 1)
-                throw new IllegalArgumentException("The start step of a match()-traversal must have one and only one label: " + startStep);
-            final String label = startStep.getLabels().iterator().next();
-            this.matchStartLabels.add(label);
-            TraversalHelper.replaceStep((Step) conjunctionTraversal.getStartStep(), new XMatchStartStep(conjunctionTraversal, label), conjunctionTraversal);
-        } else {
-            TraversalHelper.insertBeforeStep(new XMatchStartStep(conjunctionTraversal, null), (Step) conjunctionTraversal.getStartStep(), conjunctionTraversal);
-        }
-        // END STEP to XMatchEndStep
-        final Step<?, ?> endStep = conjunctionTraversal.getEndStep();
-        if (!(endStep instanceof XMatchStep.XMatchEndStep)) {
-            if (endStep.getLabels().size() > 1)
-                throw new IllegalArgumentException("The end step of a match()-traversal can have at most one label: " + endStep);
-            final String label = endStep.getLabels().size() == 0 ? null : endStep.getLabels().iterator().next();
-            if (null != label) endStep.removeLabel(label);
-            final Step<?, ?> xMatchEndStep = new XMatchEndStep(conjunctionTraversal, label);
-            if (null != label) this.matchEndLabels.add(label);
-            conjunctionTraversal.asAdmin().addStep(xMatchEndStep);
-        }
-        // this turns barrier computations into locally computable traversals
-        if (!TraversalHelper.getStepsOfAssignableClass(ReducingBarrierStep.class, conjunctionTraversal).isEmpty()) {
-            final Traversal.Admin newTraversal = new DefaultTraversal<>();
-            TraversalHelper.removeToTraversal(conjunctionTraversal.getStartStep().getNextStep(), conjunctionTraversal.getEndStep(), newTraversal);
-            TraversalHelper.insertAfterStep(new TraversalFlatMapStep<>(conjunctionTraversal, newTraversal), conjunctionTraversal.getStartStep(), conjunctionTraversal);
-        }
-    }
-
-    @Override
-    public void removeGlobalChild(final Traversal.Admin<?, ?> globalChildTraversal) {
-        this.conjunctionTraversals.remove(globalChildTraversal);
-    }
-
-    @Override
-    public List<Traversal.Admin<Object, Object>> getGlobalChildren() {
-        return Collections.unmodifiableList(this.conjunctionTraversals);
-    }
-
-    @Override
-    public Scope getScope() {
-        return Scope.global;
-    }
-
-    @Override
-    public Scope recommendNextScope() {
-        return Scope.local;
-    }
-
-    @Override
-    public void setScope(final Scope scope) {
-
-    }
-
-    public Optional<String> getStartKey() {
-        return Optional.ofNullable(this.startKey);
-    }
-
-    @Override
-    public Set<String> getScopeKeys() {
-        if (null == this.scopeKeys) {
-            this.scopeKeys = new HashSet<>();
-            this.conjunctionTraversals.forEach(traversal -> {
-                if (traversal.getStartStep() instanceof Scoping)
-                    this.scopeKeys.addAll(((Scoping) traversal.getStartStep()).getScopeKeys());
-                if (traversal.getEndStep() instanceof Scoping)
-                    this.scopeKeys.addAll(((Scoping) traversal.getEndStep()).getScopeKeys());
-            });
-            this.scopeKeys.removeAll(this.matchEndLabels);
-            this.scopeKeys.remove(this.startKey);
-        }
-        return this.scopeKeys;
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.stepString(this, this.conjunction, this.conjunctionTraversals);
-    }
-
-    @Override
-    public void reset() {
-        super.reset();
-        //this.first = true;
-    }
-
-    @Override
-    public XMatchStep<S, E> clone() {
-        final XMatchStep<S, E> clone = (XMatchStep<S, E>) super.clone();
-        clone.conjunctionTraversals = new ArrayList<>();
-        for (final Traversal.Admin<Object, Object> traversal : this.conjunctionTraversals) {
-            clone.conjunctionTraversals.add(clone.integrateChild(traversal.clone()));
-        }
-        // TODO: does it need to clone the match algorithm?
-        return clone;
-    }
-
-    private boolean hasMatched(final Conjunction conjunction, final Traverser<S> traverser) {
-        final Path path = traverser.path();
-        int counter = 0;
-        for (final Traversal.Admin<Object, Object> conjunctionTraversal : this.conjunctionTraversals) {
-            if (path.hasLabel(conjunctionTraversal.getStartStep().getId())) {
-                if (conjunction == Conjunction.OR) return true;
-                counter++;
-            }
-        }
-        return this.conjunctionTraversals.size() == counter;
-    }
-
-    private Map<String, E> getBindings(final Traverser<S> traverser) {
-        final Map<String, E> bindings = new HashMap<>();
-        traverser.path().forEach((object, labels) -> {
-            for (final String label : labels) {
-                if (this.matchEndLabels.contains(label)) {
-                    bindings.put(label, (E) object);
-                } else if (this.matchStartLabels.contains(label)) {
-                    bindings.put(label, (E) object);
-                }
-            }
-        });
-        return bindings;
-    }
-
-    @Override
-    protected Iterator<Traverser<Map<String, E>>> standardAlgorithm() throws NoSuchElementException {
-        while (true) {
-            Traverser.Admin traverser = null;
-            if (this.first) {
-                this.first = false;
-                this.matchAlgorithm.initialize(this.conjunctionTraversals);
-            } else {
-                for (final Traversal.Admin<?, ?> conjunctionTraversal : this.conjunctionTraversals) {
-                    if (conjunctionTraversal.hasNext()) {
-                        traverser = conjunctionTraversal.getEndStep().next().asAdmin();
-                        break;
-                    }
-                }
-            }
-            if (null == traverser)
-                traverser = this.starts.next();
-            else if (hasMatched(this.conjunction, traverser))
-                return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
-
-            if (this.conjunction == Conjunction.AND) {
-                this.matchAlgorithm.apply(traverser).addStart(traverser); // determine which sub-pattern the traverser should try next
-            } else {
-                for (final Traversal.Admin<?, ?> conjunctionTraversal : this.conjunctionTraversals) {
-                    final Traverser split = traverser.split();
-                    split.path().addLabel(conjunctionTraversal.getParent().asStep().getId());
-                    conjunctionTraversal.addStart(split);
-                }
-            }
-        }
-    }
-
-    @Override
-    protected Iterator<Traverser<Map<String, E>>> computerAlgorithm() throws NoSuchElementException {
-        if (this.first) {
-            this.first = false;
-            this.matchAlgorithm.initialize(this.conjunctionTraversals);
-        }
-        final Traverser.Admin traverser = this.starts.next();
-        if (hasMatched(this.conjunction, traverser)) {
-            traverser.setStepId(this.getNextStep().getId());
-            return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
-        }
-
-        if (this.conjunction == Conjunction.AND) {
-            final Traversal.Admin<Object, Object> conjunctionTraversal = this.matchAlgorithm.apply(traverser); // determine which sub-pattern the traverser should try next
-            traverser.setStepId(conjunctionTraversal.getStartStep().getId()); // go down the traversal match sub-pattern
-            return IteratorUtils.of(traverser);
-        } else {
-            final List<Traverser<Map<String, E>>> traversers = new ArrayList<>();
-            this.conjunctionTraversals.forEach(conjunctionTraversal -> {
-                final Traverser.Admin split = traverser.split();
-                split.path().addLabel(conjunctionTraversal.getParent().asStep().getId());
-                split.setStepId(conjunctionTraversal.getStartStep().getId());
-                traversers.add(split);
-            });
-            return traversers.iterator();
-        }
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ this.conjunctionTraversals.hashCode() ^ (null == this.startKey ? "null".hashCode() : this.startKey.hashCode());
-    }
-
-    @Override
-    public Set<TraverserRequirement> getRequirements() {
-        return this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
-    }
-
-    //////////////////////////////
-
-    public class XMatchStartStep extends AbstractStep<Object, Object> implements Scoping {
-
-        private final String selectKey;
-        private Set<String> scopeKeys = null;
-
-        public XMatchStartStep(final Traversal.Admin traversal, final String selectKey) {
-            super(traversal);
-            this.selectKey = selectKey;
-        }
-
-        @Override
-        protected Traverser<Object> processNextStart() throws NoSuchElementException {
-            final Traverser.Admin<Object> traverser = this.starts.next();
-            traverser.path().addLabel(this.getId());
-            XMatchStep.this.matchAlgorithm.recordStart(traverser, this.getTraversal());
-            // TODO: sideEffect check?
-            return null == this.selectKey ? traverser : traverser.split(traverser.path().getSingle(Pop.last, this.selectKey), this);
-        }
-
-        @Override
-        public String toString() {
-            return StringFactory.stepString(this, this.selectKey);
-        }
-
-        @Override
-        public int hashCode() {
-            return super.hashCode() ^ (null == this.selectKey ? "null".hashCode() : this.selectKey.hashCode());
-        }
-
-        @Override
-        public Scope getScope() {
-            return Scope.global;
-        }
-
-        @Override
-        public Scope recommendNextScope() {
-            return Scope.global;
-        }
-
-        @Override
-        public void setScope(final Scope scope) {
-
-        }
-
-        public Optional<String> getSelectKey() {
-            return Optional.ofNullable(this.selectKey);
-        }
-
-        @Override
-        public Set<String> getScopeKeys() {
-            if (null == this.scopeKeys) {
-                this.scopeKeys = new HashSet<>();
-                if (null != this.selectKey) this.scopeKeys.add(this.selectKey);
-                this.getTraversal().getSteps().forEach(step -> {
-                    if (step instanceof XMatchStep || step instanceof WhereStep)
-                        this.scopeKeys.addAll(((Scoping) step).getScopeKeys());
-                });
-            }
-            return this.scopeKeys;
-        }
-    }
-
-    public class XMatchEndStep extends EndStep {
-
-        private final String matchKey;
-
-        public XMatchEndStep(final Traversal.Admin traversal, final String matchKey) {
-            super(traversal);
-            this.matchKey = matchKey;
-        }
-
-        @Override
-        protected Traverser<S> processNextStart() throws NoSuchElementException {
-            while (true) {
-                final Traverser.Admin traverser = this.starts.next();
-                // no end label
-                if (null == this.matchKey) {
-                    if (this.traverserStepIdSetByChild) traverser.setStepId(XMatchStep.this.getId());
-                    XMatchStep.this.matchAlgorithm.recordEnd(traverser, this.getTraversal());
-                    return traverser;
-                }
-                // TODO: sideEffect check?
-                // path check
-                final Path path = traverser.path();
-                if (!path.hasLabel(this.matchKey) || traverser.get().equals(path.getSingle(Pop.first, this.matchKey))) {
-                    if (this.traverserStepIdSetByChild) traverser.setStepId(XMatchStep.this.getId());
-                    traverser.path().addLabel(this.matchKey);
-                    XMatchStep.this.matchAlgorithm.recordEnd(traverser, this.getTraversal());
-                    return traverser;
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            return StringFactory.stepString(this, this.matchKey);
-        }
-
-        @Override
-        public int hashCode() {
-            return super.hashCode() ^ (null == this.matchKey ? "null".hashCode() : this.matchKey.hashCode());
-        }
-    }
-
-
-    //////////////////////////////
-
-    public interface MatchAlgorithm extends Function<Traverser.Admin<Object>, Traversal.Admin<Object, Object>> {
-
-        public static Set<String> getRequiredLabels(final Traversal.Admin<Object, Object> traversal) {
-            final Step<?, ?> startStep = traversal.getStartStep();
-            if (startStep instanceof Scoping)
-                return ((Scoping) startStep).getScopeKeys();
-            else
-                throw new IllegalArgumentException("The provided start step must be a scoping step: " + startStep);
-        }
-
-        public void initialize(final List<Traversal.Admin<Object, Object>> traversals);
-
-        public default void recordStart(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
-
-        }
-
-        public default void recordEnd(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
-
-        }
-    }
-
-    public static class GreedyMatchAlgorithm implements MatchAlgorithm {
-
-        private List<Traversal.Admin<Object, Object>> traversals;
-        private List<String> traversalLabels = new ArrayList<>();
-        private List<Set<String>> requiredLabels = new ArrayList<>();
-
-        @Override
-        public void initialize(final List<Traversal.Admin<Object, Object>> traversals) {
-            this.traversals = traversals;
-            for (final Traversal.Admin<Object, Object> traversal : this.traversals) {
-                this.traversalLabels.add(traversal.getStartStep().getId());
-                this.requiredLabels.add(MatchAlgorithm.getRequiredLabels(traversal));
-            }
-        }
-
-        @Override
-        public Traversal.Admin<Object, Object> apply(final Traverser.Admin<Object> traverser) {
-            final Path path = traverser.path();
-            for (int i = 0; i < this.traversals.size(); i++) {
-                if (!path.hasLabel(this.traversalLabels.get(i)) && !this.requiredLabels.get(i).stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
-                    return this.traversals.get(i);
-                }
-            }
-            throw new IllegalArgumentException("The provided match pattern is unsolvable: " + this.traversals);
-        }
-    }
-
-    public static class CountMatchAlgorithm implements MatchAlgorithm {
-
-        private List<Traversal.Admin<Object, Object>> traversals;
-        private List<Integer[]> counts = new ArrayList<>();
-        private List<String> traversalLabels = new ArrayList<>();
-        private List<Set<String>> requiredLabels = new ArrayList<>();
-
-        @Override
-        public void initialize(final List<Traversal.Admin<Object, Object>> traversals) {
-            this.traversals = traversals;
-            for (int i = 0; i < this.traversals.size(); i++) {
-                final Traversal.Admin<Object, Object> traversal = this.traversals.get(i);
-                this.traversalLabels.add(traversal.getStartStep().getId());
-                this.requiredLabels.add(MatchAlgorithm.getRequiredLabels(traversal));
-                this.counts.add(new Integer[]{i, 0});
-            }
-        }
-
-        @Override
-        public Traversal.Admin<Object, Object> apply(final Traverser.Admin<Object> traverser) {
-            final Path path = traverser.path();
-            for (final Integer[] indexCounts : this.counts) {
-                if (!path.hasLabel(this.traversalLabels.get(indexCounts[0])) && !this.requiredLabels.get(indexCounts[0]).stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
-                    return this.traversals.get(indexCounts[0]);
-                }
-            }
-            throw new IllegalArgumentException("The provided match pattern is unsolvable: " + this.traversals);
-        }
-
-        public void recordEnd(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
-            final int currentIndex = this.traversals.indexOf(traversal);
-            this.counts.stream().filter(array -> currentIndex == array[0]).findAny().get()[1]++;
-            Collections.sort(this.counts, (a, b) -> a[1].compareTo(b[1]));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
new file mode 100644
index 0000000..69f30a6
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -0,0 +1,485 @@
+/*
+ *
+ *  * Licensed to the Apache Software Foundation (ASF) under one
+ *  * or more contributor license agreements.  See the NOTICE file
+ *  * distributed with this work for additional information
+ *  * regarding copyright ownership.  The ASF licenses this file
+ *  * to you under the Apache License, Version 2.0 (the
+ *  * "License"); you may not use this file except in compliance
+ *  * with the License.  You may obtain a copy of the License at
+ *  *
+ *  * http://www.apache.org/licenses/LICENSE-2.0
+ *  *
+ *  * Unless required by applicable law or agreed to in writing,
+ *  * software distributed under the License is distributed on an
+ *  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  * KIND, either express or implied.  See the License for the
+ *  * specific language governing permissions and limitations
+ *  * under the License.
+ *
+ */
+
+package org.apache.tinkerpop.gremlin.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+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.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ConjunctionStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.ReducingBarrierStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConjunctionStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>> implements TraversalParent, Scoping {
+
+    public enum Conjunction {AND, OR}
+
+    private List<Traversal.Admin<Object, Object>> conjunctionTraversals = new ArrayList<>();
+    private boolean first = true;
+    private Set<String> matchStartLabels = new HashSet<>();
+    private Set<String> matchEndLabels = new HashSet<>();
+    private Set<String> scopeKeys = null;
+    private final Conjunction conjunction;
+    private final String startKey;
+    private final MatchAlgorithm matchAlgorithm = new GreedyMatchAlgorithm();
+
+    public MatchStep(final Traversal.Admin traversal, final String startKey, final Conjunction conjunction, final Traversal... conjunctionTraversals) {
+        super(traversal);
+        this.conjunction = conjunction;
+        this.startKey = startKey;
+        if (null != this.startKey) {
+            if (this.traversal.getEndStep() instanceof StartStep)  // in case a match() is after the start step
+                this.traversal.addStep(new IdentityStep<>(this.traversal));
+            this.traversal.getEndStep().addLabel(this.startKey);
+        }
+        this.conjunctionTraversals = (List) Stream.of(conjunctionTraversals).map(Traversal::asAdmin).collect(Collectors.toList());
+        this.conjunctionTraversals.forEach(this::configureStartAndEndSteps); // recursively convert to MatchStep, MatchStartStep, or MatchEndStep
+        this.conjunctionTraversals.forEach(this::integrateChild);
+    }
+
+    private void configureStartAndEndSteps(final Traversal.Admin<?, ?> conjunctionTraversal) {
+        ConjunctionStrategy.instance().apply(conjunctionTraversal);
+        // START STEP to XMatchStep OR XMatchStartStep
+        final Step<?, ?> startStep = conjunctionTraversal.getStartStep();
+        if (startStep instanceof ConjunctionStep) {
+            final MatchStep matchStep = new MatchStep(conjunctionTraversal, this.startKey,
+                    startStep instanceof AndStep ? MatchStep.Conjunction.AND : MatchStep.Conjunction.OR,
+                    ((ConjunctionStep<?>) startStep).getLocalChildren().toArray(new Traversal[((ConjunctionStep<?>) startStep).getLocalChildren().size()]));
+            TraversalHelper.replaceStep(startStep, matchStep, conjunctionTraversal);
+            this.matchStartLabels.addAll(matchStep.matchStartLabels);
+            this.matchEndLabels.addAll(matchStep.matchEndLabels);
+        } else if (startStep instanceof StartStep) {
+            if (startStep.getLabels().size() != 1)
+                throw new IllegalArgumentException("The start step of a match()-traversal must have one and only one label: " + startStep);
+            final String label = startStep.getLabels().iterator().next();
+            this.matchStartLabels.add(label);
+            TraversalHelper.replaceStep((Step) conjunctionTraversal.getStartStep(), new MatchStartStep(conjunctionTraversal, label), conjunctionTraversal);
+        } else {
+            TraversalHelper.insertBeforeStep(new MatchStartStep(conjunctionTraversal, null), (Step) conjunctionTraversal.getStartStep(), conjunctionTraversal);
+        }
+        // END STEP to XMatchEndStep
+        final Step<?, ?> endStep = conjunctionTraversal.getEndStep();
+        if (!(endStep instanceof MatchStep.MatchEndStep)) {
+            if (endStep.getLabels().size() > 1)
+                throw new IllegalArgumentException("The end step of a match()-traversal can have at most one label: " + endStep);
+            final String label = endStep.getLabels().size() == 0 ? null : endStep.getLabels().iterator().next();
+            if (null != label) endStep.removeLabel(label);
+            final Step<?, ?> xMatchEndStep = new MatchEndStep(conjunctionTraversal, label);
+            if (null != label) this.matchEndLabels.add(label);
+            conjunctionTraversal.asAdmin().addStep(xMatchEndStep);
+        }
+        // this turns barrier computations into locally computable traversals
+        if (!TraversalHelper.getStepsOfAssignableClass(ReducingBarrierStep.class, conjunctionTraversal).isEmpty()) {
+            final Traversal.Admin newTraversal = new DefaultTraversal<>();
+            TraversalHelper.removeToTraversal(conjunctionTraversal.getStartStep().getNextStep(), conjunctionTraversal.getEndStep(), newTraversal);
+            TraversalHelper.insertAfterStep(new TraversalFlatMapStep<>(conjunctionTraversal, newTraversal), conjunctionTraversal.getStartStep(), conjunctionTraversal);
+        }
+    }
+
+    @Override
+    public void removeGlobalChild(final Traversal.Admin<?, ?> globalChildTraversal) {
+        this.conjunctionTraversals.remove(globalChildTraversal);
+    }
+
+    @Override
+    public List<Traversal.Admin<Object, Object>> getGlobalChildren() {
+        return Collections.unmodifiableList(this.conjunctionTraversals);
+    }
+
+    @Override
+    public Scope getScope() {
+        return Scope.global;
+    }
+
+    @Override
+    public Scope recommendNextScope() {
+        return Scope.local;
+    }
+
+    @Override
+    public void setScope(final Scope scope) {
+
+    }
+
+    public Optional<String> getStartKey() {
+        return Optional.ofNullable(this.startKey);
+    }
+
+    @Override
+    public Set<String> getScopeKeys() {
+        if (null == this.scopeKeys) {
+            this.scopeKeys = new HashSet<>();
+            this.conjunctionTraversals.forEach(traversal -> {
+                if (traversal.getStartStep() instanceof Scoping)
+                    this.scopeKeys.addAll(((Scoping) traversal.getStartStep()).getScopeKeys());
+                if (traversal.getEndStep() instanceof Scoping)
+                    this.scopeKeys.addAll(((Scoping) traversal.getEndStep()).getScopeKeys());
+            });
+            this.scopeKeys.removeAll(this.matchEndLabels);
+            this.scopeKeys.remove(this.startKey);
+        }
+        return this.scopeKeys;
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, this.conjunction, this.conjunctionTraversals);
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        //this.first = true;
+    }
+
+    @Override
+    public MatchStep<S, E> clone() {
+        final MatchStep<S, E> clone = (MatchStep<S, E>) super.clone();
+        clone.conjunctionTraversals = new ArrayList<>();
+        for (final Traversal.Admin<Object, Object> traversal : this.conjunctionTraversals) {
+            clone.conjunctionTraversals.add(clone.integrateChild(traversal.clone()));
+        }
+        // TODO: does it need to clone the match algorithm?
+        return clone;
+    }
+
+    private boolean hasMatched(final Conjunction conjunction, final Traverser<S> traverser) {
+        final Path path = traverser.path();
+        int counter = 0;
+        for (final Traversal.Admin<Object, Object> conjunctionTraversal : this.conjunctionTraversals) {
+            if (path.hasLabel(conjunctionTraversal.getStartStep().getId())) {
+                if (conjunction == Conjunction.OR) return true;
+                counter++;
+            }
+        }
+        return this.conjunctionTraversals.size() == counter;
+    }
+
+    private Map<String, E> getBindings(final Traverser<S> traverser) {
+        final Map<String, E> bindings = new HashMap<>();
+        traverser.path().forEach((object, labels) -> {
+            for (final String label : labels) {
+                if (this.matchEndLabels.contains(label)) {
+                    bindings.put(label, (E) object);
+                } else if (this.matchStartLabels.contains(label)) {
+                    bindings.put(label, (E) object);
+                }
+            }
+        });
+        return bindings;
+    }
+
+    @Override
+    protected Iterator<Traverser<Map<String, E>>> standardAlgorithm() throws NoSuchElementException {
+        while (true) {
+            Traverser.Admin traverser = null;
+            if (this.first) {
+                this.first = false;
+                this.matchAlgorithm.initialize(this.conjunctionTraversals);
+            } else {
+                for (final Traversal.Admin<?, ?> conjunctionTraversal : this.conjunctionTraversals) {
+                    if (conjunctionTraversal.hasNext()) {
+                        traverser = conjunctionTraversal.getEndStep().next().asAdmin();
+                        break;
+                    }
+                }
+            }
+            if (null == traverser)
+                traverser = this.starts.next();
+            else if (hasMatched(this.conjunction, traverser))
+                return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
+
+            if (this.conjunction == Conjunction.AND) {
+                this.matchAlgorithm.apply(traverser).addStart(traverser); // determine which sub-pattern the traverser should try next
+            } else {
+                for (final Traversal.Admin<?, ?> conjunctionTraversal : this.conjunctionTraversals) {
+                    final Traverser split = traverser.split();
+                    split.path().addLabel(conjunctionTraversal.getParent().asStep().getId());
+                    conjunctionTraversal.addStart(split);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected Iterator<Traverser<Map<String, E>>> computerAlgorithm() throws NoSuchElementException {
+        if (this.first) {
+            this.first = false;
+            this.matchAlgorithm.initialize(this.conjunctionTraversals);
+        }
+        final Traverser.Admin traverser = this.starts.next();
+        if (hasMatched(this.conjunction, traverser)) {
+            traverser.setStepId(this.getNextStep().getId());
+            return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
+        }
+
+        if (this.conjunction == Conjunction.AND) {
+            final Traversal.Admin<Object, Object> conjunctionTraversal = this.matchAlgorithm.apply(traverser); // determine which sub-pattern the traverser should try next
+            traverser.setStepId(conjunctionTraversal.getStartStep().getId()); // go down the traversal match sub-pattern
+            return IteratorUtils.of(traverser);
+        } else {
+            final List<Traverser<Map<String, E>>> traversers = new ArrayList<>();
+            this.conjunctionTraversals.forEach(conjunctionTraversal -> {
+                final Traverser.Admin split = traverser.split();
+                split.path().addLabel(conjunctionTraversal.getParent().asStep().getId());
+                split.setStepId(conjunctionTraversal.getStartStep().getId());
+                traversers.add(split);
+            });
+            return traversers.iterator();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ this.conjunctionTraversals.hashCode() ^ (null == this.startKey ? "null".hashCode() : this.startKey.hashCode());
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements(TraverserRequirement.PATH, TraverserRequirement.SIDE_EFFECTS);
+    }
+
+    //////////////////////////////
+
+    public class MatchStartStep extends AbstractStep<Object, Object> implements Scoping {
+
+        private final String selectKey;
+        private Set<String> scopeKeys = null;
+
+        public MatchStartStep(final Traversal.Admin traversal, final String selectKey) {
+            super(traversal);
+            this.selectKey = selectKey;
+        }
+
+        @Override
+        protected Traverser<Object> processNextStart() throws NoSuchElementException {
+            final Traverser.Admin<Object> traverser = this.starts.next();
+            traverser.path().addLabel(this.getId());
+            MatchStep.this.matchAlgorithm.recordStart(traverser, this.getTraversal());
+            // TODO: sideEffect check?
+            return null == this.selectKey ? traverser : traverser.split(traverser.path().getSingle(Pop.last, this.selectKey), this);
+        }
+
+        @Override
+        public String toString() {
+            return StringFactory.stepString(this, this.selectKey);
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode() ^ (null == this.selectKey ? "null".hashCode() : this.selectKey.hashCode());
+        }
+
+        @Override
+        public Scope getScope() {
+            return Scope.global;
+        }
+
+        @Override
+        public Scope recommendNextScope() {
+            return Scope.global;
+        }
+
+        @Override
+        public void setScope(final Scope scope) {
+
+        }
+
+        public Optional<String> getSelectKey() {
+            return Optional.ofNullable(this.selectKey);
+        }
+
+        @Override
+        public Set<String> getScopeKeys() {
+            if (null == this.scopeKeys) {
+                this.scopeKeys = new HashSet<>();
+                if (null != this.selectKey) this.scopeKeys.add(this.selectKey);
+                this.getTraversal().getSteps().forEach(step -> {
+                    if (step instanceof MatchStep || step instanceof WhereStep)
+                        this.scopeKeys.addAll(((Scoping) step).getScopeKeys());
+                });
+            }
+            return this.scopeKeys;
+        }
+    }
+
+    public class MatchEndStep extends EndStep {
+
+        private final String matchKey;
+
+        public MatchEndStep(final Traversal.Admin traversal, final String matchKey) {
+            super(traversal);
+            this.matchKey = matchKey;
+        }
+
+        @Override
+        protected Traverser<S> processNextStart() throws NoSuchElementException {
+            while (true) {
+                final Traverser.Admin traverser = this.starts.next();
+                // no end label
+                if (null == this.matchKey) {
+                    if (this.traverserStepIdSetByChild) traverser.setStepId(MatchStep.this.getId());
+                    MatchStep.this.matchAlgorithm.recordEnd(traverser, this.getTraversal());
+                    return traverser;
+                }
+                // TODO: sideEffect check?
+                // path check
+                final Path path = traverser.path();
+                if (!path.hasLabel(this.matchKey) || traverser.get().equals(path.getSingle(Pop.first, this.matchKey))) {
+                    if (this.traverserStepIdSetByChild) traverser.setStepId(MatchStep.this.getId());
+                    traverser.path().addLabel(this.matchKey);
+                    MatchStep.this.matchAlgorithm.recordEnd(traverser, this.getTraversal());
+                    return traverser;
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return StringFactory.stepString(this, this.matchKey);
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode() ^ (null == this.matchKey ? "null".hashCode() : this.matchKey.hashCode());
+        }
+    }
+
+
+    //////////////////////////////
+
+    public interface MatchAlgorithm extends Function<Traverser.Admin<Object>, Traversal.Admin<Object, Object>> {
+
+        public static Set<String> getRequiredLabels(final Traversal.Admin<Object, Object> traversal) {
+            final Step<?, ?> startStep = traversal.getStartStep();
+            if (startStep instanceof Scoping)
+                return ((Scoping) startStep).getScopeKeys();
+            else
+                throw new IllegalArgumentException("The provided start step must be a scoping step: " + startStep);
+        }
+
+        public void initialize(final List<Traversal.Admin<Object, Object>> traversals);
+
+        public default void recordStart(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
+
+        }
+
+        public default void recordEnd(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
+
+        }
+    }
+
+    public static class GreedyMatchAlgorithm implements MatchAlgorithm {
+
+        private List<Traversal.Admin<Object, Object>> traversals;
+        private List<String> traversalLabels = new ArrayList<>();
+        private List<Set<String>> requiredLabels = new ArrayList<>();
+
+        @Override
+        public void initialize(final List<Traversal.Admin<Object, Object>> traversals) {
+            this.traversals = traversals;
+            for (final Traversal.Admin<Object, Object> traversal : this.traversals) {
+                this.traversalLabels.add(traversal.getStartStep().getId());
+                this.requiredLabels.add(MatchAlgorithm.getRequiredLabels(traversal));
+            }
+        }
+
+        @Override
+        public Traversal.Admin<Object, Object> apply(final Traverser.Admin<Object> traverser) {
+            final Path path = traverser.path();
+            for (int i = 0; i < this.traversals.size(); i++) {
+                if (!path.hasLabel(this.traversalLabels.get(i)) && !this.requiredLabels.get(i).stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
+                    return this.traversals.get(i);
+                }
+            }
+            throw new IllegalStateException("The provided match pattern is unsolvable: " + this.traversals);
+        }
+    }
+
+    public static class CountMatchAlgorithm implements MatchAlgorithm {
+
+        private List<Traversal.Admin<Object, Object>> traversals;
+        private List<Integer[]> counts = new ArrayList<>();
+        private List<String> traversalLabels = new ArrayList<>();
+        private List<Set<String>> requiredLabels = new ArrayList<>();
+
+        @Override
+        public void initialize(final List<Traversal.Admin<Object, Object>> traversals) {
+            this.traversals = traversals;
+            for (int i = 0; i < this.traversals.size(); i++) {
+                final Traversal.Admin<Object, Object> traversal = this.traversals.get(i);
+                this.traversalLabels.add(traversal.getStartStep().getId());
+                this.requiredLabels.add(MatchAlgorithm.getRequiredLabels(traversal));
+                this.counts.add(new Integer[]{i, 0});
+            }
+        }
+
+        @Override
+        public Traversal.Admin<Object, Object> apply(final Traverser.Admin<Object> traverser) {
+            final Path path = traverser.path();
+            for (final Integer[] indexCounts : this.counts) {
+                if (!path.hasLabel(this.traversalLabels.get(indexCounts[0])) && !this.requiredLabels.get(indexCounts[0]).stream().filter(label -> !path.hasLabel(label)).findAny().isPresent()) {
+                    return this.traversals.get(indexCounts[0]);
+                }
+            }
+            throw new IllegalStateException("The provided match pattern is unsolvable: " + this.traversals);
+        }
+
+        public void recordEnd(final Traverser.Admin<Object> traverser, final Traversal.Admin<Object, Object> traversal) {
+            final int currentIndex = this.traversals.indexOf(traversal);
+            this.counts.stream().filter(array -> currentIndex == array[0]).findAny().get()[1]++;
+            Collections.sort(this.counts, (a, b) -> a[1].compareTo(b[1]));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Bindings.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Bindings.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Bindings.java
deleted file mode 100644
index fb01a6e..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Bindings.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.function.Function;
-
-/**
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public class Bindings<T> {
-    private final SortedMap<String, T> map = new TreeMap<>();
-
-    public Bindings() {
-    }
-
-    public Bindings(final Map<String, T> map) {
-        this.map.putAll(map);
-    }
-
-    public Bindings<T> put(final String name, final T value) {
-        map.put(name, value);
-        return this;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder("{");
-        boolean first = true;
-        for (Map.Entry<String, T> entry : map.entrySet()) {
-            if (first) first = false;
-            else sb.append(", ");
-            sb.append(entry.getKey()).append(':').append(entry.getValue());
-        }
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public static class BindingsComparator<T> implements Comparator<Bindings<T>> {
-        private final Function<T, String> toStringFunction;
-
-        public BindingsComparator(Function<T, String> toStringFunction) {
-            this.toStringFunction = toStringFunction;
-        }
-
-        @Override
-        public int compare(Bindings<T> left, Bindings<T> right) {
-            int cmp = ((Integer) left.map.size()).compareTo(right.map.size());
-            if (0 != cmp) return cmp;
-
-            Iterator<Map.Entry<String, T>> i1 = left.map.entrySet().iterator();
-            Iterator<Map.Entry<String, T>> i2 = right.map.entrySet().iterator();
-            while (i1.hasNext()) {
-                Map.Entry<String, T> e1 = i1.next();
-                Map.Entry<String, T> e2 = i2.next();
-
-                cmp = e1.getKey().compareTo(e1.getKey());
-                if (0 != cmp) return cmp;
-
-                cmp = e1.getValue().toString().compareTo(e2.getValue().toString());
-                if (0 != cmp) return cmp;
-            }
-
-            return 0;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/CrossJoinEnumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/CrossJoinEnumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/CrossJoinEnumerator.java
deleted file mode 100644
index 167de93..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/CrossJoinEnumerator.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.function.BiConsumer;
-
-/**
- * An Enumerator which finds the Cartesian product of two other Enumerators,
- * expanding at the same rate in either dimension.
- * This maximizes the size of the product with respect to the number of expansions of the base Enumerators.
- */
-public class CrossJoinEnumerator<T> implements Enumerator<T> {
-
-    private final Enumerator<T> xEnum, yEnum;
-
-    public CrossJoinEnumerator(final Enumerator<T> xEnum,
-                               final Enumerator<T> yEnum) {
-        this.xEnum = xEnum;
-        this.yEnum = yEnum;
-    }
-
-    public int size() {
-        return xEnum.size() * yEnum.size();
-    }
-
-    // note: permits random access
-    public boolean visitSolution(final int index,
-                                 final BiConsumer<String, T> visitor) {
-        int sq = (int) Math.sqrt(index);
-
-        // choose x and y such that the solution represented by index
-        // remains constant as this Enumerator expands
-        int x, y;
-
-        if (0 == index) {
-            x = y = 0;
-        } else {
-            int r = index - sq * sq;
-            if (r < sq) {
-                x = sq;
-                y = r;
-            } else {
-                x = r - sq;
-                y = sq;
-            }
-        }
-
-        // expand x if necessary
-        if (!hasIndex(xEnum, sq)) {
-            if (0 == xEnum.size()) {
-                return false;
-            }
-
-            x = index % xEnum.size();
-            y = index / xEnum.size();
-        }
-
-        // expand y if necessary
-        if (!hasIndex(yEnum, y)) {
-            int height = yEnum.size();
-            if (0 == height) {
-                return false;
-            }
-
-            x = index / height;
-            if (!hasIndex(xEnum, x)) {
-                return false;
-            }
-            y = index % height;
-        }
-
-        // solutions are visited completely (if we have reached this point), else not at all
-        return xEnum.visitSolution(x, visitor) && yEnum.visitSolution(y, visitor);
-    }
-
-    private boolean hasIndex(final Enumerator<T> e,
-                             final int index) {
-        return index < e.size() || e.visitSolution(index, (BiConsumer<String, T>) MatchStep.TRIVIAL_CONSUMER);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Enumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Enumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Enumerator.java
deleted file mode 100644
index c5f8bac..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/Enumerator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.function.BiConsumer;
-
-/**
- * An array of key/value maps accessible by index.
- * The total size of the enumerator may be unknown when it is created;
- * it grows when successive solutions are requested, computing as many as necessary.
- *
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public interface Enumerator<T> {
-
-    /**
-     * @return the number of solutions so far known; the enumerator has at least this many.
-     * This should be a relatively cheap operation.
-     */
-    int size();
-
-    /**
-     * Provides access to a solution, allowing it to be printed, put into a map, etc.
-     *
-     * @param index   the index of the solution
-     * @param visitor a consumer for each key/value pair in the solution
-     * @return whether a solution exists at the given index and was visited
-     */
-    boolean visitSolution(int index, BiConsumer<String, T> visitor);
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/InnerJoinEnumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/InnerJoinEnumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/InnerJoinEnumerator.java
deleted file mode 100644
index a26e24d..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/InnerJoinEnumerator.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
-/**
- * An Enumerator which joins the solutions of a base Enumerator according to repeated variables
- * <p/>
- * Note: this Enumerator requires random access to its base Enumerator,
- * as it maintains a list of indices at which valid solutions are found, and visits only those indices.
- *
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public class InnerJoinEnumerator<T> implements Enumerator<T> {
-    private final Enumerator<T> baseEnumerator;
-    private Iterator<Integer> iterator;
-    private final List<Integer> joinIndices;
-
-    private final Map<String, T> map;
-    private final BiConsumer<String, T> joinVisitor;
-
-    private int joinCount;
-
-    public InnerJoinEnumerator(final Enumerator<T> baseEnumerator,
-                               final Set<String> joinVariables) {
-
-        this.baseEnumerator = baseEnumerator;
-        this.joinIndices = new ArrayList<>();
-
-        map = new HashMap<>();
-        // TODO: allow for more than two instances of a variable
-        joinVisitor = (name, newValue) -> {
-            if (joinVariables.contains(name)) {
-                T value = map.get(name);
-                if (null == value) {
-                    map.put(name, newValue);
-                } else if (value.equals(newValue)) {
-                    joinCount++;
-                }
-            } else {
-                map.put(name, newValue);
-            }
-        };
-
-        iterator = new Iterator<Integer>() {
-            private int currentIndex = -1;
-
-            {
-                advanceToNext();
-            }
-
-            public boolean hasNext() {
-                // there are no calls to this method
-                return false;
-            }
-
-            public Integer next() {
-                int tmp = currentIndex;
-                advanceToNext();
-                return tmp;
-            }
-
-            private void advanceToNext() {
-                while (true) {
-                    map.clear();
-                    joinCount = 0;
-
-                    if (!baseEnumerator.visitSolution(++currentIndex, joinVisitor)) {
-                        iterator = null;
-                        return;
-                    }
-
-                    if (joinVariables.size() == joinCount) {
-                        joinIndices.add(currentIndex);
-                        return;
-                    }
-                }
-            }
-        };
-    }
-
-    public int size() {
-        return joinIndices.size();
-    }
-
-    public boolean visitSolution(int i, BiConsumer<String, T> visitor) {
-        while (i >= joinIndices.size()) {
-            if (null == iterator) {
-                return false;
-            }
-
-            iterator.next();
-        }
-
-        map.clear();
-        if (!baseEnumerator.visitSolution(joinIndices.get(i), joinVisitor)) {
-            throw new IllegalStateException();
-        }
-
-        for (Map.Entry<String, T> entry : map.entrySet()) {
-            visitor.accept(entry.getKey(), entry.getValue());
-        }
-
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/IteratorEnumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/IteratorEnumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/IteratorEnumerator.java
deleted file mode 100644
index 57d32b7..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/IteratorEnumerator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.BiConsumer;
-
-/**
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public class IteratorEnumerator<T> implements Enumerator<T> {
-    private final String name;
-    private Iterator<T> iterator;
-    private final List<T> memory = new ArrayList<>();
-
-    public IteratorEnumerator(final String name,
-                              final Iterator<T> iterator) {
-        this.name = name;
-        this.iterator = iterator;
-    }
-
-    public int size() {
-        return memory.size();
-    }
-
-    public boolean visitSolution(final int index,
-                                 final BiConsumer<String, T> visitor) {
-        T value;
-
-        if (index < memory.size()) {
-            value = memory.get(index);
-        } else do {
-            if (null == iterator) {
-                return false;
-            } else if (!iterator.hasNext()) {
-                // free up memory as soon as possible
-                iterator = null;
-                return false;
-            }
-
-            value = iterator.next();
-            memory.add(value);
-        } while (index >= memory.size());
-
-        MatchStep.visit(name, value, visitor);
-
-        return true;
-    }
-}


[2/3] incubator-tinkerpop git commit: Removed MatchStep and replaced it with XMatchStep. Renamed XMatchStep, MatchStep. All the tests are passing for OLTP and OLAP except one in OLAP that makes sense why it doesnt pass, but the pattern should be caught b

Posted by ok...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/MatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/MatchStep.java
deleted file mode 100644
index db00d80..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/MatchStep.java
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-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.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_S_SE_SL_Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
-import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
-import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.Stack;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-/**
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public final class MatchStep<S, E> extends AbstractStep<S, Map<String, E>> implements Scoping, TraversalParent {
-
-    static final BiConsumer<String, Object> TRIVIAL_CONSUMER = (s, t) -> {
-    };
-
-    private static final String ANON_LABEL_PREFIX = "_";
-
-    // optimize before processing each start object, by default
-    private static final int DEFAULT_STARTS_PER_OPTIMIZE = 1;
-
-    private final String startLabel;
-    private final Map<String, List<TraversalWrapper<S, S>>> traversalsByStartAs;
-    private final List<Traversal<?,?>> traversals = new ArrayList<>();
-
-    private int startsPerOptimize = DEFAULT_STARTS_PER_OPTIMIZE;
-    private int optimizeCounter = -1;
-    private int anonLabelCounter = 0;
-
-    private Enumerator<S> currentSolution;
-    private int currentIndex;
-
-    // initial value allows MatchStep to be used as a stand-alone query engine
-    private Traverser.Admin<S> currentStart;
-
-    public MatchStep(final Traversal.Admin traversal, final String startLabel, final Traversal... traversals) {
-        super(traversal);
-        this.startLabel = startLabel;
-        this.traversalsByStartAs = new HashMap<>();
-        this.currentStart = new B_O_S_SE_SL_Traverser<>(null, this, 1l);    // TODO: bad? P?
-        for (final Traversal tl : traversals) {
-            addTraversalPrivate(tl);
-            this.integrateChild(tl.asAdmin());
-            this.traversals.add(tl);
-        }
-        checkSolvability();
-    }
-
-    @Override
-    public Set<TraverserRequirement> getRequirements() {
-        return this.getSelfAndChildRequirements();
-    }
-
-    @Override
-    public Set<String> getScopeKeys() {
-        final Set<String> keys = new HashSet<>();
-        keys.add(this.startLabel);
-        this.traversals.forEach(t -> {
-            keys.addAll(t.asAdmin().getStartStep().getLabels());
-            keys.addAll(t.asAdmin().getEndStep().getLabels());
-        });
-        return keys;
-    }
-
-    @Override
-    public String toString() {
-        return StringFactory.stepString(this, this.traversalsByStartAs);
-    }
-
-    /**
-     * Adds an individual traversal to an already-constructed MatchStep.
-     * The query must be solvable after addition (i.e. should not require the addition of
-     * further traversals in order to be solvable)
-     * This method should be called before the query is first executed.
-     *
-     * @param traversal the traversal to add
-     */
-    public void addTraversal(final Traversal<S, S> traversal) {
-        addTraversalPrivate(traversal);
-        this.traversals.add(traversal);
-        this.integrateChild(traversal.asAdmin());
-        checkSolvability();
-    }
-
-    public void setStartsPerOptimize(final int startsPerOptimize) {
-        if (startsPerOptimize < 1) {
-            throw new IllegalArgumentException();
-        }
-        this.startsPerOptimize = startsPerOptimize;
-    }
-
-    @Override
-    protected Traverser<Map<String, E>> processNextStart() throws NoSuchElementException {
-        final Map<String, E> map = new HashMap<>();
-        final Traverser<Map<String, E>> result = this.currentStart.split(map, this);
-        final BiConsumer<String, S> resultSetter = (name, value) -> map.put(name, (E) value);
-
-        while (true) { // break out when the current solution is exhausted and there are no more starts
-            if (null == this.currentSolution) {
-                if (this.starts.hasNext()) {
-                    this.optimizeCounter = (this.optimizeCounter + 1) % this.startsPerOptimize;
-                    if (0 == this.optimizeCounter) {
-                        optimize();
-                    }
-
-                    this.currentStart = this.starts.next();
-                    this.currentSolution = solveFor(IteratorUtils.of(this.currentStart.get()));
-                    this.currentIndex = 0;
-                } else {
-                    throw FastNoSuchElementException.instance();
-                }
-            }
-
-            map.clear();
-            if (this.currentSolution.visitSolution(this.currentIndex++, resultSetter)) {
-                return result;
-            } else {
-                this.currentSolution = null;
-            }
-        }
-    }
-
-    /**
-     * @return a description of the current state of this step, including the query plan and gathered statistics
-     */
-    public String summarize() {
-        final StringBuilder sb = new StringBuilder("match \"")
-                .append(this.startLabel)
-                .append("\":\t")
-                .append(findCost(this.startLabel))
-                .append('\n');
-        summarize(this.startLabel, sb, new HashSet<>(), 1);
-        return sb.toString();
-    }
-
-    private void summarize(final String outLabel,
-                           final StringBuilder sb,
-                           final Set<String> visited,
-                           final int indent) {
-        if (!visited.contains(outLabel)) {
-            visited.add(outLabel);
-            final List<TraversalWrapper<S, S>> outs = traversalsByStartAs.get(outLabel);
-            if (null != outs) {
-                for (final TraversalWrapper<S, S> w : outs) {
-                    for (int i = 0; i < indent; i++) sb.append('\t');
-                    sb.append(outLabel).append("->").append(w.endLabel).append(":\t");
-                    sb.append(findCost(w));
-                    sb.append('\t').append(w);
-                    sb.append('\n');
-                    summarize(w.endLabel, sb, visited, indent + 1);
-                }
-            }
-        }
-    }
-
-    private void addTraversalPrivate(final Traversal<S, S> traversal) {
-        final Step<S, ?> startStep = traversal.asAdmin().getStartStep();
-        if (startStep.getLabels().isEmpty())
-            throw new IllegalArgumentException("Match traversals must have their start step labeled with as(): " + traversal);
-        if (startStep.getLabels().size() > 1)
-            throw new IllegalArgumentException("Match traversals can not have multiple labels on the start step: " + traversal);
-        final String startAs = traversal.asAdmin().getStartStep().getLabels().iterator().next();
-        ///
-        final Step<?, S> endStep = traversal.asAdmin().getEndStep();
-        if (endStep.getLabels().size() > 1)
-            throw new IllegalArgumentException("Match traversals can not have multiple labels on the end step: " + traversal);
-
-        String endAs = endStep.getLabels().isEmpty() ? null : endStep.getLabels().iterator().next();
-        checkAs(startAs);
-        if (null == endAs) {
-            endAs = createAnonymousAs();
-        } else {
-            checkAs(endAs);
-        }
-
-        final TraversalWrapper<S, S> wrapper = new TraversalWrapper<>(traversal, startAs, endAs);
-        // index all wrapped traversals by their startLabel
-        List<TraversalWrapper<S, S>> l2 = this.traversalsByStartAs.get(startAs);
-        if (null == l2) {
-            l2 = new LinkedList<>();
-            this.traversalsByStartAs.put(startAs, l2);
-        }
-        l2.add(wrapper);
-    }
-
-    // given all the wrapped traversals, determine bad patterns in the set and throw exceptions if not solvable
-    private void checkSolvability() {
-        final Set<String> pathSet = new HashSet<>();
-        final Stack<String> stack = new Stack<>();
-        stack.push(this.startLabel);
-        int countTraversals = 0;
-        while (!stack.isEmpty()) {
-            final String outAs = stack.peek();
-            if (pathSet.contains(outAs)) {
-                stack.pop();
-                pathSet.remove(outAs);
-            } else {
-                pathSet.add(outAs);
-                final List<TraversalWrapper<S, S>> l = traversalsByStartAs.get(outAs);
-                if (null != l) {
-                    for (final TraversalWrapper<S, S> tw : l) {
-                        countTraversals++;
-                        if (pathSet.contains(tw.endLabel)) {
-                            throw new IllegalArgumentException("The provided traversal set contains a cycle due to '"
-                                    + tw.endLabel + '\'');
-                        }
-                        stack.push(tw.endLabel);
-                    }
-                }
-            }
-        }
-
-        int totalTraversals = 0;
-        for (List<TraversalWrapper<S, S>> l : this.traversalsByStartAs.values()) {
-            totalTraversals += l.size();
-        }
-
-        if (countTraversals < totalTraversals) {
-            throw new IllegalArgumentException("The provided traversal set contains unreachable as-label(s)");
-        }
-    }
-
-    private static void checkAs(final String as) {
-        // note: this won't happen so long as the anon prefix is the same as Traversal.UNDERSCORE
-        if (isAnonymousAs(as)) {
-            throw new IllegalArgumentException("The step named '" + as + "' uses reserved prefix '"
-                    + ANON_LABEL_PREFIX + '\'');
-        }
-    }
-
-    private static boolean isAnonymousAs(final String as) {
-        return as.startsWith(ANON_LABEL_PREFIX);
-    }
-
-    private String createAnonymousAs() {
-        return ANON_LABEL_PREFIX + ++this.anonLabelCounter;
-    }
-
-    /**
-     * Directly applies this match query to a sequence of inputs
-     *
-     * @param inputs a sequence of inputs
-     * @return an enumerator over all solutions
-     */
-    public Enumerator<S> solveFor(final Iterator<S> inputs) {
-        return solveFor(startLabel, inputs);
-    }
-
-    private Enumerator<S> solveFor(final String localStartAs,
-                                   final Iterator<S> inputs) {
-        List<TraversalWrapper<S, S>> outs = traversalsByStartAs.get(localStartAs);
-        if (null == outs) {
-            // no out-traversals from here; just enumerate the values bound to localStartAs
-            return isAnonymousAs(localStartAs)
-                    ? new SimpleEnumerator<>(localStartAs, inputs)
-                    : new IteratorEnumerator<>(localStartAs, inputs);
-        } else {
-            // for each value bound to localStartAs, feed it into all out-traversals in parallel and join the results
-            return new SerialEnumerator<>(localStartAs, inputs, o -> {
-                Enumerator<S> result = null;
-                Set<String> leftLabels = new HashSet<>();
-
-                for (TraversalWrapper<S, S> w : outs) {
-                    TraversalUpdater<S, S> updater
-                            = new TraversalUpdater<>(w, IteratorUtils.of(o), currentStart, this.getId());
-
-                    Set<String> rightLabels = new HashSet<>();
-                    addVariables(w.endLabel, rightLabels);
-                    Enumerator<S> ie = solveFor(w.endLabel, updater);
-                    result = null == result ? ie : crossJoin(result, ie, leftLabels, rightLabels);
-                    leftLabels.addAll(rightLabels);
-                }
-
-                return result;
-            });
-        }
-    }
-
-    private static <T> Enumerator<T> crossJoin(final Enumerator<T> left,
-                                               final Enumerator<T> right,
-                                               final Set<String> leftLabels,
-                                               final Set<String> rightLabels) {
-        Set<String> shared = new HashSet<>();
-        for (String s : rightLabels) {
-            if (leftLabels.contains(s)) {
-                shared.add(s);
-            }
-        }
-
-        Enumerator<T> cj = new CrossJoinEnumerator<>(left, right);
-        return shared.size() > 0 ? new InnerJoinEnumerator<>(cj, shared) : cj;
-    }
-
-    // recursively add all non-anonymous variables from a starting point in the query
-    private void addVariables(final String localStartAs,
-                              final Set<String> variables) {
-        if (!isAnonymousAs(localStartAs)) {
-            variables.add(localStartAs);
-        }
-
-        List<TraversalWrapper<S, S>> outs = traversalsByStartAs.get(localStartAs);
-        if (null != outs) {
-            for (TraversalWrapper<S, S> w : outs) {
-                String endAs = w.endLabel;
-                if (!variables.contains(endAs)) {
-                    addVariables(endAs, variables);
-                }
-            }
-        }
-    }
-
-    // applies a visitor, skipping anonymous variables
-    static <T> void visit(final String name,
-                          final T value,
-                          final BiConsumer<String, T> visitor) {
-        if (!isAnonymousAs(name)) {
-            visitor.accept(name, value);
-        }
-    }
-
-    /**
-     * Computes and applies a new query plan based on gathered statistics about traversal inputs and outputs.
-     */
-    // note: optimize() is never called from within a solution iterator, as it changes the query plan
-    public void optimize() {
-        optimizeAt(startLabel);
-    }
-
-    private void optimizeAt(final String outAs) {
-        List<TraversalWrapper<S, S>> outs = traversalsByStartAs.get(outAs);
-        if (null != outs) {
-            for (TraversalWrapper<S, S> t : outs) {
-                optimizeAt(t.endLabel);
-                updateOrderingFactor(t);
-            }
-            Collections.sort(outs);
-        }
-    }
-
-    private double findCost(final TraversalWrapper<S, S> root) {
-        double bf = root.findBranchFactor();
-        return bf + findCost(root.endLabel, root.findBranchFactor());
-    }
-
-    private double findCost(final String outAs,
-                            final double branchFactor) {
-        double bf = branchFactor;
-
-        double cost = 0;
-
-        List<TraversalWrapper<S, S>> outs = traversalsByStartAs.get(outAs);
-        if (null != outs) {
-            for (TraversalWrapper<S, S> child : outs) {
-                cost += bf * findCost(child);
-                bf *= child.findBranchFactor();
-            }
-        }
-
-        return cost;
-    }
-
-    /**
-     * @param outLabel the out-label of one or more traversals in the query
-     * @return the expected cost, in the current query plan, of applying the branch of the query plan at
-     * the given out-label to one start value
-     */
-    public double findCost(final String outLabel) {
-        return findCost(outLabel, 1.0);
-    }
-
-    private void updateOrderingFactor(final TraversalWrapper<S, S> w) {
-        w.orderingFactor = ((w.findBranchFactor() - 1) / findCost(w));
-    }
-
-    @Override
-    public List<Traversal<?,?>> getLocalChildren() {
-        return this.traversals;
-    }
-
-    @Override
-    public Scope recommendNextScope() {
-        return Scope.local;
-    }
-
-    @Override
-    public void setScope(final Scope scope) {
-
-    }
-
-    @Override
-    public Scope getScope() {
-        return Scope.local;
-    }
-
-    /**
-     * A wrapper for a traversal in a query which maintains statistics about the traversal as
-     * it consumes inputs and produces outputs.
-     * The "branch factor" of the traversal is an important factor in determining its place in the query plan.
-     */
-    // note: input and output counts are never "refreshed".
-    // The position of a traversal in a query never changes, although its priority / likelihood of being executed does.
-    // Priority in turn affects branch factor.
-    // However, with sufficient inputs and optimizations,the branch factor is expected to converge on a stable value.
-    public static class TraversalWrapper<A, B> implements Comparable<TraversalWrapper<A, B>> {
-        private final Traversal<A, B> traversal;
-        private final String startLabel, endLabel;
-        private int totalInputs = 0;
-        private int totalOutputs = 0;
-        private double orderingFactor;
-
-        public TraversalWrapper(final Traversal<A, B> traversal,
-                                final String startLabel,
-                                final String endLabel) {
-            this.traversal = traversal;
-            this.startLabel = startLabel;
-            this.endLabel = endLabel;
-        }
-
-        public void incrementInputs() {
-            this.totalInputs++;
-        }
-
-        public void incrementOutputs(int outputs) {
-            this.totalOutputs += outputs;
-        }
-
-        // TODO: take variance into account, to avoid penalizing traversals for early encounters with super-inputs,
-        // or simply for never having been tried
-        public double findBranchFactor() {
-            return 0 == this.totalInputs ? 1 : this.totalOutputs / ((double) this.totalInputs);
-        }
-
-        @Override
-        public int compareTo(final TraversalWrapper<A, B> other) {
-            return ((Double) this.orderingFactor).compareTo(other.orderingFactor);
-        }
-
-        public Traversal<A, B> getTraversal() {
-            return this.traversal;
-        }
-
-        public void reset() {
-            this.traversal.asAdmin().reset();
-        }
-
-        @Override
-        public String toString() {
-            return this.traversal.toString();
-            //return "[" + this.startLabel + "->" + this.endLabel + "," + findBranchFactor() + ","
-            // + this.totalInputs + "," + this.totalOutputs + "," + this.traversal + "]";
-        }
-    }
-
-    /**
-     * A helper object which wraps a traversal, submitting starts and counting results per start
-     */
-    public static class TraversalUpdater<A, B> implements Iterator<B> {
-        private final TraversalWrapper<A, B> w;
-        private int outputs = -1;
-
-        public TraversalUpdater(final TraversalWrapper<A, B> w,
-                                final Iterator<A> inputs,
-                                final Traverser<A> start,
-                                final String as) {
-            this.w = w;
-
-            Iterator<A> seIter = new SideEffectIterator<>(inputs, ignored -> {
-                // only increment traversal input and output counts once an input
-                // has been completely processed by the traversal
-                if (-1 != outputs) {
-                    w.incrementInputs();
-                    w.incrementOutputs(outputs);
-                }
-                outputs = 0;
-            });
-            Iterator<Traverser<A>> starts = new MapIterator<>(seIter,
-                    o -> {
-                        final Traverser.Admin<A> traverser = ((Traverser.Admin<A>) start).split();
-                        traverser.set((A) o);
-                        return traverser;
-                    });
-
-            w.reset();
-
-            // with the traversal "empty" and ready for re-use, add new starts
-            w.traversal.asAdmin().addStarts(starts);
-        }
-
-        // note: may return true after first returning false (inheriting this behavior from e.g. DefaultTraversal)
-        @Override
-        public boolean hasNext() {
-            return w.traversal.hasNext();
-        }
-
-        @Override
-        public B next() {
-            outputs++;
-            B b = w.traversal.next();
-
-            // immediately check hasNext(), possibly updating the traverser's statistics
-            // even if we otherwise abandon the iterator
-            w.traversal.hasNext();
-
-            return b;
-        }
-    }
-
-    // an iterator which executes a side-effect the first time hasNext() is called before a next()
-    private static class SideEffectIterator<T> implements Iterator<T> {
-        private final Consumer onHasNext;
-        private final Iterator<T> baseIterator;
-        private boolean ready = true;
-
-        private SideEffectIterator(final Iterator<T> baseIterator,
-                                   final Consumer onHasNext) {
-            this.onHasNext = onHasNext;
-            this.baseIterator = baseIterator;
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (this.ready) {
-                this.onHasNext.accept(null);
-                this.ready = false;
-            }
-            return this.baseIterator.hasNext();
-        }
-
-        @Override
-        public T next() {
-            T value = this.baseIterator.next();
-            this.ready = true;
-            return value;
-        }
-    }
-
-    private static class MapIterator<A, B> implements Iterator<B> {
-        private final Function<A, B> map;
-        private final Iterator<A> baseIterator;
-
-        public MapIterator(final Iterator<A> baseIterator, final Function<A, B> map) {
-            this.map = map;
-            this.baseIterator = baseIterator;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return this.baseIterator.hasNext();
-        }
-
-        @Override
-        public B next() {
-            return this.map.apply(this.baseIterator.next());
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SerialEnumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SerialEnumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SerialEnumerator.java
deleted file mode 100644
index e4f8bef..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SerialEnumerator.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.BiConsumer;
-import java.util.function.Function;
-
-/**
- * An enumerator which consumes values from an iterator and maps each value to a secondary enumerator
- * (for example, a join)
- * Enumerated indices cover all solutions in the secondary enumerators,
- * in ascending order according to the value iterator and the enumerators' own indices.
- *
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public class SerialEnumerator<T> implements Enumerator<T> {
-    private final String name;
-    private Iterator<T> iterator;
-    private final Function<T, Enumerator<T>> constructor;
-    private final List<Enumerator<T>> memory = new ArrayList<>();
-    private final List<T> values = new ArrayList<>();
-
-    // TODO: this only assigned, not accessed until the efficient implementation of size() is restored
-    private int completedEnumsSize = 0;
-
-    public SerialEnumerator(final String name,
-                            final Iterator<T> iterator,
-                            final Function<T, Enumerator<T>> constructor) {
-        this.name = name;
-        this.iterator = iterator;
-        this.constructor = constructor;
-    }
-
-    public int size() {
-        // TODO: restore the more efficient implementation of size() while taking into account that
-        // traversal iterators such as DefaultTraversal may return hasNext=true after first returning hasNext=false
-        /*
-        int size = completedEnumsSize;
-        if (!sideEffects.isEmpty()) {
-            size += sideEffects.get(sideEffects.size() - 1).size();
-        }
-        return size;
-        */
-
-        //*
-        int size = 0;
-        for (Enumerator<T> e : memory) size += e.size();
-        return size;
-        //*/
-    }
-
-    // note: *not* intended for random access; use binary search if this is ever needed
-    public boolean visitSolution(final int index,
-                                 final BiConsumer<String, T> visitor) {
-        int totalSize = 0;
-        int memIndex = 0;
-        while (true) {
-            if (memIndex < memory.size()) {
-                Enumerator<T> e = memory.get(memIndex);
-
-                if (e.visitSolution(index - totalSize, visitor)) {
-                    // additionally, bind the value stored in this enumerator
-                    MatchStep.visit(name, values.get(memIndex), visitor);
-
-                    return true;
-                } else {
-                    totalSize += e.size();
-                    memIndex++;
-                }
-            } else {
-                if (null == iterator) {
-                    return false;
-                } else if (!iterator.hasNext()) {
-                    // free up memory as soon as possible
-                    iterator = null;
-                    return false;
-                }
-
-                if (!memory.isEmpty()) {
-                    int lastSize = memory.get(memIndex - 1).size();
-
-                    // first remove the head enumeration if it exists and is empty
-                    // (only the head will ever be empty, avoiding wasted space)
-                    if (0 == lastSize) {
-                        memIndex--;
-                        memory.remove(memIndex);
-                        values.remove(memIndex);
-                    } else {
-                        completedEnumsSize += lastSize;
-                    }
-                }
-
-                T value = iterator.next();
-                values.add(value);
-                Enumerator<T> e = constructor.apply(value);
-                memory.add(memory.size(), e);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SimpleEnumerator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SimpleEnumerator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SimpleEnumerator.java
deleted file mode 100644
index eb5da9c..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/match/SimpleEnumerator.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.process.traversal.step.map.match;
-
-import java.util.Iterator;
-import java.util.function.BiConsumer;
-
-/**
- * An enumerator of at most one element
- *
- * @author Joshua Shinavier (http://fortytwo.net)
- */
-public class SimpleEnumerator<T> implements Enumerator<T> {
-
-    private final String name;
-    private Iterator<T> iterator;
-    private T element;
-
-    public SimpleEnumerator(final String name,
-                            final Iterator<T> iterator) {
-        this.name = name;
-        this.iterator = iterator;
-    }
-
-    @Override
-    public int size() {
-        return null == element ? 0 : 1;
-    }
-
-    @Override
-    public boolean visitSolution(int index, BiConsumer<String, T> visitor) {
-        if (0 != index) {
-            return false;
-        }
-
-        if (null != iterator) {
-            if (iterator.hasNext()) {
-                element = iterator.next();
-            }
-            iterator = null;
-        }
-
-        if (null != element) {
-            MatchStep.visit(name, element, visitor);
-            return true;
-        }
-
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchWhereStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchWhereStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchWhereStrategy.java
index 3adee58..8774212 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchWhereStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/MatchWhereStrategy.java
@@ -22,8 +22,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.exp.XMatchStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.match.MatchStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchStep;
 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.util.TraversalHelper;
@@ -58,18 +57,18 @@ public final class MatchWhereStrategy extends AbstractTraversalStrategy<Traversa
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
-        if (!TraversalHelper.hasStepOfClass(XMatchStep.class, traversal))
+        if (!TraversalHelper.hasStepOfClass(MatchStep.class, traversal))
             return;
 
         // pull out match(as("a").has().has()) to has().has().match() in order to allow vendors to leverages has-containers for index lookups
-        TraversalHelper.getStepsOfClass(XMatchStep.class, traversal).forEach(matchStep -> {
+        TraversalHelper.getStepsOfClass(MatchStep.class, traversal).forEach(matchStep -> {
             if (matchStep.getStartKey().isPresent()) {
-                ((XMatchStep<?, ?>) matchStep).getGlobalChildren().stream().collect(Collectors.toList()).forEach(conjunction -> {
-                    if (conjunction.getStartStep() instanceof XMatchStep.XMatchStartStep) {
-                        ((XMatchStep<?, ?>.XMatchStartStep) conjunction.getStartStep()).getSelectKey().ifPresent(selectKey -> {
+                ((MatchStep<?, ?>) matchStep).getGlobalChildren().stream().collect(Collectors.toList()).forEach(conjunction -> {
+                    if (conjunction.getStartStep() instanceof MatchStep.MatchStartStep) {
+                        ((MatchStep.MatchStartStep) conjunction.getStartStep()).getSelectKey().ifPresent(selectKey -> {
                             if (selectKey.equals(matchStep.getStartKey().get()) && !conjunction.getSteps().stream()
-                                    .filter(step -> !(step instanceof XMatchStep.XMatchStartStep) &&
-                                            !(step instanceof XMatchStep.XMatchEndStep) &&
+                                    .filter(step -> !(step instanceof MatchStep.MatchStartStep) &&
+                                            !(step instanceof MatchStep.MatchEndStep) &&
                                             !(step instanceof HasStep))
                                     .findAny()
                                     .isPresent() && !(matchStep.getPreviousStep() instanceof EmptyStep)) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategy.java
index a390e37..783b3eb 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ComputerVerificationStrategy.java
@@ -33,7 +33,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupGlobalSte
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TailGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.match.MatchStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphStep;
@@ -58,7 +57,7 @@ public final class ComputerVerificationStrategy extends AbstractTraversalStrateg
 
     private static final ComputerVerificationStrategy INSTANCE = new ComputerVerificationStrategy();
     private static final Set<Class<?>> UNSUPPORTED_STEPS = new HashSet<>(Arrays.asList(
-            InjectStep.class, MatchStep.class, Mutating.class, SubgraphStep.class
+            InjectStep.class, Mutating.class, SubgraphStep.class
     ));
 
     private ComputerVerificationStrategy() {
@@ -94,7 +93,7 @@ public final class ComputerVerificationStrategy extends AbstractTraversalStrateg
             if ((step instanceof ReducingBarrierStep || step instanceof SupplyingBarrierStep || step instanceof OrderGlobalStep || step instanceof RangeGlobalStep || step instanceof TailGlobalStep || step instanceof DedupGlobalStep) && (step != endStep || !(traversal.getParent() instanceof EmptyStep)))
                 throw new ComputerVerificationException("Global traversals on GraphComputer may not contain mid-traversal barriers: " + step, traversal);
 
-            if(step instanceof DedupGlobalStep && !((DedupGlobalStep) step).getLocalChildren().isEmpty())
+            if (step instanceof DedupGlobalStep && !((DedupGlobalStep) step).getLocalChildren().isEmpty())
                 throw new ComputerVerificationException("Global traversals on GraphComputer may not contain by()-projecting de-duplication steps: " + step, traversal);
 
             if (step instanceof TraversalParent) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
index 8d3be3d..f365c18 100644
--- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
+++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroovyMatchTest.groovy
@@ -88,14 +88,14 @@ public abstract class GroovyMatchTest {
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_created_b__b_0created_aX() {
+        public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_created_b__b_0created_aX() {
             g.V().match('a',
                     __.as('a').out('created').as('b'),
                     __.as('b').in('created').as('a'))
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_knows_b__c_knows_bX() {
+        public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_knows_b__c_knows_bX() {
             return g.V().match('a', __.as('a').out('knows').as('b'),
                     __.as('c').out('knows').as('b'));
         }
@@ -167,8 +167,8 @@ public abstract class GroovyMatchTest {
                     .select('a', 'c').by('name')
         }
 
-        /*@Override
-        public Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_selectXnameX() {
+        @Override
+        public Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_select_byXnameX() {
             g.V.match('a',
                     __.as('a').out('created').as('b'),
                     __.as('c').out('created').as('b')).select { it.value('name') }
@@ -179,7 +179,7 @@ public abstract class GroovyMatchTest {
             g.V.out.out.match('a',
                     __.as('b').out('created').as('a'),
                     __.as('c').out('knows').as('b')).select('c').out('knows').name
-        }*/
+        }
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
index 9e64522..a209c92 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java
@@ -75,7 +75,12 @@ public abstract class AbstractGremlinProcessTest extends AbstractGremlinTest {
     public static <T> void checkResults(final List<T> expectedResults, final Traversal<?, T> traversal) {
         final List<T> results = traversal.toList();
         assertFalse(traversal.hasNext());
-        assertEquals("Checking result size", expectedResults.size(), results.size());
+        if(expectedResults.size() != results.size()) {
+            System.err.println("Expected results: " + expectedResults);
+            System.err.println("Actual results:   " + results);
+            assertEquals("Checking result size", expectedResults.size(), results.size());
+        }
+
         for (T t : results) {
             if (t instanceof Map) {
                 assertTrue("Checking map result existence: " + t, expectedResults.stream().filter(e -> e instanceof Map).filter(e -> checkMap((Map) e, (Map) t)).findAny().isPresent());

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2f802634/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
index 5e4dd1a..d1c2945 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchTest.java
@@ -21,27 +21,26 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 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.IgnoreEngine;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.match.*;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.MapHelper;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_S_SE_SL_Traverser;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.*;
-import java.util.function.BiConsumer;
-import java.util.function.Function;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL;
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
-import static org.apache.tinkerpop.gremlin.process.traversal.P.neq;
 import static org.junit.Assert.*;
 
 /**
@@ -75,11 +74,11 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, String> get_g_V_out_out_matchXa_0created_b__b_0knows_cX_selectXcX_outXcreatedX_name();
 
-    // contains a cycle
-    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_created_b__b_0created_aX();
+    //TODO: with Traversal.reverse()
+    public abstract Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_created_b__b_0created_aX();
 
     // contains an unreachable label
-    public abstract Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_knows_b__c_knows_bX();
+    public abstract Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_knows_b__c_knows_bX();
 
     // nested match()
     public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_knows_b__b_created_lop__b_matchXa1_created_b1__b1_0created_c1X_selectXc1X_cX_selectXnameX();
@@ -99,23 +98,24 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_c_nameX();
 
     //TODO: with Traversal.reverse()
-    //public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_selectXnameX();
+    public abstract Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_select_byXnameX();
 
     //TODO: with Traversal.reverse()
-    // public abstract Traversal<Vertex, String> get_g_V_out_out_hasXname_rippleX_matchXb_created_a__c_knows_bX_selectXcX_outXknowsX_name();
+    public abstract Traversal<Vertex, String> get_g_V_out_out_hasXname_rippleX_matchXb_created_a__c_knows_bX_selectXcX_outXknowsX_name();
 
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_out_bX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_out_bX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "lop")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "vadas")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "josh")).put("b", convertToVertex(graph, "ripple")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "josh")).put("b", convertToVertex(graph, "lop")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "peter")).put("b", convertToVertex(graph, "lop")));
+        checkResults(makeMapList(2,
+                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
+                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"),
+                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "vadas"),
+                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple"),
+                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
+                        "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop")),
+                traversal);
     }
 
     @Test
@@ -146,9 +146,9 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public void g_V_matchXa_knows_b__b_created_cX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_knows_b__b_created_cX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "lop")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "ripple")));
+        checkResults(makeMapList(3,
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"), "c", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"), "c", convertToVertex(graph, "ripple")), traversal);
     }
 
     @Test
@@ -156,9 +156,9 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public void g_V_matchXa_knows_b__a_created_cX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_knows_b__a_created_cX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "vadas")).put("c", convertToVertex(graph, "lop")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "lop")));
+        checkResults(makeMapList(3,
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "vadas"), "c", convertToVertex(graph, "lop"),
+                "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"), "c", convertToVertex(graph, "lop")), traversal);
     }
 
     @Test
@@ -166,9 +166,9 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public void g_V_matchXd_0knows_a__d_hasXname_vadasX__a_knows_b__b_created_cX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXd_0knows_a__d_hasXname_vadasX__a_knows_b__b_created_cX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>().put("d", convertToVertex(graph, "vadas")).put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "lop")),
-                new Bindings<Vertex>().put("d", convertToVertex(graph, "vadas")).put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "ripple")));
+        checkResults(makeMapList(4,
+                "d", convertToVertex(graph, "vadas"), "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"), "c", convertToVertex(graph, "lop"),
+                "d", convertToVertex(graph, "vadas"), "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "josh"), "c", convertToVertex(graph, "ripple")), traversal);
     }
 
     @Test
@@ -177,21 +177,26 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__a_repeatXoutX_timesX2XX_selectXab_nameX();
         printTraversalForm(traversal);
         assertTrue(traversal.hasNext());
-        assertResults(Function.identity(), traversal, new Bindings<String>().put("a", "marko").put("b", "lop"));
+        checkResults(makeMapList(2,
+                "a", "marko", "b", "lop"), traversal);
     }
 
     @Test
     @LoadGraphWith(MODERN)
+    // TODO: DEBATABLE RESULTS
     public void g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXnameX() throws Exception {
         final List<Traversal<Vertex, Map<String, String>>> traversals = Arrays.asList(
-                get_g_V_matchXa_created_lop_b__b_0created_29_c__c_repeatXoutX_timesX2XX_selectXnameX(),
-                get_g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXnameX());
+                get_g_V_matchXa_created_lop_b__b_0created_29_c__c_repeatXoutX_timesX2XX_selectXnameX());
+                //get_g_V_matchXa_created_lop_b__b_0created_29_cX_whereXc_repeatXoutX_timesX2XX_selectXnameX());  // todo: predicate traversals are local traversals?
         traversals.forEach(traversal -> {
             printTraversalForm(traversal);
-            assertResults(Function.identity(), traversal,
-                    new Bindings<String>().put("a", "marko").put("b", "lop").put("c", "marko"),
-                    new Bindings<String>().put("a", "josh").put("b", "lop").put("c", "marko"),
-                    new Bindings<String>().put("a", "peter").put("b", "lop").put("c", "marko"));
+            checkResults(makeMapList(3,
+                    "a", "marko", "b", "lop", "c", "marko",
+                    "a", "marko", "b", "lop", "c", "marko",
+                    "a", "josh", "b", "lop", "c", "marko",
+                    "a", "josh", "b", "lop", "c", "marko",
+                    "a", "peter", "b", "lop", "c", "marko",
+                    "a", "peter", "b", "lop", "c", "marko"), traversal);
         });
     }
 
@@ -205,16 +210,27 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         assertFalse(traversal.hasNext());
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    @Test
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_created_b__b_0created_aX() {
-        get_g_V_matchXa_created_b__b_0created_aX();
+        final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_created_b__b_0created_aX();
+        printTraversalForm(traversal);
+        checkResults(makeMapList(2,
+                        "a", convertToVertex(graph, "marko"), "b", convertToVertex(graph, "lop"),
+                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "lop"),
+                        "a", convertToVertex(graph, "peter"), "b", convertToVertex(graph, "lop"),
+                        "a", convertToVertex(graph, "josh"), "b", convertToVertex(graph, "ripple")),
+                traversal);
+
     }
 
-    @Test(expected = IllegalArgumentException.class)
+    // TODO: this test requires Traversal.reverse()
+    @Test(expected = IllegalStateException.class)
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_knows_b__c_knows_bX() {
-        get_g_V_matchXa_knows_b__c_knows_bX();
+        final Traversal<Vertex, Map<String, Vertex>> traversal =  get_g_V_matchXa_knows_b__c_knows_bX();
+        printTraversalForm(traversal);
+        traversal.iterate();
     }
 
     @Test
@@ -222,69 +238,39 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public void g_V_matchXa_knows_b__b_created_lop__b_matchXa1_created_b1__b1_0created_c1X_selectXc1X_cX_selectXnameX() throws Exception {
         final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_knows_b__b_created_lop__b_matchXa1_created_b1__b1_0created_c1X_selectXc1X_cX_selectXnameX();
         printTraversalForm(traversal);
-        assertResults(Function.identity(), traversal,
-                new Bindings<String>().put("a", "marko").put("b", "josh").put("c", "josh"),
-                new Bindings<String>().put("a", "marko").put("b", "josh").put("c", "josh"), // expected duplicate: two paths to this solution
-                new Bindings<String>().put("a", "marko").put("b", "josh").put("c", "marko"),
-                new Bindings<String>().put("a", "marko").put("b", "josh").put("c", "peter"));
+        checkResults(makeMapList(3,
+                "a", "marko", "b", "josh", "c", "josh",
+                "a", "marko", "b", "josh", "c", "josh", // expected duplicate: two paths to this solution
+                "a", "marko", "b", "josh", "c", "marko",
+                "a", "marko", "b", "josh", "c", "peter"), traversal);
     }
 
-    /* TODO: this test requires Traversal.reverse()
-    @Test
+    // TODO: this test requires Traversal.reverse()
+    @Test(expected = IllegalStateException.class)
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_created_b__c_created_bX_selectXnameX() throws Exception {
-        final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__c_created_bX_selectXnameX();
+        final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__c_created_bX_select_byXnameX();
         printTraversalForm(traversal);
-        assertTrue(traversal.hasNext());
-        final Map<String, Long> countMap = new HashMap<>();
-        int counter = 0;
-        while (traversal.hasNext()) {
-            counter++;
-            final Map<String, String> bindings = traversal.next();
-            // TODO: c is not being bound
-            // assertEquals(3, bindings.size());
-            assertEquals("lop", bindings.get("b"));
-            MapHelper.incr(countMap, bindings.get("a") + ":" + bindings.get("c"), 1l);
-        }
-        // TODO: without 'c' binding, cant check results
-        // assertEquals(Long.valueOf(1), countMap.get("marko:marko"));
-        //assertEquals(Long.valueOf(1), countMap.get("marko:josh"));
-        //assertEquals(Long.valueOf(1), countMap.get("marko:peter"));
-        //assertEquals(Long.valueOf(1), countMap.get("josh:marko"));
-        //assertEquals(Long.valueOf(1), countMap.get("josh:josh"));
-        //assertEquals(Long.valueOf(1), countMap.get("josh:peter"));
-        //assertEquals(Long.valueOf(1), countMap.get("peter:marko"));
-        //assertEquals(Long.valueOf(1), countMap.get("peter:josh"));
-        //assertEquals(Long.valueOf(1), countMap.get("peter:peter"));
-        //assertEquals(countMap.size(), 9);
-        //assertEquals(9, counter);
-        assertFalse(traversal.hasNext());
+        traversal.iterate();
     }
-    */
 
-    /* TODO: this test requires Traversal.reverse()
-    @Test
+    // TODO: this test requires Traversal.reverse()
+    @Test(expected = IllegalStateException.class)
     @LoadGraphWith(MODERN)
     public void g_V_out_out_hasXname_rippleX_matchXb_created_a__c_knows_bX_selectXcX_outXknowsX_name() throws Exception {
-        // TODO: Doesn't work, only bindings to 'a' in binding set.
         final Traversal<Vertex, String> traversal = get_g_V_out_out_hasXname_rippleX_matchXb_created_a__c_knows_bX_selectXcX_outXknowsX_name();
         printTraversalForm(traversal);
-        assertTrue(traversal.hasNext());
-        final List<String> results = traversal.toList();
-        assertEquals(2, results.size());
-        assertTrue(results.contains("josh"));
-        assertTrue(results.contains("vadas"));
+        traversal.iterate();
     }
-    */
 
     @Test
     @LoadGraphWith(GRATEFUL)
     public void g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__a_0sungBy_bX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_hasXname_GarciaX__a_0writtenBy_b__a_0sungBy_bX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "Garcia")).put("b", convertToVertex(graph, "CREAM PUFF WAR")),
-                new Bindings<Vertex>().put("a", convertToVertex(graph, "Garcia")).put("b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT")));
+        checkResults(makeMapList(2,
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"),
+                "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT")), traversal);
     }
 
     @Test
@@ -292,348 +278,47 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
     public void g_V_matchXa_0sungBy_b__a_0sungBy_c__b_writtenBy_d__c_writtenBy_e__d_hasXname_George_HarisonX__e_hasXname_Bob_MarleyXX() throws Exception {
         final Traversal<Vertex, Map<String, Vertex>> traversal = get_g_V_matchXa_0sungBy_b__a_0sungBy_c__b_writtenBy_d__c_writtenBy_e__d_hasXname_George_HarisonX__e_hasXname_Bob_MarleyXX();
         printTraversalForm(traversal);
-        assertResults(vertexToStr, traversal,
-                new Bindings<Vertex>()
-                        .put("a", convertToVertex(graph, "Garcia"))
-                        .put("b", convertToVertex(graph, "I WANT TO TELL YOU"))
-                        .put("c", convertToVertex(graph, "STIR IT UP"))
-                        .put("d", convertToVertex(graph, "George_Harrison"))
-                        .put("e", convertToVertex(graph, "Bob_Marley")));
+        checkResults(makeMapList(5,
+                "a", convertToVertex(graph, "Garcia"),
+                "b", convertToVertex(graph, "I WANT TO TELL YOU"),
+                "c", convertToVertex(graph, "STIR IT UP"),
+                "d", convertToVertex(graph, "George_Harrison"),
+                "e", convertToVertex(graph, "Bob_Marley")), traversal);
     }
 
     @Test
     @LoadGraphWith(MODERN)
     public void g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_c_nameX() throws Exception {
         final Traversal<Vertex, Map<String, String>> traversal = get_g_V_matchXa_created_b__b_0created_cX_whereXa_neq_cX_selectXa_c_nameX();
-        assertResults(Function.identity(), traversal,
-                new Bindings<String>().put("a", "marko").put("c", "josh"),
-                new Bindings<String>().put("a", "marko").put("c", "peter"),
-                new Bindings<String>().put("a", "josh").put("c", "marko"),
-                new Bindings<String>().put("a", "josh").put("c", "peter"),
-                new Bindings<String>().put("a", "peter").put("c", "marko"),
-                new Bindings<String>().put("a", "peter").put("c", "josh"));
+        checkResults(makeMapList(2,
+                "a", "marko", "c", "josh",
+                "a", "marko", "c", "peter",
+                "a", "josh", "c", "marko",
+                "a", "josh", "c", "peter",
+                "a", "peter", "c", "marko",
+                "a", "peter", "c", "josh"), traversal);
     }
 
 
     @Test
-    @Ignore
     @LoadGraphWith(GRATEFUL)
     public void g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX() throws Exception {
         final List<Traversal<Vertex, Map<String, Vertex>>> traversals = Arrays.asList(
-                get_g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX(),
-                get_g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_dX_whereXc_sungBy_dX_whereXd_hasXname_GarciaXX());
+                get_g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_d__c_sungBy_d__d_hasXname_GarciaXX());
+                //get_g_V_matchXa_0sungBy_b__a_0writtenBy_c__b_writtenBy_dX_whereXc_sungBy_dX_whereXd_hasXname_GarciaXX());  // TODO: the where() is trying to get Garcia's name. Why is ComputerVerificationStrategy allowing this?
 
         traversals.forEach(traversal -> {
             printTraversalForm(traversal);
-            assertResults(vertexToStr, traversal,
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Garcia"))
-                            .put("b", convertToVertex(graph, "CREAM PUFF WAR"))
-                            .put("c", convertToVertex(graph, "CREAM PUFF WAR"))
-                            .put("d", convertToVertex(graph, "Garcia")),
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Garcia"))
-                            .put("b", convertToVertex(graph, "CREAM PUFF WAR"))
-                            .put("c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"))
-                            .put("d", convertToVertex(graph, "Garcia")),
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Garcia"))
-                            .put("b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"))
-                            .put("c", convertToVertex(graph, "CREAM PUFF WAR"))
-                            .put("d", convertToVertex(graph, "Garcia")),
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Garcia"))
-                            .put("b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"))
-                            .put("c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"))
-                            .put("d", convertToVertex(graph, "Garcia")),
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Grateful_Dead"))
-                            .put("b", convertToVertex(graph, "CANT COME DOWN"))
-                            .put("c", convertToVertex(graph, "DOWN SO LONG"))
-                            .put("d", convertToVertex(graph, "Garcia")),
-                    new Bindings<Vertex>()
-                            .put("a", convertToVertex(graph, "Grateful_Dead"))
-                            .put("b", convertToVertex(graph, "THE ONLY TIME IS NOW"))
-                            .put("c", convertToVertex(graph, "DOWN SO LONG"))
-                            .put("d", convertToVertex(graph, "Garcia")));
+            checkResults(makeMapList(4,
+                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
+                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CREAM PUFF WAR"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
+                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CREAM PUFF WAR"), "d", convertToVertex(graph, "Garcia"),
+                    "a", convertToVertex(graph, "Garcia"), "b", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "c", convertToVertex(graph, "CRYPTICAL ENVELOPMENT"), "d", convertToVertex(graph, "Garcia"),
+                    "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "CANT COME DOWN"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia"),
+                    "a", convertToVertex(graph, "Grateful_Dead"), "b", convertToVertex(graph, "THE ONLY TIME IS NOW"), "c", convertToVertex(graph, "DOWN SO LONG"), "d", convertToVertex(graph, "Garcia")), traversal);
         });
     }
 
-
-    /* TODO: is it necessary to implement each of these traversals three times?
-    @Test
-    @LoadGraphWith(MODERN)
-    public void testTraversalUpdater() throws Exception {
-        assertBranchFactor(
-                2.0,
-                as("a").out("knows").as("b"),
-                new SingleIterator<>(g.V(1)));
-
-        assertBranchFactor(
-                0.0,
-                as("a").out("foo").as("b"),
-                new SingleIterator<>(g.V(1)));
-
-        assertBranchFactor(
-                7.0,
-                as("a").both().both().as("b"),
-                new SingleIterator<>(g.V(1)));
-
-        assertBranchFactor(
-                0.5,
-                as("a").outV().has("name", "marko").as("b"),
-                g.E());
-    }
-    */
-
-    @Test
-    @LoadGraphWith(MODERN)
-    public void testOptimization() throws Exception {
-        MatchStep<Object, Object> query;
-        Iterator iter;
-
-        query = new MatchStep<>(g.V().asAdmin(), "d",
-                as("d").in("knows").as("a"),
-                as("d").has("name", "vadas"),
-                as("a").out("knows").as("b"),
-                as("b").out("created").as("c"));
-        iter = g.V();
-        query.optimize();
-        //System.out.println(query.summarize());
-
-        // c costs nothing (no outgoing traversals)
-        assertEquals(0.0, query.findCost("c"), 0);
-        // b-created->c has a cost equal to its branch factor, 1.0
-        // b has only one outgoing traversal, b-created->c, so its total cost is 1.0
-        assertEquals(1.0, query.findCost("b"), 0);
-        // the cost of a-knows->b is its branch factor (1.0) plus the branch factor times the cost of b-created->c (1.0), so 2.0
-        // a has only one outgoing traversal, a-knows->b, so its total cost is 2.0
-        assertEquals(2.0, query.findCost("a"), 0);
-        // the cost of d<-knows-a is its branch factor (1.0) plus the branch factor times the cost of a-knows->b (2.0), so 3.0
-        // the cost of d->has(name,vadas) is its branch factor (1.0)
-        // the total cost of d is the cost of its first traversal times the branch factor of the first times the cost of the second,
-        //     or 3.0 + 1.0*1.0 = 4.0
-        assertEquals(4.0, query.findCost("d"), 0);
-
-        // apply the query to the graph, gathering non-trivial branch factors
-        assertResults(query.solveFor(iter),
-                new Bindings<>().put("d", convertToVertex(graph, "vadas")).put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "lop")),
-                new Bindings<>().put("d", convertToVertex(graph, "vadas")).put("a", convertToVertex(graph, "marko")).put("b", convertToVertex(graph, "josh")).put("c", convertToVertex(graph, "ripple")));
-        query.optimize();
-        //System.out.println(query.summarize());
-
-        // c still costs nothing (no outgoing traversals)
-        assertEquals(0.0, query.findCost("c"), 0);
-        // b-created->c still has a branch factor of 1.0, as we have put two items in (josh and vadas) and gotten two out (lop and ripple)
-        // b has only one outgoing traversal, b-created->c, so its total cost is 1.0
-        /* TODO: adjust and restore
-        assertEquals(1.0, query.findCost("b"), 0);
-        // a-knows->b now has a branch factor of 2.0 -- we put in marko and got out josh and vadas
-        // the cost of a-knows->b is its branch factor (2.0) plus the branch factor times the cost of b-created->c (1.0), so 4.0
-        // a has only one outgoing traversal, a-knows->b, so its total cost is 4.0
-        assertEquals(4.0, query.findCost("a"), 0);
-        // d<-knows-a has a branch factor of 1/6 -- we put in all six vertices and got out marko
-        //     we get out marko only once, because d-name->"vadas" is tried first and rules out all but one "d"
-        // the cost of d<-knows-a is its branch factor (1/6) plus the branch factor times the cost of a-knows->b (4.0), so 5/6
-        // since we optimized to put the has step first (it immediately eliminates most vertices),
-        //     the cost of d->has(name,vadas) is 1/6 -- we put in all six vertices and got out one
-        // the total cost of d is the cost of its first traversal times the branch factor of the first times the cost of the second,
-        //     or 1/6 + 1/6*5/6 = 11/36
-        */
-    }
-
-    // TODO: uncomment when query cycles are supported
-    /*
-    @Test
-    @LoadGraphWith(MODERN)
-    public void testCyclicPatterns() throws Exception {
-        MatchStep<Object, Object> query;
-        Iterator iter;
-
-        iter = g.V();
-        query = new MatchStep<>(g.V(), "a",
-                as("a").out("uses").as("b"),
-                as("b").out("dependsOn").as("c"),
-                as("c").in("created").as("a"));
-
-        assertResults(query.solve(iter),
-                new Bindings<>().put("a", "v[1]").put("b", "v[10]").put("c", "v[11]"));
-    }
-    */
-
-    @Test
-    public void testIteratorEnumerator() throws Exception {
-        IteratorEnumerator<String> ie;
-        final Map<String, String> map = new HashMap<>();
-        BiConsumer<String, String> visitor = map::put;
-
-        ie = new IteratorEnumerator<>("a", new LinkedList<String>() {{
-            add("foo");
-            add("bar");
-        }}.iterator());
-        assertEquals(0, ie.size());
-        assertTrue(ie.visitSolution(0, visitor));
-        assertEquals(1, ie.size());
-        assertEquals(1, map.size());
-        assertEquals("foo", map.get("a"));
-        map.clear();
-        assertTrue(ie.visitSolution(1, visitor));
-        assertEquals(2, ie.size());
-        assertEquals(1, map.size());
-        assertEquals("bar", map.get("a"));
-        map.clear();
-        assertFalse(ie.visitSolution(2, visitor));
-        assertEquals(2, ie.size());
-        assertEquals(0, map.size());
-        // revisit previous solutions at random
-        assertTrue(ie.visitSolution(1, visitor));
-        assertEquals(2, ie.size());
-        assertEquals(1, map.size());
-        assertEquals("bar", map.get("a"));
-
-        // empty enumerator
-        ie = new IteratorEnumerator<>("a", new LinkedList<String>() {{
-        }}.iterator());
-        map.clear();
-        assertEquals(0, ie.size());
-        assertFalse(ie.visitSolution(0, visitor));
-        assertEquals(0, ie.size());
-        assertEquals(0, map.size());
-    }
-
-    @Test
-    public void testCrossJoin() throws Exception {
-        String[] a1 = new String[]{"a", "b", "c"};
-        String[] a2 = new String[]{"1", "2", "3", "4"};
-        String[] a3 = new String[]{"@", "#"};
-
-        Enumerator<String> e1 = new IteratorEnumerator<>("letter", Arrays.asList(a1).iterator());
-        Enumerator<String> e2 = new IteratorEnumerator<>("number", Arrays.asList(a2).iterator());
-        Enumerator<String> e3 = new IteratorEnumerator<>("punc", Arrays.asList(a3).iterator());
-
-        Enumerator<String> e1e2 = new CrossJoinEnumerator<>(e1, e2);
-        Enumerator<String> e2e1 = new CrossJoinEnumerator<>(e2, e1);
-        BiConsumer<String, String> visitor = (name, value) -> {
-            System.out.println("\t" + name + ":\t" + value);
-        };
-        Enumerator<String> e1e2e3 = new CrossJoinEnumerator<>(e1e2, e3);
-
-        Enumerator<String> result;
-
-        result = e1e2;
-        assertEquals(12, exhaust(result));
-        assertEquals(12, result.size());
-
-        result = e2e1;
-        assertEquals(12, exhaust(result));
-        assertEquals(12, result.size());
-
-        result = e1e2e3;
-        assertEquals(24, exhaust(result));
-        assertEquals(24, result.size());
-
-        /*
-        int i = 0;
-        while (result.visitSolution(i, visitor)) {
-            System.out.println("solution #" + (i + 1) + "^^");
-            i++;
-        }
-        */
-    }
-
-    /* TODO: uncomment when optimized cross-joins are available
-    @Test
-    public void testCrossJoinLaziness() throws Exception {
-        List<Integer> value = new LinkedList<>();
-        for (int j = 0; j < 1000; j++) {
-            value.add(j);
-        }
-
-        int base = 3;
-        List<Enumerator<Integer>> enums = new LinkedList<>();
-        for (int k = 0; k < base; k++) {
-            List<Integer> lNew = new LinkedList<>();
-            lNew.addAll(value);
-            Enumerator<Integer> ek = new IteratorEnumerator<>("" + (char) ('a' + k), lNew.iterator());
-            enums.add(ek);
-        }
-
-        Enumerator<Integer> e = new NewCrossJoinEnumerator<>(enums);
-
-        // we now have an enumerator of 5^3^10 elements
-        EnumeratorIterator<Integer> iter = new EnumeratorIterator<>(e);
-
-        int count = 0;
-        // each binding set is unique
-        Set<String> values = new HashSet<>();
-        String s;
-        s = iter.next().toString();
-        values.add(s);
-        assertEquals(++count, values.size());
-        // begin at the head of all iterators
-        assertEquals("{a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0, j=0}", s);
-        int lim0 = (int) Math.pow(1, base);
-        // first 2^10 results are binary (0's and 1's)
-        int lim1 = (int) Math.pow(2, base);
-        for (int i = lim0; i < lim1; i++) {
-            s = iter.next().toString();
-            System.out.println("" + i + ": " + count + ": " + s); System.out.flush();
-            assertTrue(s.contains("1"));
-            assertFalse(s.contains("2"));
-            values.add(s);
-            assertEquals(++count, values.size());
-        }
-        int lim2 = (int) Math.pow(3, base);
-        for (int i = lim1; i < lim2; i++) {
-            s = iter.next().toString();
-            System.out.println("" + i + ": " + count + ": " + s); System.out.flush();
-
-            if (!s.contains("2")) {
-                findMissing(null, 0, base, "abcdefghij".getBytes(), values);
-            }
-
-
-            assertTrue(s.contains("2"));
-            assertFalse(s.contains("3"));
-            values.add(s);
-            assertEquals(++count, values.size());
-        }
-    }
-    */
-
-    @Test
-    public void testInnerJoin() throws Exception {
-        String[] a1 = new String[]{"a", "b", "c"};
-        String[] a2 = new String[]{"1", "2", "3", "4"};
-        String[] a3 = new String[]{"2", "4", "6", "8", "10"};
-
-        Enumerator<String> e1 = new IteratorEnumerator<>("letter", Arrays.asList(a1).iterator());
-        Enumerator<String> e2 = new IteratorEnumerator<>("number", Arrays.asList(a2).iterator());
-        Enumerator<String> e3 = new IteratorEnumerator<>("number", Arrays.asList(a3).iterator());
-
-        Enumerator<String> e4 = new CrossJoinEnumerator<>(e1, e3);
-        Enumerator<String> e5 = new CrossJoinEnumerator<>(e2, e4);
-
-        // without AND semantics, we have all 60 combinations, including two "number" bindings per solution
-        exhaust(e5);
-        assertEquals(60, e5.size());
-
-        // with AND semantics, we have only those six solutions for which a2 and a3 align
-        Enumerator<String> join = new InnerJoinEnumerator<>(e5, new HashSet<String>() {{
-            add("number");
-        }});
-        exhaust(join);
-        assertEquals(6, join.size());
-
-        assertResults(join,
-                new Bindings<String>().put("letter", "a").put("number", "2"),
-                new Bindings<String>().put("letter", "a").put("number", "4"),
-                new Bindings<String>().put("letter", "b").put("number", "2"),
-                new Bindings<String>().put("letter", "b").put("number", "4"),
-                new Bindings<String>().put("letter", "c").put("number", "2"),
-                new Bindings<String>().put("letter", "c").put("number", "4"));
-    }
-
     public static class Traversals extends MatchTest {
         @Override
         public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_out_bX() {
@@ -699,14 +384,14 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_created_b__b_0created_aX() {
+        public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_created_b__b_0created_aX() {
             return g.V().match("a",
                     as("a").out("created").as("b"),
                     as("b").in("created").as("a"));
         }
 
         @Override
-        public Traversal<Vertex, Map<String, Object>> get_g_V_matchXa_knows_b__c_knows_bX() {
+        public Traversal<Vertex, Map<String, Vertex>> get_g_V_matchXa_knows_b__c_knows_bX() {
             return g.V().match("a", as("a").out("knows").as("b"),
                     as("c").out("knows").as("b"));
         }
@@ -769,148 +454,19 @@ public abstract class MatchTest extends AbstractGremlinProcessTest {
                     .<String>select("a", "c").by("name");
         }
 
-        /*@Override
-        public Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_selectXnameX() {
+        @Override
+        public Traversal<Vertex, Map<String, String>> get_g_V_matchXa_created_b__c_created_bX_select_byXnameX() {
             return g.V().match("a",
                     as("a").out("created").as("b"),
-                    as("c").out("created").as("b")).select(v -> ((Vertex) v).value("name"));
+                    as("c").out("created").as("b")).<String>select().by("name");
         }
 
         @Override
         public Traversal<Vertex, String> get_g_V_out_out_hasXname_rippleX_matchXb_created_a__c_knows_bX_selectXcX_outXknowsX_name() {
             return g.V().out().out().match("a",
                     as("b").out("created").as("a"),
-                    as("c").out("knows").as("b")).select("c").out("knows").value("name");
-        }*/
-
-    }
-
-    private static final Function<Vertex, String> vertexToStr = v -> v.id().toString();
-
-    private <S, E> void assertResults(final Function<E, String> toStringFunction,
-                                      final Traversal<S, Map<String, E>> actual,
-                                      final Bindings<E>... expected) {
-        Comparator<Bindings<E>> comp = new Bindings.BindingsComparator<>(toStringFunction);
-
-        List<Bindings<E>> actualList = toBindings(actual);
-        List<Bindings<E>> expectedList = new LinkedList<>();
-        Collections.addAll(expectedList, expected);
-
-        if (expectedList.size() > actualList.size()) {
-            fail("" + (expectedList.size() - actualList.size()) + " expected results not found, including " + expectedList.get(actualList.size()));
-        } else if (actualList.size() > expectedList.size()) {
-            fail("" + (actualList.size() - expectedList.size()) + " unexpected results, including " + actualList.get(expectedList.size()));
-        }
-
-        Collections.sort(actualList, comp);
-        Collections.sort(expectedList, comp);
-
-        for (int j = 0; j < actualList.size(); j++) {
-            Bindings<E> a = actualList.get(j);
-            Bindings<E> e = expectedList.get(j);
-
-            if (0 != comp.compare(a, e)) {
-                fail("unexpected result(s), including " + a);
-            }
-        }
-        assertFalse(actual.hasNext());
-    }
-
-    private static final Function<Object, String> simpleToStringFunction = Object::toString;
-
-    private <T> void assertResults(final Enumerator<T> actual,
-                                   final Bindings<T>... expected) {
-        Comparator<Bindings<T>> comp = new Bindings.BindingsComparator<>((Function<T, String>) simpleToStringFunction);
-
-        List<Bindings<T>> actualList = toBindings(actual);
-        List<Bindings<T>> expectedList = new LinkedList<>();
-        Collections.addAll(expectedList, expected);
-
-        Collections.sort(actualList, comp);
-        Collections.sort(expectedList, comp);
-
-        for (int j = 0; j < actualList.size(); j++) {
-            if (j == expectedList.size()) {
-                fail("" + (actualList.size() - expectedList.size()) + " unexpected results, including " + actualList.get(expectedList.size()));
-            }
-
-            Bindings<T> a = actualList.get(j);
-            Bindings<T> e = expectedList.get(j);
-
-            if (0 != comp.compare(a, e)) {
-                fail("unexpected result(s), including " + a);
-            }
-        }
-        if (expectedList.size() > actualList.size()) {
-            fail("" + (expectedList.size() - actualList.size()) + " expected results not found, including " + expectedList.get(actualList.size()));
-        }
-    }
-
-    private <S, E> List<Bindings<E>> toBindings(final Traversal<S, Map<String, E>> traversal) {
-        List<Bindings<E>> result = new LinkedList<>();
-        traversal.forEachRemaining(o -> {
-            result.add(new Bindings<>(o));
-        });
-        return result;
-    }
-
-    private <T> List<Bindings<T>> toBindings(final Enumerator<T> enumerator) {
-        List<Bindings<T>> bindingsList = new LinkedList<>();
-        int i = 0;
-        bindingsList.add(new Bindings<>());
-        while (enumerator.visitSolution(i++, (name, value) -> {
-            bindingsList.get(bindingsList.size() - 1).put(name, value);
-        })) {
-            bindingsList.add(new Bindings<>());
-        }
-        bindingsList.remove(bindingsList.size() - 1);
-
-        return bindingsList;
-    }
-
-    private void assertBranchFactor(final double branchFactor,
-                                    final Traversal t,
-                                    final Iterator inputs) {
-        Traverser start = new B_O_S_SE_SL_Traverser(null, null, 1l);  // TODO bad? P?
-        MatchStep.TraversalWrapper w = new MatchStep.TraversalWrapper(t, "a", "b");
-        MatchStep.TraversalUpdater updater = new MatchStep.TraversalUpdater<>(w, inputs, start, "x");
-        while (updater.hasNext()) {
-            updater.next();
+                    as("c").out("knows").as("b")).select("c").out("knows").values("name");
         }
-        assertEquals(branchFactor, w.findBranchFactor(), 0);
-    }
 
-    private <T> int exhaust(Enumerator<T> enumerator) {
-        BiConsumer<String, T> visitor = (s, t) -> {
-        };
-        int i = 0;
-        while (enumerator.visitSolution(i, visitor)) i++;
-        return i;
-    }
-
-    private void findMissing(String s, final int i, final int n, final byte[] names, final Set<String> actual) {
-        if (0 == i) {
-            s = "{";
-        } else {
-            s += ", ";
-        }
-
-        s += (char) names[i];
-        s += "=";
-        String tmp = s;
-        for (int j = 0; j < 3; j++) {
-            s += j;
-
-            if (n - 1 == i) {
-                s += "}";
-                if (!actual.contains(s)) {
-                    fail("not in set: " + s);
-                }
-            } else {
-                findMissing(s, i + 1, n, names, actual);
-            }
-
-            s = tmp;
-        }
     }
 }