You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2022/01/14 02:00:00 UTC

[tinkerpop] branch TINKERPOP-2681 created (now 0b5ee8d)

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

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


      at 0b5ee8d  wip

This branch includes the following new commits:

     new 6b79c8b  wip
     new 0b5ee8d  wip

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


[tinkerpop] 02/02: wip

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

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

commit 0b5ee8da7e5ffbe278560c9d7f36e8d42413502a
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Jan 13 20:57:57 2022 -0500

    wip
---
 .../traversal/step/map/MergeVertexStep.java        | 32 +++++---
 .../traversal/step/map/TinkerMergeVertexStep.java  | 87 ++++++++++++++++++++++
 .../TinkerMergeVertexStepStrategy.java             | 53 +++++++++++++
 .../gremlin/tinkergraph/structure/TinkerGraph.java |  4 +-
 4 files changed, 166 insertions(+), 10 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
index ce77200..319db5d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
@@ -127,7 +127,7 @@ public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutati
 
     @Override
     public Parameters getParameters() {
-        // merge doesn't take foldups of property() calls. those need to get treated as regular old PropertyStep
+        // merge doesn't take fold ups of property() calls. those need to get treated as regular old PropertyStep
         // instances. not sure if this should support with() though.....none of the other Mutating steps do.
         return null;
     }
@@ -143,15 +143,19 @@ public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutati
         return super.processNextStart();
     }
 
