@dkuppitz found an optimization trick for MultiComparator. The startIndex for comparing should start after the last Order.shuffle.
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/341ebf98 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/341ebf98 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/341ebf98 Branch: refs/heads/centrality-recipes Commit: 341ebf9811c15d65231ea31c3617723c2fd0ab09 Parents: 379a6e5 Author: Marko A. Rodriguez <okramma...@gmail.com> Authored: Thu Jan 19 08:23:42 2017 -0700 Committer: Marko A. Rodriguez <okramma...@gmail.com> Committed: Thu Jan 19 08:23:42 2017 -0700 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 2 +- .../gremlin/structure/io/gryo/GryoVersion.java | 4 +- .../gremlin/util/function/MultiComparator.java | 15 +++-- .../util/function/MultiComparatorTest.java | 69 ++++++++++++++++++++ 4 files changed, 81 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/341ebf98/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 88cbf32..5f28790 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -26,7 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima TinkerPop 3.2.4 (Release Date: NOT OFFICIALLY RELEASED YET) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* `GroupBiOperator` no longer maintains state and thus, no more side-effect related OLAP inconsistencies. +* `GroupBiOperator` no longer maintains a detached traversal and thus, no more side-effect related OLAP inconsistencies. * Added `ProjectedTraverser` which wraps a traverser with a `List<Object>` of projected data. * Fixed an optimization bug in `CollectionBarrierSteps` where the barrier was being consumed on each `addBarrier()`. * `OrderGlobalStep` and `SampleGlobalStep` use `ProjectedTraverser` and now can work up to the local star graph in OLAP. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/341ebf98/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 f4e31fd..7818f6b 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 @@ -292,13 +292,13 @@ public enum GryoVersion { add(GryoTypeReg.of(Operator.class, 107)); add(GryoTypeReg.of(FoldStep.FoldBiOperator.class, 108)); add(GryoTypeReg.of(GroupCountStep.GroupCountBiOperator.class, 109)); - add(GryoTypeReg.of(GroupStep.GroupBiOperator.class, 117, new JavaSerializer())); // because they contain traversals + add(GryoTypeReg.of(GroupStep.GroupBiOperator.class, 117, new JavaSerializer())); add(GryoTypeReg.of(MeanGlobalStep.MeanGlobalBiOperator.class, 110)); add(GryoTypeReg.of(MeanGlobalStep.MeanNumber.class, 111)); add(GryoTypeReg.of(TreeStep.TreeBiOperator.class, 112)); add(GryoTypeReg.of(GroupStepV3d0.GroupBiOperatorV3d0.class, 113)); add(GryoTypeReg.of(RangeGlobalStep.RangeBiOperator.class, 114)); - add(GryoTypeReg.of(OrderGlobalStep.OrderBiOperator.class, 118, new JavaSerializer())); // because they contain traversals + add(GryoTypeReg.of(OrderGlobalStep.OrderBiOperator.class, 118, new JavaSerializer())); add(GryoTypeReg.of(ProfileStep.ProfileBiOperator.class, 119)); }}; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/341ebf98/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 index 5d24ddf..d97d147 100644 --- 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 @@ -33,6 +33,7 @@ public final class MultiComparator<C> implements Comparator<C>, Serializable { private List<Comparator> comparators; private boolean isShuffle; + int startIndex = 0; private MultiComparator() { // for serialization purposes @@ -41,6 +42,10 @@ public final class MultiComparator<C> implements Comparator<C>, Serializable { 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 @@ -48,12 +53,10 @@ public final class MultiComparator<C> implements Comparator<C>, Serializable { if (this.comparators.isEmpty()) { return Order.incr.compare(objectA, objectB); } else { - for (int i = 0; i < this.comparators.size(); i++) { - if (Order.shuffle != this.comparators.get(i)) { - final int comparison = this.comparators.get(i).compare(this.getObject(objectA, i), this.getObject(objectB, i)); - if (comparison != 0) - return comparison; - } + 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; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/341ebf98/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/MultiComparatorTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/MultiComparatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/MultiComparatorTest.java new file mode 100644 index 0000000..de2a741 --- /dev/null +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/MultiComparatorTest.java @@ -0,0 +1,69 @@ +/* + * 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.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Random; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Marko A. Rodriguez (http://markorodriguez.com) + */ +public class MultiComparatorTest { + + private static final Random RANDOM = new Random(); + + @Test + public void shouldHandleShuffleCorrectly() { + MultiComparator<Object> comparator = new MultiComparator<>(Arrays.asList(Order.incr, Order.decr, Order.shuffle)); + assertTrue(comparator.isShuffle()); // because its a shuffle, the comparator simply returns 0 + for (int i = 0; i < 100; i++) { + assertEquals(0, comparator.compare(RANDOM.nextInt(), RANDOM.nextInt())); + } + // + comparator = new MultiComparator<>(Arrays.asList(Order.incr, Order.shuffle, Order.decr)); + assertEquals(1, comparator.compare(1, 2)); + assertEquals(-1, comparator.compare(2, 1)); + assertEquals(0, comparator.compare(2, 2)); + assertEquals(2, comparator.startIndex); + assertFalse(comparator.isShuffle()); + // + comparator = new MultiComparator<>(Arrays.asList(Order.incr, Order.shuffle, Order.decr, Order.shuffle, Order.incr)); + assertEquals(-1, comparator.compare(1, 2)); + assertEquals(1, comparator.compare(2, 1)); + assertEquals(0, comparator.compare(2, 2)); + assertEquals(4, comparator.startIndex); + assertFalse(comparator.isShuffle()); + // + comparator = new MultiComparator<>(Collections.emptyList()); + assertEquals(-1, comparator.compare(1, 2)); + assertEquals(1, comparator.compare(2, 1)); + assertEquals(0, comparator.compare(2, 2)); + assertEquals(0, comparator.startIndex); + assertFalse(comparator.isShuffle()); + } +}