You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by rd...@apache.org on 2017/01/23 19:34:42 UTC

[28/45] tinkerpop git commit: We now have ProjectedTraveser which is a Traverser with List of projections. OrderGlobalStep uses this and thus, can order for everything within the local star graph. Added MultiComparator which is like ChainedCompar
We now have ProjectedTraveser which is a Traverser with List<Object> of projections. OrderGlobalStep uses this and thus, can order for everything within the local star graph. Added MultiComparator which is like ChainedComparator but doesn't contain traversal projections -- just comparators.


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

Branch: refs/heads/TINKERPOP-1602
Commit: 5045f67f469e163d1363f953672a3f38b4ff2a3f
Parents: 501e97a
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Wed Jan 18 09:38:21 2017 -0700
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Wed Jan 18 09:38:21 2017 -0700

----------------------------------------------------------------------
 .../traversal/step/map/OrderGlobalStep.java     |  39 ++-
 .../traversal/traverser/OrderedTraverser.java   | 235 -------------------
 .../traversal/traverser/ProjectedTraverser.java | 199 ++++++++++++++++
 .../gremlin/structure/io/gryo/GryoVersion.java  |   8 +-
 .../gremlin/util/function/MultiComparator.java  |  60 +++++
 5 files changed, 295 insertions(+), 246 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5045f67f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
index ac5df90..9c071f1 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderGlobalStep.java
@@ -27,10 +27,12 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.ComparatorHolder;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.CollectingBarrierStep;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.OrderedTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.ProjectedTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.MultiComparator;
 import org.javatuples.Pair;
 
 import java.io.Serializable;
@@ -49,6 +51,7 @@ import java.util.stream.Collectors;
 public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBarrierStep<S> implements ComparatorHolder<S, C>, TraversalParent, ByModulating {
 
     private List<Pair<Traversal.Admin<S, C>, Comparator<C>>> comparators = new ArrayList<>();
+    private MultiComparator<C> multiComparator = null;
     private long limit = Long.MAX_VALUE;
     private boolean isShuffle = false;
 
@@ -61,14 +64,16 @@ public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBa
         if (this.isShuffle)
             traverserSet.shuffle();
         else
-            traverserSet.sort(Comparator.naturalOrder());
+            traverserSet.sort((Comparator) this.multiComparator);
     }
 
     @Override
     public void processAllStarts() {
+        if (null == this.multiComparator)
+            this.multiComparator = this.createMultiComparator();
         if (this.starts.hasNext()) {
             while (this.starts.hasNext()) {
-                this.traverserSet.add(new OrderedTraverser<S>(this.starts.next(), (List) this.comparators));
+                this.traverserSet.add(this.createOrderedTraverser(this.starts.next()));
             }
             this.barrierConsumer(this.traverserSet);
         }
@@ -81,7 +86,7 @@ public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBa
         } else if (this.starts.hasNext()) {
             this.processAllStarts();
         }
