TINKERPOP-1628 Implemented TraversalSelectStep
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/c135da6e Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/c135da6e Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/c135da6e Branch: refs/heads/TINKERPOP-1447 Commit: c135da6ee3d428c633ddf8a11c6faecc92848c08 Parents: 8005cb3 Author: Daniel Kuppitz <daniel_kupp...@hotmail.com> Authored: Thu Apr 19 18:06:02 2018 -0700 Committer: Daniel Kuppitz <daniel_kupp...@hotmail.com> Committed: Wed Apr 25 16:19:21 2018 -0700 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + docs/src/recipes/shortest-path.asciidoc | 39 +++++ docs/src/reference/the-traversal.asciidoc | 18 +++ .../traversal/dsl/graph/GraphTraversal.java | 30 ++++ .../gremlin/process/traversal/dsl/graph/__.java | 14 ++ .../traversal/step/map/TraversalSelectStep.java | 157 +++++++++++++++++++ .../Process/Traversal/GraphTraversal.cs | 18 +++ .../src/Gremlin.Net/Process/Traversal/__.cs | 16 ++ gremlin-test/features/map/Select.feature | 46 +++++- .../process/AbstractGremlinProcessTest.java | 14 ++ .../process/traversal/step/map/SelectTest.java | 48 ++++++ .../structure/TinkerGraphPlayTest.java | 114 +++++++++++--- 12 files changed, 492 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index aead6ef..ab20fff 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -25,6 +25,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima This release also includes changes from <<release-3-2-9, 3.2.9>>. +* Implemented `TraversalSelectStep` which allows to `select()` runtime-generated keys. * Coerced `BulkSet` to `g:List` in GraphSON 3.0. * Deprecated `CredentialsGraph` DSL in favor of `CredentialsTraversalDsl` which uses the recommended method for Gremlin DSL development. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/docs/src/recipes/shortest-path.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/recipes/shortest-path.asciidoc b/docs/src/recipes/shortest-path.asciidoc index 04301f1..2e33055 100644 --- a/docs/src/recipes/shortest-path.asciidoc +++ b/docs/src/recipes/shortest-path.asciidoc @@ -95,5 +95,44 @@ calculated cost. With some slight modifications given the use of `select` it bec the output. Note that the path with the lowest "cost" actually has a longer path length as determined by the graph structure. +The following query illustrates how `select(<traversal>)` can be used to find all shortest weighted undirected paths +in the modern toy graph. +[gremlin-groovy,modern] +---- +g.withSack(0.0).V().as("from"). <1> + repeat(bothE(). + sack(sum). + by("weight"). + otherV(). <2> + where(neq("from")).as("to"). <3> + group("m"). <4> + by(select("from","to")). + by(sack().min()). + filter(project("s","x"). <5> + by(sack()). + by(select("m").select(select("from","to"))). + where("s", eq("x"))). + group("p"). <6> + by(select("from", "to")). + by(map(union(path().by("name").by("weight"), + sack()).fold())). + barrier()). + cap("p").unfold(). + order(). <7> + by(select(keys).select("from").id()). + by(select(keys).select("to").id()). + barrier(). + dedup(). <8> + by(select(keys).select(values).order(local).by(id)) +---- + +<1> Start the traversal from all vertices with an initial sack value of 0. +<2> Traverse into all directions and sum up the edge weight values. +<3> Filter out the initial start vertex. +<4> For the current start and end vertex, update the minimum sack value (weighted length of the path). +<5> Compare the current weighted path length to the current minimum weighted path length between the 2 vertices. Eliminate traversers that found a path that is longer than the current shortest path. +<6> Update the path and weighted path length for the current start and end vertex pair. +<7> Order the output by the start vertex id and then the end vertex id (for better readability). +<8> Deduplicate vertex pairs (the shortest path from `v[1]` to `v[6]` is the same as the path from `v[6]` to `v[1]`). http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/docs/src/reference/the-traversal.asciidoc ---------------------------------------------------------------------- diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc index dcda556..11f24e4 100644 --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@ -2338,6 +2338,22 @@ g.V(1).as("a").repeat(out().as("a")).times(2).select(last, "a") g.V(1).as("a").repeat(out().as("a")).times(2).select(all, "a") ---- +In addition to the previously shown examples, where `select()` was used to select an element based on a static key, `select()` can also accept a traversal +that emits a key. + +WARNING: Since the key used by `select(<traversal>)` cannot be determined at compile time, the `TraversalSelectStep` enables full path tracking. + +[gremlin-groovy,modern] +---- +g.withSideEffect("alias", ["marko":"okram"]).V(). <1> + values("name").sack(assign). <2> + optional(select("alias").select(sack())) <3> +---- + +<1> Inject a name alias map and start the traversal from all vertices. +<2> Select all `name` values and store them as the current traverser's sack value. +<3> Optionally select the alias for the current name from the injected map. + [[using-where-with-select]] ==== Using Where with Select @@ -2369,6 +2385,8 @@ link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/grem link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#select-org.apache.tinkerpop.gremlin.process.traversal.Pop-java.lang.String-++[`select(Pop,String)`], link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#select-java.lang.String-++[`select(String)`], link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#select-java.lang.String-java.lang.String-java.lang.String...-++[`select(String,String,String...)`], +link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#select-org.apache.tinkerpop.gremlin.process.traversal.Traversal-++[`select(Traversal)`], +link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#select-org.apache.tinkerpop.gremlin.process.traversal.Pop-org.apache.tinkerpop.gremlin.process.traversal.Traversal-++[`select(Pop,Traversal)`], link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/structure/Column.html++[`Column`], link:++http://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Pop.html++[`Pop`] http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java index a10ddb2..afc0bb4 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java @@ -112,6 +112,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.SumLocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.TailLocalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalFlatMapStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalMapStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.TraversalSelectStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.TreeStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexStep; @@ -734,6 +735,35 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> { } /** + * Map the {@link Traverser} to the object specified by the key returned by the {@code keyTraversal} and apply the {@link Pop} operation + * to it. + * + * @param keyTraversal the traversal expression that selects the key to project + * @return the traversal with an appended {@link SelectStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#select-step" target="_blank">Reference Documentation - Select Step</a> + * @since 3.3.3 + */ + public default <E2> GraphTraversal<S, E2> select(final Pop pop, final Traversal<S, E2> keyTraversal) { + this.asAdmin().getBytecode().addStep(Symbols.select, pop, keyTraversal); + return this.asAdmin().addStep(new TraversalSelectStep<>(this.asAdmin(), pop, keyTraversal)); + } + + /** + * Map the {@link Traverser} to the object specified by the key returned by the {@code keyTraversal}. Note that unlike other uses of + * {@code select} where there are multiple keys, this use of {@code select} with a traversal does not produce a + * {@code Map}. + * + * @param keyTraversal the traversal expression that selects the key to project + * @return the traversal with an appended {@link TraversalSelectStep}. + * @see <a href="http://tinkerpop.apache.org/docs/${project.version}/reference/#select-step" target="_blank">Reference Documentation - Select Step</a> + * @since 3.3.3 + */ + public default <E2> GraphTraversal<S, E2> select(final Traversal<S, E2> keyTraversal) { + this.asAdmin().getBytecode().addStep(Symbols.select, keyTraversal); + return this.asAdmin().addStep(new TraversalSelectStep<>(this.asAdmin(), null, keyTraversal)); + } + + /** * A version of {@code select} that allows for the extraction of a {@link Column} from objects in the traversal. * * @param column the column to extract http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java index 39e5258..5cbfe87 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java @@ -352,6 +352,20 @@ public class __ { } /** + * @see GraphTraversal#select(Pop, Traversal) + */ + public static <A, B> GraphTraversal<A, B> select(final Pop pop, final Traversal<A, B> keyTraversal) { + return __.<A>start().select(pop, keyTraversal); + } + + /** + * @see GraphTraversal#select(Traversal) + */ + public static <A, B> GraphTraversal<A, B> select(final Traversal<A, B> keyTraversal) { + return __.<A>start().select(keyTraversal); + } + + /** * @see GraphTraversal#unfold() */ public static <A> GraphTraversal<A, A> unfold() { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java new file mode 100644 index 0000000..dd02a8c --- /dev/null +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java @@ -0,0 +1,157 @@ +/* + * 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.step.map; + +import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.Pop; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.Traverser; +import org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating; +import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor; +import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping; +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.util.TraversalUtil; +import org.apache.tinkerpop.gremlin.structure.util.StringFactory; + +import java.util.*; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +public final class TraversalSelectStep<S, E> extends MapStep<S, E> implements TraversalParent, PathProcessor, ByModulating { + + private final Pop pop; + private Traversal.Admin<S, E> keyTraversal; + private Traversal.Admin<E, E> selectTraversal = null; + private Set<String> keepLabels; + + public TraversalSelectStep(final Traversal.Admin traversal, final Pop pop, final Traversal<S, E> keyTraversal) { + super(traversal); + this.pop = pop; + this.keyTraversal = this.integrateChild(keyTraversal.asAdmin()); + } + + @Override + protected E map(final Traverser.Admin<S> traverser) { + E end = null; + final Iterator<E> keyIterator = TraversalUtil.applyAll(traverser, this.keyTraversal); + if (keyIterator.hasNext()) { + final E key = keyIterator.next(); + final Object object = traverser.get(); + if (object instanceof Map && ((Map) object).containsKey(key)) + end = (E) ((Map) object).get(key); + else if (key instanceof String) { + final String skey = (String) key; + if (traverser.getSideEffects().exists(skey)) { + end = traverser.getSideEffects().get((String) key); + } else { + final Path path = traverser.path(); + if (path.hasLabel(skey)) + end = null == pop ? path.get(skey) : path.get(pop, skey); + } + } + } + return null != end ? TraversalUtil.applyNullable(end, this.selectTraversal) : null; + } + + @Override + public String toString() { + return StringFactory.stepString(this, this.pop, this.keyTraversal, this.selectTraversal); + } + + @Override + public TraversalSelectStep<S, E> clone() { + final TraversalSelectStep<S, E> clone = (TraversalSelectStep<S, E>) super.clone(); + clone.keyTraversal = this.keyTraversal.clone(); + if (null != this.selectTraversal) + clone.selectTraversal = this.selectTraversal.clone(); + return clone; + } + + @Override + public void setTraversal(final Traversal.Admin<?, ?> parentTraversal) { + super.setTraversal(parentTraversal); + this.integrateChild(this.selectTraversal); + } + + @Override + public int hashCode() { + int result = super.hashCode() ^ this.keyTraversal.hashCode(); + if (null != this.selectTraversal) + result ^= this.selectTraversal.hashCode(); + if (null != this.pop) + result ^= this.pop.hashCode(); + return result; + } + + @Override + public List<Traversal.Admin<?, ?>> getLocalChildren() { + return null == this.selectTraversal ? Collections.emptyList() : Collections.singletonList(this.selectTraversal); + } + + @Override + public void removeLocalChild(final Traversal.Admin<?, ?> traversal) { + if (this.selectTraversal == traversal) + this.selectTraversal = null; + } + + @Override + public void modulateBy(final Traversal.Admin<?, ?> selectTraversal) { + this.selectTraversal = this.integrateChild(selectTraversal); + } + + @Override + public Set<TraverserRequirement> getRequirements() { + return this.getSelfAndChildRequirements( + TraverserRequirement.OBJECT, + TraverserRequirement.SIDE_EFFECTS, + TraverserRequirement.PATH); + } + + //@Override + //public Set<String> getScopeKeys() { + // return Collections.singleton(this.selectKey); + //} + + public Pop getPop() { + return this.pop; + } + + @Override + public void setKeepLabels(final Set<String> keepLabels) { + this.keepLabels = new HashSet<>(keepLabels); + } + + @Override + public Set<String> getKeepLabels() { + return this.keepLabels; + } + + @Override + protected Traverser.Admin<E> processNextStart() { + final Traverser.Admin<E> traverser = super.processNextStart(); + if (!(this.getTraversal().getParent() instanceof MatchStep)) { + PathProcessor.processTraverserPathLabels(traverser, this.keepLabels); + } + return traverser; + } +} + + http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs index 5e6e9d5..9952455 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -1323,6 +1323,15 @@ namespace Gremlin.Net.Process.Traversal /// <summary> /// Adds the select step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> + public GraphTraversal<S, E2> Select<E2> (Pop pop, ITraversal keyTraversal) + { + Bytecode.AddStep("select", pop, keyTraversal); + return Wrap<S, E2>(this); + } + + /// <summary> + /// Adds the select step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> public GraphTraversal<S, E2> Select<E2> (string selectKey) { Bytecode.AddStep("select", selectKey); @@ -1341,6 +1350,15 @@ namespace Gremlin.Net.Process.Traversal } /// <summary> + /// Adds the select step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, E2> Select<E2> (ITraversal keyTraversal) + { + Bytecode.AddStep("select", keyTraversal); + return Wrap<S, E2>(this); + } + + /// <summary> /// Adds the sideEffect step to this <see cref="GraphTraversal{SType, EType}" />. /// </summary> public GraphTraversal<S, E> SideEffect (IConsumer consumer) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs index 4e34b45..27a0004 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/__.cs @@ -999,6 +999,14 @@ namespace Gremlin.Net.Process.Traversal /// <summary> /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the select step to that traversal. /// </summary> + public static GraphTraversal<object, E2> Select<E2>(Pop pop, ITraversal keyTraversal) + { + return new GraphTraversal<object, E2>().Select<E2>(pop, keyTraversal); + } + + /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the select step to that traversal. + /// </summary> public static GraphTraversal<object, E2> Select<E2>(string selectKey) { return new GraphTraversal<object, E2>().Select<E2>(selectKey); @@ -1015,6 +1023,14 @@ namespace Gremlin.Net.Process.Traversal } /// <summary> + /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the select step to that traversal. + /// </summary> + public static GraphTraversal<object, E2> Select<E2>(ITraversal keyTraversal) + { + return new GraphTraversal<object, E2>().Select<E2>(keyTraversal); + } + + /// <summary> /// Spawns a <see cref="GraphTraversal{SType, EType}" /> and adds the sideEffect step to that traversal. /// </summary> public static GraphTraversal<object, object> SideEffect(IConsumer consumer) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-test/features/map/Select.feature ---------------------------------------------------------------------- diff --git a/gremlin-test/features/map/Select.feature b/gremlin-test/features/map/Select.feature index 35d9322..713dd81 100644 --- a/gremlin-test/features/map/Select.feature +++ b/gremlin-test/features/map/Select.feature @@ -514,4 +514,48 @@ Feature: Step - select() Then the result should be unordered | result | | d[2].l | - | d[2].l | \ No newline at end of file + | d[2].l | + + Scenario: g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX + Given the modern graph + And the traversal of + """ + g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")) + """ + When iterated to list + Then the result should be unordered + | result | + | d[3].l | + | d[1].l | + | d[3].l | + | d[3].l | + | d[1].l | + | d[1].l | + + Scenario: g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX + Given the modern graph + And the traversal of + """ + g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")).by(__.math("_+_")) + """ + When iterated to list + Then the result should be unordered + | result | + | d[6].d | + | d[2].d | + | d[6].d | + | d[6].d | + | d[2].d | + | d[2].d | + + Scenario: g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX + Given the modern graph + And the traversal of + """ + g.V().as("a").out("knows").as("a").select(Pop.all, __.constant("a")) + """ + When iterated to list + Then the result should be unordered + | result | + | l[v[marko],v[vadas]] | + | l[v[marko],v[josh]] | http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java index 9dbf261..2861724 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/AbstractGremlinProcessTest.java @@ -129,6 +129,8 @@ public abstract class AbstractGremlinProcessTest extends AbstractGremlinTest { for (T t : results) { if (t instanceof Map) { assertThat("Checking map result existence: " + t, expectedResults.stream().filter(e -> e instanceof Map).filter(e -> internalCheckMap((Map) e, (Map) t)).findAny().isPresent(), is(true)); + } else if (t instanceof List) { + assertThat("Checking list result existence: " + t, expectedResults.stream().filter(e -> e instanceof List).filter(e -> internalCheckList((List) e, (List) t)).findAny().isPresent(), is(true)); } else { assertThat("Checking result existence: " + t, expectedResults.contains(t), is(true)); } @@ -162,6 +164,18 @@ public abstract class AbstractGremlinProcessTest extends AbstractGremlinTest { } } + private static <A> boolean internalCheckList(final List<A> expectedList, final List<A> actualList) { + if (expectedList.size() != actualList.size()) { + return false; + } + for (int i = 0; i < actualList.size(); i++) { + if (!actualList.get(i).equals(expectedList.get(i))) { + return false; + } + } + return true; + } + private static <A, B> boolean internalCheckMap(final Map<A, B> expectedMap, final Map<A, B> actualMap) { final List<Map.Entry<A, B>> actualList = actualMap.entrySet().stream().sorted((a, b) -> a.getKey().toString().compareTo(b.getKey().toString())).collect(Collectors.toList()); final List<Map.Entry<A, B>> expectedList = expectedMap.entrySet().stream().sorted((a, b) -> a.getKey().toString().compareTo(b.getKey().toString())).collect(Collectors.toList()); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java index 3620456..3140004 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectTest.java @@ -83,6 +83,12 @@ public abstract class SelectTest extends AbstractGremlinProcessTest { public abstract Traversal<Vertex, Vertex> get_g_V_chooseXoutE_count_isX0X__asXaX__asXbXX_chooseXselectXaX__selectXaX__selectXbXX(); + public abstract Traversal<Vertex, Long> get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX(); + + public abstract Traversal<Vertex, Double> get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX(); + + public abstract Traversal<Vertex, List<Vertex>> get_g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX(); + // below are original back()-tests public abstract Traversal<Vertex, Vertex> get_g_VX1X_asXhereX_out_selectXhereX(final Object v1Id); @@ -341,6 +347,33 @@ public abstract class SelectTest extends AbstractGremlinProcessTest { assertEquals(3, xCounter); } + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX() { + final Traversal<Vertex, Long> traversal = get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX(); + printTraversalForm(traversal); + checkResults(Arrays.asList(3L, 1L, 3L, 3L, 1L, 1L), traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX() { + final Traversal<Vertex, Double> traversal = get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX(); + printTraversalForm(traversal); + checkResults(Arrays.asList(6D, 2D, 6D, 6D, 2D, 2D), traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX() { + final Vertex marko = convertToVertex(graph, "marko"); + final Vertex vadas = convertToVertex(graph, "vadas"); + final Vertex josh = convertToVertex(graph, "josh"); + final Traversal<Vertex, List<Vertex>> traversal = get_g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX(); + printTraversalForm(traversal); + checkResults(Arrays.asList(Arrays.asList(marko, vadas), Arrays.asList(marko, josh)), traversal); + } + // below are original back()-tests @Test @@ -722,6 +755,21 @@ public abstract class SelectTest extends AbstractGremlinProcessTest { return g.V().choose(__.outE().count().is(0L), __.as("a"), __.as("b")).choose(__.select("a"), __.select("a"), __.select("b")); } + @Override + public Traversal<Vertex, Long> get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX() { + return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").select(__.select("a")); + } + + @Override + public Traversal<Vertex, Double> get_g_V_asXaX_groupXmX_by_byXbothE_countX_barrier_selectXmX_selectXselectXaXX_byXmathX_plus_XX() { + return g.V().as("a").group("m").by().by(__.bothE().count()).barrier().select("m").<Double>select(__.select("a")).by(__.math("_+_")); + } + + @Override + public Traversal<Vertex, List<Vertex>> get_g_V_asXaX_outXknowsX_asXaX_selectXall_constantXaXX() { + return g.V().as("a").out("knows").as("a").select(Pop.all, (Traversal) __.constant("a")); + } + // below are original back()-tests @Override http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c135da6e/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java ---------------------------------------------------------------------- diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java index a13a4ad..e0018fc 100644 --- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java +++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphPlayTest.java @@ -19,15 +19,15 @@ package org.apache.tinkerpop.gremlin.tinkergraph.structure; import org.apache.tinkerpop.gremlin.process.computer.Computer; -import org.apache.tinkerpop.gremlin.process.traversal.Operator; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Pop; 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.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.PathRetractionStrategy; -import org.apache.tinkerpop.gremlin.structure.Graph; -import org.apache.tinkerpop.gremlin.structure.T; -import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.*; import org.apache.tinkerpop.gremlin.structure.io.graphml.GraphMLIo; import org.apache.tinkerpop.gremlin.util.TimeUtil; import org.junit.Ignore; @@ -36,24 +36,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.BiFunction; import java.util.function.Supplier; import static org.apache.tinkerpop.gremlin.process.traversal.Operator.sum; -import static org.apache.tinkerpop.gremlin.process.traversal.P.lt; import static org.apache.tinkerpop.gremlin.process.traversal.P.neq; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.both; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.choose; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.has; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.sack; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.union; -import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.valueMap; +import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.*; /** * @author Stephen Mallette (http://stephen.genoprime.com) @@ -131,12 +122,91 @@ public class TinkerGraphPlayTest { @Ignore public void testPlayDK() throws Exception { - Graph graph = TinkerGraph.open(); - GraphTraversalSource g = graph.traversal(); - graph.io(GraphMLIo.build()).readGraph("/projects/apache/tinkerpop/data/grateful-dead.xml"); - System.out.println(g.V().filter(outE("sungBy").count().is(0)).explain()); - System.out.println(g.V().filter(outE("sungBy").count().is(lt(1))).explain()); - System.out.println(g.V().filter(outE("sungBy").count().is(1)).explain()); + final Map<String, String> aliases = new HashMap<>(); + aliases.put("marko","okram"); + final GraphTraversalSource g = TinkerFactory.createModern().traversal(); + /*g.withSideEffect("a", aliases).V().hasLabel("person"). + values("name").as("n"). + optional(select("a").select(select("n"))). + forEachRemaining(System.out::println);*/ + + // shortest path lengths (by summed weight) + g.withSack(0.0).V().has("person", "name", "marko"). + repeat(__.bothE(). + sack(sum). + by("weight"). + otherV(). + group("m"). + by(). + by(sack().min()).as("x"). + // where(P.eq("m")).by(sack()).by(select(select("x"))). // could be that easy, but "x" is unknown here + filter(project("s","x"). + by(sack()). + by(select("m").select(select("x"))). + where("s", P.eq("x"))). + group("p"). + by(). + by(project("path","length"). + by(path().by("name").by("weight")). + by(sack())) + ). + cap("p").unfold(). + group(). + by(select(Column.keys).values("name")). + by(Column.values).next().entrySet(). + forEach(System.out::println); + + System.out.println("---"); + + // longest path lengths (by summed weight) + g.withSack(0.0).V().has("person", "name", "marko"). + repeat(__.bothE().simplePath(). + sack(sum). + by("weight"). + otherV(). + group("m"). + by(). + by(sack().max()).as("x"). + filter(project("s","x"). + by(sack()). + by(select("m").select(select("x"))). + where("s", P.eq("x"))). + group("p"). + by(). + by(project("path","length"). + by(path().by("name").by("weight")). + by(sack())) + ). + cap("p").unfold(). + group(). + by(select(Column.keys).values("name")). + by(Column.values).next().entrySet(). + forEach(System.out::println); + + System.out.println("---"); + + // all shortest paths (by summed weight) + g.withSack(0.0).V().as("a"). + repeat(__.bothE(). + sack(sum). + by("weight"). + otherV().as("b"). + group("m"). + by(select("a","b").by("name")). + by(sack().min()). + filter(project("s","x"). + by(sack()). + by(select("m").select(select("a", "b").by("name"))). + where("s", P.eq("x"))). + group("p"). + by(select("a","b").by("name")). + by(map(union(path().by("name").by("weight"), sack()).fold())) + ). + cap("p").unfold(). + order(). + by(select(Column.keys).select("a")). + by(select(Column.keys).select("b")). + forEachRemaining(System.out::println); } @Test