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 <[email protected]> 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
