You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2019/03/28 15:55:31 UTC

[tinkerpop] branch tp4 updated: Generalized order() to support arbitrary number of asc and desc by()s. Borrowed many ideas from TP3, but greatly simplified the implementation as there is no GraphComputer concepts to worry about.

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

okram pushed a commit to branch tp4
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/tp4 by this push:
     new e1f13b3  Generalized order() to support arbitrary number of asc and desc by()s. Borrowed many ideas from TP3, but greatly simplified the implementation as there is no GraphComputer concepts to worry about.
e1f13b3 is described below

commit e1f13b3956c4ac0a060a55308e1f73dd5369cf2d
Author: Marko A. Rodriguez <ok...@gmail.com>
AuthorDate: Thu Mar 28 09:55:22 2019 -0600

    Generalized order() to support arbitrary number of asc and desc by()s. Borrowed many ideas from TP3, but greatly simplified the implementation as there is no GraphComputer concepts to worry about.
---
 .../tinkerpop/language/gremlin/Traversal.java      |   7 +-
 .../language/gremlin/common/CommonTraversal.java   |  16 +++-
 .../tinkerpop/language/gremlin/common/__.java      |   4 +
 .../language/gremlin/core/CoreTraversal.java       |  17 +++-
 .../bytecode/compiler/CompilationCircle.java       |  17 +++-
 .../tinkerpop/machine/bytecode/compiler/Order.java |  85 +++++++++++++++++
 .../machine/function/barrier/OrderBarrier.java     |  48 ++++++++--
 .../tinkerpop/machine/function/map/PathMap.java    |   4 +-
 .../traverser/species/ProjectedTraverser.java      | 103 +++++++++++++++++++++
 .../tinkerpop/machine/util/MultiComparator.java    |  74 +++++++++++++++
 .../tinkerpop/machine/processor/beam/BeamTest.java |   3 +-
 .../machine/processor/pipes/PipesTest.java         |   3 +-
 12 files changed, 363 insertions(+), 18 deletions(-)

diff --git a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/Traversal.java b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/Traversal.java
index b8d478c..f917ee1 100644
--- a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/Traversal.java
+++ b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/Traversal.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.language.gremlin;
 
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.structure.data.TMap;
 import org.apache.tinkerpop.machine.traverser.Traverser;
 import org.apache.tinkerpop.machine.traverser.path.Path;
@@ -34,9 +35,13 @@ public interface Traversal<C, S, E> extends Iterator<E> {
 
     public Traversal<C, S, E> barrier();
 
+    public Traversal<C, S, E> by(final String byString);
+
     public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal);
 
-    public Traversal<C, S, E> by(final String byString);
+    public Traversal<C, S, E> by(final Order order);
+
+    public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal, final Order order);
 
     public Traversal<C, S, E> c(final C coefficient);
 
diff --git a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/CommonTraversal.java b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/CommonTraversal.java
index d6adf91..0d7ff05 100644
--- a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/CommonTraversal.java
+++ b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/CommonTraversal.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.language.gremlin.TraversalUtil;
 import org.apache.tinkerpop.machine.Machine;
 import org.apache.tinkerpop.machine.bytecode.Bytecode;
 import org.apache.tinkerpop.machine.bytecode.compiler.CommonCompiler.Symbols;
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.bytecode.compiler.Pred;
 import org.apache.tinkerpop.machine.coefficient.Coefficient;
 import org.apache.tinkerpop.machine.coefficient.LongCoefficient;
@@ -59,14 +60,25 @@ public class CommonTraversal<C, S, E> extends AbstractTraversal<C, S, E> {
     }
 
     @Override
+    public Traversal<C, S, E> by(final String byString) {
+        this.bytecode.lastInstruction().addArg(byString);
+        return this;
+    }
+
+    @Override
     public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal) {
         this.bytecode.lastInstruction().addArg(TraversalUtil.getBytecode(byTraversal));
         return this;
     }
 
     @Override
-    public Traversal<C, S, E> by(final String byString) {
-        this.bytecode.lastInstruction().addArg(byString);
+    public Traversal<C, S, E> by(final Order order) {
+        return this.by(__.identity(), order);
+    }
+
+    @Override
+    public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal, final Order order) {
+        this.bytecode.lastInstruction().addArgs(TraversalUtil.getBytecode(byTraversal), order.name());
         return this;
     }
 
diff --git a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/__.java b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/__.java
index 8d7aef4..3361a5c 100644
--- a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/__.java
+++ b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/common/__.java
@@ -41,6 +41,10 @@ public class __ {
         return __.<C, S>start().constant(constant);
     }
 
