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

andreac pushed a commit to branch 3.8-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.8-dev by this push:
     new aea480543a Fix sample in repeat computer algorithm to retain sample 
size (#3273)
aea480543a is described below

commit aea480543a4de599c06575f144f138ea497842ec
Author: andreachild <[email protected]>
AuthorDate: Fri Nov 7 12:14:13 2025 -0800

    Fix sample in repeat computer algorithm to retain sample size (#3273)
    
    Fixed SampleGlobalStep computer algorithm to return the correct sample size 
when used in repeat by retaining only the traversers which have passed through 
all loops when merging traverser sets. Prior to this fix the traverser sets 
would be merged together and traversers which were excluded from the sample 
would potentially be added to the sample in the next loop.
---
 CHANGELOG.asciidoc                                 |  1 +
 .../traversal/step/filter/SampleGlobalStep.java    | 47 ++++++++++++--
 .../traversal/traverser/ProjectedTraverser.java    |  5 ++
 .../step/filter/SampleGlobalStepTest.java          | 72 +++++++++++++++++++++-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  4 ++
 gremlin-go/driver/cucumber/gremlin.go              |  4 ++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  4 ++
 gremlin-python/src/main/python/radish/gremlin.py   |  4 ++
 .../gremlin/test/features/filter/Sample.feature    | 38 ++++++++++++
 9 files changed, 172 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 7506380a30..e140262567 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -136,6 +136,7 @@ This release also includes changes from <<release-3-7-XXX, 
3.7.XXX>>.
 * Modified `RepeatUnrollStrategy` to use a more conservative approach, only 
unrolling repeat loops containing safe navigation and filtering steps.
 * Modified `limit()`, `skip()`, range()` in `repeat()` to track per-iteration 
counters.
 * Moved `Traverser` loop logic into new interface `NL_SL_Traverser` and 
changed loop-supporting `Traverser`s to extend the common interface.
+* Fixed `sample()` in `repeat()` computer algorithm to retain the configured 
sample size per loop
 
 == TinkerPop 3.7.0 (Gremfir Master of the Pan Flute)
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
index fbc3e8d66b..c6f9a50d74 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
@@ -18,6 +18,14 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
 
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Set;
+import java.util.function.BinaryOperator;
+import org.apache.tinkerpop.gremlin.process.computer.MemoryComputeKey;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.lambda.ConstantTraversal;
@@ -32,12 +40,6 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.util.TraversalProduct;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-import java.util.Set;
-
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
@@ -47,6 +49,7 @@ public final class SampleGlobalStep<S> extends 
CollectingBarrierStep<S> implemen
     private Traversal.Admin<S, Number> probabilityTraversal = new 
ConstantTraversal<>(1.0d);;
     private final int amountToSample;
     private final Random random = new Random();
+    private final SampleGlobalStep.SampleBiOperator<S> traverserReducer = new 
SampleBiOperator<>();
 
     public SampleGlobalStep(final Traversal.Admin traversal, final int 
amountToSample) {
         super(traversal);
@@ -135,7 +138,39 @@ public final class SampleGlobalStep<S> extends 
CollectingBarrierStep<S> implemen
         traverserSet.addAll(sampledSet);
     }
 
+    @Override
+    public MemoryComputeKey<TraverserSet<S>> getMemoryComputeKey() {
+        return MemoryComputeKey.of(this.getId(), traverserReducer, false, 
true);
+    }
+    
+    public static final class SampleBiOperator<S> implements 
BinaryOperator<TraverserSet<S>>, Serializable {
+        @Override
+        public TraverserSet<S> apply(final TraverserSet<S> setA, final 
TraverserSet<S> setB) {
+            int maxLoops = -1;
+            // if the traversers have gone through loops, only retain the ones 
that have passed through the most loops
+            // if there are no loops, all traversers are retained
+            final TraverserSet<S> result = new TraverserSet<>();
+            maxLoops = processTraverserSet(setA, maxLoops, result);
+            processTraverserSet(setB, maxLoops, result);
+            return result;
+        }
 
+        private static <S> int processTraverserSet(final TraverserSet<S> 
traverserSet, final int currentMaxLoops, final TraverserSet<S> result) {
+            int max = currentMaxLoops;
+            for (final Traverser.Admin<S> traverser : traverserSet) {
+                final int loops = traverser.getLoopNames().isEmpty() ? 0 : 
traverser.loops();
+                if (loops > max) {
+                    max = loops;
+                    result.clear();
+                    result.add(traverser);
+                } else if (loops == max) {
+                    result.add(traverser);
+                }
+            }
+            return max;
+        }
+    }
+    
     private Optional<ProjectedTraverser<S, Number>> 
createProjectedTraverser(final Traverser.Admin<S> traverser) {
         final TraversalProduct product = TraversalUtil.produce(traverser, 
this.probabilityTraversal);
         if (product.isProductive()) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
index 7cef844979..10ed1c55a0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/ProjectedTraverser.java
@@ -176,6 +176,11 @@ public final class ProjectedTraverser<T, P> implements 
Traverser.Admin<T> {
         return this.baseTraverser.loops(loopName);
     }
 
+    @Override
+    public Set<String> getLoopNames() {
+        return this.baseTraverser.getLoopNames();
+    }
+
     @Override
     public long bulk() {
         return this.baseTraverser.bulk();
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStepTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStepTest.java
index eebea0a40f..2698cace97 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStepTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStepTest.java
@@ -18,26 +18,48 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.filter;
 
-import org.apache.tinkerpop.gremlin.process.traversal.Scope;
+import java.util.stream.Collectors;
+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.dsl.graph.__;
 import org.apache.tinkerpop.gremlin.process.traversal.step.StepTest;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.B_NL_O_S_SE_SL_Traverser;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.B_O_S_SE_SL_Traverser;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
 import org.apache.tinkerpop.gremlin.structure.T;
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
 public class SampleGlobalStepTest extends StepTest {
 
+    @Rule
+    public MockitoRule mockitoRule = MockitoJUnit.rule();
+    @Mock
+    protected Step<String, ?> mockStep;
+
+    @Before
+    public void setup() {
+        when(mockStep.getTraversal()).thenReturn(EmptyTraversal.instance());
+    }
+    
     @Override
     protected List<Traversal> getTraversals() {
         return Arrays.asList(
@@ -65,4 +87,52 @@ public class SampleGlobalStepTest extends StepTest {
     public void shouldThrowForMultipleByModulators() {
         __.V().sample(1).by("age").by(T.id);
     }
+
+    @Test
+    public void testSampleBiOperatorCombinesTraverserSetsWithLoops() {
+        final SampleGlobalStep.SampleBiOperator<String> operator = new 
SampleGlobalStep.SampleBiOperator<>();
+
+        final TraverserSet<String> setA = new TraverserSet<>();
+        setA.add(createTraverser("a", 1));
+        setA.add(createTraverser("b", 2));
+
+        final TraverserSet<String> setB = new TraverserSet<>();
+        setB.add(createTraverser("c", 2));
+        setB.add(createTraverser("d", 1));
+        setB.add(createTraverser("e", 2));
+        setB.add(createTraverser("f", 0));
+
+        final TraverserSet<String> result = operator.apply(setA, setB);
+        assertEquals(3, result.size());
+        
assertTrue(result.stream().map(Traverser::get).collect(Collectors.toList()).containsAll(List.of("b",
 "c", "e")));
+    }
+
+    @Test
+    public void testSampleBiOperatorCombinesTraverserSetsWithoutLoops() {
+        final SampleGlobalStep.SampleBiOperator<String> operator = new 
SampleGlobalStep.SampleBiOperator<>();
+
+        final TraverserSet<String> setA = new TraverserSet<>();
+        setA.add(createTraverser("a", 0));
+        setA.add(createTraverser("b", 0));
+
+        final TraverserSet<String> setB = new TraverserSet<>();
+        setB.add(createTraverser("c", 0));
+
+        final TraverserSet<String> result = operator.apply(setA, setB);
+        assertEquals(3, result.size());
+        
assertTrue(result.stream().map(Traverser::get).collect(Collectors.toList()).containsAll(List.of("a",
 "b", "c")));
+    }
+    
+    private B_O_S_SE_SL_Traverser.Admin<String> createTraverser(final String 
str, final int loops) {
+        final Traverser.Admin<String> traverser = new 
B_NL_O_S_SE_SL_Traverser<>(str, mockStep, 1).asAdmin();
+        if (loops > 0) {
+            traverser.initialiseLoops("repeatStep1", null);
+            for (int i = 0; i < loops; i++) {
+                traverser.incrLoops();
+            }
+        }
+        return traverser;
+    }
+    
+    
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index cfe8d03945..d575eb7c64 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -592,6 +592,10 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_withStrategiesXSeedStrategyX_V_group_byXlabelX_byXbothE_weight_order_fold_sampleXlocal_5XXunfold",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new SeedStrategy(seed: 999999)).V().Group<object, 
object>().By(T.Label).By(__.BothE().Values<object>("weight").Order().Fold().Sample(Scope.Local,
 5)).Unfold<object>()}}, 
                
{"g_withStrategiesXSeedStrategyX_V_order_byXlabel_descX_sampleX1X_byXageX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.WithStrategies(new SeedStrategy(seed: 
999999)).V().Order().By(T.Label, Order.Desc).Sample(1).By("age")}}, 
                {"g_VX1X_valuesXageX_sampleXlocal_5X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V(p["vid1"]).Values<object>("age").Sample(Scope.Local, 5)}}, 
+               {"g_V_repeatXsampleX2XX_timesX2X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Repeat(__.Sample(2)).Times(2)}}, 
+               {"g_V_sampleX2X_sampleX2X", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Sample(2).Sample(2)}}, 
+               
{"g_V3_repeatXout_order_byXperformancesX_sampleX2X_aggregateXxXX_untilXloops_isX2XX_capXxX_unfold",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V(p["vid3"]).Repeat(__.Out().Order().By("performances").Sample(2).Aggregate("x")).Until(__.Loops().Is(2)).Cap<object>("x").Unfold<object>()}},
 
+               
{"g_V3_out_order_byXperformancesX_sampleX2X_aggregateXxX_out_order_byXperformancesX_sampleX2X_aggregateXxX_capXxX_unfold",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V(p["vid3"]).Out().Order().By("performances").Sample(2).Aggregate("x").Out().Order().By("performances").Sample(2).Aggregate("x").Cap<object>("x").Unfold<object>()}},
 
                {"g_VX1X_outXcreatedX_inXcreatedX_simplePath", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V(p["vid1"]).Out("created").In("created").SimplePath()}}, 
                {"g_V_repeatXboth_simplePathX_timesX3X_path", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Repeat(__.Both().SimplePath()).Times(3).Path()}}, 
                
{"g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.V().As("a").Out().As("b").Out().As("c").SimplePath().By(T.Label).From("b").To("c").Path().By("name")}},
 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 63119f6df3..19fa18dbe8 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -562,6 +562,10 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     
"g_withStrategiesXSeedStrategyX_V_group_byXlabelX_byXbothE_weight_order_fold_sampleXlocal_5XXunfold":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.SeedStrategy(gremlingo.SeedStrategyConfig{Seed: 
999999})).V().Group().By(gremlingo.T.Label).By(gremlingo.T__.BothE().Values("weight").Order().Fold().Sample(gremlingo.Scope.Local,
 5)).Unfold()}}, 
     "g_withStrategiesXSeedStrategyX_V_order_byXlabel_descX_sampleX1X_byXageX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.WithStrategies(gremlingo.SeedStrategy(gremlingo.SeedStrategyConfig{Seed: 
999999})).V().Order().By(gremlingo.T.Label, 
gremlingo.Order.Desc).Sample(1).By("age")}}, 
     "g_VX1X_valuesXageX_sampleXlocal_5X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).Values("age").Sample(gremlingo.Scope.Local, 5)}}, 
+    "g_V_repeatXsampleX2XX_timesX2X": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Repeat(gremlingo.T__.Sample(2)).Times(2)}}, 
+    "g_V_sampleX2X_sampleX2X": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Sample(2).Sample(2)}}, 
+    
"g_V3_repeatXout_order_byXperformancesX_sampleX2X_aggregateXxXX_untilXloops_isX2XX_capXxX_unfold":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid3"]).Repeat(gremlingo.T__.Out().Order().By("performances").Sample(2).Aggregate("x")).Until(gremlingo.T__.Loops().Is(2)).Cap("x").Unfold()}},
 
+    
"g_V3_out_order_byXperformancesX_sampleX2X_aggregateXxX_out_order_byXperformancesX_sampleX2X_aggregateXxX_capXxX_unfold":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid3"]).Out().Order().By("performances").Sample(2).Aggregate("x").Out().Order().By("performances").Sample(2).Aggregate("x").Cap("x").Unfold()}},
 
     "g_VX1X_outXcreatedX_inXcreatedX_simplePath": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V(p["vid1"]).Out("created").In("created").SimplePath()}}, 
     "g_V_repeatXboth_simplePathX_timesX3X_path": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Repeat(gremlingo.T__.Both().SimplePath()).Times(3).Path()}}, 
     
"g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().As("a").Out().As("b").Out().As("c").SimplePath().By(gremlingo.T.Label).From("b").To("c").Path().By("name")}},
 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 5e0fc66f47..e022c7e336 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -593,6 +593,10 @@ const gremlins = {
     
g_withStrategiesXSeedStrategyX_V_group_byXlabelX_byXbothE_weight_order_fold_sampleXlocal_5XXunfold:
 [function({g}) { return g.withStrategies(new SeedStrategy({seed: 
999999})).V().group().by(T.label).by(__.bothE().values("weight").order().fold().sample(Scope.local,
 5)).unfold() }], 
     g_withStrategiesXSeedStrategyX_V_order_byXlabel_descX_sampleX1X_byXageX: 
[function({g}) { return g.withStrategies(new SeedStrategy({seed: 
999999})).V().order().by(T.label, Order.desc).sample(1).by("age") }], 
     g_VX1X_valuesXageX_sampleXlocal_5X: [function({g, vid1}) { return 
g.V(vid1).values("age").sample(Scope.local, 5) }], 
+    g_V_repeatXsampleX2XX_timesX2X: [function({g}) { return 
g.V().repeat(__.sample(2)).times(2) }], 
+    g_V_sampleX2X_sampleX2X: [function({g}) { return g.V().sample(2).sample(2) 
}], 
+    
g_V3_repeatXout_order_byXperformancesX_sampleX2X_aggregateXxXX_untilXloops_isX2XX_capXxX_unfold:
 [function({g, vid3}) { return 
g.V(vid3).repeat(__.out().order().by("performances").sample(2).aggregate("x")).until(__.loops().is(2)).cap("x").unfold()
 }], 
+    
g_V3_out_order_byXperformancesX_sampleX2X_aggregateXxX_out_order_byXperformancesX_sampleX2X_aggregateXxX_capXxX_unfold:
 [function({g, vid3}) { return 
g.V(vid3).out().order().by("performances").sample(2).aggregate("x").out().order().by("performances").sample(2).aggregate("x").cap("x").unfold()
 }], 
     g_VX1X_outXcreatedX_inXcreatedX_simplePath: [function({g, vid1}) { return 
g.V(vid1).out("created").in_("created").simplePath() }], 
     g_V_repeatXboth_simplePathX_timesX3X_path: [function({g}) { return 
g.V().repeat(__.both().simplePath()).times(3).path() }], 
     
g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX: 
[function({g}) { return 
g.V().as("a").out().as("b").out().as("c").simplePath().by(T.label).from_("b").to("c").path().by("name")
 }], 
diff --git a/gremlin-python/src/main/python/radish/gremlin.py 
b/gremlin-python/src/main/python/radish/gremlin.py
index f371334d8f..bd7cf96d74 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -565,6 +565,10 @@ world.gremlins = {
     
'g_withStrategiesXSeedStrategyX_V_group_byXlabelX_byXbothE_weight_order_fold_sampleXlocal_5XXunfold':
 [(lambda 
g:g.with_strategies(SeedStrategy(seed=999999)).V().group().by(T.label).by(__.both_e().values('weight').order().fold().sample(Scope.local,
 5)).unfold())], 
     'g_withStrategiesXSeedStrategyX_V_order_byXlabel_descX_sampleX1X_byXageX': 
[(lambda g:g.with_strategies(SeedStrategy(seed=999999)).V().order().by(T.label, 
Order.desc).sample(1).by('age'))], 
     'g_VX1X_valuesXageX_sampleXlocal_5X': [(lambda g, 
vid1=None:g.V(vid1).values('age').sample(Scope.local, 5))], 
+    'g_V_repeatXsampleX2XX_timesX2X': [(lambda 
g:g.V().repeat(__.sample(2)).times(2))], 
+    'g_V_sampleX2X_sampleX2X': [(lambda g:g.V().sample(2).sample(2))], 
+    
'g_V3_repeatXout_order_byXperformancesX_sampleX2X_aggregateXxXX_untilXloops_isX2XX_capXxX_unfold':
 [(lambda g, 
vid3=None:g.V(vid3).repeat(__.out().order().by('performances').sample(2).aggregate('x')).until(__.loops().is_(2)).cap('x').unfold())],
 
+    
'g_V3_out_order_byXperformancesX_sampleX2X_aggregateXxX_out_order_byXperformancesX_sampleX2X_aggregateXxX_capXxX_unfold':
 [(lambda g, 
vid3=None:g.V(vid3).out().order().by('performances').sample(2).aggregate('x').out().order().by('performances').sample(2).aggregate('x').cap('x').unfold())],
 
     'g_VX1X_outXcreatedX_inXcreatedX_simplePath': [(lambda g, 
vid1=None:g.V(vid1).out('created').in_('created').simple_path())], 
     'g_V_repeatXboth_simplePathX_timesX3X_path': [(lambda 
g:g.V().repeat(__.both().simple_path()).times(3).path())], 
     
'g_V_asXaX_out_asXbX_out_asXcX_simplePath_byXlabelX_fromXbX_toXcX_path_byXnameX':
 [(lambda 
g:g.V().as_('a').out().as_('b').out().as_('c').simple_path().by(T.label).from_('b').to('c').path().by('name'))],
 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Sample.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Sample.feature
index 3706652ae7..f9b3bcd21f 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Sample.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/filter/Sample.feature
@@ -107,3 +107,41 @@ Feature: Step - sample()
     Then the result should be unordered
       | result |
       | d[29].i |
+
+  Scenario: g_V_repeatXsampleX2XX_timesX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().repeat(sample(2)).times(2)
+      """
+    When iterated to list
+    Then the result should have a count of 2
+
+  Scenario: g_V_sampleX2X_sampleX2X
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().sample(2).sample(2)
+      """
+    When iterated to list
+    Then the result should have a count of 2
+
+  Scenario: 
g_V3_repeatXout_order_byXperformancesX_sampleX2X_aggregateXxXX_untilXloops_isX2XX_capXxX_unfold
+    Given the grateful graph
+    And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+    And the traversal of
+      """
+      
g.V(vid3).repeat(__.out().order().by("performances").sample(2).aggregate('x')).until(__.loops().is(2)).cap('x').unfold()
+      """
+    When iterated to list
+    Then the result should have a count of 4
+
+  Scenario: 
g_V3_out_order_byXperformancesX_sampleX2X_aggregateXxX_out_order_byXperformancesX_sampleX2X_aggregateXxX_capXxX_unfold
+    Given the grateful graph
+    And using the parameter vid3 defined as "v[NOT FADE AWAY].id"
+    And the traversal of
+      """
+      
g.V(vid3).out().order().by("performances").sample(2).aggregate('x').out().order().by("performances").sample(2).aggregate('x').cap('x').unfold()
+      """
+    When iterated to list
+    Then the result should have a count of 4
\ No newline at end of file

Reply via email to