-        return ((OrderedTraverser) this.traverserSet.remove()).getInternal();
+        return ((ProjectedTraverser) this.traverserSet.remove()).getInternal();
     }
 
     public void setLimit(final long limit) {
@@ -155,7 +160,25 @@ public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBa
 
     @Override
     public MemoryComputeKey<TraverserSet<S>> getMemoryComputeKey() {
-        return MemoryComputeKey.of(this.getId(), new OrderBiOperator<>(this.limit, this.isShuffle), false, true);
+        if (null == this.multiComparator)
+            this.multiComparator = this.createMultiComparator();
+        return MemoryComputeKey.of(this.getId(), new OrderBiOperator<>(this.limit, this.isShuffle, this.multiComparator), false, true);
+    }
+
+    private ProjectedTraverser<S> createOrderedTraverser(final Traverser.Admin<S> traverser) {
+        final List<Object> projections = new ArrayList<>(this.comparators.size());
+        for (final Pair<Traversal.Admin<S, C>, Comparator<C>> pair : this.comparators) {
+            projections.add(TraversalUtil.apply(traverser, pair.getValue0()));
+        }
+        return new ProjectedTraverser<S>(traverser, projections);
+    }
+
+    private MultiComparator<C> createMultiComparator() {
+        final List<Comparator<C>> list = new ArrayList<>(this.comparators.size());
+        for (final Pair<Traversal.Admin<S, C>, Comparator<C>> pair : this.comparators) {
+            list.add(pair.getValue1());
+        }
+        return new MultiComparator<>(list);
     }
 
     ////////////////
@@ -164,14 +187,16 @@ public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBa
 
         private long limit;
         private boolean isShuffle;
+        private MultiComparator comparator;
 
         private OrderBiOperator() {
             // for serializers that need a no-arg constructor
         }
 
-        public OrderBiOperator(final long limit, final boolean isShuffle) {
+        public OrderBiOperator(final long limit, final boolean isShuffle, final MultiComparator multiComparator) {
             this.limit = limit;
             this.isShuffle = isShuffle;
+            this.comparator = multiComparator;
         }
 
         @Override
@@ -181,7 +206,7 @@ public final class OrderGlobalStep<S, C extends Comparable> extends CollectingBa
                 if (this.isShuffle)
                     setA.shuffle();
                 else
-                    setA.sort(Comparator.naturalOrder());
+                    setA.sort(this.comparator);
                 long counter = 0L;
                 final Iterator<Traverser.Admin<S>> traversers = setA.iterator();
                 while (traversers.hasNext()) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5045f67f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/OrderedTraverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/OrderedTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/OrderedTraverser.java
deleted file mode 100644
index 4dddaa3..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/OrderedTraverser.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.tinkerpop.gremlin.process.traversal.traverser;
-
-import org.apache.tinkerpop.gremlin.process.traversal.Order;
-import org.apache.tinkerpop.gremlin.process.traversal.Path;
-import org.apache.tinkerpop.gremlin.process.traversal.Step;
-import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
-import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
-import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
-import org.apache.tinkerpop.gremlin.structure.util.Attachable;
-import org.javatuples.Pair;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * @author Marko A. Rodriguez (http://markorodriguez.com)
- */
-public final class OrderedTraverser<T> implements Traverser.Admin<T> {
-
-    private Traverser.Admin<T> internal;
-    private int order;
-    private final List<Pair<Object, Comparator<?>>> orderChecks = new ArrayList<>();
-
-    private OrderedTraverser() {
-        // for serialization
-    }
-
-    public OrderedTraverser(final Traverser.Admin<T> internal, final List<Pair<Traversal.Admin<T, ?>, Comparator>> checks) {
-        this(internal, 0);
-        for (final Pair<Traversal.Admin<T, ?>, Comparator> pairs : checks) {
-            this.orderChecks.add(Pair.with(TraversalUtil.apply(this.internal, pairs.getValue0()), pairs.getValue1()));
-        }
-    }
-
-    public OrderedTraverser(final Traverser.Admin<T> internal, final int order) {
-        this.internal = internal instanceof OrderedTraverser ? ((OrderedTraverser) internal).internal : internal;
-        this.order = order;
-    }
-
-    public Traverser.Admin<T> getInternal() {
-        return this.internal;
-    }
-
-    public int order() {
-        return this.order;
-    }
-
-    @Override
-    public void merge(final Admin<?> other) {
-        this.internal.merge(other);
-    }
-
-    @Override
-    public <R> Admin<R> split(R r, Step<T, R> step) {
-        return new OrderedTraverser<>(this.internal.split(r, step), this.order);
-    }
-
-    @Override
-    public Admin<T> split() {
-        return new OrderedTraverser<>(this.internal.split(), this.order);
-    }
-
-    @Override
-    public void addLabels(final Set<String> labels) {
-        this.internal.addLabels(labels);
-    }
-
-    @Override
-    public void keepLabels(final Set<String> labels) {
-        this.internal.keepLabels(labels);
-    }
-
-    @Override
-    public void dropLabels(final Set<String> labels) {
-        this.internal.dropLabels(labels);
-    }
-
-    @Override
-    public void dropPath() {
-        this.internal.dropPath();
-    }
-
-    @Override
-    public void set(final T t) {
-        this.internal.set(t);
-    }
-
-    @Override
-    public void incrLoops(final String stepLabel) {
-        this.internal.incrLoops(stepLabel);
-    }
-
-    @Override
-    public void resetLoops() {
-        this.internal.resetLoops();
-    }
-
-    @Override
-    public String getStepId() {
-        return this.internal.getStepId();
-    }
-
-    @Override
-    public void setStepId(final String stepId) {
-        this.internal.setStepId(stepId);
-    }
-
-    @Override
-    public void setBulk(final long count) {
-        this.internal.setBulk(count);
-    }
-
-    @Override
-    public Admin<T> detach() {
-        this.internal = this.internal.detach();
-        return this;
-    }
-
-    @Override
-    public T attach(final Function<Attachable<T>, T> method) {
-        return this.internal.attach(method);
-    }
-
-    @Override
-    public void setSideEffects(final TraversalSideEffects sideEffects) {
-        this.internal.setSideEffects(sideEffects);
-    }
-
-    @Override
-    public TraversalSideEffects getSideEffects() {
-        return this.internal.getSideEffects();
-    }
-
-    @Override
-    public Set<String> getTags() {
-        return this.internal.getTags();
-    }
-
-    @Override
-    public T get() {
-        return this.internal.get();
-    }
-
-    @Override
-    public <S> S sack() {
-        return this.internal.sack();
-    }
-
-    @Override
-    public <S> void sack(final S object) {
-        this.internal.sack(object);
-    }
-
-    @Override
-    public Path path() {
-        return this.internal.path();
-    }
-
-    @Override
-    public int loops() {
-        return this.internal.loops();
-    }
-
-    @Override
-    public long bulk() {
-        return this.internal.bulk();
-    }
-
-    @Override
-    public int hashCode() {
-        return this.internal.hashCode();
-    }
-
-    @Override
-    public boolean equals(final Object object) {
-        return object instanceof OrderedTraverser && ((OrderedTraverser) object).internal.equals(this.internal);
-    }
-
-    @Override
-    public OrderedTraverser<T> clone() {
-        try {
-            final OrderedTraverser<T> clone = (OrderedTraverser<T>) super.clone();
-            clone.internal = (Traverser.Admin<T>) this.internal.clone();
-            return clone;
-        } catch (final CloneNotSupportedException e) {
-            throw new IllegalStateException(e.getMessage(), e);
-        }
-    }
-
-    @Override
-    public int compareTo(final Traverser<T> o) {
-        if (!(o instanceof OrderedTraverser))
-            return 0;
-        else {
-            if (this.orderChecks.isEmpty()) {
-                return Order.incr.compare(this.get(), o.get());
-            } else {
-                final OrderedTraverser<T> other = (OrderedTraverser<T>) o;
-                for (int i = 0; i < this.orderChecks.size(); i++) {
-                    final Comparator comparator = this.orderChecks.get(i).getValue1();
-                    final Object thisObject = this.orderChecks.get(i).getValue0();
-                    final Object otherObject = other.orderChecks.get(i).getValue0();
-                    final int comparison = comparator.compare(thisObject, otherObject);
-                    if (comparison != 0)
-                        return comparison;
-
-                }
-                return 0;
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5045f67f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
new file mode 100644
index 0000000..67e723a
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
@@ -0,0 +1,199 @@
+/*
+ *  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.traverser;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.structure.util.Attachable;
+
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class ProjectedTraverser<T> implements Traverser.Admin<T> {
+
+    private Traverser.Admin<T> internal;
+    private List<Object> projections;
+
+    private ProjectedTraverser() {
+        // for serialization
+    }
+
+    public ProjectedTraverser(final Traverser.Admin<T> internal, final List<Object> projections) {
+        this.internal = internal;
+        this.projections = projections;
+    }
+
+
+    public Traverser.Admin<T> getInternal() {
+        return this.internal;
+    }
+
+    public List<Object> getProjections() {
+        return this.projections;
+    }
+
+    @Override
+    public void merge(final Admin<?> other) {
+        this.internal.merge(other);
+    }
+
+    @Override
+    public <R> Admin<R> split(R r, Step<T, R> step) {
+        return new ProjectedTraverser<>(this.internal.split(r, step), this.projections);
+    }
+
+    @Override
+    public Admin<T> split() {
+        return new ProjectedTraverser<>(this.internal.split(), this.projections);
+    }
+
+    @Override
+    public void addLabels(final Set<String> labels) {
+        this.internal.addLabels(labels);
+    }
+
+    @Override
+    public void keepLabels(final Set<String> labels) {
+        this.internal.keepLabels(labels);
+    }
+
+    @Override
+    public void dropLabels(final Set<String> labels) {
+        this.internal.dropLabels(labels);
+    }
+
+    @Override
+    public void dropPath() {
+        this.internal.dropPath();
+    }
+
+    @Override
+    public void set(final T t) {
+        this.internal.set(t);
+    }
+
+    @Override
+    public void incrLoops(final String stepLabel) {
+        this.internal.incrLoops(stepLabel);
+    }
+
+    @Override
+    public void resetLoops() {
+        this.internal.resetLoops();
+    }
+
+    @Override
+    public String getStepId() {
+        return this.internal.getStepId();
+    }
+
+    @Override
+    public void setStepId(final String stepId) {
+        this.internal.setStepId(stepId);
+    }
+
+    @Override
+    public void setBulk(final long count) {
+        this.internal.setBulk(count);
+    }
+
+    @Override
+    public Admin<T> detach() {
+        this.internal = this.internal.detach();
+        return this;
+    }
+
+    @Override
+    public T attach(final Function<Attachable<T>, T> method) {
+        return this.internal.attach(method);
+    }
+
+    @Override
+    public void setSideEffects(final TraversalSideEffects sideEffects) {
+        this.internal.setSideEffects(sideEffects);
+    }
+
+    @Override
+    public TraversalSideEffects getSideEffects() {
+        return this.internal.getSideEffects();
+    }
+
+    @Override
+    public Set<String> getTags() {
+        return this.internal.getTags();
+    }
+
+    @Override
+    public T get() {
+        return this.internal.get();
+    }
+
+    @Override
+    public <S> S sack() {
+        return this.internal.sack();
+    }
+
+    @Override
+    public <S> void sack(final S object) {
+        this.internal.sack(object);
+    }
+
+    @Override
+    public Path path() {
+        return this.internal.path();
+    }
+
+    @Override
+    public int loops() {
+        return this.internal.loops();
+    }
+
+    @Override
+    public long bulk() {
+        return this.internal.bulk();
+    }
+
+    @Override
+    public int hashCode() {
+        return this.internal.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        return object instanceof ProjectedTraverser && ((ProjectedTraverser) object).internal.equals(this.internal);
+    }
+
+    @Override
+    public ProjectedTraverser<T> clone() {
+        try {
+            final ProjectedTraverser<T> clone = (ProjectedTraverser<T>) super.clone();
+            clone.internal = (Traverser.Admin<T>) this.internal.clone();
+            return clone;
+        } catch (final CloneNotSupportedException e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5045f67f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java
----------------------------------------------------------------------
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 a04f2d9..f4e31fd 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
@@ -51,13 +51,11 @@ import org.apache.tinkerpop.gremlin.process.traversal.traverser.LP_O_OB_P_S_SE_S
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.LP_O_OB_S_SE_SL_Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.O_OB_S_SE_SL_Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.traverser.OrderedTraverser;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.ProjectedTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
-import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ImmutableMetrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
-import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation;
 import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.Direction;
@@ -81,6 +79,7 @@ import org.apache.tinkerpop.gremlin.structure.util.star.StarGraph;
 import org.apache.tinkerpop.gremlin.structure.util.star.StarGraphSerializer;
 import org.apache.tinkerpop.gremlin.util.function.HashSetSupplier;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.apache.tinkerpop.gremlin.util.function.MultiComparator;
 import org.apache.tinkerpop.shaded.kryo.KryoSerializable;
 import org.apache.tinkerpop.shaded.kryo.serializers.JavaSerializer;
 import org.javatuples.Pair;
@@ -246,7 +245,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(O_OB_S_SE_SL_Traverser.class, 89));
             add(GryoTypeReg.of(LP_O_OB_S_SE_SL_Traverser.class, 90));
             add(GryoTypeReg.of(LP_O_OB_P_S_SE_SL_Traverser.class, 91));
-            add(GryoTypeReg.of(OrderedTraverser.class, 164));   // ***LAST ID***
+            add(GryoTypeReg.of(ProjectedTraverser.class, 164));
             add(GryoTypeReg.of(DefaultRemoteTraverser.class, 123, new GryoSerializers.DefaultRemoteTraverserSerializer()));
 
             add(GryoTypeReg.of(Bytecode.class, 122, new GryoSerializers.BytecodeSerializer()));
@@ -261,6 +260,7 @@ public enum GryoVersion {
             add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
             add(GryoTypeReg.of(TraversalOptionParent.Pick.class, 137));
             add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer()));
+            add(GryoTypeReg.of(MultiComparator.class, 165));   // ***LAST ID***
 
             add(GryoTypeReg.of(TraverserSet.class, 58));
             add(GryoTypeReg.of(Tree.class, 61));

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/5045f67f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/MultiComparator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/MultiComparator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/MultiComparator.java
new file mode 100644
index 0000000..427aa3d
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/MultiComparator.java
@@ -0,0 +1,60 @@
+/*
+ *  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.util.function;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.ProjectedTraverser;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class MultiComparator<C> implements Comparator<C>, Serializable {
+
+    private final List<Comparator> comparators;
+
+    public MultiComparator(final List<Comparator<C>> comparators) {
+        this.comparators = (List) comparators;
+    }
+
+    @Override
+    public int compare(final C objectA, final C objectB) {
+        if (this.comparators.isEmpty()) {
+            return Order.incr.compare(objectA, objectB);
+        } else {
+            for (int i = 0; i < this.comparators.size(); i++) {
+                final int comparison = this.comparators.get(i).compare(this.getObject(objectA, i), this.getObject(objectB, i));
+                if (comparison != 0)
+                    return comparison;
+            }
+            return 0;
+        }
+    }
+
+    private final Object getObject(final C object, final int index) {
+        if (object instanceof ProjectedTraverser)
+            return ((ProjectedTraverser) object).getProjections().get(index);
+        else
+            return object;
+    }
+}