+    public static <C, S> Traversal<C, S, S> identity() {
+        return __.<C, S>start().identity();
+    }
+
     public static <C> Traversal<C, Long, Long> incr() {
         return __.<C, Long>start().incr();
     }
diff --git a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/core/CoreTraversal.java b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/core/CoreTraversal.java
index 41f605a..b1a46e9 100644
--- a/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/core/CoreTraversal.java
+++ b/java/language/gremlin/src/main/java/org/apache/tinkerpop/language/gremlin/core/CoreTraversal.java
@@ -22,10 +22,12 @@ import org.apache.tinkerpop.language.gremlin.AbstractTraversal;
 import org.apache.tinkerpop.language.gremlin.P;
 import org.apache.tinkerpop.language.gremlin.Traversal;
 import org.apache.tinkerpop.language.gremlin.TraversalUtil;
+import org.apache.tinkerpop.language.gremlin.common.__;
 import org.apache.tinkerpop.machine.Machine;
 import org.apache.tinkerpop.machine.bytecode.Bytecode;
 import org.apache.tinkerpop.machine.bytecode.compiler.CoreCompiler.Symbols;
 import org.apache.tinkerpop.machine.bytecode.compiler.Oper;
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.bytecode.compiler.Pred;
 import org.apache.tinkerpop.machine.coefficient.Coefficient;
 import org.apache.tinkerpop.machine.coefficient.LongCoefficient;
@@ -62,14 +64,25 @@ public class CoreTraversal<C, S, E> extends AbstractTraversal<C, S, E> {
     }
 
     @Override
+    public Traversal<C, S, E> by(final String byString) {
+        this.bytecode.lastInstruction().addArg(byString);
+        return this;
+    }
+
+    @Override
     public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal) {
         this.bytecode.lastInstruction().addArg(TraversalUtil.getBytecode(byTraversal));
         return this;
     }
 
     @Override
-    public Traversal<C, S, E> by(final String byString) {
-        this.bytecode.lastInstruction().addArg(byString);
+    public Traversal<C, S, E> by(final Order order) {
+        return this.by(__.identity(), order);
+    }
+
+    @Override
+    public Traversal<C, S, E> by(final Traversal<C, ?, ?> byTraversal, final Order order) {
+        this.bytecode.lastInstruction().addArgs(TraversalUtil.getBytecode(byTraversal), order);
         return this;
     }
 
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/CompilationCircle.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/CompilationCircle.java
index 94f8e95..62cfadf 100644
--- a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/CompilationCircle.java
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/CompilationCircle.java
@@ -18,6 +18,8 @@
  */
 package org.apache.tinkerpop.machine.bytecode.compiler;
 
+import org.apache.tinkerpop.machine.traverser.Traverser;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
@@ -36,7 +38,7 @@ public final class CompilationCircle<C, S, E> implements Serializable, Cloneable
         this.hasCompilations = !this.compilations.isEmpty();
     }
 
-    public E process(final S object) {
+    public E processObject(final S object) {
         if (this.hasCompilations) {
             this.currentCompilation = (this.currentCompilation + 1) % this.compilations.size();
             return this.compilations.get(this.currentCompilation).mapObject(object).object();
@@ -45,6 +47,15 @@ public final class CompilationCircle<C, S, E> implements Serializable, Cloneable
         }
     }
 
+    public E processTraverser(final Traverser<C, S> traverser) {
+        if (this.hasCompilations) {
+            this.currentCompilation = (this.currentCompilation + 1) % this.compilations.size();
+            return this.compilations.get(this.currentCompilation).mapTraverser(traverser).object();
+        } else {
+            return (E) traverser.object();
+        }
+    }
+
     public boolean isEmpty() {
         return this.compilations.isEmpty();
     }
@@ -53,6 +64,10 @@ public final class CompilationCircle<C, S, E> implements Serializable, Cloneable
         this.currentCompilation = -1;
     }
 
