http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java index bc105e6..2a07723 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV2d0.java @@ -27,8 +27,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.StepConfigurationProxy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; @@ -241,23 +239,6 @@ final class TraversalSerializersV2d0 { } } - final static class StepConfigurationJacksonSerializer extends StdScalarSerializer<StepConfiguration> { - - public StepConfigurationJacksonSerializer() { - super(StepConfiguration.class); - } - - @Override - public void serialize(final StepConfiguration stepConfiguration, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) - throws IOException { - jsonGenerator.writeStartObject(); - for (final Map.Entry<Object, Object> entry : ConfigurationConverter.getMap(stepConfiguration.getConfiguration()).entrySet()) { - jsonGenerator.writeObjectField((String) entry.getKey(), entry.getValue()); - } - jsonGenerator.writeEndObject(); - } - } - /////////////////// // DESERIALIZERS // ////////////////// @@ -505,18 +486,4 @@ final class TraversalSerializersV2d0 { return new TraversalStrategyProxy<>(this.clazz, new MapConfiguration(data)); } } - - final static class StepConfigurationProxyJacksonDeserializer<T extends StepConfiguration> extends AbstractObjectDeserializer<StepConfigurationProxy> { - private final Class<T> clazz; - - public StepConfigurationProxyJacksonDeserializer(final Class<T> clazz) { - super(StepConfigurationProxy.class); - this.clazz = clazz; - } - - @Override - public StepConfigurationProxy<T> createObject(final Map<String, Object> data) { - return new StepConfigurationProxy<>(this.clazz, new MapConfiguration(data)); - } - } }
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java index 59ba4a0..8086b2a 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/TraversalSerializersV3d0.java @@ -27,8 +27,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.StepConfigurationProxy; import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; import org.apache.tinkerpop.gremlin.process.traversal.util.AndP; import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; @@ -236,23 +234,6 @@ final class TraversalSerializersV3d0 { } } - final static class StepConfigurationJacksonSerializer extends StdScalarSerializer<StepConfiguration> { - - public StepConfigurationJacksonSerializer() { - super(StepConfiguration.class); - } - - @Override - public void serialize(final StepConfiguration stepConfiguration, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) - throws IOException { - jsonGenerator.writeStartObject(); - for (final Map.Entry<Object, Object> entry : ConfigurationConverter.getMap(stepConfiguration.getConfiguration()).entrySet()) { - jsonGenerator.writeObjectField((String) entry.getKey(), entry.getValue()); - } - jsonGenerator.writeEndObject(); - } - } - /////////////////// // DESERIALIZERS // ////////////////// @@ -502,18 +483,4 @@ final class TraversalSerializersV3d0 { return new TraversalStrategyProxy<>(this.clazz, new MapConfiguration(data)); } } - - final static class StepConfigurationProxyJacksonDeserializer<T extends StepConfiguration> extends AbstractObjectDeserializer<StepConfigurationProxy> { - private final Class<T> clazz; - - public StepConfigurationProxyJacksonDeserializer(final Class<T> clazz) { - super(StepConfigurationProxy.class); - this.clazz = clazz; - } - - @Override - public StepConfigurationProxy<T> createObject(final Map<String, Object> data) { - return new StepConfigurationProxy<>(this.clazz, new MapConfiguration(data)); - } - } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java index 5d4b30b..6bb7b34 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoVersion.java @@ -43,7 +43,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.MeanGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.OrderGlobalStep; import org.apache.tinkerpop.gremlin.process.traversal.step.map.TreeStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.DefaultStepConfiguration; import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy; @@ -311,7 +310,6 @@ public enum GryoVersion { add(GryoTypeReg.of(TraversalOptionParent.Pick.class, 137)); add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer())); add(GryoTypeReg.of(MultiComparator.class, 165)); - add(GryoTypeReg.of(DefaultStepConfiguration.class, 174)); // ***LAST ID*** add(GryoTypeReg.of(ConnectiveStrategy.class, 138)); add(GryoTypeReg.of(HaltedTraverserStrategy.class, 139)); @@ -375,7 +373,7 @@ public enum GryoVersion { add(GryoTypeReg.of(RangeGlobalStep.RangeBiOperator.class, 114)); add(GryoTypeReg.of(OrderGlobalStep.OrderBiOperator.class, 118)); add(GryoTypeReg.of(ProfileStep.ProfileBiOperator.class, 119)); - add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); + add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); // ***LAST ID*** // placeholder serializers for classes that don't live here in core. this will allow them to be used if // present or ignored if the class isn't available. either way the registration numbers are held as @@ -488,7 +486,6 @@ public enum GryoVersion { add(GryoTypeReg.of(TraversalOptionParent.Pick.class, 137)); add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer())); add(GryoTypeReg.of(MultiComparator.class, 165)); - add(GryoTypeReg.of(DefaultStepConfiguration.class, 174)); // ***LAST ID*** add(GryoTypeReg.of(TraverserSet.class, 58)); @@ -555,7 +552,7 @@ public enum GryoVersion { add(GryoTypeReg.of(MatchStep.CountMatchAlgorithm.class, 160)); add(GryoTypeReg.of(MatchStep.GreedyMatchAlgorithm.class, 167)); // skip 171, 172 to sync with tp33 - add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); + add(GryoTypeReg.of(IndexedTraverserSet.VertexIndexedTraverserSet.class, 173)); // ***LAST ID*** }}; } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalTest.java index 9009d0b..d621755 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalTest.java @@ -42,7 +42,7 @@ import static org.junit.Assert.assertEquals; public class GraphTraversalTest { private static final Logger logger = LoggerFactory.getLogger(GraphTraversalTest.class); - private static Set<String> NO_GRAPH = new HashSet<>(Arrays.asList("asAdmin", "by", "with", "option", "iterate", "to", "from", "profile", "pageRank", "peerPressure", "program", "none")); + private static Set<String> NO_GRAPH = new HashSet<>(Arrays.asList("asAdmin", "by", "with", "option", "iterate", "to", "from", "profile", "pageRank", "peerPressure", "shortestPath", "program", "none")); private static Set<String> NO_ANONYMOUS = new HashSet<>(Arrays.asList("start", "__")); private static Set<String> IGNORES_BYTECODE = new HashSet<>(Arrays.asList("asAdmin", "iterate", "mapValues", "mapKeys")); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java deleted file mode 100644 index 6b3fc1c..0000000 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * 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.util; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.MapConfiguration; -import org.apache.commons.lang.reflect.FieldUtils; -import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep; -import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection; -import org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException; -import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal; -import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; -import org.apache.tinkerpop.gremlin.process.traversal.Step; -import org.apache.tinkerpop.gremlin.process.traversal.Traversal; -import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; -import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration; -import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.NoSuchElementException; - -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -/** - * @author Stephen Mallette (http://stephen.genoprime.com) - */ -public class DefaultStepConfigurationTest { - - @Test - public void shouldApplyDefaultConfiguration() throws Exception { - final Traversal t = __.V().pageRank().with(new DefaultStepConfiguration("modulateBy", "xxx")); - final Step s = t.asAdmin().getEndStep(); - assertEquals("xxx", FieldUtils.readField(s, "pageRankProperty", true)); - } - - @Test - public void shouldApplyDefaultConfigurationWithClassValidation() throws Exception { - final Traversal t = __.V().pageRank().with(new DefaultStepConfiguration(PageRankVertexProgramStep.class, "modulateBy", "xxx")); - final Step s = t.asAdmin().getEndStep(); - assertEquals("xxx", FieldUtils.readField(s, "pageRankProperty", true)); - } - - @Test - public void shouldApplyDefaultConfigurationInOrder() throws Exception { - final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>(); - methods.put("setY", Collections.singletonList(100L)); - methods.put("setX", Collections.singletonList("xxx")); - methods.put("setZ", Collections.singletonList("zzz" )); - final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods); - final MockStep step = new MockStep(__.__().asAdmin()); - - conf.accept(step); - - assertThat(step.list, contains(100L, "Xxxx", "Zzzz")); - } - - @Test - public void shouldGenerateConfiguration() throws Exception { - final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>(); - methods.put("setY", Collections.singletonList(100L)); - methods.put("setX", Collections.singletonList("xxx")); - methods.put("setZ", Collections.singletonList("zzz" )); - final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods); - final MapConfiguration c = (MapConfiguration) conf.getConfiguration(); - c.setDelimiterParsingDisabled(false); - - assertEquals(100L, c.getList("setY").get(0)); - assertEquals("xxx", c.getList("setX").get(0)); - assertEquals("zzz", c.getList("setZ").get(0)); - } - - @Test(expected = IllegalStateException.class) - public void shouldValidateClass() { - __.V().pageRank().with(new DefaultStepConfiguration(MockStep.class, "modulateBy", "xxx")); - } - - @Test - public void shouldAllowNoSuchMethodIfUsingRemote() { - // create a fake remote - final GraphTraversalSource g = EmptyGraph.instance().traversal().withRemote(new RemoteConnection() { - @Override - public <E> Iterator<Traverser.Admin<E>> submit(final Traversal<?, E> traversal) throws RemoteConnectionException { - return null; - } - - @Override - public <E> RemoteTraversal<?, E> submit(final Bytecode bytecode) throws RemoteConnectionException { - return null; - } - - @Override - public void close() throws Exception { - - } - }); - - // try to set a fake configuration option - lack of exception is good. not really sure how else to directly - // assert this - final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>(); - methods.put("setFakeyFakerton", Collections.singletonList(100L)); - final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods); - g.V().with(conf); - } - - @Test(expected = IllegalStateException.class) - public void shouldNotAllowNoSuchMethodUnlessUsingRemote() { - final GraphTraversalSource g = EmptyGraph.instance().traversal(); - - // try to set a fake configuration option - final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>(); - methods.put("setFakeyFakerton", Collections.singletonList(100L)); - final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods); - g.V().with(conf); - } - - static class MockStep extends AbstractStep { - - List<Object> list = new ArrayList<>(); - - MockStep(final Traversal.Admin t) { - super(t); - } - - public void setX(final String s) { - list.add("X" + s); - } - - public void setY(final Long s) { - list.add(s); - } - - public void setZ(final String s) { - list.add("Z" + s); - } - - - @Override - protected Traverser.Admin processNextStart() throws NoSuchElementException { - return null; - } - } -} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java index de4dded..4e86ebd 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperPartialEmbeddedTypeTest.java @@ -22,8 +22,6 @@ import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraver import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traverser; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.DefaultStepConfiguration; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.StepConfigurationProxy; import org.apache.tinkerpop.shaded.jackson.databind.JsonMappingException; import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper; import org.junit.Test; @@ -336,14 +334,6 @@ public class GraphSONMapperPartialEmbeddedTypeTest extends AbstractGraphSONTest } } - @Test - public void shouldHandleWithDefaultStepConfiguration() throws Exception { - final DefaultStepConfiguration stepConfig = new DefaultStepConfiguration("setInterval", 1000); - final StepConfigurationProxy deserStepConfig = serializeDeserializeAuto(mapper, stepConfig); - assertEquals(1000, deserStepConfig.getConfiguration().getInt("setInterval")); - assertEquals(DefaultStepConfiguration.class, deserStepConfig.getStepConfigurationClass()); - } - // Class needs to be defined as statics as it's a nested class. public static class FunObject { private String val; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java index 3013098..fcb040a 100644 --- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java +++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapperTest.java @@ -20,7 +20,6 @@ package org.apache.tinkerpop.gremlin.structure.io.gryo; import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser; import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.DefaultStepConfiguration; import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.io.IoX; @@ -378,12 +377,6 @@ public class GryoMapperTest { assertThat(Arrays.equals(bb.array(), serializeDeserialize(bb, ByteBuffer.class).array()), is(true)); } - @Test - public void shouldHandleDefaultStepConfiguration() throws Exception { - final DefaultStepConfiguration stepConf = new DefaultStepConfiguration("pageRankProperty", "xxx"); - assertEquals(stepConf, serializeDeserialize(stepConf, DefaultStepConfiguration.class)); - } - public <T> T serializeDeserialize(final Object o, final Class<T> clazz) throws Exception { final Kryo kryo = builder.get().create().createMapper(); try (final ByteArrayOutputStream stream = new ByteArrayOutputStream()) { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/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 537cdbe..45eecfa 100644 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs +++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversal.cs @@ -1359,6 +1359,15 @@ namespace Gremlin.Net.Process.Traversal } /// <summary> + /// Adds the shortestPath step to this <see cref="GraphTraversal{SType, EType}" />. + /// </summary> + public GraphTraversal<S, Path> ShortestPath () + { + Bytecode.AddStep("shortestPath"); + return Wrap<S, Path>(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/c42fb5a0/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs ---------------------------------------------------------------------- diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs deleted file mode 100644 index a01ac1c..0000000 --- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs +++ /dev/null @@ -1,32 +0,0 @@ -#region License - -/* - * 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. - */ - -#endregion - -namespace Gremlin.Net.Process.Traversal -{ - /// <summary> - /// A configuration for a step supplied to the with() modulator of a traversal. - /// </summary> - public interface IStepConfiguration - { - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js index f143542..b139c9f 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/process/graph-traversal.js @@ -933,6 +933,16 @@ class GraphTraversal extends Traversal { } /** + * Graph traversal shortestPath method. + * @param {...Object} args + * @returns {GraphTraversal} + */ + shortestPath(...args) { + this.bytecode.addStep('shortestPath', args); + return this; + } + + /** * Graph traversal sideEffect method. * @param {...Object} args * @returns {GraphTraversal} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py index bb81d87..518ef13 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py @@ -425,6 +425,10 @@ class GraphTraversal(Traversal): self.bytecode.add_step("select", *args) return self + def shortestPath(self, *args): + self.bytecode.add_step("shortestPath", *args) + return self + def sideEffect(self, *args): self.bytecode.add_step("sideEffect", *args) return self http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java index 25d7a55..fde1b8d 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/AbstractGremlinTest.java @@ -170,6 +170,10 @@ public abstract class AbstractGremlinTest { return convertToVertex(graph, vertexName).id(); } + public Vertex convertToVertex(final String vertexName) { + return convertToVertex(graph, vertexName); + } + public Vertex convertToVertex(final Graph graph, final String vertexName) { // all test graphs have "name" as a unique id which makes it easy to hardcode this...works for now return graph.traversal().V().has("name", vertexName).next(); http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java index 3d51a94..520ec6e 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/ProcessComputerSuite.java @@ -25,6 +25,7 @@ import org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVerte import org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgramTest; import org.apache.tinkerpop.gremlin.process.computer.clustering.peerpressure.PeerPressureVertexProgramTest; import org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgramTest; +import org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathVertexProgramTest; import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine; import org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionComputerTest; import org.apache.tinkerpop.gremlin.process.traversal.step.ComplexTest; @@ -69,6 +70,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.map.ProfileTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.ProgramTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.ProjectTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertiesTest; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.ShortestPathTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.SelectTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.SumTest; import org.apache.tinkerpop.gremlin.process.traversal.step.map.UnfoldTest; @@ -162,6 +164,7 @@ public class ProcessComputerSuite extends AbstractGremlinSuite { ProjectTest.Traversals.class, ProgramTest.Traversals.class, PropertiesTest.Traversals.class, + ShortestPathTest.Traversals.class, SelectTest.Traversals.class, UnfoldTest.Traversals.class, ValueMapTest.Traversals.class, @@ -189,6 +192,7 @@ public class ProcessComputerSuite extends AbstractGremlinSuite { // algorithms PageRankVertexProgramTest.class, PeerPressureVertexProgramTest.class, + ShortestPathVertexProgramTest.class, BulkLoaderVertexProgramTest.class, BulkDumperVertexProgramTest.class, @@ -252,6 +256,7 @@ public class ProcessComputerSuite extends AbstractGremlinSuite { ProjectTest.class, ProgramTest.class, PropertiesTest.class, + ShortestPathTest.class, SelectTest.class, UnfoldTest.class, ValueMapTest.class, http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java new file mode 100644 index 0000000..cf17578 --- /dev/null +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathTestHelper.java @@ -0,0 +1,72 @@ +/* + * 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.computer.search.path; + +import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Path; +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.step.util.ImmutablePath; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; + +import java.util.Collections; +import java.util.List; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +public class ShortestPathTestHelper { + + private final AbstractGremlinProcessTest test; + private final GraphTraversalSource g; + + public ShortestPathTestHelper(final AbstractGremlinProcessTest test, final GraphTraversalSource g) { + this.test = test; + this.g = g; + } + + public void checkResults(final List<Path> expected, final List<Path> actual) { + AbstractGremlinProcessTest.checkResults(expected, __.inject(actual.toArray(new Path[actual.size()]))); + } + + public Path makePath(final String... names) { + return makePath(false, names); + } + + public Path makePath(final boolean includeEdges, final String... names) { + Path path = ImmutablePath.make(); + boolean first = true; + for (final String name : names) { + final Vertex vertex = test.convertToVertex(name); + if (!first) { + if (includeEdges) { + final Edge edge = g.V(((Vertex) path.get(path.size() - 1)).id()) + .bothE().filter(__.otherV().is(P.eq(vertex))) + .next(); + path = path.extend(edge, Collections.emptySet()); + } + } + path = path.extend(vertex, Collections.emptySet()); + first = false; + } + return path; + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgramTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgramTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgramTest.java new file mode 100644 index 0000000..b53d6ae --- /dev/null +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgramTest.java @@ -0,0 +1,264 @@ +/* + * 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.computer.search.path; + +import org.apache.tinkerpop.gremlin.LoadGraphWith; +import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; +import org.apache.tinkerpop.gremlin.process.computer.ComputerResult; +import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.junit.Before; +import org.junit.Test; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW; +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL; +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +public class ShortestPathVertexProgramTest extends AbstractGremlinProcessTest { + + private ShortestPathTestHelper helper; + + @Before + public void initializeHelper() throws Exception { + this.helper = new ShortestPathTestHelper(this, g); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindAllShortestPathsWithDefaultParameters() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build().create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS).map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindAllShortestPathsWithEdgesIncluded() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build().includeEdges(true).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS).map(p -> helper.makePath(true, p)) + .collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindOutDirectedShortestPaths() throws Exception { + final List<ShortestPathVertexProgram> programs = Arrays.asList( + ShortestPathVertexProgram.build().edgeTraversal(__.outE()).create(graph), + ShortestPathVertexProgram.build().edgeDirection(Direction.OUT).create(graph)); + for (final ShortestPathVertexProgram program : programs) { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(program).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> (p[0].equals("marko") && !p[p.length - 1].equals("peter")) + || (p[0].equals("vadas") && p.length == 1) + || (p[0].equals("lop") && p.length == 1) + || (p[0].equals("josh") && Arrays.asList("lop", "josh", "ripple").contains(p[p.length - 1])) + || (p[0].equals("ripple") && p.length == 1) + || (p[0].equals("peter") && Arrays.asList("lop", "peter").contains(p[p.length - 1]))) + .map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindInDirectedShortestPaths() throws Exception { + final List<ShortestPathVertexProgram> programs = Arrays.asList( + ShortestPathVertexProgram.build().edgeTraversal(__.inE()).create(graph), + ShortestPathVertexProgram.build().edgeDirection(Direction.IN).create(graph)); + for (final ShortestPathVertexProgram program : programs) { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(program).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> (p[0].equals("marko") && p.length == 1) + || (p[0].equals("vadas") && Arrays.asList("marko", "vadas").contains(p[p.length - 1])) + || (p[0].equals("lop") && Arrays.asList("marko", "lop", "josh", "peter").contains(p[p.length - 1])) + || (p[0].equals("josh") && Arrays.asList("marko", "josh").contains(p[p.length - 1])) + || (p[0].equals("ripple") && Arrays.asList("marko", "josh", "ripple").contains(p[p.length - 1])) + || (p[0].equals("peter") && p.length == 1)) + .map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindDirectedShortestPathsWithEdgesIncluded() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build().edgeTraversal(__.outE()).includeEdges(true).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> (p[0].equals("marko") && !p[p.length - 1].equals("peter")) + || (p[0].equals("vadas") && p.length == 1) + || (p[0].equals("lop") && p.length == 1) + || (p[0].equals("josh") && Arrays.asList("lop", "josh", "ripple").contains(p[p.length - 1])) + || (p[0].equals("ripple") && p.length == 1) + || (p[0].equals("peter") && Arrays.asList("lop", "peter").contains(p[p.length - 1]))) + .map(p -> helper.makePath(true, p)).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindShortestPathsWithStartVertexFilter() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build().source(__.has("name", "marko")).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> p[0].equals("marko")).map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindShortestPathsWithEndVertexFilter() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build().target(__.has("name", "marko")).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> p[p.length - 1].equals("marko")).map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldFindShortestPathsWithStartEndVertexFilter() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build() + .source(__.has("name", "marko")) + .target(__.hasLabel("software")).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> + p[0].equals("marko") && Arrays.asList("lop", "ripple").contains(p[p.length - 1])) + .map(helper::makePath).collect(Collectors.toList()); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(MODERN) + public void shouldUseCustomDistanceProperty() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build() + .source(__.has("name", "marko")) + .target(__.has("name", "josh")) + .distanceProperty("weight").create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + assertEquals(1, shortestPaths.size()); + assertEquals(helper.makePath("marko", "lop", "josh"), shortestPaths.get(0)); + } + + @Test + @LoadGraphWith(CREW) + public void shouldFindEqualLengthPaths() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build() + .edgeTraversal(__.bothE("uses")) + .source(__.has("name", "daniel")) + .target(__.has("name", "stephen")).create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.asList( + helper.makePath("daniel", "gremlin", "stephen"), + helper.makePath("daniel", "tinkergraph", "stephen")); + helper.checkResults(expected, shortestPaths); + } + + @Test + @LoadGraphWith(GRATEFUL) + public void shouldFindEqualLengthPathsUsingDistanceProperty() throws Exception { + final ComputerResult result = graph.compute(graphProvider.getGraphComputer(graph).getClass()). + program(ShortestPathVertexProgram.build() + .edgeTraversal(__.outE("followedBy")) + .source(__.has("song", "name", "MIGHT AS WELL")) + .target(__.has("song", "name", "MAYBE YOU KNOW HOW I FEEL")) + .distanceProperty("weight") + .create(graph)).submit().get(); + assertTrue(result.memory().exists(ShortestPathVertexProgram.SHORTEST_PATHS)); + final List<Path> shortestPaths = result.memory().get(ShortestPathVertexProgram.SHORTEST_PATHS); + final List<Path> expected = Arrays.asList( + helper.makePath("MIGHT AS WELL", "DRUMS", "MAYBE YOU KNOW HOW I FEEL"), + helper.makePath("MIGHT AS WELL", "SHIP OF FOOLS", "MAYBE YOU KNOW HOW I FEEL")); + helper.checkResults(expected, shortestPaths); + } + + public static String[][] ALL_SHORTEST_PATHS = new String[][]{ + new String[]{"marko"}, + new String[]{"marko", "vadas"}, + new String[]{"marko", "lop"}, + new String[]{"marko", "lop", "peter"}, + new String[]{"marko", "josh"}, + new String[]{"marko", "josh", "ripple"}, + new String[]{"vadas"}, + new String[]{"vadas", "marko"}, + new String[]{"vadas", "marko", "lop"}, + new String[]{"vadas", "marko", "lop", "peter"}, + new String[]{"vadas", "marko", "josh", "ripple"}, + new String[]{"vadas", "marko", "josh"}, + new String[]{"lop"}, + new String[]{"lop", "marko"}, + new String[]{"lop", "marko", "vadas"}, + new String[]{"lop", "josh"}, + new String[]{"lop", "josh", "ripple"}, + new String[]{"lop", "peter"}, + new String[]{"josh"}, + new String[]{"josh", "marko"}, + new String[]{"josh", "marko", "vadas"}, + new String[]{"josh", "lop"}, + new String[]{"josh", "lop", "peter"}, + new String[]{"josh", "ripple"}, + new String[]{"ripple"}, + new String[]{"ripple", "josh"}, + new String[]{"ripple", "josh", "marko"}, + new String[]{"ripple", "josh", "marko", "vadas"}, + new String[]{"ripple", "josh", "lop"}, + new String[]{"ripple", "josh", "lop", "peter"}, + new String[]{"peter"}, + new String[]{"peter", "lop"}, + new String[]{"peter", "lop", "marko"}, + new String[]{"peter", "lop", "marko", "vadas"}, + new String[]{"peter", "lop", "josh"}, + new String[]{"peter", "lop", "josh", "ripple"} + }; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ShortestPathTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ShortestPathTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ShortestPathTest.java new file mode 100644 index 0000000..71f4469 --- /dev/null +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ShortestPathTest.java @@ -0,0 +1,310 @@ +/* + * 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.LoadGraphWith; +import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest; +import org.apache.tinkerpop.gremlin.process.GremlinProcessRunner; +import org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathTestHelper; +import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW; +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.GRATEFUL; +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; +import static org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathVertexProgramTest.ALL_SHORTEST_PATHS; +import static org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.ShortestPathVertexProgramStep.ShortestPath.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Daniel Kuppitz (http://gremlin.guru) + */ +@RunWith(GremlinProcessRunner.class) +public abstract class ShortestPathTest extends AbstractGremlinProcessTest { + + private ShortestPathTestHelper helper; + + @Before + public void initializeHelper() throws Exception { + this.helper = new ShortestPathTestHelper(this, g); + } + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath(); + + public abstract Traversal<Vertex, Path> get_g_V_both_dedup_shortestPath(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_edgesIncluded(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_directionXINX(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_edgesXoutEX(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_edgesIncluded_edgesXoutEX(); + + public abstract Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_targetXhasXname_markoXX(); + + public abstract Traversal<Vertex, Path> get_g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX(); + + public abstract Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX(); + + public abstract Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX(); + + public abstract Traversal<Vertex, Path> get_g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX(); + + public abstract Traversal<Vertex, Path> get_g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX(); + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS).map(helper::makePath) + .collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_both_dedup_shortestPath() { + final Traversal<Vertex, Path> traversal = get_g_V_both_dedup_shortestPath(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS).map(helper::makePath) + .collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_edgesIncluded() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_edgesIncluded(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS).map(p -> helper.makePath(true, p)) + .collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_directionXINX() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_directionXINX(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> (p[0].equals("marko") && p.length == 1) + || (p[0].equals("vadas") && Arrays.asList("marko", "vadas").contains(p[p.length - 1])) + || (p[0].equals("lop") && Arrays.asList("marko", "lop", "josh", "peter").contains(p[p.length - 1])) + || (p[0].equals("josh") && Arrays.asList("marko", "josh").contains(p[p.length - 1])) + || (p[0].equals("ripple") && Arrays.asList("marko", "josh", "ripple").contains(p[p.length - 1])) + || (p[0].equals("peter") && p.length == 1)) + .map(helper::makePath).collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_edgesXoutEX() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_edgesXoutEX(); + printTraversalForm(traversal); + checkOutDirectedPaths(false, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_edgesIncluded_edgesXoutEX() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_edgesIncluded_edgesXoutEX(); + printTraversalForm(traversal); + checkOutDirectedPaths(true, traversal); + } + + private void checkOutDirectedPaths(final boolean includeEdges, final Traversal<Vertex, Path> traversal) { + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> (p[0].equals("marko") && !p[p.length - 1].equals("peter")) + || (p[0].equals("vadas") && p.length == 1) + || (p[0].equals("lop") && p.length == 1) + || (p[0].equals("josh") && Arrays.asList("lop", "josh", "ripple").contains(p[p.length - 1])) + || (p[0].equals("ripple") && p.length == 1) + || (p[0].equals("peter") && Arrays.asList("lop", "peter").contains(p[p.length - 1]))) + .map(names -> helper.makePath(includeEdges, names)).collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_markoX_shortestPath() { + final Traversal<Vertex, Path> traversal = get_g_V_hasXname_markoX_shortestPath(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> p[0].equals("marko")).map(helper::makePath).collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_targetXhasXname_markoXX() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_targetXhasXname_markoXX(); + printTraversalForm(traversal); + checkPathsToMarko(traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX() { + final Traversal<Vertex, Path> traversal = get_g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX(); + printTraversalForm(traversal); + checkPathsToMarko(traversal); + } + + private void checkPathsToMarko(final Traversal<Vertex, Path> traversal) { + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> p[p.length - 1].equals("marko")).map(helper::makePath).collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX() { + final Traversal<Vertex, Path> traversal = get_g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.stream(ALL_SHORTEST_PATHS) + .filter(p -> + p[0].equals("marko") && Arrays.asList("lop", "ripple").contains(p[p.length - 1])) + .map(helper::makePath).collect(Collectors.toList()); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(MODERN) + public void g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX() { + final Traversal<Vertex, Path> traversal = get_g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX(); + printTraversalForm(traversal); + assertTrue(traversal.hasNext()); + assertEquals(helper.makePath("marko", "lop", "josh"), traversal.next()); + assertFalse(traversal.hasNext()); + } + @Test + @LoadGraphWith(CREW) + public void g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX() { + final Traversal<Vertex, Path> traversal = get_g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.asList( + helper.makePath("daniel", "gremlin", "stephen"), + helper.makePath("daniel", "tinkergraph", "stephen")); + checkResults(expected, traversal); + } + + @Test + @LoadGraphWith(GRATEFUL) + public void g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX() { + final Traversal<Vertex, Path> traversal = get_g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX(); + printTraversalForm(traversal); + final List<Path> expected = Arrays.asList( + helper.makePath("MIGHT AS WELL", "DRUMS", "MAYBE YOU KNOW HOW I FEEL"), + helper.makePath("MIGHT AS WELL", "SHIP OF FOOLS", "MAYBE YOU KNOW HOW I FEEL")); + checkResults(expected, traversal); + } + + public static class Traversals extends ShortestPathTest { + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath() { + return g.V().shortestPath().dedup(); + } + + @Override + public Traversal<Vertex, Path> get_g_V_both_dedup_shortestPath() { + return g.V().both().dedup().shortestPath(); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_edgesIncluded() { + return g.V().shortestPath().with(INCLUDE_EDGES, true); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_directionXINX() { + return g.V().shortestPath().with(EDGES, Direction.IN); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_edgesXoutEX() { + return g.V().shortestPath().with(EDGES, __.outE()); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_edgesIncluded_edgesXoutEX() { + return g.V().shortestPath().with(INCLUDE_EDGES, true).with(EDGES, __.outE()); + } + + @Override + public Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath() { + return g.V().has("name", "marko").shortestPath(); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_targetXhasXname_markoXX() { + return g.V().shortestPath().with(TARGET, __.has("name", "marko")); + } + + @Override + public Traversal<Vertex, Path> get_g_V_shortestPath_targetXvaluesXnameX_isXmarkoXX() { + return g.V().shortestPath().with(TARGET, __.<Vertex, String>values("name").is("marko")); + } + + @Override + public Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath_targetXhasLabelXsoftwareXX() { + return g.V().has("name", "marko").shortestPath().with(TARGET, __.hasLabel("software")); + } + + @Override + public Traversal<Vertex, Path> get_g_V_hasXname_markoX_shortestPath_targetXhasXname_joshXX_distanceXweightX() { + return g.V().has("name", "marko").shortestPath() + .with(TARGET, __.has("name","josh")) + .with(DISTANCE, "weight"); + } + + @Override + public Traversal<Vertex, Path> get_g_V_hasXname_danielX_shortestPath_targetXhasXname_stephenXX_edgesXbothEXusesXX() { + return g.V().has("name", "daniel").shortestPath() + .with(TARGET, __.has("name","stephen")) + .with(EDGES, __.bothE("uses")); + } + + @Override + public Traversal<Vertex, Path> get_g_V_hasXsong_name_MIGHT_AS_WELLX_shortestPath_targetXhasXsong_name_MAYBE_YOU_KNOW_HOW_I_FEELXX_edgesXoutEXfollowedByXX_distanceXweightX() { + return g.V().has("song", "name", "MIGHT AS WELL") + .shortestPath(). + with(TARGET, __.has("song", "name", "MAYBE YOU KNOW HOW I FEEL")). + with(EDGES, __.outE("followedBy")). + with(DISTANCE, "weight"); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 199a4ba..e5efd7f 100644 --- a/pom.xml +++ b/pom.xml @@ -1222,6 +1222,9 @@ limitations under the License. org/apache/tinkerpop/gremlin/process/computer/ranking/pagerank/PageRankVertexProgram.java </include> <include> + org/apache/tinkerpop/gremlin/process/computer/search/path/ShortestPathVertexProgram.java + </include> + <include> org/apache/tinkerpop/gremlin/process/computer/traversal/TraversalVertexProgram.java </include> <!-- traversal --> http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c42fb5a0/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 e0018fc..4828fef 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,10 +19,10 @@ package org.apache.tinkerpop.gremlin.tinkergraph.structure; import org.apache.tinkerpop.gremlin.process.computer.Computer; -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.computer.ComputerResult; +import org.apache.tinkerpop.gremlin.process.computer.Memory; +import org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathVertexProgram; +import org.apache.tinkerpop.gremlin.process.traversal.*; 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.__; @@ -212,23 +212,99 @@ public class TinkerGraphPlayTest { @Test @Ignore public void testPlay7() throws Exception { - /*TinkerGraph graph = TinkerGraph.open(); - graph.createIndex("name",Vertex.class); - graph.io(GraphMLIo.build()).readGraph("/Users/marko/software/tinkerpop/tinkerpop3/data/grateful-dead.xml");*/ - //System.out.println(g.V().properties().key().groupCount().next()); - TinkerGraph graph = TinkerFactory.createModern(); - GraphTraversalSource g = graph.traversal(); - final List<Supplier<GraphTraversal<?, ?>>> traversals = Arrays.asList( - () -> g.V().out().as("v").match( - __.as("v").outE().count().as("outDegree"), - __.as("v").inE().count().as("inDegree")).select("v", "outDegree", "inDegree").by(valueMap()).by().by().local(union(select("v"), select("inDegree", "outDegree")).unfold().fold()) - ); - - traversals.forEach(traversal -> { - logger.info("pre-strategy: {}", traversal.get()); - logger.info("post-strategy: {}", traversal.get().iterate()); - logger.info(TimeUtil.clockWithResult(50, () -> traversal.get().toList()).toString()); - }); + final TinkerGraph graph = TinkerFactory.createModern(); + final GraphTraversalSource g = graph.traversal(); + final ShortestPathVertexProgram shortestPathByHops = ShortestPathVertexProgram.build() + .source(__.has("name", P.within("marko"))) + .target(__.has("name","josh")) + .includeEdges(true) + .create(null); + final ShortestPathVertexProgram shortestPathByWeight = ShortestPathVertexProgram.build() + .source(__.has("name", P.within("marko"))) + .target(__.has("name","josh")) + .distanceProperty("weight") + .includeEdges(true) + .create(null); +/**/ + System.out.println("Shortest path from marko to josh (by number of hops)\n--"); + graph.compute().program(shortestPathByHops).submit().get().memory() + .<List<Path>>get(ShortestPathVertexProgram.SHORTEST_PATHS) + .forEach(System.out::println); + g.inject(graph.compute().program(shortestPathByHops).submit().get().memory() + .<List<Path>>get(ShortestPathVertexProgram.SHORTEST_PATHS)) + .unfold().map(unfold().values("name","weight").fold()) + .forEachRemaining(System.out::println); + + System.out.println("\n\nShortest path from marko to josh (by weighted distance)\n--"); + graph.compute().program(shortestPathByWeight).submit().get().memory() + .<List<Path>>get(ShortestPathVertexProgram.SHORTEST_PATHS) + .forEach(System.out::println); + + g.inject(graph.compute().program(shortestPathByWeight).submit().get().memory() + .<List<Path>>get(ShortestPathVertexProgram.SHORTEST_PATHS)) + .unfold().map(unfold().values("name","weight").fold()) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer().V().hasLabel("person").both()//.dedup() + .shortestPath().to(has("name","peter")) + .path().forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer().V().hasLabel("person") + .union(identity(), identity()) + .shortestPath().to(has("name","peter")) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer().V().hasLabel("person") + .shortestPath().to(has("name","peter")) + .map(union(identity(), tail(Scope.local, 1)).fold()).forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V().hasLabel("person") + .shortestPath().to(has("name","peter")).identity() + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V().hasLabel("person").as("p") + .shortestPath().to(__.<Vertex>has("name","peter").where(neq("p"))) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V()//.hasLabel("person") + .shortestPath().to(__.has("name","marko")).by(__.inE()) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V()//.hasLabel("person") + .shortestPath().to(__.not(identity())).by(__.inE()) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V().not(identity()) + .shortestPath().by(__.inE()) + .forEachRemaining(System.out::println); + + System.out.println("----"); + + g.withComputer() + .V().not(identity()) + .shortestPath().to(__.not(identity())).by(__.inE()) + .forEachRemaining(System.out::println); } @Test