This is an automated email from the ASF dual-hosted git repository. andreac pushed a commit to branch global-repeat-poc in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 0b6a37fe8f6caf9e2c423bb6d15b85c047d588e7 Author: Andrea Child <[email protected]> AuthorDate: Sun Aug 24 22:56:07 2025 -0700 Q's first attempt to change limit in repeat to per-iteration counters. Fixed RangeGlobalStep requirements. Change to nested loop requirement. Modify counter key to account for nested repeats. Added temporary playground test for various traversals. Added information for logging. Draft code for logging, different test case. Account for traversals with varying path lengths. Added more tests. Handle scenario where repeat contains out.limit. Only throw FastNoSuchElementException when not using iteration counts. Added more tests. Fix typo. Revert changes to StringFactory. Fixed bug with loop name. Fixed getLoopNames logic. Added feature tests. Set loop name for computer algorithm. Troubleshooting graph computer. Fixed standard algo. Moved tests to new file. Replaced tests with ones against modern graph. --- .../process/traversal/step/branch/RepeatStep.java | 64 ++- .../traversal/step/filter/RangeGlobalStep.java | 90 +++- .../traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java | 7 + .../traverser/B_LP_NL_O_S_SE_SL_Traverser.java | 1 + .../traverser/B_NL_O_S_SE_SL_Traverser.java | 7 + .../traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java | 1 + .../traverser/LP_NL_O_OB_S_SE_SL_Traverser.java | 1 + .../traverser/NL_O_OB_S_SE_SL_Traverser.java | 1 + .../gremlin/test/features/filter/Range.feature | 121 +++++ .../structure/TinkerGraphRepeatLimitTest.java | 569 +++++++++++++++++++++ 10 files changed, 838 insertions(+), 24 deletions(-) diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java index e56b2c06b2..a51af34575 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java @@ -18,11 +18,18 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.branch; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier; import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; +import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.ComputerAwareStep; import org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement; import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException; @@ -31,13 +38,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Set; - /** * @author Marko A. Rodriguez (http://markorodriguez.com) */ @@ -71,6 +71,9 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav this.repeatTraversal = repeatTraversal; // .clone(); this.repeatTraversal.addStep(new RepeatEndStep(this.repeatTraversal)); this.integrateChild(this.repeatTraversal); + + // Enable per-iteration counters on any RangeGlobalStep instances within the repeat traversal + this.enablePerIterationCountersOnRangeSteps(this.repeatTraversal); } @@ -129,6 +132,26 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav return emitFirst == this.emitFirst && null != this.emitTraversal && TraversalUtil.test(traverser, this.emitTraversal); } + /** + * Recursively enables per-iteration counters on all RangeGlobalStep instances within a traversal. + */ + private void enablePerIterationCountersOnRangeSteps(final Traversal.Admin<?, ?> traversal) { + for (final Step<?, ?> step : traversal.getSteps()) { + if (step instanceof RangeGlobalStep) { + ((RangeGlobalStep<?>) step).enablePerIterationCounters(); + } + if (step instanceof TraversalParent) { + final TraversalParent parent = (TraversalParent) step; + for (final Traversal.Admin<?, ?> childTraversal : parent.getGlobalChildren()) { + this.enablePerIterationCountersOnRangeSteps(childTraversal); + } + for (final Traversal.Admin<?, ?> childTraversal : parent.getLocalChildren()) { + this.enablePerIterationCountersOnRangeSteps(childTraversal); + } + } + } + } + @Override public String toString() { if (this.untilFirst && this.emitFirst) @@ -173,6 +196,10 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav clone.untilTraversal = this.untilTraversal.clone(); if (null != this.emitTraversal) clone.emitTraversal = this.emitTraversal.clone(); + + // Enable per-iteration counters on the cloned repeat traversal + clone.enablePerIterationCountersOnRangeSteps(clone.repeatTraversal); + return clone; } @@ -229,7 +256,13 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav } private Iterator<Traverser.Admin<S>> initStart(final Traverser.Admin<S> start) { - start.initialiseLoops(this.getId(), this.loopName); + String ln; + if (this.loopName != null) { + ln = this.loopName; + } else { + ln = this.getId(); + } + start.initialiseLoops(this.getId(), ln); if (doUntil(start, true)) { start.resetLoops(); return IteratorUtils.of(start); @@ -249,13 +282,22 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav throw new IllegalStateException("The repeat()-traversal was not defined: " + this); final Traverser.Admin<S> start = this.starts.next(); + System.out.printf("RepeatStep.computerAlgorithm: received traverser%n"); if (doUntil(start, true)) { + System.out.printf("RepeatStep.computerAlgorithm: doUntil=true, exiting%n"); start.setStepId(this.getNextStep().getId()); start.addLabels(this.labels); return IteratorUtils.of(start); } else { + System.out.printf("RepeatStep.computerAlgorithm: entering repeat body%n"); start.setStepId(this.repeatTraversal.getStartStep().getId()); - start.initialiseLoops(start.getStepId(), this.loopName); + String ln; + if (this.loopName != null) { + ln = this.loopName; + } else { + ln = this.getId(); + } + start.initialiseLoops(this.getId(), ln); if (doEmit(start, true)) { final Traverser.Admin<S> emitSplit = start.split(); emitSplit.resetLoops(); @@ -347,8 +389,11 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav protected Iterator<Traverser.Admin<S>> computerAlgorithm() throws NoSuchElementException { final RepeatStep<S> repeatStep = (RepeatStep<S>) this.getTraversal().getParent(); final Traverser.Admin<S> start = this.starts.next(); +// System.out.printf("RepeatEndStep.computerAlgorithm: %s loops=%d before incrLoops%n", start.path(), start.loops()); start.incrLoops(); +// System.out.printf("RepeatEndStep.computerAlgorithm: %s loops=%d after incrLoops%n", start.path(), start.loops()); if (repeatStep.doUntil(start, false)) { +// System.out.printf("RepeatEndStep.computerAlgorithm: doUntil=true, calling resetLoops for %s%n", start.path()); start.resetLoops(); start.setStepId(repeatStep.getNextStep().getId()); start.addLabels(repeatStep.labels); @@ -357,6 +402,7 @@ public final class RepeatStep<S> extends ComputerAwareStep<S, S> implements Trav start.setStepId(repeatStep.getId()); if (repeatStep.doEmit(start, false)) { final Traverser.Admin<S> emitSplit = start.split(); +// System.out.printf("RepeatEndStep.computerAlgorithm: doEmit=true, calling resetLoops for emitSplit %s%n", emitSplit.path()); emitSplit.resetLoops(); emitSplit.setStepId(repeatStep.getNextStep().getId()); emitSplit.addLabels(repeatStep.labels); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java index c246dc9948..07054930e4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java @@ -18,25 +18,30 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.step.filter; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BinaryOperator; import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey; +import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; import org.apache.tinkerpop.gremlin.process.traversal.step.Bypassing; import org.apache.tinkerpop.gremlin.process.traversal.step.FilteringBarrier; import org.apache.tinkerpop.gremlin.process.traversal.step.Ranging; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent; 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.FastNoSuchElementException; +import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; -import java.io.Serializable; -import java.util.Collections; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.BinaryOperator; - /** * @author Bob Briody (http://bobbriody.com) * @author Marko A. Rodriguez (http://markorodriguez.com) @@ -47,6 +52,10 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, private long high; private AtomicLong counter = new AtomicLong(0l); private boolean bypass; + + // Per-iteration counter tracking for repeat steps + private Map<String, AtomicLong> perIterationCounters = new HashMap<>(); + private boolean usePerIterationCounters = false; public RangeGlobalStep(final Traversal.Admin traversal, final long low, final long high) { super(traversal); @@ -59,33 +68,65 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, @Override protected boolean filter(final Traverser.Admin<S> traverser) { +// System.out.printf("Filter called: %s loops=%d%n", traverser.path(), traverser.loops()); if (this.bypass) return true; - if (this.high != -1 && this.counter.get() >= this.high) { + // Determine which counter to use + AtomicLong currentCounter = this.counter; + if (usePerIterationCounters) { + StringBuilder sb = new StringBuilder(); + Traversal.Admin<?,?> t = this.traversal; + while (!t.isRoot()) { + TraversalParent pt = t.getParent(); + Step<?, ?> ps = pt.asStep(); + String pid = ps.getId(); + if (traverser.getLoopNames().contains(pid)) { + sb.append(pid).append(":"); + sb.append(traverser.loops(pid)).append(":"); + } + t = ps.getTraversal(); + } + sb.append(this.getId()).append(":").append(traverser.loops()); + + // Create counter key that isolates between different repeat step contexts + String iterationKey = sb.toString(); +// Object vId = ((Vertex) traverser.get()).property("id").value(); + currentCounter = perIterationCounters.computeIfAbsent(iterationKey, k -> new AtomicLong(0L)); + // System.out.printf("IterationKey: %s Traverser: %s Path: %s Counter: %s High: %s%n", iterationKey, vId, traverser.path(), currentCounter.get(), this.high); + } + + System.out.printf("Traverser: %s%n", traverser); + if (this.high != -1 && currentCounter.get() >= this.high) { + if (usePerIterationCounters) { + System.out.printf("Filter false for Traverser: %s Counter: %d%n", traverser.path(), currentCounter.get()); + return false; + } + // System.out.printf("FastNoSuchElementException for Traverser: %s Counter: %d%n", traverser.path(), currentCounter.get()); throw FastNoSuchElementException.instance(); } long avail = traverser.bulk(); - if (this.counter.get() + avail <= this.low) { + if (currentCounter.get() + avail <= this.low) { // Will not surpass the low w/ this traverser. Skip and filter the whole thing. - this.counter.getAndAdd(avail); + currentCounter.getAndAdd(avail); + // System.out.printf("False for Traverser: %s Counter: %d%n", traverser.path(), currentCounter.get()); return false; } // Skip for the low and trim for the high. Both can happen at once. long toSkip = 0; - if (this.counter.get() < this.low) { - toSkip = this.low - this.counter.get(); + if (currentCounter.get() < this.low) { + toSkip = this.low - currentCounter.get(); } long toTrim = 0; - if (this.high != -1 && this.counter.get() + avail >= this.high) { - toTrim = this.counter.get() + avail - this.high; + if (this.high != -1 && currentCounter.get() + avail >= this.high) { + toTrim = currentCounter.get() + avail - this.high; } long toEmit = avail - toSkip - toTrim; - this.counter.getAndAdd(toSkip + toEmit); + currentCounter.getAndAdd(toSkip + toEmit); traverser.setBulk(toEmit); return true; @@ -95,6 +136,15 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, public void reset() { super.reset(); this.counter.set(0l); + this.perIterationCounters.clear(); + } + + /** + * Enables per-iteration counter tracking for use within repeat steps. + * When enabled, separate counters are maintained for each repeat iteration. + */ + public void enablePerIterationCounters() { + this.usePerIterationCounters = true; } @Override @@ -116,6 +166,8 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, public RangeGlobalStep<S> clone() { final RangeGlobalStep<S> clone = (RangeGlobalStep<S>) super.clone(); clone.counter = new AtomicLong(0l); + clone.perIterationCounters = new HashMap<>(); + clone.usePerIterationCounters = this.usePerIterationCounters; return clone; } @@ -135,6 +187,12 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, @Override public Set<TraverserRequirement> getRequirements() { + if (usePerIterationCounters) { + final Set<TraverserRequirement> requirements = new HashSet<>(); + requirements.add(TraverserRequirement.BULK); + requirements.add(TraverserRequirement.NESTED_LOOP); + return requirements; + } return Collections.singleton(TraverserRequirement.BULK); } @@ -166,7 +224,9 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging, @Override public void addBarrier(final TraverserSet<S> barrier) { +// System.out.printf("=== addBarrier called with %d traversers ===%n", barrier.size()); IteratorUtils.removeOnNext(barrier.iterator()).forEachRemaining(traverser -> { +// System.out.printf("Barrier traverser: %s loops=%d%n", traverser.path(), traverser.loops()); traverser.setSideEffects(this.getTraversal().getSideEffects()); this.addStart(traverser); }); diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java index 1af9dbefef..57cdf63c2d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_P_S_SE_SL_Traverser.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.traverser; +import java.util.Set; import org.apache.commons.collections.map.ReferenceMap; import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter; @@ -47,6 +48,11 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser return this.nestedLoops.peek().count(); } + @Override + public Set<String> getLoopNames() { + return loopNames.keySet(); + } + @Override public int loops(final String loopName) { if (loopName == null) @@ -62,6 +68,7 @@ public class B_LP_NL_O_P_S_SE_SL_Traverser<T> extends B_LP_O_P_S_SE_SL_Traverser if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java index 401bfd279a..1d30928564 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_NL_O_S_SE_SL_Traverser.java @@ -62,6 +62,7 @@ public class B_LP_NL_O_S_SE_SL_Traverser<T> extends B_LP_O_S_SE_SL_Traverser<T> if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java index 6e18d12a61..3ce0884c6e 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_NL_O_S_SE_SL_Traverser.java @@ -18,6 +18,7 @@ */ package org.apache.tinkerpop.gremlin.process.traversal.traverser; +import java.util.Set; import org.apache.commons.collections.map.ReferenceMap; import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.LabelledCounter; @@ -56,11 +57,17 @@ public class B_NL_O_S_SE_SL_Traverser<T> extends B_O_S_SE_SL_Traverser<T> { throw new IllegalArgumentException("Loop name not defined: " + loopName); } + @Override + public Set<String> getLoopNames() { + return loopNames.keySet(); + } + @Override public void initialiseLoops(final String stepLabel, final String loopName) { if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java index 77157b8a22..595c1b923d 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_P_S_SE_SL_Traverser.java @@ -63,6 +63,7 @@ public class LP_NL_O_OB_P_S_SE_SL_Traverser<T> extends LP_O_OB_P_S_SE_SL_Travers if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java index 14c2fe379a..3b61be4b47 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_NL_O_OB_S_SE_SL_Traverser.java @@ -68,6 +68,7 @@ public class LP_NL_O_OB_S_SE_SL_Traverser<T> extends LP_O_OB_S_SE_SL_Traverser<T if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java index c30e893308..3040784706 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/NL_O_OB_S_SE_SL_Traverser.java @@ -63,6 +63,7 @@ public class NL_O_OB_S_SE_SL_Traverser<T> extends O_OB_S_SE_SL_Traverser<T> { if (this.nestedLoops.empty() || !this.nestedLoops.peek().hasLabel(stepLabel)) { final LabelledCounter lc = new LabelledCounter(stepLabel, (short) 0); this.nestedLoops.push(lc); + this.loopNames.put(stepLabel, lc); if (loopName != null) this.loopNames.put(loopName, lc); } diff --git a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature index 0ae5d50ca5..1be68c25b1 100644 --- a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature +++ b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Range.feature @@ -411,3 +411,124 @@ Feature: Step - range() | result | | l[d[2].i] | | l[d[5].i] | + + Scenario: 111.1 + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid1).repeat(__.limit(1)).times(2).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 111.2 + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid1).repeat(__.limit(1)).until(__.loops().is(2)).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 111.3 + Given the modern graph + And using the parameter vid1 defined as "v[marko].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid1).limit(1).limit(1).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 222.1 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(__.limit(1).in()).times(2).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 222.2 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(__.limit(1).in()).until(loops().is(2)).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 222.3 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).limit(1).in().limit(1).in().values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 333.1 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(__.limit(1).in()).times(1).repeat(__.limit(1).in()).times(1).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 333.2 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(__.limit(1).in()).until(loops().is(1)).repeat(__.limit(1).in()).until(loops().is(1)).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 444.1 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(__.limit(1).in().repeat(__.limit(1).in()).times(1)).times(1).values("name") + """ + When iterated to list + Then the result should be unordered + | result | + | marko | + + Scenario: 444.2 + Given the modern graph + And using the parameter vid5 defined as "v[ripple].id" + And the traversal of + """ + g.withoutStrategies(RepeatUnrollStrategy).V(vid5).repeat(limit(1).in().aggregate('x')).times(2).cap('x') + """ + When iterated next + Then the result should be unordered + | result | + | v[josh] | + | v[marko] | \ No newline at end of file diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphRepeatLimitTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphRepeatLimitTest.java new file mode 100644 index 0000000000..24213f7655 --- /dev/null +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphRepeatLimitTest.java @@ -0,0 +1,569 @@ +/* + * 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.structure; + +import java.util.List; +import java.util.function.Function; +import org.apache.commons.collections.CollectionUtils; +import org.apache.tinkerpop.gremlin.process.computer.Computer; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +public class TinkerGraphRepeatLimitTest { + private static GraphTraversalSource gSource; + private static GraphTraversalSource gComputerSource; + + @BeforeClass + public static void setup() { + gSource = TinkerGraph.open().traversal().withoutStrategies(RepeatUnrollStrategy.class); + load(gSource); + gComputerSource = gSource.withComputer(Computer.compute().workers(3)); + } + + @Test + public void testBasicRepeatLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(1).out("knows")) + .times(2), + s -> s.V().has("id", "l1-0") + .limit(1).out("knows") + .limit(1).out("knows")); + } + + @Test + public void testBasicRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(2).out("knows")) + .times(2), + s -> s.V().has("id", "l1-0") + .limit(2).out("knows") + .limit(2).out("knows")); + + } + + @Test + public void testRepeatOutLimit() { + testTraversals(s -> s.V().has("id", "l2-0") + // adding order inside repeat breaks things + .repeat(__.out("knows").limit(2)) + .times(2), + s -> s.V().has("id", "l2-0") + .out("knows").limit(2) + .out("knows").limit(2)); + } + + @Test + public void testRepeatWithBothAndLimit() { + testTraversals(s -> s.V().has("id", "l3-0") + .repeat(__.both("knows").order().by("id").limit(3)) + .times(2), + s -> s.V().has("id", "l3-0") + .both("knows").order().by("id").limit(3) + .both("knows").order().by("id").limit(3)); + } + + @Test + public void testRepeatWithFilterAndLimit() { + testTraversals(s -> s.V().has("id", "l2-0") + .repeat(__.out("knows").has("id", P.neq("l4-3")).order().limit(2)) + .times(2), + s -> s.V().has("id", "l2-0") + .out("knows").has("id", P.neq("l4-3")).order().limit(2) + .out("knows").has("id", P.neq("l4-3")).order().limit(2)); + } + + @Test + public void testChainedRepeatLimit() { + testTraversals(s -> s.V().has("id", "l2-0") + .repeat(__.order().by("id").limit(1).out("knows")).times(2) + .repeat(__.order().by("id").limit(1).in("knows")).times(2), + s -> s.V().has("id", "l2-0") + .order().by("id").limit(1).out("knows") + .order().by("id").limit(1).out("knows") + .order().by("id").limit(1).in("knows") + .order().by("id").limit(1).in("knows")); + } + + @Test + public void testChainedRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l2-0") + .repeat(__.order().by("id").limit(2).out("knows")).times(2) + .repeat(__.order().by("id").limit(3).in("knows")).times(2), + s -> s.V().has("id", "l2-0") + .order().by("id").limit(2).out("knows") + .order().by("id").limit(2).out("knows") + .order().by("id").limit(3).in("knows") + .order().by("id").limit(3).in("knows")); + } + + @Test + public void testNestedRepeatLimit() { + testTraversals(s -> s.V().has("id", "l3-0") + .repeat(__.order().by("id").limit(1).out("knows") + .repeat(__.order().by("id").limit(1).in("knows")) + .times(2)) + .times(2), s -> s.V().has("id", "l3-0") + .order().by("id").limit(1).out("knows") + .order().by("id").limit(1).in("knows") + .order().by("id").limit(1).in("knows") + .order().by("id").limit(1).out("knows") + .order().by("id").limit(1).in("knows") + .order().by("id").limit(1).in("knows")); + } + + @Test + public void testNestedRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l3-0") + .repeat(__.order().by("id").limit(2).out("knows") + .repeat(__.order().by("id").limit(3).in("knows")) + .times(2)) + .times(2), s -> s.V().has("id", "l3-0") + .order().by("id").limit(2).out("knows") + .order().by("id").limit(3).in("knows") + .order().by("id").limit(3).in("knows") + .order().by("id").limit(2).out("knows") + .order().by("id").limit(3).in("knows") + .order().by("id").limit(3).in("knows")); + } + + @Test + public void testTripleNestedRepeatLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(1).out("knows") + .repeat(__.limit(1).in("knows") + .repeat(__.limit(1).out("knows")) + .times(2)) + .times(2)) + .times(2), + s -> s.V().has("id", "l1-0") + .limit(1).out("knows") + .limit(1).in("knows") + .limit(1).out("knows") + .limit(1).out("knows") + .limit(1).in("knows") + .limit(1).out("knows") + .limit(1).out("knows") + .limit(1).out("knows") + .limit(1).in("knows") + .limit(1).out("knows") + .limit(1).out("knows") + .limit(1).in("knows") + .limit(1).out("knows") + .limit(1).out("knows")); + } + + @Test + public void testTripleNestedRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(2).out("knows") + .repeat(__.limit(3).in("knows") + .repeat(__.limit(4).out("knows")) + .times(2)) + .times(2)) + .times(2), + s -> s.V().has("id", "l1-0") + .limit(2).out("knows") + .limit(3).in("knows") + .limit(4).out("knows") + .limit(4).out("knows") + .limit(3).in("knows") + .limit(4).out("knows") + .limit(4).out("knows") + .limit(2).out("knows") + .limit(3).in("knows") + .limit(4).out("knows") + .limit(4).out("knows") + .limit(3).in("knows") + .limit(4).out("knows") + .limit(4).out("knows")); + } + + @Test + public void testAggregateRepeatLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(1).out("knows").aggregate("x")) + .times(2) + .cap("x"), + s -> s.V().has("id", "l1-0") + .limit(1).out("knows").aggregate("x") + .limit(1).out("knows").aggregate("x") + .cap("x")); + } + + @Test + public void testAggregateRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .repeat(__.limit(3).out("knows").aggregate("x")) + .times(2) + .cap("x"), + s -> s.V().has("id", "l1-0") + .limit(3).out("knows").aggregate("x") + .limit(3).out("knows").aggregate("x") + .cap("x")); + } + + @Test + public void testUnionRepeatLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .union(out().limit(1), out().out().limit(1)) + .repeat(__.limit(1)).times(1), + s -> s.V().has("id", "l1-0") + .union(out().limit(1), out().out().limit(1)) + .limit(1)); + } + + @Test + public void testUnionRepeatLimitIncreasedLimit() { + testTraversals(s -> s.V().has("id", "l1-0") + .union(out().limit(1), out().out().limit(1)) + .repeat(__.limit(3)).times(1), + s -> s.V().has("id", "l1-0") + .union(out().limit(1), out().out().limit(1)) + .limit(3)); + } + + private List<?> toListAndPrint(String header, GraphTraversal<?, ?> t) { + System.out.println("=====" + header + "==================================="); + System.out.println(t); + List<?> list = t.toList(); + for (Object o : list) { + System.out.println(o); + } + return list; + } + + private void testTraversals(Function<GraphTraversalSource, GraphTraversal<Vertex, Vertex>> repeatFunction, + Function<GraphTraversalSource, GraphTraversal<Vertex, Vertex>> nonRepeatFunction) { + List<?> repeatTraversal = toListAndPrint("repeatTraversal", repeatFunction.apply(gSource)); + List<?> withComputerTraversal = toListAndPrint("withComputerTraversal", repeatFunction.apply(gComputerSource)); + List<?> nonRepeatTraversal = toListAndPrint("nonRepeatTraversal", nonRepeatFunction.apply(gSource)); + assertFalse(repeatTraversal.isEmpty()); + assertTrue(CollectionUtils.isEqualCollection(repeatTraversal, nonRepeatTraversal)); + // due to non-sequential processing of computer algorithm, can not assert equality but only size + assertEquals(repeatTraversal.size(), withComputerTraversal.size()); + } + + private static void load(GraphTraversalSource g) { + g.addV("node").property("id", "l1-0").iterate(); + + g.addV("node").property("id", "l2-0").iterate(); + g.addV("node").property("id", "l2-1").iterate(); + + g.addV("node").property("id", "l3-0").iterate(); + g.addV("node").property("id", "l3-1").iterate(); + g.addV("node").property("id", "l3-2").iterate(); + + g.addV("node").property("id", "l4-0").iterate(); + g.addV("node").property("id", "l4-1").iterate(); + g.addV("node").property("id", "l4-2").iterate(); + g.addV("node").property("id", "l4-3").iterate(); + + g.addV("node").property("id", "l5-0").iterate(); + g.addV("node").property("id", "l5-1").iterate(); + g.addV("node").property("id", "l5-2").iterate(); + g.addV("node").property("id", "l5-3").iterate(); + g.addV("node").property("id", "l5-4").iterate(); + + g.V().has("id", "l1-0").as("n1").V().has("id", "l2-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l1-0").as("n1").V().has("id", "l2-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l1-0").as("n1").V().has("id", "l2-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l1-0").as("n1").V().has("id", "l2-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l2-0").as("n1").V().has("id", "l3-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l2-1").as("n1").V().has("id", "l3-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-0").as("n1").V().has("id", "l4-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-1").as("n1").V().has("id", "l4-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l3-2").as("n1").V().has("id", "l4-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-0").as("n1").V().has("id", "l5-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-1").as("n1").V().has("id", "l5-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-2").as("n1").V().has("id", "l5-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l4-3").as("n1").V().has("id", "l5-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + + // Add layer 6 nodes + g.addV("node").property("id", "l6-0").iterate(); + g.addV("node").property("id", "l6-1").iterate(); + g.addV("node").property("id", "l6-2").iterate(); + g.addV("node").property("id", "l6-3").iterate(); + g.addV("node").property("id", "l6-4").iterate(); + g.addV("node").property("id", "l6-5").iterate(); + + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + + // Connect layer 5 to layer 6 with "friend" edges (same pattern) + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-0").as("n1").V().has("id", "l6-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-1").as("n1").V().has("id", "l6-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-2").as("n1").V().has("id", "l6-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-3").as("n1").V().has("id", "l6-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l5-4").as("n1").V().has("id", "l6-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + + // Add layer 7 nodes + g.addV("node").property("id", "l7-0").iterate(); + g.addV("node").property("id", "l7-1").iterate(); + g.addV("node").property("id", "l7-2").iterate(); + g.addV("node").property("id", "l7-3").iterate(); + g.addV("node").property("id", "l7-4").iterate(); + g.addV("node").property("id", "l7-5").iterate(); + g.addV("node").property("id", "l7-6").iterate(); + + // Connect layer 6 to layer 7 with "knows" edges + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-0").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-1").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-2").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-3").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-4").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-5").as("n2").addE("knows").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-6").as("n2").addE("knows").from("n1").to("n2").iterate(); + + // Connect layer 6 to layer 7 with "friend" edges + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-0").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-1").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-2").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-3").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-4").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-0").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-1").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-2").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-3").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-4").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-5").as("n2").addE("friend").from("n1").to("n2").iterate(); + g.V().has("id", "l6-5").as("n1").V().has("id", "l7-6").as("n2").addE("friend").from("n1").to("n2").iterate(); + } +}