+    public int size() {
+        return this.compilations.size();
+    }
+
     @Override
     public int hashCode() {
         return this.compilations.hashCode();
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/Order.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/Order.java
new file mode 100644
index 0000000..34a673c
--- /dev/null
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/bytecode/compiler/Order.java
@@ -0,0 +1,85 @@
+/*
+ * 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.machine.bytecode.compiler;
+
+import org.apache.tinkerpop.machine.util.NumberHelper;
+
+import java.util.Comparator;
+import java.util.Random;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public enum Order implements Comparator<Object> {
+
+    shuffle {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return RANDOM.nextBoolean() ? -1 : 1;
+        }
+
+        @Override
+        public Order reversed() {
+            return shuffle;
+        }
+    },
+
+    asc {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return first instanceof Number && second instanceof Number
+                    ? NumberHelper.compare((Number) first, (Number) second)
+                    : Comparator.<Comparable>naturalOrder().compare((Comparable) first, (Comparable) second);
+        }
+
+        @Override
+        public Order reversed() {
+            return desc;
+        }
+    },
+
+    desc {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return first instanceof Number && second instanceof Number
+                    ? NumberHelper.compare((Number) second, (Number) first)
+                    : Comparator.<Comparable>reverseOrder().compare((Comparable) first, (Comparable) second);
+        }
+
+        @Override
+        public Order reversed() {
+            return asc;
+        }
+    };
+
+    private static final Random RANDOM = new Random();
+
+    /**
+     * {@inheritDoc}
+     */
+    public abstract int compare(final Object first, final Object second);
+
+    @Override
+    public abstract Order reversed();
+
+    public static Order valueOf(final Object object) {
+        return Order.valueOf((String) object);
+    }
+}
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/barrier/OrderBarrier.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/barrier/OrderBarrier.java
index fd3dc20..e7d8b66 100644
--- a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/barrier/OrderBarrier.java
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/barrier/OrderBarrier.java
@@ -19,22 +19,36 @@
 package org.apache.tinkerpop.machine.function.barrier;
 
 import org.apache.tinkerpop.machine.bytecode.Instruction;
+import org.apache.tinkerpop.machine.bytecode.compiler.Compilation;
+import org.apache.tinkerpop.machine.bytecode.compiler.CompilationCircle;
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.coefficient.Coefficient;
 import org.apache.tinkerpop.machine.function.AbstractFunction;
 import org.apache.tinkerpop.machine.function.BarrierFunction;
+import org.apache.tinkerpop.machine.processor.FilterProcessor;
 import org.apache.tinkerpop.machine.traverser.Traverser;
 import org.apache.tinkerpop.machine.traverser.TraverserSet;
