You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2023/07/06 17:22:07 UTC
[tinkerpop] branch TINKERPOP-2965 created (now 9fc263727a)
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a change to branch TINKERPOP-2965
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
at 9fc263727a TINKERPOP-2965 Fixed bug in FilterRankingStrategy
This branch includes the following new commits:
new 9fc263727a TINKERPOP-2965 Fixed bug in FilterRankingStrategy
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[tinkerpop] 01/01: TINKERPOP-2965 Fixed bug in FilterRankingStrategy
Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch TINKERPOP-2965
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 9fc263727a745aa9e3110343a58fcdb213115e3e
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Jul 6 13:19:48 2023 -0400
TINKERPOP-2965 Fixed bug in FilterRankingStrategy
This problem showed up in 3.5.6/3.6.3 after TINKERPOP-2919 which improved performance. The changes failed to properly propogate labels up from child traversals into the TraversalParent cache it created. As a result, labels started shifting around when they shouldn't have.
---
CHANGELOG.asciidoc | 3 +-
.../optimization/FilterRankingStrategy.java | 33 +++++++++----
.../process/traversal/util/DepthComparator.java | 54 ++++++++++++++++++++++
.../process/traversal/util/TraversalHelper.java | 35 ++++++++++++++
.../traversal/util/TraversalHelperTest.java | 43 ++++++++++++++++-
.../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs | 2 +
gremlin-go/driver/cucumber/gremlin.go | 2 +
.../gremlin-javascript/test/cucumber/gremlin.js | 2 +
gremlin-python/src/main/python/radish/gremlin.py | 2 +
gremlin-test/features/filter/Where.feature | 36 +++++++++++++++
10 files changed, 200 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 6225ef9b79..66d77bf20a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -28,7 +28,8 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
* Added `gremlin.spark.dontDeleteNonEmptyOutput` to stop deleting the output folder if it is not empty in `spark-gremlin`.
* Upgraded `gremlin-javascript` and `gremlint` to Node 16.20.0.
* Upgraded `gremlin-go` to Go 1.20.
-* Improved the python Translator class
+* Improved the python Translator class.
+* Fixed bug in `FilterRankingStrategy` that was preventing certain traversals from recognizing labels in child traversals.
* Added `gremlin-java8.bat` file as a workaround to allow loading the console using Java 8 on Windows.
* Fixed a bug in `gremlin-server` where timeout tasks were not cancelled and could cause very large memory usage when timeout is large.
* Removed `jcabi-manifests` dependency from `gremlin-core`, `gremlin-driver`, and `gremlin-server`.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
index 65723a2894..9ebfeb7ed8 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/FilterRankingStrategy.java
@@ -38,17 +38,15 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.filter.WhereTraversal
import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Graph;
import org.javatuples.Pair;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
@@ -83,20 +81,37 @@ public final class FilterRankingStrategy extends AbstractTraversalStrategy<Trave
// traversals. This little cache keeps the effective data of that function which is if there is a
// lambda in the children and the set of scope keys. note that the lambda sorta trumps the labels in
// that if there is a lambda there's no real point to doing any sort of eval of the labels.
+ //
+ // this cache holds the parent and a pair. the first item in the pair is a boolean which is true if
+ // lambda is present and false otherwise. the second item in the pair is a set of labels from any
+ // Scoping steps
final Map<TraversalParent, Pair<Boolean, Set<String>>> traversalParentCache = new HashMap<>();
final Map<Step, Integer> stepRanking = new HashMap<>();
- // build up the little cache
+ // gather the parents and their Scoping/LambdaHolder steps to build up the cache. since the traversal is
+ // processed in depth first manner, the entries gathered to m are deepest child first and held in order,
+ // so that the cache can be constructed with parent's knowing their children were processed first
final Map<TraversalParent, List<Step<?,?>>> m =
- TraversalHelper.getStepsOfAssignableClassRecursively(traversal, Scoping.class, LambdaHolder.class).stream().
- collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent()));
+ TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, TraversalParent.class).stream().
+ collect(Collectors.groupingBy(step -> ((Step) step).getTraversal().getParent(), LinkedHashMap::new, Collectors.toList()));
+
+ // build the cache and use it to detect if any children impact the Pair in any way. in the case of a
+ // child with a lambda, the parent would simply inherit that true. in the case of additional labels they
+ // would just be appended to the list for the parent.
m.forEach((k, v) -> {
- final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder);
+ final boolean hasLambda = v.stream().anyMatch(s -> s instanceof LambdaHolder ||
+ (traversalParentCache.containsKey(s) && traversalParentCache.get(s).getValue0()));
if (hasLambda) {
traversalParentCache.put(k, Pair.with(true, Collections.emptySet()));
} else {
- traversalParentCache.put(k, Pair.with(false, v.stream().filter(s -> s instanceof Scoping).
- flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet())));
+ final Set<String> currentEntryScopeLabels = v.stream().filter(s -> s instanceof Scoping).
+ flatMap(s -> ((Scoping) s).getScopeKeys().stream()).collect(Collectors.toSet());
+ final Set<String> allScopeLabels = new HashSet<>(currentEntryScopeLabels);
+ v.stream().filter(traversalParentCache::containsKey).forEach(s -> {
+ final TraversalParent parent = (TraversalParent) s;
+ allScopeLabels.addAll(traversalParentCache.get(parent).getValue1());
+ });
+ traversalParentCache.put(k, Pair.with(false, allScopeLabels));
}
});
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
new file mode 100644
index 0000000000..915379c9d3
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/DepthComparator.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.util;
+
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
+
+import java.util.Comparator;
+
+/**
+ * A {@code Comparator} that compares steps on the depth of the traversal that they are in.
+ */
+public final class DepthComparator implements Comparator<Step<?,?>> {
+
+ private static final DepthComparator instance = new DepthComparator();
+
+ private DepthComparator() {}
+
+ public static DepthComparator instance() {
+ return instance;
+ }
+
+ @Override
+ public int compare(final Step<?, ?> step1, final Step<?, ?> step2) {
+ return getDepth(step2) - getDepth(step1);
+ }
+
+ private int getDepth(final Step<?,?> step) {
+ if (step == null)
+ return 0;
+ int depth = 0;
+ if (!(step instanceof EmptyStep)) {
+ final Step<?,?> parent = (Step) step.getTraversal().getParent();
+ depth = Math.max(depth, getDepth(parent) + 1);
+ }
+ return depth;
+ }
+}
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
index 9625a56174..19117d6e9a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelper.java
@@ -54,14 +54,17 @@ import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.Stack;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -313,6 +316,38 @@ public final class TraversalHelper {
return list;
}
+ /**
+ * Get steps of the specified classes throughout the traversal, collecting them in a fashion that orders them
+ * from the deepest steps first.
+ */
+ public static List<Step<?,?>> getStepsOfAssignableClassRecursivelyFromDepth(final Traversal.Admin<?, ?> traversal, final Class<?>... stepClasses) {
+ final List<Step<?,?>> list = new ArrayList<>();
+ final Stack<Step<?,?>> stack = new Stack<>();
+
+ traversal.getSteps().forEach(stack::push);
+
+ while (!stack.isEmpty()) {
+ final Step<?,?> current = stack.pop();
+ list.add(current);
+
+ if (current instanceof TraversalParent) {
+ ((TraversalParent) current).getLocalChildren().forEach(localChild -> localChild.getSteps().forEach(stack::push));
+ ((TraversalParent) current).getGlobalChildren().forEach(globalChild -> globalChild.getSteps().forEach(stack::push));
+ }
+ }
+
+ // sort by depth
+ list.sort(DepthComparator.instance());
+
+ return list.stream().filter(s -> {
+ for (Class<?> stepClass : stepClasses) {
+ if (stepClass.isAssignableFrom(s.getClass()))
+ return true;
+ }
+ return false;
+ }).collect(Collectors.toList());
+ }
+
public static boolean isGlobalChild(Traversal.Admin<?, ?> traversal) {
while (!(traversal.isRoot())) {
if (traversal.getParent().getLocalChildren().contains(traversal))
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
index 5e277ad3cf..c7884451ac 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/util/TraversalHelperTest.java
@@ -41,8 +41,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.IdentityStep;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
-import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
import org.apache.tinkerpop.gremlin.structure.PropertyType;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
@@ -446,4 +444,45 @@ public class TraversalHelperTest {
assertEquals(3, steps.stream().filter(s -> s instanceof VertexStep).count());
assertEquals(1, steps.stream().filter(s -> s instanceof FoldStep).count());
}
+
+ @Test
+ public void shouldGetStepsOfAssignableClassRecursivelyFromDepthNoTypes() {
+ final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+ final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal);
+ assertEquals(0, steps.size());
+ }
+
+ @Test
+ public void shouldGetStepsOfAssignableClassRecursivelyFromDepthOneType() {
+ final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+ final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, VertexStep.class);
+ assertEquals(3, steps.size());
+ assertThat(steps.stream().allMatch(s -> s instanceof VertexStep), is(true));
+ }
+
+ @Test
+ public void shouldGetStepsOfAssignableClassRecursivelyFromDepthMultipleTypes() {
+ final Traversal.Admin<?,?> traversal = __.V().repeat(__.out()).project("x").by(out().in().fold()).asAdmin();
+ final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, VertexStep.class, FoldStep.class);
+ assertEquals(4, steps.size());
+ assertEquals(3, steps.stream().filter(s -> s instanceof VertexStep).count());
+ assertEquals(1, steps.stream().filter(s -> s instanceof FoldStep).count());
+ }
+
+ @Test
+ public void shouldGetStepsOfAssignableClassRecursivelyFromDepthEnsureOrder() {
+ final Traversal.Admin<?,?> traversal = __.V().union(
+ __.union(__.values("a"),
+ __.union(__.values("b"), __.union(__.values("c"))),
+ __.values("d")),
+ __.values("e")).values("f").asAdmin();
+ final List<Step<?,?>> steps = TraversalHelper.getStepsOfAssignableClassRecursivelyFromDepth(traversal, PropertiesStep.class);
+ assertEquals(6, steps.size());
+ assertEquals("c", ((PropertiesStep) steps.get(0)).getPropertyKeys()[0]);
+ assertEquals("b", ((PropertiesStep) steps.get(1)).getPropertyKeys()[0]);
+ assertEquals("d", ((PropertiesStep) steps.get(2)).getPropertyKeys()[0]);
+ assertEquals("a", ((PropertiesStep) steps.get(3)).getPropertyKeys()[0]);
+ assertEquals("e", ((PropertiesStep) steps.get(4)).getPropertyKeys()[0]);
+ assertEquals("f", ((PropertiesStep) steps.get(5)).getPropertyKeys()[0]);
+ }
}
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 5929439eb7..030deae2a4 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -333,6 +333,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
{"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a",P.Lt("b").Or(P.Gt("c")).And(P.Neq("d"))).By("age").By("weight").By(__.In("created").Values<object>("age").Min<object>()).Select<object>("a","c [...]
{"g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid1"]).As("a").Out().Has("age").Where(P.Gt("a")).By("age").Values<object>("name")}},
{"g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V(p["vid3"]).As("a").In().Out().As("b").Where("a",P.Eq("b")).By("age").Values<object>("name")}},
+ {"g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.HasLabel("software"),__.HasLabel("person"))).Select<object>("n").By("name")}},
+ {"g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().As("n").Where(__.Or(__.Select<object>("n").HasLabel("software"),__.Select<object>("n").HasLabel("person"))).Select<object>("n").By("name")}},
{"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age [...]
{"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","j [...]
{"g_V_outE_propertyXweight_nullX", new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV("person").Property(T.Id,1).Property("name","marko").Property("age",29).As("marko").AddV("person").Property(T.Id,2).Property("name","vadas").Property("age",27).As("vadas").AddV("software").Property(T.Id,3).Property("name","lop").Property("lang","java").As("lop").AddV("person").Property(T.Id,4).Property("name","josh").Property("age",32).As("josh"). [...]
diff --git a/gremlin-go/driver/cucumber/gremlin.go b/gremlin-go/driver/cucumber/gremlin.go
index 24877ae13f..a6ddf27eca 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -304,6 +304,8 @@ var translationMap = map[string][]func(g *gremlingo.GraphTraversalSource, p map[
"g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("a").OutE("created").As("b").InV().As("c").In("created").As("d").Where("a", gremlingo.P.Lt("b").Or(gremlingo.P.Gt("c")).And(gremlingo.P.Neq("d"))).By("age").By("weight").By(gremlingo.T__.In("created").Values("age"). [...]
"g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid1"]).As("a").Out().Has("age").Where(gremlingo.P.Gt("a")).By("age").Values("name")}},
"g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V(p["vid3"]).As("a").In().Out().As("b").Where("a", gremlingo.P.Eq("b")).By("age").Values("name")}},
+ "g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.HasLabel("software"), gremlingo.T__.HasLabel("person"))).Select("n").By("name")}},
+ "g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.V().As("n").Where(gremlingo.T__.Or(gremlingo.T__.Select("n").HasLabel("software"), gremlingo.T__.Select("n").HasLabel("person"))).Select("n").By("name")}},
"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property(grem [...]
"g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("per [...]
"g_V_outE_propertyXweight_nullX": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person").Property(gremlingo.T.Id, 1).Property("name", "marko").Property("age", 29).As("marko").AddV("person").Property(gremlingo.T.Id, 2).Property("name", "vadas").Property("age", 27).As("vadas").AddV("software").Property(gremlingo.T.Id, 3).Property("name", "lop").Property("lang", "java").As("lop").AddV("person").Property(gremlingo.T.Id, 4).Pr [...]
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 680ce38e25..2dd768ef17 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
@@ -321,6 +321,8 @@ const gremlins = {
g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX: [function({g}) { return g.V().as("a").outE("created").as("b").inV().as("c").in_("created").as("d").where("a",P.lt("b").or(P.gt("c")).and(P.neq("d"))).by("age").by("weight").by(__.in_("created").values("age").min()).select("a","c","d").by("name") }],
g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name: [function({g, vid1}) { return g.V(vid1).as("a").out().has("age").where(P.gt("a")).by("age").values("name") }],
g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name: [function({g, vid3}) { return g.V(vid3).as("a").in_().out().as("b").where("a",P.eq("b")).by("age").values("name") }],
+ g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX: [function({g}) { return g.V().as("n").where(__.or(__.hasLabel("software"),__.hasLabel("person"))).select("n").by("name") }],
+ g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX: [function({g}) { return g.V().as("n").where(__.or(__.select("n").hasLabel("software"),__.select("n").hasLabel("person"))).select("n").by("name") }],
g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","rip [...]
g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X: [function({g, vid1}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).p [...]
g_V_outE_propertyXweight_nullX: [function({g}) { return g.addV("person").property(T.id,1).property("name","marko").property("age",29).as("marko").addV("person").property(T.id,2).property("name","vadas").property("age",27).as("vadas").addV("software").property(T.id,3).property("name","lop").property("lang","java").as("lop").addV("person").property(T.id,4).property("name","josh").property("age",32).as("josh").addV("software").property(T.id,5).property("name","ripple").property("lang"," [...]
diff --git a/gremlin-python/src/main/python/radish/gremlin.py b/gremlin-python/src/main/python/radish/gremlin.py
index 6397b767ab..a57daf0582 100644
--- a/gremlin-python/src/main/python/radish/gremlin.py
+++ b/gremlin-python/src/main/python/radish/gremlin.py
@@ -306,6 +306,8 @@ world.gremlins = {
'g_V_asXaX_outEXcreatedX_asXbX_inV_asXcX_inXcreatedX_asXdX_whereXa_ltXbX_orXgtXcXX_andXneqXdXXX_byXageX_byXweightX_byXinXcreatedX_valuesXageX_minX_selectXa_c_dX': [(lambda g:g.V().as_('a').outE('created').as_('b').inV().as_('c').in_('created').as_('d').where('a',P.lt('b').or_(P.gt('c')).and_(P.neq('d'))).by('age').by('weight').by(__.in_('created').age.min_()).select('a','c','d').by('name'))],
'g_VX1X_asXaX_out_hasXageX_whereXgtXaXX_byXageX_name': [(lambda g, vid1=None:g.V(vid1).as_('a').out().has('age').where(P.gt('a')).by('age').name)],
'g_VX3X_asXaX_in_out_asXbX_whereXa_eqXbXX_byXageX_name': [(lambda g, vid3=None:g.V(vid3).as_('a').in_().out().as_('b').where('a',P.eq('b')).by('age').name)],
+ 'g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX': [(lambda g:g.V().as_('n').where(__.or_(__.hasLabel('software'),__.hasLabel('person'))).select('n').by('name'))],
+ 'g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX': [(lambda g:g.V().as_('n').where(__.or_(__.select('n').hasLabel('software'),__.select('n').hasLabel('person'))).select('n').by('name'))],
'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX': [(lambda g, vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name',' [...]
'g_VX1X_asXaX_outXcreatedX_addEXcreatedByX_toXaX_propertyXweight_2X': [(lambda g, vid1=None:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5 [...]
'g_V_outE_propertyXweight_nullX': [(lambda g:g.addV('person').property(T.id_,1).property('name','marko').property('age',29).as_('marko').addV('person').property(T.id_,2).property('name','vadas').property('age',27).as_('vadas').addV('software').property(T.id_,3).property('name','lop').property('lang','java').as_('lop').addV('person').property(T.id_,4).property('name','josh').property('age',32).as_('josh').addV('software').property(T.id_,5).property('name','ripple').property('lang','ja [...]
diff --git a/gremlin-test/features/filter/Where.feature b/gremlin-test/features/filter/Where.feature
index f4e8f9be82..4a68b5a873 100644
--- a/gremlin-test/features/filter/Where.feature
+++ b/gremlin-test/features/filter/Where.feature
@@ -338,4 +338,40 @@ Feature: Step - where()
| lop |
| lop |
| lop |
+ | ripple |
+
+ Scenario: g_V_asXnX_whereXorXhasLabelXsoftwareX_hasLabelXpersonXXX_selectXnX_byXnameX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().as("n").where(
+ __.or(__.hasLabel("software"), __.hasLabel("person"))
+ ).select("n").by("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+ | vadas |
+ | josh |
+ | peter |
+ | lop |
+ | ripple |
+
+ Scenario: g_V_asXnX_whereXorXselectXnX_hasLabelXsoftwareX_selectXnX_hasLabelXpersonXXX_selectXnX_byXnameX
+ Given the modern graph
+ And the traversal of
+ """
+ g.V().as("n").
+ where(__.or(__.select("n").hasLabel("software"), __.select("n").hasLabel("person"))).
+ select("n").by("name")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | marko |
+ | vadas |
+ | josh |
+ | peter |
+ | lop |
| ripple |
\ No newline at end of file