-    @Override
-    protected Iterator<Vertex> flatMap(final Traverser.Admin<S> traverser) {
-        final Map<Object,Object> searchCreate = TraversalUtil.apply(traverser, searchCreateTraversal);
-
+    /**
+     * Use the {@code Map} of search criteria to most efficiently return a {@code Stream<Vertex>} of matching elements.
+     * Providers might override this method when extending this step to provide their own optimized mechanisms for
+     * matching the list of vertices. This implementation is only optimized for the {@link T#id} so any other usage
+     * will simply be in-memory filtering which could be slow.
+     */
+    protected Stream<Vertex> createSearchStream(final Map<Object,Object> search) {
         final Graph graph = this.getTraversal().getGraph().get();
+
         Stream<Vertex> stream;
         // prioritize lookup by id
-        if (searchCreate.containsKey(T.id))
-            stream = IteratorUtils.stream(graph.vertices(searchCreate.get(T.id)));
+        if (search.containsKey(T.id))
+            stream = IteratorUtils.stream(graph.vertices(search.get(T.id)));
         else
             stream = IteratorUtils.stream(graph.vertices());
 
@@ -159,7 +163,7 @@ public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutati
         // for other Mutation steps
         stream = stream.filter(v -> {
             // try to match on all search criteria skipping T.id as it was handled above
-            return searchCreate.entrySet().stream().filter(kv -> kv.getKey() != T.id).allMatch(kv -> {
+            return search.entrySet().stream().filter(kv -> kv.getKey() != T.id).allMatch(kv -> {
                 if (kv.getKey() == T.label) {
                     return v.label().equals(kv.getValue());
                 } else {
@@ -167,7 +171,17 @@ public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutati
                     return vp.isPresent() && kv.getValue().equals(vp.value());
                 }
             });
-        }).map(v -> {
+        });
+
+        return stream;
+    }
+
+    @Override
+    protected Iterator<Vertex> flatMap(final Traverser.Admin<S> traverser) {
+        final Map<Object,Object> searchCreate = TraversalUtil.apply(traverser, searchCreateTraversal);
+
+        Stream<Vertex> stream = createSearchStream(searchCreate);
+        stream = stream.map(v -> {
             // if no onMatch is defined then there is no update - return the vertex unchanged
             if (null == onMatchTraversal) return v;
 
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java
new file mode 100644
index 0000000..5876879
--- /dev/null
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/TinkerMergeVertexStep.java
@@ -0,0 +1,87 @@
+/*
+ * 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.tinkergraph.process.traversal.step.map;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MergeVertexStep;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerHelper;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * Optimizes {@code mergeV()} searches by attempting to use an index where possible.
+ */
+public class TinkerMergeVertexStep<S> extends MergeVertexStep<S> {
+    public TinkerMergeVertexStep(final MergeVertexStep step) {
+        super(step.getTraversal(), step.isStart(), step.getSearchCreateTraversal());
+        if (step.getOnMatchTraversal() != null) this.addChildOption(Merge.onMatch, step.getOnMatchTraversal());
+        if (step.getOnCreateTraversal() != null) this.addChildOption(Merge.onCreate, step.getOnCreateTraversal());
+    }
+
+    @Override
+    protected Stream<Vertex> createSearchStream(final Map<Object, Object> search) {
+        final TinkerGraph graph = (TinkerGraph) this.getTraversal().getGraph().get();
+        Optional<String> firstIndex = Optional.empty();
+
+        Stream<Vertex> stream;
+        // prioritize lookup by id but otherwise attempt an index lookup
+        if (search.containsKey(T.id)) {
+            stream = IteratorUtils.stream(graph.vertices(search.get(T.id)));
+        } else {
+            // look for the first index we can find - that's the lucky winner. may or may not be the most selective
+            final Set<String> indexedKeys = graph.getIndexedKeys(Vertex.class);
+            firstIndex = search.keySet().stream().
+                    filter(k -> k instanceof String).
+                    map(k -> (String) k).
+                    filter(indexedKeys::contains).findFirst();
+
+            // use the index if possible otherwise just in memory filter
+            stream = firstIndex.map(s -> TinkerHelper.queryVertexIndex(graph, s, search.get(s)).stream().map(v -> (Vertex) v)).
+                    orElseGet(() -> IteratorUtils.stream(graph.vertices()));
+        }
+
+        final Optional<String> indexUsed = firstIndex;
+        stream = stream.filter(v -> {
+            // try to match on all search criteria skipping T.id as it was handled above
+            return search.entrySet().stream().filter(kv -> {
+                final Object k = kv.getKey();
+                return k != T.id && !(indexUsed.isPresent() && indexUsed.get().equals(k));
+            }).allMatch(kv -> {
+                if (kv.getKey() == T.label) {
+                    return v.label().equals(kv.getValue());
+                } else {
+                    final VertexProperty<Object> vp = v.property(kv.getKey().toString());
+                    return vp.isPresent() && kv.getValue().equals(vp.value());
+                }
+            });
+        });
+
+        return stream;
+    }
+}
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerMergeVertexStepStrategy.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerMergeVertexStepStrategy.java
new file mode 100644
index 0000000..e5806ea
--- /dev/null
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/optimization/TinkerMergeVertexStepStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.tinkergraph.process.traversal.strategy.optimization;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MergeVertexStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.step.map.TinkerMergeVertexStep;
+
+/**
+ * Optimizes {@code mergeV()} search lookups by using {@link TinkerMergeVertexStep}.
+ */
+public final class TinkerMergeVertexStepStrategy extends AbstractTraversalStrategy<TraversalStrategy.ProviderOptimizationStrategy>
+        implements TraversalStrategy.ProviderOptimizationStrategy {
+
+    private static final TinkerMergeVertexStepStrategy INSTANCE = new TinkerMergeVertexStepStrategy();
+
+    private TinkerMergeVertexStepStrategy() {
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        if (TraversalHelper.onGraphComputer(traversal))
+            return;
+
+        for (final MergeVertexStep originalMergeVertexStep : TraversalHelper.getStepsOfClass(MergeVertexStep.class, traversal)) {
+            final TinkerMergeVertexStep tinkerMergeVertexStep = new TinkerMergeVertexStep(originalMergeVertexStep);
+            TraversalHelper.replaceStep(originalMergeVertexStep, tinkerMergeVertexStep, traversal);
+        }
+    }
+
+    public static TinkerMergeVertexStepStrategy instance() {
+        return INSTANCE;
+    }
+}
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index b9dda16..514d008 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -39,6 +39,7 @@ import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComp
 import org.apache.tinkerpop.gremlin.tinkergraph.process.computer.TinkerGraphComputerView;
 import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.optimization.TinkerGraphCountStrategy;
 import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.optimization.TinkerGraphStepStrategy;
+import org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.optimization.TinkerMergeVertexStepStrategy;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.io.File;
@@ -72,7 +73,8 @@ public final class TinkerGraph implements Graph {
     static {
         TraversalStrategies.GlobalCache.registerStrategies(TinkerGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(
                 TinkerGraphStepStrategy.instance(),
-                TinkerGraphCountStrategy.instance()));
+                TinkerGraphCountStrategy.instance(),
+                TinkerMergeVertexStepStrategy.instance()));
     }
 
     private static final Configuration EMPTY_CONFIGURATION = new BaseConfiguration() {{

[tinkerpop] 01/02: wip

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

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

commit 6b79c8bd19567dbdd371f911dbb5cc285fba88c4
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Wed Jan 12 10:12:16 2022 -0500

    wip
---
 .../tinkerpop/gremlin/jsr223/CoreImports.java      |   5 +-
 .../language/grammar/GenericLiteralVisitor.java    |  12 +-
 .../language/grammar/GremlinBaseVisitor.java       |  50 +++
 .../language/grammar/TraversalMethodVisitor.java   |  29 ++
 .../grammar/TraversalSourceSpawnMethodVisitor.java |  12 +
 .../tinkerpop/gremlin/process/traversal/Merge.java |  46 +++
 .../{step/TraversalOptionParent.java => Pick.java} |  13 +-
 .../gremlin/process/traversal/Translator.java      |   9 +-
 .../traversal/dsl/graph/GraphTraversal.java        |  75 ++++-
 .../traversal/dsl/graph/GraphTraversalSource.java  |  63 +++-
 .../traversal/step/TraversalOptionParent.java      |  11 +-
 .../process/traversal/step/branch/BranchStep.java  |   3 +-
 .../process/traversal/step/branch/ChooseStep.java  |   9 +-
 .../process/traversal/step/branch/UnionStep.java   |  10 +-
 .../traversal/step/map/MergeVertexStep.java        | 273 ++++++++++++++++
 .../traversal/translator/DotNetTranslator.java     |   5 +-
 .../traversal/translator/GroovyTranslator.java     |   6 +-
 .../traversal/translator/JavascriptTranslator.java |   4 +-
 .../traversal/translator/PythonTranslator.java     |   4 +-
 .../io/binary/TypeSerializerRegistry.java          |   4 +-
 .../structure/io/binary/types/EnumSerializer.java  |   4 +-
 .../structure/io/graphson/GraphSONModule.java      |  14 +-
 .../io/graphson/GraphSONTypeSerializerV2d0.java    |   6 +-
 .../io/graphson/GraphSONTypeSerializerV3d0.java    |   6 +-
 .../gremlin/structure/io/gryo/GryoVersion.java     |   6 +-
 .../traversal/step/branch/BranchStepTest.java      |   2 +-
 .../traversal/step/branch/ChooseStepTest.java      |   2 +-
 .../GraphBinaryReaderWriterRoundTripTest.java      |   4 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    | 344 +--------------------
 gremlin-language/src/main/antlr4/Gremlin.g4        |  32 ++
 gremlin-test/features/map/MergeVertex.feature      | 265 ++++++++++++++++
 .../tinkerpop/gremlin/features/StepDefinition.java |   7 +-
 .../process/ProcessLimitedStandardSuite.java       |  55 ----
 .../process/traversal/step/branch/BranchTest.java  |   4 +-
 .../process/traversal/step/branch/ChooseTest.java  |   6 +-
 .../decoration/EventStrategyProcessTest.java       |  62 ++++
 .../tinkerpop/gremlin/structure/io/Model.java      |   4 +-
 .../_3_2_3/manual-graphson-generator.groovy        |   5 +-
 .../_3_2_4/manual-graphson-generator.groovy        |   5 +-
 .../io/gryo/_3_2_3/manual-gryo-generator.groovy    |   8 +-
 .../io/gryo/_3_2_4/manual-gryo-generator.groovy    |   8 +-
 41 files changed, 993 insertions(+), 499 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index 194a192..a34f0d7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -58,6 +58,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.IO;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
@@ -200,7 +201,7 @@ public final class CoreImports {
         CLASS_IMPORTS.add(Scope.class);
         CLASS_IMPORTS.add(T.class);
         CLASS_IMPORTS.add(TraversalOptionParent.class);
-        CLASS_IMPORTS.add(TraversalOptionParent.Pick.class);
+        CLASS_IMPORTS.add(Pick.class);
         CLASS_IMPORTS.add(P.class);
         CLASS_IMPORTS.add(TextP.class);
         CLASS_IMPORTS.add(WithOptions.class);
@@ -349,7 +350,7 @@ public final class CoreImports {
         Collections.addAll(ENUM_IMPORTS, Pop.values());
         Collections.addAll(ENUM_IMPORTS, Scope.values());
         Collections.addAll(ENUM_IMPORTS, T.values());
-        Collections.addAll(ENUM_IMPORTS, TraversalOptionParent.Pick.values());
+        Collections.addAll(ENUM_IMPORTS, Pick.values());
     }
 
     private CoreImports() {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index f71bcf7..151174a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -20,9 +20,9 @@ package org.apache.tinkerpop.gremlin.language.grammar;
 
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.apache.commons.text.StringEscapeUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
@@ -33,6 +33,7 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -81,6 +82,13 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
     }
 
     /**
+     * Parse a map literal context and return the map literal
+     */
+    public static Map getMapLiteral(final GremlinParser.GenericLiteralMapContext mapLiteral) {
+        return (Map) (instance().visitGenericLiteralMap(mapLiteral));
+    }
+
+    /**
      * Parse a boolean literal context and return the boolean literal
      */
     public static boolean getBooleanLiteral(final GremlinParser.BooleanLiteralContext booleanLiteral) {
@@ -464,7 +472,7 @@ public class GenericLiteralVisitor extends GremlinBaseVisitor<Object> {
      */
     @Override
     public Object visitTraversalOptionParent(final GremlinParser.TraversalOptionParentContext ctx) {
-        return TraversalEnumParser.parseTraversalEnumFromContext(TraversalOptionParent.Pick.class, ctx);
+        return TraversalEnumParser.parseTraversalEnumFromContext(Pick.class, ctx);
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinBaseVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinBaseVisitor.java
index fd48b79..0a93e4e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinBaseVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinBaseVisitor.java
@@ -1521,4 +1521,54 @@ public class GremlinBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
 	public T visitStructureVertex(final GremlinParser.StructureVertexContext ctx) {
 		notImplemented(ctx); return null;
 	}
+
+	@Override
+	public T visitTraversalSourceSpawnMethod_mergeV_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeV_MapContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalSourceSpawnMethod_mergeV_Traversal(final GremlinParser.TraversalSourceSpawnMethod_mergeV_TraversalContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalSourceSpawnMethod_mergeE(final GremlinParser.TraversalSourceSpawnMethod_mergeEContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_option_Merge_Map(GremlinParser.TraversalMethod_option_Merge_MapContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMerge(final GremlinParser.TraversalMergeContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_mergeV_Map(final GremlinParser.TraversalMethod_mergeV_MapContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_mergeV_Traversal(final GremlinParser.TraversalMethod_mergeV_TraversalContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_mergeE_Map(final GremlinParser.TraversalMethod_mergeE_MapContext ctx) {
+		notImplemented(ctx); return null;
+	}
+
+	@Override
+	public T visitTraversalMethod_mergeE_Traversal(final GremlinParser.TraversalMethod_mergeE_TraversalContext ctx) {
+		notImplemented(ctx); return null;
+	}
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index fac55d6..be0fff5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.language.grammar;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
@@ -86,6 +87,16 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
     }
 
     @Override
+    public GraphTraversal visitTraversalMethod_mergeV_Map(final GremlinParser.TraversalMethod_mergeV_MapContext ctx) {
+        return this.graphTraversal.mergeV(GenericLiteralVisitor.getMapLiteral(ctx.genericLiteralMap()));
+    }
+
+    @Override
+    public GraphTraversal visitTraversalMethod_mergeV_Traversal(final GremlinParser.TraversalMethod_mergeV_TraversalContext ctx) {
+        return this.graphTraversal.mergeV(antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+    }
+
+    @Override
     public GraphTraversal visitTraversalMethod_addE_Traversal(final GremlinParser.TraversalMethod_addE_TraversalContext ctx) {
         return this.graphTraversal.addE(antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
@@ -973,6 +984,24 @@ public class TraversalMethodVisitor extends TraversalRootVisitor<GraphTraversal>
      * {@inheritDoc}
      */
     @Override
+    public GraphTraversal visitTraversalMethod_option_Merge_Map(final GremlinParser.TraversalMethod_option_Merge_MapContext ctx) {
+        return graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()),
+                (Map) new GenericLiteralVisitor(antlr).visitGenericLiteralMap(ctx.genericLiteralMap()));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public GraphTraversal visitTraversalMethod_option_Merge_Traversal(final GremlinParser.TraversalMethod_option_Merge_TraversalContext ctx) {
+        return this.graphTraversal.option(TraversalEnumParser.parseTraversalEnumFromContext(Merge.class, ctx.traversalMerge()),
+                antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public GraphTraversal visitTraversalMethod_optional(final GremlinParser.TraversalMethod_optionalContext ctx) {
         return this.graphTraversal.optional(antlr.tvisitor.visitNestedTraversal(ctx.nestedTraversal()));
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index 73e8612..664afac 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -22,6 +22,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 
+import java.util.Map;
+
 /**
  * Use a {@link GraphTraversalSource} as the source and returns a {@link GraphTraversal} object.
  */
@@ -114,4 +116,14 @@ public class TraversalSourceSpawnMethodVisitor extends GremlinBaseVisitor<GraphT
         }
         return graphTraversal;
     }
+
+    @Override
+    public GraphTraversal visitTraversalSourceSpawnMethod_mergeV_Map(final GremlinParser.TraversalSourceSpawnMethod_mergeV_MapContext ctx) {
+        return this.traversalSource.mergeV(GenericLiteralVisitor.getMapLiteral(ctx.genericLiteralMap()));
+    }
+
+    @Override
+    public GraphTraversal visitTraversalSourceSpawnMethod_mergeV_Traversal(final GremlinParser.TraversalSourceSpawnMethod_mergeV_TraversalContext ctx) {
+        return this.traversalSource.mergeV(anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
+    }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Merge.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Merge.java
new file mode 100644
index 0000000..a64d8ce
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Merge.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Element;
+
+import java.util.Map;
+
+/**
+ * Options relevant to upsert-like steps such as {@link GraphTraversalSource#mergeV(Map)}.
+ */
+public enum Merge {
+
+    /**
+     * Allows definition of the action to take when a merge operation ends up not matching the search criteria.
+     * Typically, this event means that an {@link Element} will be created.
+     *
+     * @since 3.6.0
+     */
+    onCreate,
+
+    /**
+     * Allows definition of the action to take when a merge operation ends up successfully matching the search criteria.
+     * Typically, this event means that the matched {@link Element} will be returned.
+     *
+     * @since 3.6.0
+     */
+    onMatch
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java
similarity index 66%
copy from gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java
copy to gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java
index 6eb60a2..980c7dd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Pick.java
@@ -16,16 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.tinkerpop.gremlin.process.traversal.step;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+package org.apache.tinkerpop.gremlin.process.traversal;
 
 /**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * A token used with {@code option()}.
  */
-public interface TraversalOptionParent<M, S, E> extends TraversalParent {
-
-    public static enum Pick {any, none}
-
-    public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption);
+public enum Pick {
+    any, none
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
index 30dccc4..0be7555 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
@@ -19,7 +19,6 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal;
 
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
@@ -165,9 +164,9 @@ public interface Translator<S, T> {
             protected abstract String getSyntax(final VertexProperty.Cardinality o);
 
             /**
-             * Take the {@link TraversalOptionParent.Pick} argument and convert it to a string representation in the target language.
+             * Take the {@link Pick} argument and convert it to a string representation in the target language.
              */
-            protected abstract String getSyntax(final TraversalOptionParent.Pick o);
+            protected abstract String getSyntax(final Pick o);
 
             /**
              * Take the numeric argument and convert it to a string representation in the target language. Languages
@@ -308,8 +307,8 @@ public interface Translator<S, T> {
                     return script.append(getSyntax((SackFunctions.Barrier) object));
                 } else if (object instanceof VertexProperty.Cardinality) {
                     return script.append(getSyntax((VertexProperty.Cardinality) object));
-                } else if (object instanceof TraversalOptionParent.Pick) {
-                    return script.append(getSyntax((TraversalOptionParent.Pick) object));
+                } else if (object instanceof Pick) {
+                    return script.append(getSyntax((Pick) object));
                 } else if (object instanceof Enum) {
                     return produceScript((Enum<?>) object);
                 } else if (object instanceof Vertex) {
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 95927d6..721c1f7 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
@@ -26,15 +26,18 @@ import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PeerPres
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ProgramVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPathVertexProgramStep;
 import org.apache.tinkerpop.gremlin.process.traversal.Failure;
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 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.lambda.ColumnTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.FunctionTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.LoopTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraverser;
@@ -100,6 +103,7 @@ 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;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanLocalStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MergeVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinLocalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.NoOpBarrierStep;
@@ -1071,6 +1075,37 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     }
 
     /**
+     * Performs a merge (i.e. upsert) style operation for an {@link Vertex} using a {@code Map} as an argument.
+     * The {@code Map} represents search criteria and will match each of the supplied key/value pairs where the keys
+     * may be {@code String} property values or a value of {@link T}. If a match is not made it will use that search
+     * criteria to create the new {@link Vertex}.
+     *
+     * @param searchCreate This {@code Map} can have a key of {@link T} or a {@code String}.
+     * @since 3.6.0
+     */
+    public default GraphTraversal<S, Vertex> mergeV(final Map<Object, Object> searchCreate) {
+        this.asAdmin().getBytecode().addStep(Symbols.mergeV, searchCreate);
+        final MergeVertexStep<S> step = new MergeVertexStep<>(this.asAdmin(), false, searchCreate);
+        return this.asAdmin().addStep(step);
+    }
+
+    /**
+     * Performs a merge (i.e. upsert) style operation for an {@link Vertex} using a {@code Map} as an argument.
+     * The {@code Map} represents search criteria and will match each of the supplied key/value pairs where the keys
+     * may be {@code String} property values or a value of {@link T}. If a match is not made it will use that search
+     * criteria to create the new {@link Vertex}.
+     *
+     *  @param searchCreate This anonymous {@link Traversal} must produce a {@code Map} that may have a keys of
+     *  {@link T} or a {@code String}.
+     *  @since 3.6.0
+     */
+    public default GraphTraversal<S, Vertex> mergeV(final Traversal<S, Map<Object, Object>> searchCreate) {
+        this.asAdmin().getBytecode().addStep(Symbols.mergeV, searchCreate);
+        final MergeVertexStep<S> step = new MergeVertexStep<>(this.asAdmin(), false, searchCreate.asAdmin());
+        return this.asAdmin().addStep(step);
+    }
+
+    /**
      * Adds an {@link Edge} with the specified edge label.
      *
      * @param edgeLabel the label of the newly added edge
@@ -3024,7 +3059,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
     /**
      * This step modifies {@link #choose(Function)} to specifies the available choices that might be executed.
      *
-     * @param pick       the token that would trigger this option which may be a {@link TraversalOptionParent.Pick},
+     * @param pick       the token that would trigger this option which may be a {@link Pick},
      *                   a {@link Traversal}, {@link Predicate}, or object depending on the step being modulated.
      * @param traversalOption the option as a traversal
      * @return the traversal with the modulated step
@@ -3033,7 +3068,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      */
     public default <M, E2> GraphTraversal<S, E> option(final M pick, final Traversal<?, E2> traversalOption) {
         this.asAdmin().getBytecode().addStep(Symbols.option, pick, traversalOption);
-        ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addGlobalChildOption(pick, (Traversal.Admin<E, E2>) traversalOption.asAdmin());
+        ((TraversalOptionParent<M, E, E2>) this.asAdmin().getEndStep()).addChildOption(pick, (Traversal.Admin<E, E2>) traversalOption.asAdmin());
         return this;
     }
 
@@ -3047,7 +3082,39 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
      */
     public default <E2> GraphTraversal<S, E> option(final Traversal<?, E2> traversalOption) {
         this.asAdmin().getBytecode().addStep(Symbols.option, traversalOption);
-        ((TraversalOptionParent<Object, E, E2>) this.asAdmin().getEndStep()).addGlobalChildOption(TraversalOptionParent.Pick.any, (Traversal.Admin<E, E2>) traversalOption.asAdmin());
+        ((TraversalOptionParent<Object, E, E2>) this.asAdmin().getEndStep()).addChildOption(Pick.any, (Traversal.Admin<E, E2>) traversalOption.asAdmin());
+        return this;
+    }
+
+    /**
+     * This step modifies merge related steps to specify the available choices that might be executed on the available
+     * {@link Merge} options.
+     *
+     * @param traversal the option as a traversal
+     * @return the traversal with the modulated step
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+     * @since 3.6.0
+     */
+    public default <E2> GraphTraversal<S, E> option(final Merge merge, final Traversal<?, E2> traversal) {
+        this.asAdmin().getBytecode().addStep(Symbols.option, merge, traversal);
+        ((TraversalOptionParent<Merge, E, E2>) this.asAdmin().getEndStep()).addChildOption(merge, (Traversal.Admin<E, E2>) traversal.asAdmin());
+        return this;
+    }
+
+    /**
+     * This step modifies merge related steps to specify the available choices that might be executed on the available
+     * {@link Merge} options.
+     *
+     * @param m
+     * @return the traversal with the modulated step
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergev-step" target="_blank">Reference Documentation - MergeV Step</a>
+     * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#mergee-step" target="_blank">Reference Documentation - MergeE Step</a>
+     * @since 3.6.0
+     */
+    public default <E2> GraphTraversal<S, E> option(final Merge merge, final Map<Object, Object> m) {
+        this.asAdmin().getBytecode().addStep(Symbols.option, merge, m);
+        ((TraversalOptionParent<Merge, E, E2>) this.asAdmin().getEndStep()).addChildOption(merge, (Traversal.Admin<E, E2>) new ConstantTraversal<>(m).asAdmin());
         return this;
     }
 
@@ -3150,6 +3217,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
         public static final String tree = "tree";
         public static final String addV = "addV";
         public static final String addE = "addE";
+        public static final String mergeV = "mergeV";
+        public static final String mergeE = "mergeE";
         public static final String from = "from";
         public static final String filter = "filter";
         public static final String or = "or";
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index fbb873f..6726255 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -30,17 +30,20 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeStartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.MergeVertexStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IoStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.RequirementsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 
+import java.util.Map;
 import java.util.Optional;
 import java.util.function.BinaryOperator;
 import java.util.function.Supplier;
@@ -298,6 +301,8 @@ public class GraphTraversalSource implements TraversalSource {
     /**
      * Spawns a {@link GraphTraversal} by adding a vertex with the specified label. If the {@code label} is
      * {@code null} then it will default to {@link Vertex#DEFAULT_LABEL}.
+     *
+     * @since 3.1.0-incubating
      */
     public GraphTraversal<Vertex, Vertex> addV(final String vertexLabel) {
         if (null == vertexLabel) throw new IllegalArgumentException("vertexLabel cannot be null");
@@ -310,6 +315,8 @@ public class GraphTraversalSource implements TraversalSource {
     /**
      * Spawns a {@link GraphTraversal} by adding a vertex with the label as determined by a {@link Traversal}. If the
      * {@code vertexLabelTraversal} is {@code null} then it will default to {@link Vertex#DEFAULT_LABEL}.
+     *
+     * @since 3.3.1
      */
     public GraphTraversal<Vertex, Vertex> addV(final Traversal<?, String> vertexLabelTraversal) {
         if (null == vertexLabelTraversal) throw new IllegalArgumentException("vertexLabelTraversal cannot be null");
@@ -321,6 +328,8 @@ public class GraphTraversalSource implements TraversalSource {
 
     /**
      * Spawns a {@link GraphTraversal} by adding a vertex with the default label.
+     *
+     * @since 3.1.0-incubating
      */
     public GraphTraversal<Vertex, Vertex> addV() {
         final GraphTraversalSource clone = this.clone();
@@ -330,7 +339,9 @@ public class GraphTraversalSource implements TraversalSource {
     }
 
     /**
-     * Spawns a {@link GraphTraversal} by adding a edge with the specified label.
+     * Spawns a {@link GraphTraversal} by adding an edge with the specified label.
+     *
+     * @since 3.1.0-incubating
      */
     public GraphTraversal<Edge, Edge> addE(final String label) {
         final GraphTraversalSource clone = this.clone();
@@ -341,6 +352,8 @@ public class GraphTraversalSource implements TraversalSource {
 
     /**
      * Spawns a {@link GraphTraversal} by adding a edge with a label as specified by the provided {@link Traversal}.
+     *
+     * @since 3.3.1
      */
     public GraphTraversal<Edge, Edge> addE(final Traversal<?, String> edgeLabelTraversal) {
         final GraphTraversalSource clone = this.clone();
@@ -350,6 +363,50 @@ public class GraphTraversalSource implements TraversalSource {
     }
 
     /**
+     * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Vertex} using a
+     * {@code Map} as an argument. The {@code Map} represents search criteria and will match each of the supplied
+     * key/value pairs where the keys may be {@code String} property values or a value of {@link T}. If a match is not
+     * made it will use that search criteria to create the new {@link Vertex}.
+     *
+     * @param searchCreate This {@code Map} can have a key of {@link T} or a {@code String}.
+     * @since 3.6.0
+     */
+    public GraphTraversal<Vertex, Vertex> mergeV(final Map<Object, Object> searchCreate) {
+        final GraphTraversalSource clone = this.clone();
+        clone.bytecode.addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+        final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(clone);
+        return traversal.addStep(new MergeVertexStep(traversal, true, searchCreate));
+    }
+
+    /**
+     * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Vertex} using a
+     * {@code Map} as an argument. The {@code Map} represents search criteria and will match each of the supplied
+     * key/value pairs where the keys may be {@code String} property values or a value of {@link T}. If a match is not
+     * made it will use that search criteria to create the new {@link Vertex}.
+     *
+     * @param searchCreate This anonymous {@link Traversal} must produce a {@code Map} that may have a keys of
+     * {@link T} or a {@code String}.
+     * @since 3.6.0
+     */
+    public <S> GraphTraversal<S, Vertex> mergeV(final Traversal<S, Map<Object, Object>> searchCreate) {
+        final GraphTraversalSource clone = this.clone();
+        clone.bytecode.addStep(GraphTraversal.Symbols.mergeV, searchCreate);
+        final GraphTraversal.Admin<S, Vertex> traversal = new DefaultGraphTraversal<>(clone);
+        return traversal.addStep(new MergeVertexStep(traversal, true, searchCreate.asAdmin()));
+    }
+
+    /**
+     * Spawns a {@link GraphTraversal} by doing a merge (i.e. upsert) style operation for an {@link Edge} using a
+     * {@code Map} as an argument.
+     */
+//    public GraphTraversal<Edge, Edge> mergeE(final Map<?, Object> searchCreate) {
+//        final GraphTraversalSource clone = this.clone();
+//        clone.bytecode.addStep(GraphTraversal.Symbols.mergeE, searchCreate);
+//        final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(clone);
+//        return traversal.addStep(new MergeVertexStartStep(traversal, searchCreate));
+//    }
+
+    /**
      * Spawns a {@link GraphTraversal} starting it with arbitrary values.
      */
     public <S> GraphTraversal<S, S> inject(S... starts) {
@@ -364,6 +421,8 @@ public class GraphTraversalSource implements TraversalSource {
     /**
      * Spawns a {@link GraphTraversal} starting with all vertices or some subset of vertices as specified by their
      * unique identifier.
+     *
+     * @since 3.0.0-incubating
      */
     public GraphTraversal<Vertex, Vertex> V(final Object... vertexIds) {
         // a single null is [null]
@@ -377,6 +436,8 @@ public class GraphTraversalSource implements TraversalSource {
     /**
      * Spawns a {@link GraphTraversal} starting with all edges or some subset of edges as specified by their unique
      * identifier.
+     *
+     * @since 3.0.0-incubating
      */
     public GraphTraversal<Edge, Edge> E(final Object... edgeIds) {
         // a single null is [null]
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java
index 6eb60a2..ef9b92c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/TraversalOptionParent.java
@@ -18,14 +18,19 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 
 /**
+ * Describes steps that can be parent to a {@link Traversal} from {@code option()}.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public interface TraversalOptionParent<M, S, E> extends TraversalParent {
 
-    public static enum Pick {any, none}
-
-    public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption);
+    /**
+     * The child as defined by the token it takes, like {@link Pick}. This traversal may be of local or global scope
+     * depending on the step implementation that works with {@code option()}.
+     */
+    public void addChildOption(final M token, final Traversal.Admin<S, E> traversalOption);
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
index 361ed54..085cf57 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.PredicateTraversal;
@@ -63,7 +64,7 @@ public class BranchStep<S, E, M> extends ComputerAwareStep<S, E> implements Trav
     }
 
     @Override
-    public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
+    public void addChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
         if (pickToken instanceof Pick) {
             if (this.traversalPickOptions.containsKey(pickToken))
                 this.traversalPickOptions.get(pickToken).add(traversalOption);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
index a804d8f..86ec39e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.HasNextStep;
 
@@ -36,18 +37,18 @@ public final class ChooseStep<S, E, M> extends BranchStep<S, E, M> {
 
     public ChooseStep(final Traversal.Admin traversal, final Traversal.Admin<S, ?> predicateTraversal, final Traversal.Admin<S, E> trueChoice, final Traversal.Admin<S, E> falseChoice) {
         this(traversal, (Traversal.Admin<S, M>) predicateTraversal.addStep(new HasNextStep<>(predicateTraversal)));
-        this.addGlobalChildOption((M) Boolean.TRUE, trueChoice);
-        this.addGlobalChildOption((M) Boolean.FALSE, falseChoice);
+        this.addChildOption((M) Boolean.TRUE, trueChoice);
+        this.addChildOption((M) Boolean.FALSE, falseChoice);
     }
 
     @Override
-    public void addGlobalChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
+    public void addChildOption(final M pickToken, final Traversal.Admin<S, E> traversalOption) {
         if (pickToken instanceof Pick) {
             if (Pick.any.equals(pickToken))
                 throw new IllegalArgumentException("Choose step can not have an any-option as only one option per traverser is allowed");
             if (this.traversalPickOptions.containsKey(pickToken))
                 throw new IllegalArgumentException("Choose step can only have one traversal per pick token: " + pickToken);
         }
-        super.addGlobalChildOption(pickToken, traversalOption);
+        super.addChildOption(pickToken, traversalOption);
     }
 }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
index de70479..1ce6137 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/UnionStep.java
@@ -18,8 +18,8 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.branch;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -28,21 +28,21 @@ import java.util.Collections;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class UnionStep<S, E> extends BranchStep<S, E, TraversalOptionParent.Pick> {
+public final class UnionStep<S, E> extends BranchStep<S, E, Pick> {
 
     public UnionStep(final Traversal.Admin traversal, final Traversal.Admin<?, E>... unionTraversals) {
         super(traversal);
         this.setBranchTraversal(new ConstantTraversal<>(Pick.any));
         for (final Traversal.Admin<?, E> union : unionTraversals) {
-            this.addGlobalChildOption(Pick.any, (Traversal.Admin) union);
+            this.addChildOption(Pick.any, (Traversal.Admin) union);
         }
     }
 
     @Override
-    public void addGlobalChildOption(final Pick pickToken, final Traversal.Admin<S, E> traversalOption) {
+    public void addChildOption(final Pick pickToken, final Traversal.Admin<S, E> traversalOption) {
         if (Pick.any != pickToken)
             throw new IllegalArgumentException("Union step only supports the any token: " + pickToken);
-        super.addGlobalChildOption(pickToken, traversalOption);
+        super.addChildOption(pickToken, traversalOption);
     }
 
     @Override
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
new file mode 100644
index 0000000..ce77200
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java
@@ -0,0 +1,273 @@
+/*
+ * 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.Merge;
+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.TraverserGenerator;
+import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.Mutating;
+import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Parameters;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.CallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.Event;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.ListCallbackRegistry;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ * Implementation for the {@code mergeV()} step covering both the start step version and the one used mid-traversal.
+ */
+public class MergeVertexStep<S> extends FlatMapStep<S, Vertex> implements Mutating<Event>,
+        TraversalOptionParent<Merge, S, Vertex> {
+
+    private final boolean isStart;
+    private boolean first = true;
+    private Traversal.Admin<S,Map<Object, Object>> searchCreateTraversal;
+    private Traversal.Admin<S, Map<Object, Object>> onCreateTraversal = null;
+    private Traversal.Admin<S, Map<String, Object>> onMatchTraversal = null;
+
+    private CallbackRegistry<Event> callbackRegistry;
+
+    public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final Map<Object, Object> searchCreate) {
+        this(traversal, isStart, new ConstantTraversal<>(searchCreate));
+    }
+
+    public MergeVertexStep(final Traversal.Admin traversal, final boolean isStart, final Traversal.Admin<S,Map<Object, Object>> searchCreateTraversal) {
+        super(traversal);
+        this.isStart = isStart;
+        this.searchCreateTraversal = integrateChild(searchCreateTraversal);
+    }
+
+    public Traversal.Admin<S, Map<Object, Object>> getSearchCreateTraversal() {
+        return searchCreateTraversal;
+    }
+
+    public Traversal.Admin<S, Map<Object, Object>> getOnCreateTraversal() {
+        return onCreateTraversal;
+    }
+
+    public Traversal.Admin<S, Map<String, Object>> getOnMatchTraversal() {
+        return onMatchTraversal;
+    }
+
+    /**
+     * Determines if this is a start step.
+     */
+    public boolean isStart() {
+        return isStart;
+    }
+
+    public boolean isFirst() {
+        return first;
+    }
+
+    public CallbackRegistry<Event> getCallbackRegistry() {
+        return callbackRegistry;
+    }
+
+    @Override
+    public void addChildOption(final Merge token, final Traversal.Admin<S, Vertex> traversalOption) {
+        if (token == Merge.onCreate) {
+            this.onCreateTraversal = this.integrateChild(traversalOption);
+        } else if (token == Merge.onMatch) {
+            this.onMatchTraversal = this.integrateChild(traversalOption);
+        } else {
+            throw new UnsupportedOperationException(String.format("Option %s for Merge is not supported", token.name()));
+        }
+    }
+
+    @Override
+    public <S, E> List<Traversal.Admin<S, E>> getLocalChildren() {
+        final List<Traversal.Admin<S, E>> children = new ArrayList<>();
+        if (searchCreateTraversal != null) children.add((Traversal.Admin<S, E>) searchCreateTraversal);
+        if (onMatchTraversal != null) children.add((Traversal.Admin<S, E>) onMatchTraversal);
+        if (onCreateTraversal != null) children.add((Traversal.Admin<S, E>) onCreateTraversal);
+        return children;
+    }
+
+    @Override
+    public void configure(final Object... keyValues) {
+        // this is a Mutating step but property() should not be folded into this step. this exception should not
+        // end up visible to users really
+    }
+
+    @Override
+    public Parameters getParameters() {
+        // merge doesn't take foldups of property() calls. those need to get treated as regular old PropertyStep
+        // instances. not sure if this should support with() though.....none of the other Mutating steps do.
+        return null;
+    }
+
+    @Override
+    protected Traverser.Admin<Vertex> processNextStart() {
+        // when it's a start step a traverser needs to be created to kick off the traversal.
+        if (isStart && first) {
+            first = false;
+            final TraverserGenerator generator = this.getTraversal().getTraverserGenerator();
+            this.addStart(generator.generate(false, (Step) this, 1L));
+        }
+        return super.processNextStart();
+    }
+
+    @Override
+    protected Iterator<Vertex> flatMap(final Traverser.Admin<S> traverser) {
+        final Map<Object,Object> searchCreate = TraversalUtil.apply(traverser, searchCreateTraversal);
+
+        final Graph graph = this.getTraversal().getGraph().get();
+        Stream<Vertex> stream;
+        // prioritize lookup by id
+        if (searchCreate.containsKey(T.id))
+            stream = IteratorUtils.stream(graph.vertices(searchCreate.get(T.id)));
+        else
+            stream = IteratorUtils.stream(graph.vertices());
+
+        // in-memory filter is not going to be nice here. it will be up to graphs to optimize this step as they do
+        // for other Mutation steps
+        stream = stream.filter(v -> {
+            // try to match on all search criteria skipping T.id as it was handled above
+            return searchCreate.entrySet().stream().filter(kv -> kv.getKey() != T.id).allMatch(kv -> {
+                if (kv.getKey() == T.label) {
+                    return v.label().equals(kv.getValue());
+                } else {
+                    final VertexProperty<Object> vp = v.property(kv.getKey().toString());
+                    return vp.isPresent() && kv.getValue().equals(vp.value());
+                }
+            });
+        }).map(v -> {
+            // if no onMatch is defined then there is no update - return the vertex unchanged
+            if (null == onMatchTraversal) return v;
+
+            // assume good input from GraphTraversal - folks might drop in a T here even though it is immutable
+            final Map<String, Object> onMatchMap = TraversalUtil.apply(traverser, onMatchTraversal);
+            onMatchMap.forEach((key, value) -> {
+                // trigger callbacks for eventing - in this case, it's a VertexPropertyChangedEvent. if there's no
+                // registry/callbacks then just set the property
+                if (this.callbackRegistry != null && !callbackRegistry.getCallbacks().isEmpty()) {
+                    final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
+                    final Property<Object> oldValue = eventStrategy.detach(v.property(key));
+                    final Event.VertexPropertyChangedEvent vpce = new Event.VertexPropertyChangedEvent(eventStrategy.detach(v), oldValue, value);
+                    this.callbackRegistry.getCallbacks().forEach(c -> c.accept(vpce));
+                }
+                v.property(key, value);
+            });
+
+            return v;
+        });
+
+        // if the stream has something then there is a match (possibly updated) and is returned, otherwise a new
+        // vertex is created
+        final Iterator<Vertex> vertices = stream.iterator();
+        if (vertices.hasNext()) {
+            return vertices;
+        } else {
+            final Vertex vertex;
+
+            // if there is an onCreateTraversal then the search criteria is ignored for the creation as it is provided
+            // by way of the traversal which will return the Map
+            final Map<Object,Object> m = null == onCreateTraversal ? searchCreate : TraversalUtil.apply(traverser, onCreateTraversal);
+            final List<Object> keyValues = new ArrayList<>();
+            for (Map.Entry<Object, Object> entry : m.entrySet()) {
+                keyValues.add(entry.getKey());
+                keyValues.add(entry.getValue());
+            }
+            vertex = this.getTraversal().getGraph().get().addVertex(keyValues.toArray(new Object[keyValues.size()]));
+
+            // trigger callbacks for eventing - in this case, it's a VertexAddedEvent
+            if (this.callbackRegistry != null && !callbackRegistry.getCallbacks().isEmpty()) {
+                final EventStrategy eventStrategy = getTraversal().getStrategies().getStrategy(EventStrategy.class).get();
+                final Event.VertexAddedEvent vae = new Event.VertexAddedEvent(eventStrategy.detach(vertex));
+                this.callbackRegistry.getCallbacks().forEach(c -> c.accept(vae));
+            }
+
+            return IteratorUtils.of(vertex);
+        }
+    }
+
+    @Override
+    public CallbackRegistry<Event> getMutatingCallbackRegistry() {
+        if (null == callbackRegistry) callbackRegistry = new ListCallbackRegistry<>();
+        return callbackRegistry;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        if (searchCreateTraversal != null)
+            result ^= searchCreateTraversal.hashCode();
+        if (onCreateTraversal != null)
+            result ^= onCreateTraversal.hashCode();
+        if (onMatchTraversal != null)
+            result ^= onMatchTraversal.hashCode();
+        return result;
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        first = true;
+        searchCreateTraversal.reset();
+        if (onCreateTraversal != null) onCreateTraversal.reset();
+        if (onMatchTraversal != null) onMatchTraversal.reset();
+    }
+
+    @Override
+    public Set<TraverserRequirement> getRequirements() {
+        return this.getSelfAndChildRequirements();
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.stepString(this, searchCreateTraversal, onCreateTraversal, onMatchTraversal);
+    }
+
+    @Override
+    public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) {
+        super.setTraversal(parentTraversal);
+        this.integrateChild(searchCreateTraversal);
+        this.integrateChild(onCreateTraversal);
+        this.integrateChild(onMatchTraversal);
+    }
+
+    @Override
+    public MergeVertexStep<S> clone() {
+        final MergeVertexStep<S> clone = (MergeVertexStep<S>) super.clone();
+        clone.searchCreateTraversal = searchCreateTraversal.clone();
+        clone.onCreateTraversal = onCreateTraversal != null ? onCreateTraversal.clone() : null;
+        clone.onMatchTraversal = onMatchTraversal != null ? onMatchTraversal.clone() : null;
+        return clone;
+    }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
index 4f375e5..5f3ae25 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/DotNetTranslator.java
@@ -19,10 +19,10 @@
 
 package org.apache.tinkerpop.gremlin.process.traversal.translator;
 
-import org.apache.commons.configuration2.ConfigurationConverter;
 import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
@@ -30,7 +30,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
@@ -171,7 +170,7 @@ public final class DotNetTranslator implements Translator.ScriptTranslator {
         }
 
         @Override
-        protected String getSyntax(final TraversalOptionParent.Pick o) {
+        protected String getSyntax(final Pick o) {
             return "Pick." + SymbolHelper.toCSharp(o.toString());
         }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
index ef544b4..bfa3065 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
@@ -24,14 +24,12 @@ import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.jsr223.CoreImports;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
@@ -175,7 +173,7 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
         }
 
         @Override
-        protected String getSyntax(final TraversalOptionParent.Pick o) {
+        protected String getSyntax(final Pick o) {
             return "TraversalOptionParent.Pick." + o.toString();
         }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
index e9cf748..f95d288 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/JavascriptTranslator.java
@@ -23,13 +23,13 @@ import org.apache.commons.configuration2.ConfigurationConverter;
 import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
@@ -167,7 +167,7 @@ public final class JavascriptTranslator implements Translator.ScriptTranslator {
         }
 
         @Override
-        protected String getSyntax(final TraversalOptionParent.Pick o) {
+        protected String getSyntax(final Pick o) {
             return "Pick." + o.toString();
         }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
index 09e4447..987fa3e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/PythonTranslator.java
@@ -23,6 +23,7 @@ import org.apache.commons.configuration2.ConfigurationConverter;
 import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Script;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
@@ -30,7 +31,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Translator;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
@@ -188,7 +188,7 @@ public final class PythonTranslator implements Translator.ScriptTranslator {
         }
 
         @Override
-        protected String getSyntax(final TraversalOptionParent.Pick o) {
+        protected String getSyntax(final Pick o) {
             return "Pick." + resolveSymbol(o.toString());
         }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
index ced0088..0c4b913 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/TypeSerializerRegistry.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.binary;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.structure.io.binary.types.*;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
@@ -30,7 +31,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
@@ -119,7 +119,7 @@ public class TypeSerializerRegistry {
             new RegistryEntry<>(Direction.class, EnumSerializer.DirectionSerializer),
             new RegistryEntry<>(Operator.class, EnumSerializer.OperatorSerializer),
             new RegistryEntry<>(Order.class, EnumSerializer.OrderSerializer),
-            new RegistryEntry<>(TraversalOptionParent.Pick.class, EnumSerializer.PickSerializer),
+            new RegistryEntry<>(Pick.class, EnumSerializer.PickSerializer),
             new RegistryEntry<>(Pop.class, EnumSerializer.PopSerializer),
             new RegistryEntry<>(Lambda.class, new LambdaSerializer()),
             new RegistryEntry<>(P.class, new PSerializer<>(DataType.P, P.class)),
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java
index 12e2d15..52b4c08 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EnumSerializer.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.structure.io.binary.types;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.structure.io.binary.DataType;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryReader;
 import org.apache.tinkerpop.gremlin.structure.io.binary.GraphBinaryWriter;
@@ -26,7 +27,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.T;
@@ -49,7 +49,7 @@ public class EnumSerializer<E extends Enum> extends SimpleTypeSerializer<E> {
     public static final EnumSerializer<Direction> DirectionSerializer = new EnumSerializer<>(DataType.DIRECTION, Direction::valueOf);
     public static final EnumSerializer<Operator> OperatorSerializer = new EnumSerializer<>(DataType.OPERATOR, Operator::valueOf);
     public static final EnumSerializer<Order> OrderSerializer = new EnumSerializer<>(DataType.ORDER, Order::valueOf);
-    public static final EnumSerializer<TraversalOptionParent.Pick> PickSerializer = new EnumSerializer<>(DataType.PICK, TraversalOptionParent.Pick::valueOf);
+    public static final EnumSerializer<Pick> PickSerializer = new EnumSerializer<>(DataType.PICK, Pick::valueOf);
     public static final EnumSerializer<Pop> PopSerializer = new EnumSerializer<>(DataType.POP, Pop::valueOf);
     public static final EnumSerializer<Scope> ScopeSerializer = new EnumSerializer<>(DataType.SCOPE, Scope::valueOf);
     public static final EnumSerializer<T> TSerializer = new EnumSerializer<>(DataType.T, T::valueOf);
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
index eda0d37..fccab3f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONModule.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
@@ -32,7 +33,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy;
@@ -178,7 +178,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             Order.class,
                             Pop.class,
                             SackFunctions.Barrier.class,
-                            TraversalOptionParent.Pick.class,
+                            Pick.class,
                             Scope.class,
                             T.class).forEach(e -> put(e, e.getSimpleName()));
                     Arrays.asList(
@@ -262,7 +262,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     Pop.class,
                     SackFunctions.Barrier.class,
                     Scope.class,
-                    TraversalOptionParent.Pick.class,
+                    Pick.class,
                     T.class).forEach(e -> addSerializer(e, new TraversalSerializersV3d0.EnumJacksonSerializer()));
             addSerializer(P.class, new TraversalSerializersV3d0.PJacksonSerializer());
             addSerializer(Lambda.class, new TraversalSerializersV3d0.LambdaJacksonSerializer());
@@ -304,7 +304,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     Pop.values(),
                     SackFunctions.Barrier.values(),
                     Scope.values(),
-                    TraversalOptionParent.Pick.values(),
+                    Pick.values(),
                     T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV3d0.EnumJacksonDeserializer(e.getDeclaringClass())));
             addDeserializer(P.class, new TraversalSerializersV3d0.PJacksonDeserializer());
             addDeserializer(TextP.class, new TraversalSerializersV3d0.TextPJacksonDeserializer());
@@ -416,7 +416,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                             Order.class,
                             Pop.class,
                             SackFunctions.Barrier.class,
-                            TraversalOptionParent.Pick.class,
+                            Pick.class,
                             Scope.class,
                             T.class).forEach(e -> put(e, e.getSimpleName()));
                     Arrays.asList(
@@ -496,7 +496,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     Pop.class,
                     SackFunctions.Barrier.class,
                     Scope.class,
-                    TraversalOptionParent.Pick.class,
+                    Pick.class,
                     T.class).forEach(e -> addSerializer(e, new TraversalSerializersV2d0.EnumJacksonSerializer()));
             addSerializer(P.class, new TraversalSerializersV2d0.PJacksonSerializer());
             addSerializer(Lambda.class, new TraversalSerializersV2d0.LambdaJacksonSerializer());
@@ -532,7 +532,7 @@ abstract class GraphSONModule extends TinkerPopJacksonModule {
                     Pop.values(),
                     SackFunctions.Barrier.values(),
                     Scope.values(),
-                    TraversalOptionParent.Pick.values(),
+                    Pick.values(),
                     T.values()).flatMap(Stream::of).forEach(e -> addDeserializer(e.getClass(), new TraversalSerializersV2d0.EnumJacksonDeserializer(e.getDeclaringClass())));
             addDeserializer(P.class, new TraversalSerializersV2d0.PJacksonDeserializer());
             addDeserializer(TextP.class, new TraversalSerializersV2d0.TextPJacksonDeserializer());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
index 3fdb50a..e50037c 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV2d0.java
@@ -21,11 +21,11 @@ package org.apache.tinkerpop.gremlin.structure.io.graphson;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics;
 import org.apache.tinkerpop.gremlin.structure.Column;
@@ -131,8 +131,8 @@ public class GraphSONTypeSerializerV2d0 extends AbstractGraphSONTypeSerializer {
             mapped = Pop.class;
         else if (SackFunctions.Barrier.class.isAssignableFrom(c))
             mapped = SackFunctions.Barrier.class;
-        else if (TraversalOptionParent.Pick.class.isAssignableFrom(c))
-            mapped = TraversalOptionParent.Pick.class;
+        else if (Pick.class.isAssignableFrom(c))
+            mapped = Pick.class;
         else if (Scope.class.isAssignableFrom(c))
             mapped = Scope.class;
         else if (T.class.isAssignableFrom(c))
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
index eca91ef..4349e47 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONTypeSerializerV3d0.java
@@ -21,11 +21,11 @@ package org.apache.tinkerpop.gremlin.structure.io.graphson;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.util.Metrics;
@@ -165,8 +165,8 @@ public class GraphSONTypeSerializerV3d0 extends AbstractGraphSONTypeSerializer {
             mapped = Pop.class;
         else if (SackFunctions.Barrier.class.isAssignableFrom(c))
             mapped = SackFunctions.Barrier.class;
-        else if (TraversalOptionParent.Pick.class.isAssignableFrom(c))
-            mapped = TraversalOptionParent.Pick.class;
+        else if (Pick.class.isAssignableFrom(c))
+            mapped = Pick.class;
         else if (Scope.class.isAssignableFrom(c))
             mapped = Scope.class;
         else if (T.class.isAssignableFrom(c))
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
index bd2b1b0..eda92fe 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
@@ -30,11 +30,11 @@ import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -329,7 +329,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(Column.class, 132));
             add(GryoTypeReg.of(Pop.class, 133));
             add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
-            add(GryoTypeReg.of(TraversalOptionParent.Pick.class, 137));
+            add(GryoTypeReg.of(Pick.class, 137));
             add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer()));
             add(GryoTypeReg.of(MultiComparator.class, 165));
 
@@ -529,7 +529,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(Column.class, 132));
             add(GryoTypeReg.of(Pop.class, 133));
             add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
-            add(GryoTypeReg.of(TraversalOptionParent.Pick.class, 137));
+            add(GryoTypeReg.of(Pick.class, 137));
             add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer()));
             add(GryoTypeReg.of(MultiComparator.class, 165));
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStepTest.java
index f68af08..629ea72 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStepTest.java
@@ -28,7 +28,7 @@ import java.util.List;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
-import static org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.none;
+import static org.apache.tinkerpop.gremlin.process.traversal.Pick.none;
 
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStepTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStepTest.java
index 885da77..604ae20 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStepTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStepTest.java
@@ -29,7 +29,7 @@ import java.util.List;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
-import static org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.none;
+import static org.apache.tinkerpop.gremlin.process.traversal.Pick.none;
 
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
index 3fd54e2..1800331 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/binary/GraphBinaryReaderWriterRoundTripTest.java
@@ -27,13 +27,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
@@ -221,7 +221,7 @@ public class GraphBinaryReaderWriterRoundTripTest {
                 new Object[] {"Operator", Operator.sum, null},
                 new Object[] {"Operator", Operator.div, null},
                 new Object[] {"Order", Order.desc, null},
-                new Object[] {"Pick", TraversalOptionParent.Pick.any, null},
+                new Object[] {"Pick", Pick.any, null},
                 new Object[] {"Pop", Pop.mixed, null},
                 new Object[] {"Scope", Scope.global, null},
                 new Object[] {"T", T.label, null},
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 52bb2c7..23d914d 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -486,346 +486,4 @@ const gremlins = {
     g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_capXaX_unfold_mean: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("foo").cap("a").unfold().mean() }], 
     g_injectXnull_10_20_nullX_mean: [function({g, xx1, xx2}) { return g.inject(null,xx1,xx2,null).mean() }], 
     g_injectXlistXnull_10_20_nullXX_meanXlocalX: [function({g, xx1}) { return g.inject(xx1).mean(Scope.local) }], 
-    g_V_age_min: [function({g}) { return g.V().values("age").min() }], 
-    g_V_foo_min: [function({g}) { return g.V().values("foo").min() }], 
-    g_V_name_min: [function({g}) { return g.V().values("name").min() }], 
-    g_V_age_fold_minXlocalX: [function({g}) { return g.V().values("age").fold().min(Scope.local) }], 
-    g_V_aggregateXaX_byXageX_capXaX_minXlocalX: [function({g}) { return g.V().aggregate("a").by("age").cap("a").min(Scope.local) }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXageX_capXaX_minXlocalX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("age").cap("a").min(Scope.local) }], 
-    g_V_aggregateXaX_byXageX_capXaX_unfold_min: [function({g}) { return g.V().aggregate("a").by("age").cap("a").unfold().min() }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXageX_capXaX_unfold_min: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("age").cap("a").unfold().min() }], 
-    g_V_aggregateXaX_byXfooX_capXaX_minXlocalX: [function({g}) { return g.V().aggregate("a").by("foo").cap("a").min(Scope.local) }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_capXaX_minXlocalX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("foo").cap("a").min(Scope.local) }], 
-    g_V_aggregateXaX_byXfooX_capXaX_unfold_min: [function({g}) { return g.V().aggregate("a").by("foo").cap("a").unfold().min() }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_capXaX_unfold_min: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("foo").cap("a").unfold().min() }], 
-    g_V_foo_fold_minXlocalX: [function({g}) { return g.V().values("foo").fold().min(Scope.local) }], 
-    g_V_name_fold_minXlocalX: [function({g}) { return g.V().values("name").fold().min(Scope.local) }], 
-    g_V_repeatXbothX_timesX5X_age_min: [function({g}) { return g.V().repeat(__.both()).times(5).values("age").min() }], 
-    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_minX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").min()) }], 
-    g_V_foo_injectX9999999999X_min: [function({g, xx1}) { return g.V().values("foo").inject(xx1).min() }], 
-    g_V_name_order: [function({g}) { return g.V().values("name").order() }], 
-    g_V_name_order_byXa1_b1X_byXb2_a2X: [function({g, c1, c2}) { return g.V().values("name").order().by(c1).by(c2) }], 
-    g_V_order_byXname_ascX_name: [function({g}) { return g.V().order().by("name",Order.asc).values("name") }], 
-    g_V_order_byXnameX_name: [function({g}) { return g.V().order().by("name").values("name") }], 
-    g_V_outE_order_byXweight_descX_weight: [function({g}) { return g.V().outE().order().by("weight",Order.desc).values("weight") }], 
-    g_V_order_byXname_a1_b1X_byXname_b2_a2X_name: [function({g, c1, c2}) { return g.V().order().by("name",c1).by("name",c2).values("name") }], 
-    g_V_asXaX_outXcreatedX_asXbX_order_byXshuffleX_selectXa_bX: [function({g}) { return g.V().as("a").out("created").as("b").order().by(Order.shuffle).select("a","b") }], 
-    g_V_both_hasLabelXpersonX_order_byXage_descX_limitX5X_name: [function({g}) { return g.V().both().hasLabel("person").order().by("age",Order.desc).limit(5).values("name") }], 
-    g_V_properties_order_byXkey_descX_key: [function({g}) { return g.V().properties().order().by(T.key,Order.desc).key() }], 
-    g_V_hasLabelXpersonX_order_byXvalueXageX_descX_name: [function({g, l1}) { return g.V().hasLabel("person").order().by(l1,Order.desc).values("name") }], 
-    g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_orderXlocalX_byXvaluesX: [function({g}) { return g.V().hasLabel("person").group().by("name").by(__.outE().values("weight").sum()).order(Scope.local).by(Column.values) }], 
-    g_V_mapXbothE_weight_foldX_order_byXsumXlocalX_descX: [function({g}) { return g.V().map(__.bothE().values("weight").order().by(Order.asc).fold()).order().by(__.sum(Scope.local),Order.desc) }], 
-    g_V_group_byXlabelX_byXname_order_byXdescX_foldX: [function({g}) { return g.V().group().by(T.label).by(__.values("name").order().by(Order.desc).fold()) }], 
-    g_V_hasLabelXpersonX_group_byXnameX_byXoutE_weight_sumX_unfold_order_byXvalues_descX: [function({g}) { return g.V().hasLabel("person").group().by("name").by(__.outE().values("weight").sum()).unfold().order().by(Column.values,Order.desc) }], 
-    g_V_asXvX_mapXbothE_weight_foldX_sumXlocalX_asXsX_selectXv_sX_order_byXselectXsX_descX: [function({g}) { return g.V().as("v").map(__.bothE().values("weight").fold()).sum(Scope.local).as("s").select("v","s").order().by(__.select("s"),Order.desc) }], 
-    g_V_hasLabelXpersonX_fold_orderXlocalX_byXageX: [function({g}) { return g.V().hasLabel("person").fold().order(Scope.local).by("age") }], 
-    g_V_both_hasLabelXpersonX_order_byXage_descX_name: [function({g}) { return g.V().both().hasLabel("person").order().by("age",Order.desc).values("name") }], 
-    g_V_order_byXoutE_count_descX: [function({g}) { return g.V().order().by(__.outE().count(),Order.desc) }], 
-    g_V_hasLabelXpersonX_order_byXageX: [function({g}) { return g.V().hasLabel("person").order().by("age") }], 
-    g_V_order_byXageX: [function({g}) { return g.V().order().by("age") }], 
-    g_V_fold_orderXlocalX_byXageX: [function({g}) { return g.V().fold().order(Scope.local).by("age") }], 
-    g_V_fold_orderXlocalX_byXage_descX: [function({g}) { return g.V().fold().order(Scope.local).by("age",Order.desc) }], 
-    g_V_orXhasLabelXpersonX_hasXsoftware_name_lopXX_order_byXageX: [function({g}) { return g.V().or(__.hasLabel("person"),__.has("software","name","lop")).order().by("age") }], 
-    g_withStrategiesXProductiveByStrategyX_V_orXhasLabelXpersonX_hasXsoftware_name_lopXX_order_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().or(__.hasLabel("person"),__.has("software","name","lop")).order().by("age") }], 
-    g_VX1X_hasXlabel_personX_mapXmapXint_ageXX_orderXlocalX_byXvalues_descX_byXkeys_ascX: [function({g, l1, v1}) { return g.V(v1).hasLabel("person").map(l1).order(Scope.local).by(Column.values,Order.desc).by(Column.keys,Order.asc) }], 
-    g_V_hasXsong_name_OHBOYX_outXfollowedByX_outXfollowedByX_order_byXperformancesX_byXsongType_descX: [function({g}) { return g.V().has("song","name","OH BOY").out("followedBy").out("followedBy").order().by("performances").by("songType",Order.desc).by("name") }], 
-    g_V_hasLabelXsongX_order_byXperformances_descX_byXnameX_rangeX110_120X_name: [function({g}) { return g.V().hasLabel("song").order().by("performances",Order.desc).by("name").range(110,120).values("name") }], 
-    g_VX1X_elementMap_orderXlocalX_byXkeys_descXunfold: [function({g, vid1}) { return g.V(vid1).elementMap().order(Scope.local).by(Column.keys,Order.desc).unfold() }], 
-    g_VX1X_elementMap_orderXlocalX_byXkeys_ascXunfold: [function({g, vid1}) { return g.V(vid1).elementMap().order(Scope.local).by(Column.keys,Order.asc).unfold() }], 
-    g_V_pageRank_hasXpageRankX: [function({g}) { return g.V().pageRank().has("gremlin.pageRankVertexProgram.pageRank") }], 
-    g_V_outXcreatedX_pageRank_withXedges_bothEX_withXpropertyName_projectRankX_withXtimes_0X_valueMapXname_projectRankX: [function({g}) { return g.V().out("created").pageRank().with_("~tinkerpop.pageRank.edges",__.bothE()).with_("~tinkerpop.pageRank.propertyName","projectRank").with_("~tinkerpop.pageRank.times",0).valueMap("name","projectRank") }], 
-    g_V_pageRank_order_byXpageRank_descX_byXnameX_name: [function({g}) { return g.V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank",Order.desc).by("name").values("name") }], 
-    g_V_pageRank_order_byXpageRank_descX_name_limitX2X: [function({g}) { return g.V().pageRank().order().by("gremlin.pageRankVertexProgram.pageRank",Order.desc).values("name").limit(2) }], 
-    g_V_pageRank_withXedges_outEXknowsXX_withXpropertyName_friendRankX_project_byXnameX_byXvaluesXfriendRankX_mathX: [function({g}) { return g.V().pageRank().with_("~tinkerpop.pageRank.edges",__.outE("knows")).with_("~tinkerpop.pageRank.propertyName","friendRank").project("name","friendRank").by("name").by(__.values("friendRank").math("ceil(_ * 100)")) }], 
-    g_V_hasLabelXpersonX_pageRank_withXpropertyName_kpageRankX_project_byXnameX_byXvaluesXpageRankX_mathX: [function({g}) { return g.V().hasLabel("person").pageRank().with_("~tinkerpop.pageRank.propertyName","pageRank").project("name","pageRank").by("name").by(__.values("pageRank").math("ceil(_ * 100)")) }], 
-    g_V_pageRank_withXpropertyName_pageRankX_asXaX_outXknowsX_pageRank_asXbX_selectXa_bX_by_byXmathX: [function({g}) { return g.V().pageRank().with_("~tinkerpop.pageRank.propertyName","pageRank").as("a").out("knows").values("pageRank").as("b").select("a","b").by().by(__.math("ceil(_ * 100)")) }], 
-    g_V_hasLabelXsoftwareX_hasXname_rippleX_pageRankX1X_withXedges_inEXcreatedX_withXtimes_1X_withXpropertyName_priorsX_inXcreatedX_unionXboth__identityX_valueMapXname_priorsX: [function({g}) { return g.V().hasLabel("software").has("name","ripple").pageRank(1.0).with_("~tinkerpop.pageRank.edges",__.inE("created")).with_("~tinkerpop.pageRank.times",1).with_("~tinkerpop.pageRank.propertyName","priors").in_("created").union(__.both(),__.identity()).valueMap("name","priors") }], 
-    g_V_outXcreatedX_groupXmX_byXlabelX_pageRankX1X_withXpropertyName_pageRankX_withXedges_inEX_withXtimes_1X_inXcreatedX_groupXmX_byXpageRankX_capXmX: [function({g}) { return g.V().out("created").group("m").by(T.label).pageRank(1.0).with_("~tinkerpop.pageRank.propertyName","pageRank").with_("~tinkerpop.pageRank.edges",__.inE()).with_("~tinkerpop.pageRank.times",1).in_("created").group("m").by("pageRank").cap("m") }], 
-    g_VX1X_name_path: [function({g, vid1}) { return g.V(vid1).values("name").path() }], 
-    g_VX1X_out_path_byXageX_byXnameX: [function({g, vid1}) { return g.V(vid1).out().path().by("age").by("name") }], 
-    g_V_repeatXoutX_timesX2X_path_byXitX_byXnameX_byXlangX: [function({g}) { return g.V().repeat(__.out()).times(2).path().by().by("name").by("lang") }], 
-    g_V_out_out_path_byXnameX_byXageX: [function({g}) { return g.V().out().out().path().by("name").by("age") }], 
-    g_V_asXaX_hasXname_markoX_asXbX_hasXage_29X_asXcX_path: [function({g}) { return g.V().as("a").has("name","marko").as("b").has("age",29).as("c").path() }], 
-    g_VX1X_outEXcreatedX_inV_inE_outV_path: [function({g, vid1}) { return g.V(vid1).outE("created").inV().inE().outV().path() }], 
-    g_V_asXaX_out_asXbX_out_asXcX_path_fromXbX_toXcX_byXnameX: [function({g}) { return g.V().as("a").out().as("b").out().as("c").path().from_("b").to("c").by("name") }], 
-    g_VX1X_out_path_byXageX: [function({g, vid1}) { return g.V(vid1).out().path().by("age") }], 
-    g_withStrategiesXProductiveByStrategyX_VX1X_out_path_byXageX: [function({g, vid1}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V(vid1).out().path().by("age") }], 
-    g_injectX1_null_nullX_path: [function({g}) { return g.inject(1,null,null).path() }], 
-    g_injectX1_null_nullX_path_dedup: [function({g}) { return g.inject(1,null,null).path().dedup() }], 
-    g_V_peerPressure_hasXclusterX: [function({g}) { return g.V().peerPressure().has("gremlin.peerPressureVertexProgram.cluster") }], 
-    g_V_peerPressure_withXpropertyName_clusterX_withXedges_outEXknowsXX_pageRankX1X_byXrankX_withXedges_outEXknowsX_withXtimes_2X_group_byXclusterX_byXrank_sumX_limitX100X: [function({g}) { return g.V().peerPressure().with_("~tinkerpop.peerPressure.propertyName","cluster").with_("~tinkerpop.peerPressure.edges",__.outE("knows")).pageRank(1.0).with_("~tinkerpop.pageRank.propertyName","rank").with_("~tinkerpop.pageRank.edges",__.outE("knows")).with_("~tinkerpop.pageRank.times",1).group().by [...]
-    g_V_hasXname_rippleX_inXcreatedX_peerPressure_withXedges_outEX_withyXpropertyName_clusterX_repeatXunionXidentity__bothX_timesX2X_dedup_valueMapXname_clusterX: [function({g}) { return g.V().has("name","ripple").in_("created").peerPressure().with_("~tinkerpop.peerPressure.edges",__.outE()).with_("~tinkerpop.peerPressure.propertyName","cluster").repeat(__.union(__.identity(),__.both())).times(2).dedup().valueMap("name","cluster") }], 
-    g_V_hasLabelXpersonX_projectXa_bX_byXoutE_countX_byXageX: [function({g}) { return g.V().hasLabel("person").project("a","b").by(__.outE().count()).by("age") }], 
-    g_V_outXcreatedX_projectXa_bX_byXnameX_byXinXcreatedX_countX_order_byXselectXbX__descX_selectXaX: [function({g}) { return g.V().out("created").project("a","b").by("name").by(__.in_("created").count()).order().by(__.select("b"),Order.desc).select("a") }], 
-    g_V_valueMap_projectXxX_byXselectXnameXX: [function({g}) { return g.V().valueMap().project("x").by(__.select("name")) }], 
-    g_V_projectXa_bX_byXinE_countX_byXageX: [function({g}) { return g.V().project("a","b").by(__.inE().count()).by("age") }], 
-    g_withStrategiesXProductiveByStrategyX_V_projectXa_bX_byXinE_countX_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().project("a","b").by(__.inE().count()).by("age") }], 
-    g_V_hasXageX_propertiesXnameX: [function({g}) { return g.V().has("age").properties("name").value() }], 
-    g_V_hasXageX_propertiesXname_ageX_value: [function({g}) { return g.V().has("age").properties("name","age").value() }], 
-    g_V_hasXageX_propertiesXage_nameX_value: [function({g}) { return g.V().has("age").properties("age","name").value() }], 
-    g_V_propertiesXname_age_nullX_value: [function({g}) { return g.V().properties("name","age",null).value() }], 
-    g_V_valuesXname_age_nullX: [function({g}) { return g.V().values("name","age",null) }], 
-    g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a","b") }], 
-    g_VX1X_asXaX_outXknowsX_asXbX_selectXa_bX_byXnameX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a","b").by("name") }], 
-    g_VX1X_asXaX_outXknowsX_asXbX_selectXaX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a") }], 
-    g_VX1X_asXaX_outXknowsX_asXbX_selectXaX_byXnameX: [function({g, vid1}) { return g.V(vid1).as("a").out("knows").as("b").select("a").by("name") }], 
-    g_V_asXaX_out_asXbX_selectXa_bX_byXnameX: [function({g}) { return g.V().as("a").out().as("b").select("a","b").by("name") }], 
-    g_V_asXaX_out_aggregateXxX_asXbX_selectXa_bX_byXnameX: [function({g}) { return g.V().as("a").out().aggregate("x").as("b").select("a","b").by("name") }], 
-    g_V_asXaX_name_order_asXbX_selectXa_bX_byXnameX_by_XitX: [function({g}) { return g.V().as("a").values("name").order().as("b").select("a","b").by("name").by() }], 
-    g_V_hasXname_gremlinX_inEXusesX_order_byXskill_ascX_asXaX_outV_asXbX_selectXa_bX_byXskillX_byXnameX: [function({g}) { return g.V().has("name","gremlin").inE("uses").order().by("skill",Order.asc).as("a").outV().as("b").select("a","b").by("skill").by("name") }], 
-    g_V_hasXname_isXmarkoXX_asXaX_selectXaX: [function({g}) { return g.V().has("name",__.is("marko")).as("a").select("a") }], 
-    g_V_label_groupCount_asXxX_selectXxX: [function({g}) { return g.V().label().groupCount().as("x").select("x") }], 
-    g_V_hasLabelXpersonX_asXpX_mapXbothE_label_groupCountX_asXrX_selectXp_rX: [function({g}) { return g.V().hasLabel("person").as("p").map(__.bothE().label().groupCount()).as("r").select("p","r") }], 
-    g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX: [function({g, xx1}) { return g.V().choose(__.outE().count().is(xx1),__.as("a"),__.as("b")).choose(__.select("a"),__.select("a"),__.select("b")) }], 
-    g_VX1X_groupXaX_byXconstantXaXX_byXnameX_selectXaX_selectXaX: [function({g, vid1}) { return g.V(vid1).group("a").by(__.constant("a")).by(__.values("name")).barrier().select("a").select("a") }], 
-    g_VX1X_asXhereX_out_selectXhereX: [function({g, vid1}) { return g.V(vid1).as("here").out().select("here") }], 
-    g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX: [function({g, vid4}) { return g.V(vid4).as("here").out().select("here") }], 
-    g_VX4X_out_asXhereX_hasXlang_javaX_selectXhereX_name: [function({g, vid4}) { return g.V(vid4).out().as("here").has("lang","java").select("here").values("name") }], 
-    g_VX1X_outE_asXhereX_inV_hasXname_vadasX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE().as("here").inV().has("name","vadas").select("here") }], 
-    g_VX1X_outEXknowsX_hasXweight_1X_asXhereX_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").has("weight",1.0).as("here").inV().has("name","josh").select("here") }], 
-    g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_asXfakeX_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").as("here").has("weight",1.0).as("fake").inV().has("name","josh").select("here") }], 
-    g_V_asXhereXout_name_selectXhereX: [function({g}) { return g.V().as("here").out().values("name").select("here") }], 
-    g_V_outXcreatedX_unionXasXprojectX_inXcreatedX_hasXname_markoX_selectXprojectX__asXprojectX_inXcreatedX_inXknowsX_hasXname_markoX_selectXprojectXX_groupCount_byXnameX: [function({g}) { return g.V().out("created").union(__.as("project").in_("created").has("name","marko").select("project"),__.as("project").in_("created").in_("knows").has("name","marko").select("project")).groupCount().by("name") }], 
-    g_V_untilXout_outX_repeatXin_asXaXX_selectXaX_byXtailXlocalX_nameX: [function({g}) { return g.V().until(__.out().out()).repeat(__.in_().as("a")).select("a").by(__.tail(Scope.local).values("name")) }], 
-    g_V_outE_weight_groupCount_selectXkeysX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.keys).unfold() }], 
-    g_V_hasLabelXsoftwareX_asXnameX_asXlanguageX_asXcreatorsX_selectXname_language_creatorsX_byXnameX_byXlangX_byXinXcreatedX_name_fold_orderXlocalXX: [function({g}) { return g.V().hasLabel("software").as("name").as("language").as("creators").select("name","language","creators").by("name").by("lang").by(__.in_("created").values("name").fold().order(Scope.local)) }], 
-    g_V_outE_weight_groupCount_unfold_selectXkeysX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().unfold().select(Column.keys).unfold() }], 
-    g_V_outE_weight_groupCount_unfold_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().unfold().select(Column.values).unfold() }], 
-    g_V_untilXout_outX_repeatXin_asXaX_in_asXbXX_selectXa_bX_byXnameX: [function({g}) { return g.V().until(__.out().out()).repeat(__.in_().as("a").in_().as("b")).select("a","b").by("name") }], 
-    g_V_outE_weight_groupCount_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.values).unfold() }], 
-    g_V_asXaX_whereXoutXknowsXX_selectXaX: [function({g}) { return g.V().as("a").where(__.out("knows")).select("a") }], 
-    g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXfirst_aX: [function({g, vid1}) { return g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.first,"a") }], 
-    g_V_asXaX_outXknowsX_asXbX_localXselectXa_bX_byXnameXX: [function({g}) { return g.V().as("a").out("knows").as("b").local(__.select("a","b").by("name")) }], 
-    g_VX1X_asXaX_repeatXout_asXaXX_timesX2X_selectXlast_aX: [function({g, vid1}) { return g.V(vid1).as("a").repeat(__.out().as("a")).times(2).select(Pop.last,"a") }], 
-    g_VX1X_outEXknowsX_asXhereX_hasXweight_1X_inV_hasXname_joshX_selectXhereX: [function({g, vid1}) { return g.V(vid1).outE("knows").as("here").has("weight",1.0).inV().has("name","josh").select("here") }], 
-    g_V_asXaX_hasXname_markoX_asXbX_asXcX_selectXa_b_cX_by_byXnameX_byXageX: [function({g}) { return g.V().as("a").has("name","marko").as("b").as("c").select("a","b","c").by().by("name").by("age") }], 
-    g_V_outE_weight_groupCount_selectXvaluesX_unfold_groupCount_selectXvaluesX_unfold: [function({g}) { return g.V().outE().values("weight").groupCount().select(Column.values).unfold().groupCount().select(Column.values).unfold() }], 
-    g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX: [function({g}) { return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")) }], 
-    g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX: [function({g}) { return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")).by(__.math("_+_")) }], 
-    g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX: [function({g}) { return g.V().as("a").out("knows").as("a").select(Pop.all,__.constant("a")) }], 
-    g_V_selectXaX: [function({g}) { return g.V().select("a") }], 
-    g_V_selectXaX_count: [function({g}) { return g.V().select("a").count() }], 
-    g_V_selectXa_bX: [function({g}) { return g.V().select("a","b") }], 
-    g_V_valueMap_selectXaX: [function({g}) { return g.V().valueMap().select("a") }], 
-    g_V_valueMap_selectXa_bX: [function({g}) { return g.V().valueMap().select("a","b") }], 
-    g_V_selectXfirst_aX: [function({g}) { return g.V().select(Pop.first,"a") }], 
-    g_V_selectXfirst_a_bX: [function({g}) { return g.V().select(Pop.first,"a","b") }], 
-    g_V_valueMap_selectXfirst_aX: [function({g}) { return g.V().valueMap().select(Pop.first,"a") }], 
-    g_V_valueMap_selectXfirst_a_bX: [function({g}) { return g.V().valueMap().select(Pop.first,"a","b") }], 
-    g_V_selectXlast_aX: [function({g}) { return g.V().select(Pop.last,"a") }], 
-    g_V_selectXlast_a_bX: [function({g}) { return g.V().select(Pop.last,"a","b") }], 
-    g_V_valueMap_selectXlast_aX: [function({g}) { return g.V().valueMap().select(Pop.last,"a") }], 
-    g_V_valueMap_selectXlast_a_bX: [function({g}) { return g.V().valueMap().select(Pop.last,"a","b") }], 
-    g_V_selectXall_aX: [function({g}) { return g.V().select(Pop.all,"a") }], 
-    g_V_selectXall_a_bX: [function({g}) { return g.V().select(Pop.all,"a","b") }], 
-    g_V_valueMap_selectXall_aX: [function({g}) { return g.V().valueMap().select(Pop.all,"a") }], 
-    g_V_valueMap_selectXall_a_bX: [function({g}) { return g.V().valueMap().select(Pop.all,"a","b") }], 
-    g_V_asXa_bX_out_asXcX_path_selectXkeysX: [function({g}) { return g.V().as("a","b").out().as("c").path().select(Column.keys) }, function({g}) { return g.V().as("a","b").out().as("c").path().select(Column.keys) }], 
-    g_V_hasXperson_name_markoX_barrier_asXaX_outXknows_selectXaX: [function({g}) { return g.V().has("person","name","marko").barrier().as("a").out("knows").select("a") }], 
-    g_V_hasXperson_name_markoX_elementMapXnameX_asXaX_unionXidentity_identityX_selectXaX_selectXnameX: [function({g}) { return g.V().has("person","name","marko").elementMap("name").as("a").union(__.identity(),__.identity()).select("a").select("name") }], 
-    g_V_hasXperson_name_markoX_count_asXaX_unionXidentity_identityX_selectXaX: [function({g}) { return g.V().has("person","name","marko").count().as("a").union(__.identity(),__.identity()).select("a") }], 
-    g_V_hasXperson_name_markoX_path_asXaX_unionXidentity_identityX_selectXaX_unfold: [function({g}) { return g.V().has("person","name","marko").path().as("a").union(__.identity(),__.identity()).select("a").unfold() }], 
-    g_EX11X_propertiesXweightX_asXaX_selectXaX_byXkeyX: [function({g, eid11}) { return g.E(eid11).properties("weight").as("a").select("a").by(T.key) }], 
-    g_EX11X_propertiesXweightX_asXaX_selectXaX_byXvalueX: [function({g, eid11}) { return g.E(eid11).properties("weight").as("a").select("a").by(T.value) }], 
-    g_V_asXaX_selectXaX_byXageX: [function({g}) { return g.V().as("a").select("a").by("age") }], 
-    g_V_asXa_nX_selectXa_nX_byXageX_byXnameX: [function({g}) { return g.V().as("a","n").select("a","n").by("age").by("name") }], 
-    g_withStrategiesXProductiveByStrategyX_V_asXaX_selectXaX_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().as("a").select("a").by("age") }], 
-    g_withSideEffectXk_nullX_injectXxX_selectXkX: [function({g}) { return g.withSideEffect("k",null).inject("x").select("k") }], 
-    g_V_shortestPath: [function({g}) { return g.V().identity().shortestPath() }], 
-    g_V_both_dedup_shortestPath: [function({g}) { return g.V().both().dedup().shortestPath() }], 
-    g_V_shortestPath_edgesIncluded: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.includeEdges") }], 
-    g_V_shortestPath_directionXINX: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.edges",Direction.IN) }], 
-    g_V_shortestPath_edgesXoutEX: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.edges",__.outE()) }], 
-    g_V_shortestPath_edgesIncluded_edgesXoutEX: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.includeEdges").with_("~tinkerpop.shortestPath.edges",__.outE()) }], 
-    g_V_hasXname_markoX_shortestPath: [function({g}) { return g.V().has("name","marko").shortestPath() }], 
-    g_V_shortestPath_targetXhasXname_markoXX: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","marko")) }], 
-    g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX: [function({g}) { return g.V().identity().shortestPath().with_("~tinkerpop.shortestPath.target",__.values("name").is("marko")) }], 
-    g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX: [function({g}) { return g.V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.target",__.hasLabel("software")) }], 
-    g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX: [function({g}) { return g.V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","josh")).with_("~tinkerpop.shortestPath.distance","weight") }], 
-    g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX: [function({g}) { return g.V().has("name","daniel").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("name","stephen")).with_("~tinkerpop.shortestPath.edges",__.bothE("uses")) }], 
-    g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX: [function({g}) { return g.V().has("song","name","MIGHT AS WELL").shortestPath().with_("~tinkerpop.shortestPath.target",__.has("song","name","MAYBE YOU KNOW HOW I FEEL")).with_("~tinkerpop.shortestPath.edges",__.outE("followedBy")).with_("~tinkerpop.shortestPath.distance","weight") }], 
-    g_V_hasXname_markoX_shortestPath_maxDistanceX1X: [function({g}) { return g.V().has("name","marko").shortestPath().with_("~tinkerpop.shortestPath.maxDistance",1) }], 
-    g_V_hasXname_vadasX_shortestPath_distanceXweightX_maxDistanceX1_3X: [function({g}) { return g.V().has("name","vadas").shortestPath().with_("~tinkerpop.shortestPath.distance","weight").with_("~tinkerpop.shortestPath.maxDistance",1.3) }], 
-    g_V_age_sum: [function({g}) { return g.V().values("age").sum() }], 
-    g_V_foo_sum: [function({g}) { return g.V().values("foo").sum() }], 
-    g_V_age_fold_sumXlocalX: [function({g}) { return g.V().values("age").fold().sum(Scope.local) }], 
-    g_V_foo_fold_sumXlocalX: [function({g}) { return g.V().values("foo").fold().sum(Scope.local) }], 
-    g_V_hasLabelXsoftwareX_group_byXnameX_byXbothE_weight_sumX: [function({g}) { return g.V().hasLabel("software").group().by("name").by(__.bothE().values("weight").sum()) }], 
-    g_V_aggregateXaX_byXageX_sumXlocalX: [function({g}) { return g.V().aggregate("a").by("age").cap("a").sum(Scope.local) }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXageX_sumXlocalX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("age").cap("a").sum(Scope.local) }], 
-    g_V_aggregateXaX_byXageX_capXaX_unfold_sum: [function({g}) { return g.V().aggregate("a").by("age").cap("a").unfold().sum() }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXageX_capXaX_unfold_sum: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("age").cap("a").unfold().sum() }], 
-    g_V_aggregateXaX_byXfooX_sumXlocalX: [function({g}) { return g.V().aggregate("a").by("foo").cap("a").sum(Scope.local) }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_sumXlocalX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("foo").cap("a").sum(Scope.local) }], 
-    g_V_aggregateXaX_byXfooX_capXaX_unfold_sum: [function({g}) { return g.V().aggregate("a").by("foo").cap("a").unfold().sum() }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXaX_byXfooX_capXaX_unfold_sum: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("a").by("foo").cap("a").unfold().sum() }], 
-    g_injectXnull_10_5_nullX_sum: [function({g, xx1, xx2}) { return g.inject(null,xx1,xx2,null).sum() }], 
-    g_injectXlistXnull_10_5_nullXX_sumXlocalX: [function({g, xx1}) { return g.inject(xx1).sum(Scope.local) }], 
-    g_V_localXoutE_foldX_unfold: [function({g}) { return g.V().local(__.outE().fold()).unfold() }], 
-    g_V_valueMap_unfold_mapXkeyX: [function({g, l1}) { return g.V().valueMap().unfold().map(l1) }], 
-    g_VX1X_repeatXboth_simplePathX_untilXhasIdX6XX_path_byXnameX_unfold: [function({g, vid6, vid1}) { return g.V(vid1).repeat(__.both().simplePath()).until(__.hasId(vid6)).path().by("name").unfold() }], 
-    g_V_valueMap: [function({g}) { return g.V().valueMap() }], 
-    g_V_valueMapXtrueX: [function({g}) { return g.V().valueMap(true) }], 
-    g_V_valueMap_withXtokensX: [function({g}) { return g.V().valueMap().with_("~tinkerpop.valueMap.tokens") }], 
-    g_V_valueMapXname_ageX: [function({g}) { return g.V().valueMap("name","age") }], 
-    g_V_valueMapXtrue_name_ageX: [function({g}) { return g.V().valueMap(true,"name","age") }], 
-    g_V_valueMapXname_ageX_withXtokensX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens") }], 
-    g_V_valueMapXname_ageX_withXtokens_labelsX_byXunfoldX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens",2).by(__.unfold()) }], 
-    g_V_valueMapXname_ageX_withXtokens_idsX_byXunfoldX: [function({g}) { return g.V().valueMap("name","age").with_("~tinkerpop.valueMap.tokens",1).by(__.unfold()) }], 
-    g_VX1X_outXcreatedX_valueMap: [function({g, vid1}) { return g.V(vid1).out("created").valueMap() }], 
-    g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMapXtrueX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap(true) }], 
-    g_V_hasLabelXpersonX_filterXoutEXcreatedXX_valueMap_withXtokensX: [function({g}) { return g.V().hasLabel("person").filter(__.outE("created")).valueMap().with_("~tinkerpop.valueMap.tokens") }], 
-    g_VX1X_valueMapXname_locationX_byXunfoldX_by: [function({g, vid1}) { return g.V(vid1).valueMap("name","location").by(__.unfold()).by() }], 
-    g_V_valueMapXname_age_nullX: [function({g}) { return g.V().valueMap("name","age",null) }], 
-    g_V_valueMapXname_ageX_byXisXxXXbyXunfoldX: [function({g}) { return g.V().valueMap("name","age").by(__.is("x")).by(__.unfold()) }], 
-    g_VXnullX: [function({g}) { return g.V(null) }], 
-    g_VXlistXnullXX: [function({g, xx1}) { return g.V(xx1) }], 
-    g_VX1_nullX: [function({g, vid1}) { return g.V(vid1,null) }], 
-    g_VXlistX1_2_3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
-    g_VXlistXv1_v2_v3XX_name: [function({g, xx1}) { return g.V(xx1).values("name") }], 
-    g_V: [function({g}) { return g.V() }], 
-    g_VXv1X_out: [function({g, v1}) { return g.V(v1).out() }], 
-    g_VX1X_out: [function({g, vid1}) { return g.V(vid1).out() }], 
-    g_VX2X_in: [function({g, vid2}) { return g.V(vid2).in_() }], 
-    g_VX4X_both: [function({g, vid4}) { return g.V(vid4).both() }], 
-    g_E: [function({g}) { return g.E() }], 
-    g_EX11X: [function({g, eid11}) { return g.E(eid11) }], 
-    g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }], 
-    g_EXe11X: [function({g, e11}) { return g.E(e11) }], 
-    g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7,e11) }], 
-    g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }], 
-    g_EXnullX: [function({g}) { return g.E(null) }], 
-    g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }], 
-    g_EX11_nullX: [function({g, eid11}) { return g.E(eid11,null) }], 
-    g_VX1X_outE: [function({g, vid1}) { return g.V(vid1).outE() }], 
-    g_VX2X_outE: [function({g, vid2}) { return g.V(vid2).inE() }], 
-    g_VX4X_bothEXcreatedX: [function({g, vid4}) { return g.V(vid4).bothE("created") }], 
-    g_VX4X_bothE: [function({g, vid4}) { return g.V(vid4).bothE() }], 
-    g_VX1X_outE_inV: [function({g, vid1}) { return g.V(vid1).both() }], 
-    g_VX2X_inE_outV: [function({g, vid2}) { return g.V(vid2).inE().outV() }], 
-    g_V_outE_hasXweight_1X_outV: [function({g}) { return g.V().outE().has("weight",1.0).outV() }], 
-    g_V_out_outE_inV_inE_inV_both_name: [function({g}) { return g.V().out().outE().inV().inE().inV().both().values("name") }], 
-    g_VX1X_outEXknowsX_bothV_name: [function({g, vid1}) { return g.V(vid1).outE("knows").bothV().values("name") }], 
-    g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
-    g_VX4X_bothE_otherV: [function({g, vid4}) { return g.V(vid4).bothE().otherV() }], 
-    g_VX4X_bothE_hasXweight_lt_1X_otherV: [function({g, vid4}) { return g.V(vid4).bothE().has("weight",P.lt(1.0)).otherV() }], 
-    g_VX2X_inE: [function({g, vid2}) { return g.V(vid2).bothE() }], 
-    get_g_VX1X_outE_otherV: [function({g, vid1}) { return g.V(vid1).outE().otherV() }], 
-    g_VX1X_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
-    g_VX1AsStringX_outXknowsX: [function({g, vid1}) { return g.V(vid1).out("knows") }], 
-    g_VX1X_outXknows_createdX: [function({g, vid1}) { return g.V(vid1).out("knows","created") }], 
-    g_VX1X_outEXknowsX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows").inV() }], 
-    g_VX1X_outEXknows_createdX_inV: [function({g, vid1}) { return g.V(vid1).outE("knows","created").inV() }], 
-    g_V_out_out: [function({g}) { return g.V().out().out() }], 
-    g_VX1X_out_out_out: [function({g, vid1}) { return g.V(vid1).out().out().out() }], 
-    g_VX1X_out_name: [function({g, vid1}) { return g.V(vid1).out().values("name") }], 
-    g_VX1X_to_XOUT_knowsX: [function({g, vid1}) { return g.V(vid1).to(Direction.OUT,"knows") }], 
-    g_VX1_2_3_4X_name: [function({g, vid4, vid3, vid2, vid1}) { return g.addV("person").property("name","marko").property("age",29).as("marko").addV("person").property("name","vadas").property("age",27).as("vadas").addV("software").property("name","lop").property("lang","java").as("lop").addV("person").property("name","josh").property("age",32).as("josh").addV("software").property("name","ripple").property("lang","java").as("ripple").addV("person").property("name","peter").property("age" [...]
-    g_V_hasLabelXpersonX_V_hasLabelXsoftwareX_name: [function({g}) { return g.V().hasLabel("person").V().hasLabel("software").values("name") }], 
-    g_V_hasLabelXloopsX_bothEXselfX: [function({g}) { return g.V().hasLabel("loops").bothE("self") }], 
-    g_V_hasLabelXloopsX_bothXselfX: [function({g}) { return g.V().hasLabel("loops").both("self") }], 
-    g_injectX1X_VXnullX: [function({g}) { return g.inject(1).V(null) }], 
-    g_injectX1X_VX1_nullX: [function({g, vid1}) { return g.inject(1).V(vid1,null) }], 
-    Primitives_Number_eqXbyteX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXshortX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXlongX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXbigintX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXfloatX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXdoubleX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    Primitives_Number_eqXbigdecimalX: [function({g, xx1, xx2}) { return g.inject(xx1).unfold().where(__.is(xx2)) }], 
-    g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return g.V().values("name").aggregate("x").cap("x") }], 
-    g_V_valueXnameX_aggregateXglobal_xX_capXxX: [function({g}) { return g.V().values("name").aggregate(Scope.global,"x").cap("x") }], 
-    g_V_aggregateXxX_byXnameX_capXxX: [function({g}) { return g.V().aggregate("x").by("name").cap("x") }], 
-    g_V_out_aggregateXaX_path: [function({g}) { return g.V().out().aggregate("a").path() }], 
-    g_V_hasLabelXpersonX_aggregateXxX_byXageX_capXxX_asXyX_selectXyX: [function({g}) { return g.V().hasLabel("person").aggregate("x").by("age").cap("x").as("y").select("y") }], 
-    g_V_aggregateXxX_byXageX_capXxX: [function({g}) { return g.V().aggregate("x").by("age").cap("x") }], 
-    g_V_aggregateXlocal_xX_byXageX_capXxX: [function({g}) { return g.V().aggregate(Scope.local,"x").by("age").cap("x") }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXlocal_xX_byXageX_capXxX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate(Scope.local,"x").by("age").cap("x") }], 
-    g_V_aggregateXlocal_a_nameX_out_capXaX: [function({g}) { return g.V().aggregate(Scope.local,"a").by("name").out().cap("a") }], 
-    g_VX1X_aggregateXlocal_aX_byXnameX_out_aggregateXlocal_aX_byXnameX_name_capXaX: [function({g, vid1}) { return g.V(vid1).aggregate(Scope.local,"a").by("name").out().aggregate(Scope.local,"a").by("name").values("name").cap("a") }], 
-    g_withSideEffectXa_setX_V_both_name_aggregateXlocal_aX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().both().values("name").aggregate(Scope.local,"a").cap("a") }], 
-    g_V_aggregateXlocal_aX_byXoutEXcreatedX_countX_out_out_aggregateXlocal_aX_byXinEXcreatedX_weight_sumX: [function({g}) { return g.V().aggregate(Scope.local,"a").by(__.outE("created").count()).out().out().aggregate(Scope.local,"a").by(__.inE("created").values("weight").sum()).cap("a") }], 
-    g_V_aggregateXxX_byXvaluesXageX_isXgtX29XXX_capXxX: [function({g}) { return g.V().aggregate("x").by(__.values("age").is(P.gt(29))).cap("x") }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXxX_byXvaluesXageX_isXgtX29XXX_capXxX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("x").by(__.values("age").is(P.gt(29))).cap("x") }], 
-    g_V_aggregateXxX_byXout_order_byXnameXX_capXxX: [function({g}) { return g.V().aggregate("x").by(__.out().order().by("name")).cap("x") }], 
-    g_withStrategiesXProductiveByStrategyX_V_aggregateXxX_byXout_order_byXnameXX_capXxX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().aggregate("x").by(__.out().order().by("name")).cap("x") }], 
-    g_V_fail: [function({g}) { return g.V().fail() }], 
-    g_V_failXmsgX: [function({g}) { return g.V().fail("msg") }], 
-    g_V_unionXout_failX: [function({g}) { return g.V().union(__.out(),__.fail()) }], 
-    g_V_group_byXnameX: [function({g}) { return g.V().group().by("name") }], 
-    g_V_group_byXageX: [function({g}) { return g.V().group().by("age") }], 
-    g_withStrategiesXProductiveByStrategyX_V_group_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().group().by("age") }], 
-    g_V_group_byXnameX_byXageX: [function({g}) { return g.V().group().by("name").by("age") }], 
-    g_V_group_byXnameX_by: [function({g}) { return g.V().group().by("name").by() }], 
-    g_V_groupXaX_byXnameX_capXaX: [function({g}) { return g.V().group("a").by("name").cap("a") }], 
-    g_V_hasXlangX_groupXaX_byXlangX_byXnameX_out_capXaX: [function({g}) { return g.V().has("lang").group("a").by("lang").by("name").out().cap("a") }], 
-    g_V_hasXlangX_group_byXlangX_byXcountX: [function({g}) { return g.V().has("lang").group().by("lang").by(__.count()) }], 
-    g_V_repeatXout_groupXaX_byXnameX_byXcountX_timesX2X_capXaX: [function({g}) { return g.V().repeat(__.out().group("a").by("name").by(__.count())).times(2).cap("a") }], 
-    g_V_group_byXoutE_countX_byXnameX: [function({g}) { return g.V().order().by("name").group().by(__.outE().count()).by("name") }], 
-    g_V_groupXaX_byXlabelX_byXoutE_weight_sumX_capXaX: [function({g}) { return g.V().group("a").by(T.label).by(__.outE().values("weight").sum()).cap("a") }], 
-    g_V_repeatXbothXfollowedByXX_timesX2X_group_byXsongTypeX_byXcountX: [function({g}) { return g.V().repeat(__.both("followedBy")).times(2).group().by("songType").by(__.count()) }], 
-    g_V_repeatXbothXfollowedByXX_timesX2X_groupXaX_byXsongTypeX_byXcountX_capXaX: [function({g}) { return g.V().repeat(__.both("followedBy")).times(2).group("a").by("songType").by(__.count()).cap("a") }], 
-    g_V_group_byXname_substring_1X_byXconstantX1XX: [function({g, l1}) { return g.V().group().by(l1).by(__.constant(1)) }], 
-    g_V_groupXaX_byXname_substring_1X_byXconstantX1XX_capXaX: [function({g, l1}) { return g.V().group("a").by(l1).by(__.constant(1)).cap("a") }], 
-    g_V_out_group_byXlabelX_selectXpersonX_unfold_outXcreatedX_name_limitX2X: [function({g}) { return g.V().out().group().by(T.label).select("person").unfold().out("created").values("name").limit(2) }], 
-    g_V_hasLabelXsongX_group_byXnameX_byXproperties_groupCount_byXlabelXX: [function({g}) { return g.V().hasLabel("song").group().by("name").by(__.properties().groupCount().by(T.label)) }], 
-    g_V_hasLabelXsongX_groupXaX_byXnameX_byXproperties_groupCount_byXlabelXX_out_capXaX: [function({g}) { return g.V().hasLabel("song").group("a").by("name").by(__.properties().groupCount().by(T.label)).out().cap("a") }], 
-    g_V_outXfollowedByX_group_byXsongTypeX_byXbothE_group_byXlabelX_byXweight_sumXX: [function({g}) { return g.V().out("followedBy").group().by("songType").by(__.bothE().group().by(T.label).by(__.values("weight").sum())) }], 
-    g_V_groupXmX_byXnameX_byXinXknowsX_nameX_capXmX: [function({g}) { return g.V().group("m").by("name").by(__.in_("knows").values("name")).cap("m") }], 
-    g_V_group_byXlabelX_byXbothE_groupXaX_byXlabelX_byXweight_sumX_weight_sumX: [function({g}) { return g.V().group().by(T.label).by(__.bothE().group("a").by(T.label).by(__.values("weight").sum()).values("weight").sum()) }], 
-    g_withSideEffectXa__marko_666_noone_blahX_V_groupXaX_byXnameX_byXoutE_label_foldX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().group("a").by("name").by(__.outE().label().fold()).cap("a").unfold().group().by(Column.keys).by(__.select(Column.values).order(Scope.local).by(Order.asc)) }], 
-    g_V_hasLabelXpersonX_asXpX_outXcreatedX_group_byXnameX_byXselectXpX_valuesXageX_sumX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group().by("name").by(__.select("p").values("age").sum()) }], 
-    g_V_hasLabelXpersonX_asXpX_outXcreatedX_groupXaX_byXnameX_byXselectXpX_valuesXageX_sumX_capXaX: [function({g}) { return g.V().hasLabel("person").as("p").out("created").group("a").by("name").by(__.select("p").values("age").sum()).cap("a") }], 
-    g_V_group_byXlabelX_byXlabel_countX: [function({g}) { return g.V().group().by(__.label()).by(__.label().count()) }], 
-    g_V_groupXmX_byXlabelX_byXlabel_countX_capXmX: [function({g}) { return g.V().group("m").by(__.label()).by(__.label().count()).cap("m") }], 
-    g_V_outXcreatedX_groupCount_byXnameX: [function({g}) { return g.V().out("created").groupCount().by("name") }], 
-    g_V_groupCount_byXageX: [function({g}) { return g.V().groupCount().by("age") }], 
-    g_withStrategiesXProductiveByStrategyX_V_groupCount_byXageX: [function({g}) { return g.withStrategies(new ProductiveByStrategy({productiveKeys:[]})).V().groupCount().by("age") }], 
-    g_V_outXcreatedX_name_groupCount: [function({g}) { return g.V().out("created").values("name").groupCount() }], 
-    g_V_outXcreatedX_groupCountXaX_byXnameX_capXaX: [function({g}) { return g.V().out("created").groupCount("a").by("name").cap("a") }], 
-    g_V_outXcreatedX_name_groupCountXaX_capXaX: [function({g}) { return g.V().out("created").values("name").groupCount("a").cap("a") }], 
-    g_V_repeatXout_groupCountXaX_byXnameXX_timesX2X_capXaX: [function({g}) { return g.V().repeat(__.out().groupCount("a").by("name")).times(2).cap("a") }], 
-    g_V_both_groupCountXaX_byXlabelX_asXbX_barrier_whereXselectXaX_selectXsoftwareX_isXgtX2XXX_selectXbX_name: [function({g}) { return g.V().both().groupCount("a").by(T.label).as("b").barrier().where(__.select("a").select("software").is(P.gt(2))).select("b").values("name") }], 
-    g_V_unionXoutXknowsX__outXcreatedX_inXcreatedXX_groupCount_selectXvaluesX_unfold_sum: [function({g}) { return g.V().union(__.out("knows"),__.out("created").in_("created")).groupCount().select(Column.values).unfold().sum() }], 
-    g_V_hasXnoX_groupCount: [function({g}) { return g.V().has("no").groupCount() }], 
-    g_V_hasXnoX_groupCountXaX_capXaX: [function({g}) { return g.V().has("no").groupCount("a").cap("a") }], 
-    g_V_unionXrepeatXoutX_timesX2X_groupCountXmX_byXlangXX__repeatXinX_timesX2X_groupCountXmX_byXnameXX_capXmX: [function({g}) { return g.V().union(__.repeat(__.out()).times(2).groupCount("m").by("lang"),__.repeat(__.in_()).times(2).groupCount("m").by("name")).cap("m") }], 
-    g_V_outXcreatedX_groupCountXxX_capXxX: [function({g}) { return g.V().out("created").groupCount("x").cap("x") }], 
-    g_V_groupCount_byXbothE_countX: [function({g}) { return g.V().groupCount().by(__.bothE().count()) }], 
-    g_V_both_groupCountXaX_out_capXaX_selectXkeysX_unfold_both_groupCountXaX_capXaX: [function({g}) { return g.V().both().groupCount("a").out().cap("a").select(Column.keys).unfold().both().groupCount("a").cap("a") }], 
-    g_V_hasXperson_name_markoX_bothXknowsX_groupCount_byXvaluesXnameX_foldX: [function({g}) { return g.V().has("person","name","marko").both("knows").groupCount().by(__.values("name").fold()) }], 
-    g_VX1X_out_injectXv2X_name: [function({g, vid1, v2}) { return g.V(vid1).out().inject(v2).values("name") }], 
-    g_VX1X_out_name_injectXdanielX_asXaX_mapXlengthX_path: [function({g, l1, vid1}) { return g.V(vid1).out().values("name").inject("daniel").as("a").map(l1).path() }], 
-    g_VX1X_injectXg_VX4XX_out_name: [function({g, vid1, v4}) { return g.V(vid1).inject(v4).out().values("name") }], 
-    g_injectXnull_1_3_nullX: [function({g}) { return g.inject(null,1,3,null) }], 
-    g_injectX10_20_null_20_10_10X_groupCountXxX_dedup_asXyX_projectXa_bX_by_byXselectXxX_selectXselectXyXXX: [function({g}) { return g.inject(10,20,null,20,10,10).groupCount("x").dedup().as("y").project("a","b").by().by(__.select("x").select(__.select("y"))) }], 
-    g_injectXname_marko_age_nullX_selectXname_ageX: [function({g, xx1}) { return g.inject(xx1).select("name","age") }], 
-    g_injectXnull_nullX: [function({g}) { return g.inject(null,null) }], 
-    g_injectXnullX: [function({g}) { return g.inject(null) }], 
-    g_inject: [function({g}) { return g.inject() }], 
-    g_VX1X_valuesXageX_injectXnull_nullX: [function({g, xx1}) { return g.V(xx1).values("age").inject(null,null) }], 
-    g_VX1X_valuesXageX_injectXnullX: [function({g, xx1}) { return g.V(xx1).values("age").inject(null) }], 
-    g_VX1X_valuesXageX_inject: [function({g, xx1}) { return g.V(xx1).values("age").inject() }], 
-    g_injectXnull_1_3_nullX_asXaX_selectXaX: [function({g}) { return g.inject(null,1,3,null).as("a").select("a") }], 
-    g_io_readXkryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_io_read_withXreader_gryoX: [function({g}) { return g.io("data/tinkerpop-modern.kryo").with_("~tinkerpop.io.reader","gryo").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_io_readXgraphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_io_read_withXreader_graphsonX: [function({g}) { return g.io("data/tinkerpop-modern.json").with_("~tinkerpop.io.reader","graphson").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_io_readXgraphmlX: [function({g}) { return g.io("data/tinkerpop-modern.xml").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_io_read_withXreader_graphmlX: [function({g}) { return g.io("data/tinkerpop-modern.xml").with_("~tinkerpop.io.reader","graphml").read() }, function({g}) { return g.V() }, function({g}) { return g.E() }], 
-    g_withSackXhelloX_V_outE_sackXassignX_byXlabelX_inV_sack: [function({g}) { return g.withSack("hello").V().outE().sack(Operator.assign).by(T.label).inV().sack() }], 
-    g_withSackX0X_V_outE_sackXsumX_byXweightX_inV_sack_sum: [function({g}) { return g.withSack(0.0).V().outE().sack(Operator.sum).by("weight").inV().sack().sum() }], 
-    g_withSackX0X_V_repeatXoutE_sackXsumX_byXweightX_inVX_timesX2X_sack: [function({g}) { return g.withSack(0.0).V().repeat(__.outE().sack(Operator.sum).by("weight").inV()).times(2).sack() }], 
-    g_withBulkXfalseX_withSackX1_sumX_VX1X_localXoutEXknowsX_barrierXnormSackX_inVX_inXknowsX_barrier_sack: [function({g, vid1}) { return g.withBulk(false).withSack(1.0,Operator.sum).V(vid1).local(__.outE("knows").barrier(Barrier.normSack).inV()).in_("knows").barrier().sack() }], 
-    g_withBulkXfalseX_withSackX1_sumX_V_out_barrier_sack: [function({g}) { return g.withBulk(false).withSack(1,Operator.sum).V().out().barrier().sack() }], 
-    g_withSackX1_sumX_VX1X_localXoutXknowsX_barrierXnormSackXX_inXknowsX_barrier_sack: [function({g, vid1}) { return g.withSack(1.0,Operator.sum).V(vid1).local(__.out("knows").barrier(Barrier.normSack)).in_("knows").barrier().sack() }], 
-    g_V_sackXassignX_byXageX_sack: [function({g}) { return g.V().sack(Operator.assign).by("age").sack() }], 
-    g_V_hasXageX_groupCountXaX_byXnameX_out_capXaX: [function({g}) { return g.V().has("age").groupCount("a").by("name").out().cap("a") }], 
-    g_V_storeXa_nameX_out_capXaX: [function({g}) { return g.V().store("a").by("name").out().cap("a") }], 
-    g_VX1X_storeXaX_byXnameX_out_storeXaX_byXnameX_name_capXaX: [function({g, vid1}) { return g.V(vid1).store("a").by("name").out().store("a").by("name").values("name").cap("a") }], 
-    g_withSideEffectXa_setX_V_both_name_storeXaX_capXaX: [function({g, xx1}) { return g.withSideEffect("a",xx1).V().both().values("name").store("a").cap("a") }], 
-    g_V_storeXaX_byXoutEXcreatedX_countX_out_out_storeXaX_byXinEXcreatedX_weight_sumX: [function({g}) { return g.V().store("a").by(__.outE("created").count()).out().out().store("a").by(__.inE("created").values("weight").sum()).cap("a") }], 
-}
-
-exports.gremlin = gremlins
+    g_injectX0X_mergeVXlabel_person_name_stephenX: [
\ No newline at end of file
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 b/gremlin-language/src/main/antlr4/Gremlin.g4
index e285634..9021c36 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -97,6 +97,8 @@ traversalSourceSpawnMethod
 	| traversalSourceSpawnMethod_addV
 	| traversalSourceSpawnMethod_E
 	| traversalSourceSpawnMethod_V
+	| traversalSourceSpawnMethod_mergeE
+	| traversalSourceSpawnMethod_mergeV
 	| traversalSourceSpawnMethod_inject
     | traversalSourceSpawnMethod_io
     ;
@@ -128,6 +130,16 @@ traversalSourceSpawnMethod_io
     : 'io' LPAREN stringLiteral RPAREN
     ;
 
+traversalSourceSpawnMethod_mergeV
+    : 'mergeV' LPAREN genericLiteralMap RPAREN #traversalSourceSpawnMethod_mergeV_Map
+    | 'mergeV' LPAREN nestedTraversal RPAREN #traversalSourceSpawnMethod_mergeV_Traversal
+    ;
+
+traversalSourceSpawnMethod_mergeE
+    : 'mergeE' LPAREN genericLiteralMap RPAREN
+    | 'mergeE' LPAREN nestedTraversal RPAREN
+    ;
+
 chainedTraversal
     : traversalMethod
     | chainedTraversal DOT traversalMethod
@@ -157,6 +169,8 @@ traversalMethod
 	: traversalMethod_V
 	| traversalMethod_addE
 	| traversalMethod_addV
+	| traversalMethod_mergeE
+	| traversalMethod_mergeV
 	| traversalMethod_aggregate
 	| traversalMethod_and
 	| traversalMethod_as
@@ -272,6 +286,17 @@ traversalMethod_addV
 	| 'addV' LPAREN nestedTraversal RPAREN #traversalMethod_addV_Traversal
 	;
 
+traversalMethod_mergeV
+    : 'mergeV' LPAREN genericLiteralMap RPAREN #traversalMethod_mergeV_Map
+    | 'mergeV' LPAREN nestedTraversal RPAREN #traversalMethod_mergeV_Traversal
+    ;
+
+traversalMethod_mergeE
+    : 'mergeE' LPAREN genericLiteralMap RPAREN #traversalMethod_mergeE_Map
+    | 'mergeE' LPAREN nestedTraversal RPAREN #traversalMethod_mergeE_Traversal
+    ;
+
+
 traversalMethod_aggregate
 	: 'aggregate' LPAREN traversalScope COMMA stringLiteral RPAREN #traversalMethod_aggregate_Scope_String
 	| 'aggregate' LPAREN stringLiteral RPAREN #traversalMethod_aggregate_String
@@ -531,6 +556,8 @@ traversalMethod_not
 
 traversalMethod_option
 	: 'option' LPAREN traversalPredicate COMMA nestedTraversal RPAREN #traversalMethod_option_Predicate_Traversal
+	| 'option' LPAREN traversalMerge COMMA genericLiteralMap RPAREN #traversalMethod_option_Merge_Map
+	| 'option' LPAREN traversalMerge COMMA nestedTraversal RPAREN #traversalMethod_option_Merge_Traversal
 	| 'option' LPAREN genericLiteral COMMA nestedTraversal RPAREN #traversalMethod_option_Object_Traversal
 	| 'option' LPAREN nestedTraversal RPAREN #traversalMethod_option_Traversal
 	;
@@ -835,6 +862,11 @@ traversalToken
     | 'value' | 'T.value'
     ;
 
+traversalMerge
+    : 'onCreate' | 'Merge.onCreate'
+    | 'onMatch' | 'Merge.onMatch'
+    ;
+
 traversalOrder
     : 'incr' | 'Order.incr'
     | 'decr' | 'Order.decr'
diff --git a/gremlin-test/features/map/MergeVertex.feature b/gremlin-test/features/map/MergeVertex.feature
new file mode 100644
index 0000000..1f8ae9d
--- /dev/null
+++ b/gremlin-test/features/map/MergeVertex.feature
@@ -0,0 +1,265 @@
+# 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.
+
+@StepClassMap @StepMergeV
+Feature: Step - mergeV()
+
+  Scenario: g_mergeVXlabel_person_name_stephenX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And the traversal of
+      """
+      g.mergeV(xx1)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\")"
+
+  Scenario: g_mergeVXlabel_person_name_markoX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And the traversal of
+      """
+      g.mergeV(xx1)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\")"
+
+  Scenario: g_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\", \"age\": 19}]"
+    And the traversal of
+      """
+      g.mergeV(xx1).option(Merge.onCreate,xx2)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\").has(\"age\", 19)"
+
+  Scenario: g_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And using the parameter xx2 defined as "m[{\"age\": 19}]"
+    And the traversal of
+      """
+      g.mergeV(xx1).option(Merge.onMatch,xx2)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\", 19)"
+
+  Scenario: g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\", \"age\": 19}]"
+    And the traversal of
+      """
+      g.withSideEffect("c", xx1).
+        withSideEffect("m", xx2).
+        mergeV(__.select("c")).option(Merge.onCreate, __.select("m"))
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\").has(\"age\", 19)"
+
+  Scenario: g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And using the parameter xx2 defined as "m[{\"age\": 19}]"
+    And the traversal of
+      """
+      g.withSideEffect("c", xx1).
+        withSideEffect("m", xx2).
+        mergeV(__.select("c")).option(Merge.onMatch, __.select("m"))
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\", 19)"
+
+  @MultiMetaProperties
+  Scenario: g_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And the traversal of
+      """
+      g.mergeV(xx1).property("name","vadas","acl","public")
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().properties(\"name\").hasValue(\"vadas\").has(\"acl\",\"public\")"
+
+  Scenario: g_injectX0X_mergeVXlabel_person_name_stephenX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And the traversal of
+      """
+      g.inject(0).mergeV(xx1)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\")"
+
+  Scenario: g_injectX0X_mergeVXlabel_person_name_markoX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And the traversal of
+      """
+      g.inject(0).mergeV(xx1)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\")"
+
+  Scenario: g_injectX0X_mergeVXlabel_person_name_stephenX_optionXonCreate_label_person_name_stephen_age_19X_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\", \"age\": 19}]"
+    And the traversal of
+      """
+      g.inject(0).mergeV(xx1).option(Merge.onCreate,xx2)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\").has(\"age\", 19)"
+
+  Scenario: g_injectX0X_mergeVXlabel_person_name_markoX_optionXonMatch_age_19X_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And using the parameter xx2 defined as "m[{\"age\": 19}]"
+    And the traversal of
+      """
+      g.inject(0).mergeV(xx1).option(Merge.onMatch,xx2)
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\", 19)"
+
+  Scenario: g_withSideEffectXc_label_person_name_stephenX_withSideEffectXm_label_person_name_stephen_age_19X_injectX0X_mergeVXselectXcXX_optionXonCreate_selectXmXX_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\", \"age\": 19}]"
+    And the traversal of
+      """
+      g.withSideEffect("c", xx1).
+        withSideEffect("m", xx2).
+        inject(0).mergeV(__.select("c")).option(Merge.onCreate, __.select("m"))
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\").has(\"age\", 19)"
+
+  Scenario: g_withSideEffectXc_label_person_name_markoX_withSideEffectXm_age_19X_injectX0X_mergeVXselectXcXX_optionXonMatch_selectXmXX_option
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And using the parameter xx2 defined as "m[{\"age\": 19}]"
+    And the traversal of
+      """
+      g.withSideEffect("c", xx1).
+        withSideEffect("m", xx2).
+        inject(0).mergeV(__.select("c")).option(Merge.onMatch, __.select("m"))
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\").has(\"age\", 19)"
+
+  @MultiMetaProperties
+  Scenario: g_injectX0X_mergeVXlabel_person_name_markoX_propertyXname_vadas_acl_publicX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And the traversal of
+      """
+      g.inject(0).mergeV(xx1).property("name","vadas","acl","public")
+      """
+    When iterated to list
+    Then the result should have a count of 1
+    And the graph should return 1 for count of "g.V().properties(\"name\").hasValue(\"vadas\").has(\"acl\",\"public\")"
+
+  Scenario: g_injectXlabel_person_name_marko_label_person_name_stephenX_mergeVXidentityX
+    Given the empty graph
+    And the graph initializer of
+      """
+      g.addV("person").property("name", "marko").property("age", 29).as("marko")
+      """
+    And using the parameter xx1 defined as "m[{\"t[label]\": \"person\", \"name\":\"marko\"}]"
+    And using the parameter xx2 defined as "m[{\"t[label]\": \"person\", \"name\":\"stephen\"}]"
+    And the traversal of
+      """
+      g.inject(xx1, xx2).mergeV(__.identity())
+      """
+    When iterated to list
+    Then the result should have a count of 2
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"stephen\")"
+    And the graph should return 1 for count of "g.V().has(\"person\",\"name\",\"marko\")"
+    And the graph should return 2 for count of "g.V()"
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
index e4d5e37..340d984 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
@@ -87,8 +87,11 @@ public final class StepDefinition {
     private static final Pattern ioPattern = Pattern.compile("g\\.io\\(\"(.*)\"\\).*");
     private List<Pair<Pattern, Function<String,String>>> stringMatcherConverters = new ArrayList<Pair<Pattern, Function<String,String>>>() {{
         // expects json so that should port to the Gremlin script form - replace curly json braces with square ones
-        // for Gremlin sake.
-        add(Pair.with(Pattern.compile("m\\[(.*)\\]"), s -> s.replace('{','[').replace('}', ']')));
+        // for Gremlin sake. allow for support of T as keys in maps, though this is starting to get a big ugly.
+        add(Pair.with(Pattern.compile("m\\[(.*)\\]"), s ->
+                s.replace("\"t[label]\"", "T.label").
+                        replace("\"t[id]\"", "T.id").
+                        replace('{','[').replace('}', ']')));
 
         add(Pair.with(Pattern.compile("l\\[\\]"), s -> "[]"));
         add(Pair.with(Pattern.compile("l\\[(.*)\\]"), s -> {
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessLimitedStandardSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessLimitedStandardSuite.java
index ddf3280..610ac7f 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessLimitedStandardSuite.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessLimitedStandardSuite.java
@@ -23,64 +23,11 @@ import org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ComplexTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.BranchTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.ChooseTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.LocalTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.OptionalTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.RepeatTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.branch.UnionTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CoinTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.CyclicPathTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DedupTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.DropTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.FilterTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.IsTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.OrTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.SampleTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.SimplePathTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.TailTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddEdgeTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.CoalesceTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConstantTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.CountTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.FlatMapTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.GraphTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.IndexTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.LoopsTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.MatchTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MathTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MaxTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MinTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PathTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.ProfileTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ProjectTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertiesTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ReadTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.SumTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.ValueMapTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.WriteTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.AggregateTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ExplainTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupCountTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GroupTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SackTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectCapTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SideEffectTest;
-import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StoreTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.SubgraphTest;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.TreeTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategyProcessTest;
@@ -92,8 +39,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.Transl
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategyProcessTest;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategyProcessTest;
-import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite;
 import org.junit.runners.model.InitializationError;
 import org.junit.runners.model.RunnerBuilder;
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchTest.java
index ed4b2e7..642cda4 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchTest.java
@@ -40,8 +40,8 @@ import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.identi
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.label;
 import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values;
-import static org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.any;
-import static org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick.none;
+import static org.apache.tinkerpop.gremlin.process.traversal.Pick.any;
+import static org.apache.tinkerpop.gremlin.process.traversal.Pick.none;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java
index 28f3abe..d1f4933 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseTest.java
@@ -22,9 +22,9 @@ import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
 import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.MapHelper;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Test;
@@ -195,7 +195,7 @@ public abstract class ChooseTest extends AbstractGremlinProcessTest {
             return g.V().choose(label())
                     .option("blah", out("knows"))
                     .option("bleep", out("created"))
-                    .option(TraversalOptionParent.Pick.none, identity()).values("name");
+                    .option(Pick.none, identity()).values("name");
         }
 
         @Override
@@ -212,7 +212,7 @@ public abstract class ChooseTest extends AbstractGremlinProcessTest {
         public Traversal<Vertex, Map<String, Long>> get_g_V_hasLabelXpersonX_chooseXageX__optionX27L__constantXyoungXX_optionXnone__constantXoldXX_groupCount() {
             return g.V().hasLabel("person").choose(values("age"))
                     .option(27L, __.constant("young"))
-                    .option(TraversalOptionParent.Pick.none, __.constant("old"))
+                    .option(Pick.none, __.constant("old"))
                     .groupCount();
         }
 
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
index 5aa9823..ed1e6a2 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategyProcessTest.java
@@ -21,6 +21,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
+import org.apache.tinkerpop.gremlin.process.traversal.Merge;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.MutationListener;
 import org.apache.tinkerpop.gremlin.structure.Edge;
@@ -40,7 +41,9 @@ import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
@@ -83,6 +86,31 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
 
     @Test
     @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+    public void shouldTriggerAddVertexViaMergeV() {
+        final StubMutationListener listener1 = new StubMutationListener();
+        final StubMutationListener listener2 = new StubMutationListener();
+        final EventStrategy.Builder builder = EventStrategy.build()
+                .addListener(listener1)
+                .addListener(listener2);
+
+        if (graph.features().graph().supportsTransactions())
+            builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+        final EventStrategy eventStrategy = builder.create();
+
+        graph.addVertex("some", "thing");
+        final GraphTraversalSource gts = create(eventStrategy);
+        final Map<Object,Object> m = new HashMap<>();
+        m.put("any", "thing");
+        gts.V().mergeV(m).property("any", "thing").next();
+
+        tryCommit(graph, g -> assertEquals(1, IteratorUtils.count(gts.V().has("any", "thing"))));
+        assertEquals(1, listener1.addVertexEventRecorded());
+        assertEquals(1, listener2.addVertexEventRecorded());
+    }
+
+    @Test
+    @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
     public void shouldTriggerAddVertexFromStart() {
         final StubMutationListener listener1 = new StubMutationListener();
         final StubMutationListener listener2 = new StubMutationListener();
@@ -246,6 +274,40 @@ public class EventStrategyProcessTest extends AbstractGremlinProcessTest {
 
     @Test
     @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
+    public void shouldTriggerAddVertexPropertyChangedViaMergeV() {
+        final StubMutationListener listener1 = new StubMutationListener();
+        final StubMutationListener listener2 = new StubMutationListener();
+        final EventStrategy.Builder builder = EventStrategy.build()
+                .addListener(listener1)
+                .addListener(listener2);
+
+        if (graph.features().graph().supportsTransactions())
+            builder.eventQueue(new EventStrategy.TransactionalEventQueue(graph));
+
+        final EventStrategy eventStrategy = builder.create();
+
+        final Vertex vSome = graph.addVertex("some", "thing");
+        vSome.property(VertexProperty.Cardinality.single, "that", "thing");
+        final GraphTraversalSource gts = create(eventStrategy);
+
+        final Map<Object,Object> m1 = new HashMap<>();
+        m1.put("any", "thing");
+        gts.mergeV(m1).iterate();
+
+        final Map<Object,Object> m2 = new HashMap<>();
+        m2.put("any", "thing else");
+        gts.mergeV(m1).option(Merge.onMatch, m2).iterate();
+
+        tryCommit(graph, g -> assertEquals(1, IteratorUtils.count(gts.V().has("any", "thing else"))));
+
+        assertEquals(1, listener1.addVertexEventRecorded());
+        assertEquals(1, listener2.addVertexEventRecorded());
+        assertEquals(1, listener2.vertexPropertyChangedEventRecorded());
+        assertEquals(1, listener1.vertexPropertyChangedEventRecorded());
+    }
+
+    @Test
+    @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
     @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_META_PROPERTIES)
     public void shouldTriggerAddVertexPropertyPropertyChanged() {
         final StubMutationListener listener1 = new StubMutationListener();
diff --git a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
index 62aad55..0926627 100644
--- a/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
+++ b/gremlin-tools/gremlin-io-test/src/main/java/org/apache/tinkerpop/gremlin/structure/io/Model.java
@@ -26,12 +26,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
 import org.apache.tinkerpop.gremlin.process.traversal.Order;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.Pick;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
 import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.TextP;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
@@ -178,7 +178,7 @@ public class Model {
         addGraphProcessEntry(Direction.OUT, "Direction", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Operator.sum, "Operator", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Order.shuffle, "Order", "", before3_5_0);
-        addGraphProcessEntry(TraversalOptionParent.Pick.any, "Pick", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
+        addGraphProcessEntry(Pick.any, "Pick", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(Pop.all, "Pop", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         addGraphProcessEntry(org.apache.tinkerpop.gremlin.util.function.Lambda.function("{ it.get() }"), "Lambda", "", Compatibilities.UNTYPED_GRAPHSON.matchToArray());
         final TraversalMetrics tm = createStaticTraversalMetrics();
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_3/manual-graphson-generator.groovy b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_3/manual-graphson-generator.groovy
index 878f6a3..3806884 100644
--- a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_3/manual-graphson-generator.groovy
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_3/manual-graphson-generator.groovy
@@ -22,16 +22,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetri
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics
 
 import java.time.*
-import java.nio.file.*
+
 import org.apache.tinkerpop.gremlin.driver.ser.*
 import org.apache.tinkerpop.gremlin.process.traversal.*
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.*
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.graphson.*
 import org.apache.tinkerpop.gremlin.driver.message.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick
-import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 import org.apache.commons.configuration.BaseConfiguration
 
 import java.util.concurrent.TimeUnit
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_4/manual-graphson-generator.groovy b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_4/manual-graphson-generator.groovy
index e1ff14d..6b497b7 100644
--- a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_4/manual-graphson-generator.groovy
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/graphson/_3_2_4/manual-graphson-generator.groovy
@@ -22,16 +22,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetri
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics
 
 import java.time.*
-import java.nio.file.*
+
 import org.apache.tinkerpop.gremlin.driver.ser.*
 import org.apache.tinkerpop.gremlin.process.traversal.*
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.*
 import org.apache.tinkerpop.gremlin.structure.*
 import org.apache.tinkerpop.gremlin.structure.io.graphson.*
 import org.apache.tinkerpop.gremlin.driver.message.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick
-import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 import org.apache.commons.configuration.BaseConfiguration
 
 import java.util.concurrent.TimeUnit
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_3/manual-gryo-generator.groovy b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_3/manual-gryo-generator.groovy
index d231aa7..4f0dfac 100644
--- a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_3/manual-gryo-generator.groovy
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_3/manual-gryo-generator.groovy
@@ -21,19 +21,13 @@
 import org.apache.commons.configuration.BaseConfiguration
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetrics
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics
 import org.apache.tinkerpop.shaded.kryo.io.Output
 
 import java.time.*
-import java.nio.file.*
-import org.apache.tinkerpop.gremlin.driver.ser.*
+
 import org.apache.tinkerpop.gremlin.process.traversal.*
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.*
 import org.apache.tinkerpop.gremlin.structure.*
-import org.apache.tinkerpop.gremlin.structure.io.graphson.*
-import org.apache.tinkerpop.gremlin.driver.message.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick
 import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 
 import java.util.concurrent.TimeUnit
diff --git a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_4/manual-gryo-generator.groovy b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_4/manual-gryo-generator.groovy
index 6e66f36..d67eec4 100644
--- a/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_4/manual-gryo-generator.groovy
+++ b/gremlin-tools/gremlin-io-test/src/test/resources/org/apache/tinkerpop/gremlin/structure/io/gryo/_3_2_4/manual-gryo-generator.groovy
@@ -21,19 +21,13 @@
 import org.apache.commons.configuration.BaseConfiguration
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetrics
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalMetrics
 import org.apache.tinkerpop.shaded.kryo.io.Output
 
 import java.time.*
-import java.nio.file.*
-import org.apache.tinkerpop.gremlin.driver.ser.*
+
 import org.apache.tinkerpop.gremlin.process.traversal.*
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.*
 import org.apache.tinkerpop.gremlin.structure.*
-import org.apache.tinkerpop.gremlin.structure.io.graphson.*
-import org.apache.tinkerpop.gremlin.driver.message.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.*
-import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent.Pick
 import org.apache.tinkerpop.gremlin.structure.io.gryo.*
 
 import java.util.concurrent.TimeUnit