+import org.apache.tinkerpop.machine.traverser.species.ProjectedTraverser;
+import org.apache.tinkerpop.machine.util.IteratorUtils;
+import org.apache.tinkerpop.machine.util.MultiComparator;
 
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class OrderBarrier<C, S> extends AbstractFunction<C> implements BarrierFunction<C, S, Traverser<C, S>, TraverserSet<C, S>> {
+public final class OrderBarrier<C, S, P> extends AbstractFunction<C> implements BarrierFunction<C, S, Traverser<C, S>, TraverserSet<C, S>> {
 
-    private OrderBarrier(final Coefficient<C> coefficient, final String label) {
+    private MultiComparator<P> comparator;
+    private final CompilationCircle<C, S, P> compilationCircle;
+
+    private OrderBarrier(final Coefficient<C> coefficient, final String label, final MultiComparator<P> comparator, final CompilationCircle<C, S, P> compilationCircle) {
         super(coefficient, label);
+        this.comparator = comparator;
+        this.compilationCircle = compilationCircle;
     }
 
     @Override
@@ -50,8 +64,8 @@ public final class OrderBarrier<C, S> extends AbstractFunction<C> implements Bar
 
     @Override
     public Iterator<Traverser<C, S>> createIterator(final TraverserSet<C, S> barrier) {
-        barrier.sort(Comparator.comparingLong(t -> (Long) t.object()));
-        return barrier.iterator();
+        barrier.sort((Comparator) this.comparator);
+        return IteratorUtils.map(barrier.iterator(), t -> ((ProjectedTraverser<C, S, P>) t).getBaseTraverser());
     }
 
     @Override
@@ -59,14 +73,32 @@ public final class OrderBarrier<C, S> extends AbstractFunction<C> implements Bar
         return true;
     }
 
-
     @Override
     public TraverserSet<C, S> apply(final Traverser<C, S> traverser, final TraverserSet<C, S> traverserSet) {
-        traverserSet.add(traverser);
+        final List<P> projections = new ArrayList<>();
+        this.compilationCircle.reset();
+        for (int i = 0; i < compilationCircle.size(); i++) {
+            projections.add(this.compilationCircle.processTraverser(traverser));
+        }
+        traverserSet.add(new ProjectedTraverser<>(traverser, projections));
         return traverserSet;
     }
 
-    public static <C, S> OrderBarrier<C, S> compile(final Instruction<C> instruction) {
-        return new OrderBarrier<>(instruction.coefficient(), instruction.label());
+    public static <C, S, P> OrderBarrier<C, S, P> compile(final Instruction<C> instruction) {
+        final List<Compilation<C, S, P>> compilations = new ArrayList<>();
+        final List<Comparator<P>> comparators = new ArrayList<>();
+
+        for (int i = 0; i < instruction.args().length; i = i + 2) {
+            compilations.add(Compilation.compile(instruction.args()[i]));
+            comparators.add((Comparator<P>) Order.valueOf(instruction.args()[i + 1]));
+        }
+
+        if (comparators.isEmpty()) {
+            compilations.add(new Compilation<>(new FilterProcessor(true)));
+            comparators.add((Comparator<P>) Order.asc);
+        }
+
+        return new OrderBarrier<>(instruction.coefficient(), instruction.label(), new MultiComparator<>(comparators), new CompilationCircle<>(compilations));
     }
+
 }
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/map/PathMap.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/map/PathMap.java
index 0e708f8..7702568 100644
--- a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/map/PathMap.java
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/function/map/PathMap.java
@@ -59,11 +59,11 @@ public final class PathMap<C, S> extends AbstractFunction<C> implements MapFunct
             final Path newPath = new BasicPath();
             if (this.hasPathLabels) {
                 for (final String label : this.pathLabels) {
-                    newPath.add(label, this.byCompilations.process(oldPath.get(Path.Pop.last, label)));
+                    newPath.add(label, this.byCompilations.processObject(oldPath.get(Path.Pop.last, label)));
                 }
             } else {
                 for (int i = 0; i < oldPath.size(); i++) {
-                    newPath.add(oldPath.label(i), this.byCompilations.process(oldPath.object(i)));
+                    newPath.add(oldPath.label(i), this.byCompilations.processObject(oldPath.object(i)));
                 }
             }
             return newPath;
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/traverser/species/ProjectedTraverser.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/traverser/species/ProjectedTraverser.java
new file mode 100644
index 0000000..935a516
--- /dev/null
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/traverser/species/ProjectedTraverser.java
@@ -0,0 +1,103 @@
+/*
+ * 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.machine.traverser.species;
+
+import org.apache.tinkerpop.machine.coefficient.Coefficient;
+import org.apache.tinkerpop.machine.function.CFunction;
+import org.apache.tinkerpop.machine.traverser.Traverser;
+import org.apache.tinkerpop.machine.traverser.path.Path;
+
+import java.util.List;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public class ProjectedTraverser<C, S, P> implements Traverser<C, S> {
+
+    private final Traverser<C, S> baseTraverser;
+    private final List<P> projections;
+
+    public ProjectedTraverser(final Traverser<C, S> baseTraverser, List<P> projections) {
+        this.baseTraverser = baseTraverser;
+        this.projections = projections;
+    }
+
+    public P getProjection(final int index) {
+        return this.projections.get(index);
+    }
+
+    public Traverser<C, S> getBaseTraverser() {
+        return this.baseTraverser;
+    }
+
+    @Override
+    public Coefficient<C> coefficient() {
+        return this.baseTraverser.coefficient();
+    }
+
+    @Override
+    public S object() {
+        return this.baseTraverser.object();
+    }
+
+    @Override
+    public Path path() {
+        return this.baseTraverser.path();
+    }
+
+    @Override
+    public void incrLoops() {
+        this.baseTraverser.incrLoops();
+    }
+
+    @Override
+    public int loops() {
+        return this.baseTraverser.loops();
+    }
+
+    @Override
+    public void resetLoops() {
+        this.baseTraverser.resetLoops();
+    }
+
+    @Override
+    public int hashCode() {
+        return this.baseTraverser.hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        return object instanceof ProjectedTraverser && this.baseTraverser.equals(((ProjectedTraverser) object).baseTraverser);
+    }
+
+    @Override
+    public <E> Traverser<C, E> split(final CFunction<C> function, final E object) {
+        return null;
+    }
+
+    @Override
+    public <E> Traverser<C, E> split(E object) {
+        return null;
+    }
+
+    @Override
+    public Traverser<C, S> clone() {
+        return new ProjectedTraverser<>(this.baseTraverser.clone(), this.projections);
+    }
+}
diff --git a/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/util/MultiComparator.java b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/util/MultiComparator.java
new file mode 100644
index 0000000..02f7a20
--- /dev/null
+++ b/java/machine/machine-core/src/main/java/org/apache/tinkerpop/machine/util/MultiComparator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.machine.util;
+
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
+import org.apache.tinkerpop.machine.traverser.species.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 List<Comparator> comparators;
+    private boolean isShuffle;
+    private int startIndex = 0;
+
+    private MultiComparator() {
+        // for serialization purposes
+    }
+
+    public MultiComparator(final List<Comparator<C>> comparators) {
+        this.comparators = (List) comparators;
+        this.isShuffle = !this.comparators.isEmpty() && Order.shuffle == this.comparators.get(this.comparators.size() - 1);
+        for (int i = 0; i < this.comparators.size(); i++) {
+            if (this.comparators.get(i) == Order.shuffle)
+                this.startIndex = i + 1;
+        }
+    }
+
+    @Override
+    public int compare(final C objectA, final C objectB) {
+        if (this.comparators.isEmpty()) {
+            return Order.asc.compare(objectA, objectB);
+        } else {
+            for (int i = this.startIndex; 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;
+        }
+    }
+
+    public boolean isShuffle() {
+        return this.isShuffle;
+    }
+
+    private Object getObject(final C object, final int index) {
+        if (object instanceof ProjectedTraverser)
+            return ((ProjectedTraverser) object).getProjection(index);
+        else
+            return object;
+    }
+}
diff --git a/java/machine/processor/beam/src/test/java/org/apache/tinkerpop/machine/processor/beam/BeamTest.java b/java/machine/processor/beam/src/test/java/org/apache/tinkerpop/machine/processor/beam/BeamTest.java
index 63b24cb..b3f2cde 100644
--- a/java/machine/processor/beam/src/test/java/org/apache/tinkerpop/machine/processor/beam/BeamTest.java
+++ b/java/machine/processor/beam/src/test/java/org/apache/tinkerpop/machine/processor/beam/BeamTest.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.language.gremlin.TraversalSource;
 import org.apache.tinkerpop.language.gremlin.TraversalUtil;
 import org.apache.tinkerpop.language.gremlin.core.__;
 import org.apache.tinkerpop.machine.Machine;
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.coefficient.LongCoefficient;
 import org.apache.tinkerpop.machine.species.LocalMachine;
 import org.apache.tinkerpop.machine.species.remote.MachineServer;
@@ -77,7 +78,7 @@ public class BeamTest {
                 .withProcessor(BeamProcessor.class)
                 .withStrategy(IdentityStrategy.class);
 
-        Traversal<Long, ?, ?> traversal = g.inject(7L, 3L, 5L, 20L, 1L, 2L).incr().order().incr().barrier().incr();
+        Traversal<Long, ?, ?> traversal = g.inject(7L, 3L, 5L, 20L, 1L, 2L).incr().order().by(Order.desc);
         System.out.println(TraversalUtil.getBytecode(traversal));
         System.out.println(traversal);
         System.out.println(TraversalUtil.getBytecode(traversal));
diff --git a/java/machine/processor/pipes/src/test/java/org/apache/tinkerpop/machine/processor/pipes/PipesTest.java b/java/machine/processor/pipes/src/test/java/org/apache/tinkerpop/machine/processor/pipes/PipesTest.java
index b3b2f93..cfd3cc1 100644
--- a/java/machine/processor/pipes/src/test/java/org/apache/tinkerpop/machine/processor/pipes/PipesTest.java
+++ b/java/machine/processor/pipes/src/test/java/org/apache/tinkerpop/machine/processor/pipes/PipesTest.java
@@ -25,6 +25,7 @@ import org.apache.tinkerpop.language.gremlin.TraversalSource;
 import org.apache.tinkerpop.language.gremlin.TraversalUtil;
 import org.apache.tinkerpop.language.gremlin.common.__;
 import org.apache.tinkerpop.machine.Machine;
+import org.apache.tinkerpop.machine.bytecode.compiler.Order;
 import org.apache.tinkerpop.machine.coefficient.LongCoefficient;
 import org.apache.tinkerpop.machine.species.LocalMachine;
 import org.apache.tinkerpop.machine.species.remote.MachineServer;
@@ -69,7 +70,7 @@ public class PipesTest {
                 .withProcessor(PipesProcessor.class)
                 .withStrategy(IdentityStrategy.class);
 
-        Traversal<Long, ?, ?> traversal = g.inject(7L,3L,5L,20L,1L,2L).incr().order();
+        Traversal<Long, ?, ?> traversal = g.inject(7L, 3L, 5L, 20L, 1L, 2L).incr().order().by(Order.desc);
         System.out.println(TraversalUtil.getBytecode(traversal));
         System.out.println(traversal);
         System.out.println(TraversalUtil.getBytecode(traversal));