Repository: incubator-tinkerpop Updated Branches: refs/heads/TINKERPOP-1307 085be9469 -> 6113c9283
Fixes a problem where cardinality is better respected with subgraph step. SubgraphStep now consults the parent graph features to determine cardinality of a property. Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/636b2e5f Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/636b2e5f Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/636b2e5f Branch: refs/heads/TINKERPOP-1307 Commit: 636b2e5fc22ae2b92a96c5bda8c5979a756779d5 Parents: 0a34d2d Author: Stephen Mallette <[email protected]> Authored: Fri May 13 13:36:01 2016 -0400 Committer: Stephen Mallette <[email protected]> Committed: Mon May 16 09:04:50 2016 -0400 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + .../traversal/step/sideEffect/SubgraphStep.java | 19 +++++----- .../step/sideEffect/GroovySubgraphTest.groovy | 5 +++ .../traversal/step/sideEffect/SubgraphTest.java | 38 ++++++++++++++++++-- 4 files changed, 52 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/636b2e5f/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 1e33187..a0d5c70 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -29,6 +29,7 @@ TinkerPop 3.1.3 (NOT OFFICIALLY RELEASED YET) * Fixed a bug in `BulkSet.equals()` which made itself apparent when using `store()` and `aggregate()` with labeled `cap()`. * Ensured that all asserts of vertex and edge counts were being applied properly in the test suite. * Fixed bug in `gremlin-driver` where certain channel-level errors would not allow the driver to reconnect. +* `SubgraphStep` now consults the parent graph features to determine cardinality of a property. * Use of `Ctrl-C` in Gremlin Console now triggers closing of open remotes. * Bumped SLF4J to 1.7.21 as previous versions suffered from a memory leak. * Fixed a bug in `Neo4jGraphStepStrategy` where it wasn't defined properly as a `ProviderOptimizationStrategy`. http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/636b2e5f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java index 7290bdb..c7bcd57 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java @@ -43,6 +43,7 @@ public final class SubgraphStep extends SideEffectStep<Edge> implements SideEffe private Graph subgraph; private String sideEffectKey; + private Graph.Features.VertexFeatures parentGraphFeatures; private static final Map<String, Object> DEFAULT_CONFIGURATION = new HashMap<String, Object>() {{ put(Graph.GRAPH, "org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph"); // hard coded because TinkerGraph is not part of gremlin-core @@ -56,12 +57,13 @@ public final class SubgraphStep extends SideEffectStep<Edge> implements SideEffe @Override protected void sideEffect(final Traverser.Admin<Edge> traverser) { + parentGraphFeatures = ((Graph) traversal.getGraph().get()).features().vertex(); if (null == this.subgraph) { this.subgraph = traverser.sideEffects(this.sideEffectKey); if (!this.subgraph.features().vertex().supportsUserSuppliedIds() || !this.subgraph.features().edge().supportsUserSuppliedIds()) throw new IllegalArgumentException("The provided subgraph must support user supplied ids for vertices and edges: " + this.subgraph); } - SubgraphStep.addEdgeToSubgraph(this.subgraph, traverser.get()); + addEdgeToSubgraph(traverser.get()); } @Override @@ -93,24 +95,25 @@ public final class SubgraphStep extends SideEffectStep<Edge> implements SideEffe /// - private static Vertex getOrCreate(final Graph subgraph, final Vertex vertex) { + private Vertex getOrCreate(final Vertex vertex) { final Iterator<Vertex> vertexIterator = subgraph.vertices(vertex.id()); if (vertexIterator.hasNext()) return vertexIterator.next(); final Vertex subgraphVertex = subgraph.addVertex(T.id, vertex.id(), T.label, vertex.label()); vertex.properties().forEachRemaining(vertexProperty -> { - final VertexProperty<?> subgraphVertexProperty = subgraphVertex.property(vertexProperty.key(), vertexProperty.value(), T.id, vertexProperty.id()); - vertexProperty.properties().forEachRemaining(property -> subgraphVertexProperty.<Object>property(property.key(), property.value())); + final VertexProperty.Cardinality cardinality = parentGraphFeatures.getCardinality(vertexProperty.key()); + final VertexProperty<?> subgraphVertexProperty = subgraphVertex.property(cardinality, vertexProperty.key(), vertexProperty.value(), T.id, vertexProperty.id()); + vertexProperty.properties().forEachRemaining(property -> subgraphVertexProperty.property(property.key(), property.value())); }); return subgraphVertex; } - private static void addEdgeToSubgraph(final Graph subgraph, final Edge edge) { + private void addEdgeToSubgraph(final Edge edge) { final Iterator<Edge> edgeIterator = subgraph.edges(edge.id()); if (edgeIterator.hasNext()) return; final Iterator<Vertex> vertexIterator = edge.vertices(Direction.BOTH); - final Vertex subGraphOutVertex = getOrCreate(subgraph, vertexIterator.next()); - final Vertex subGraphInVertex = getOrCreate(subgraph, vertexIterator.next()); + final Vertex subGraphOutVertex = getOrCreate(vertexIterator.next()); + final Vertex subGraphInVertex = getOrCreate(vertexIterator.next()); final Edge subGraphEdge = subGraphOutVertex.addEdge(edge.label(), subGraphInVertex, T.id, edge.id()); - edge.properties().forEachRemaining(property -> subGraphEdge.<Object>property(property.key(), property.value())); + edge.properties().forEachRemaining(property -> subGraphEdge.property(property.key(), property.value())); } } http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/636b2e5f/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovySubgraphTest.groovy ---------------------------------------------------------------------- diff --git a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovySubgraphTest.groovy b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovySubgraphTest.groovy index 1918b00..c3ae74a 100644 --- a/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovySubgraphTest.groovy +++ b/gremlin-groovy-test/src/main/groovy/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroovySubgraphTest.groovy @@ -41,5 +41,10 @@ public abstract class GroovySubgraphTest { final Graph subgraph) { TraversalScriptHelper.compute("g.withSideEffect('sg') { subgraph }.V.repeat(__.bothE('created').subgraph('sg').outV).times(5).name.dedup", g, "subgraph", subgraph) } + + @Override + public Traversal<Vertex, Vertex> get_g_withSideEffectXsgX_V_hasXname_danielX_outE_subgraphXsgX_inV(final Graph subgraph) { + TraversalScriptHelper.compute("g.withSideEffect('sg') { subgraph }.V.has('name','daniel').outE.subgraph('sg').inV", g, "subgraph", subgraph); + } } } http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/636b2e5f/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java index ad4b0cc..dc55685 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphTest.java @@ -30,16 +30,19 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; +import java.util.List; import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN; +import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.CREW; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.bothE; import static org.apache.tinkerpop.gremlin.structure.Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES; import static org.apache.tinkerpop.gremlin.structure.Graph.Features.ElementFeatures.FEATURE_USER_SUPPLIED_IDS; import static org.apache.tinkerpop.gremlin.structure.Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; - /** * @author Stephen Mallette (http://stephen.genoprime.com) */ @@ -49,6 +52,8 @@ public abstract class SubgraphTest extends AbstractGremlinProcessTest { public abstract Traversal<Vertex, String> get_g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup(final Graph subgraph); + public abstract Traversal<Vertex, Vertex> get_g_withSideEffectXsgX_V_hasXname_danielX_outE_subgraphXsgX_inV(final Graph subgraph); + @Test @LoadGraphWith(MODERN) @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = FEATURE_ADD_VERTICES) @@ -90,17 +95,39 @@ public abstract class SubgraphTest extends AbstractGremlinProcessTest { public void g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup() throws Exception { final Configuration config = graphProvider.newGraphConfiguration("subgraph", this.getClass(), name.getMethodName(), MODERN); graphProvider.clear(config); - final Graph subgraph = graphProvider.openTestGraph(config); + Graph subgraph = graphProvider.openTestGraph(config); ///// final Traversal<Vertex, String> traversal = get_g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup(subgraph); printTraversalForm(traversal); checkResults(Arrays.asList("marko", "josh", "peter"), traversal); - final Graph subGraph = traversal.asAdmin().getSideEffects().<Graph>get("sg").get(); + subgraph = traversal.asAdmin().getSideEffects().<Graph>get("sg").get(); assertVertexEdgeCounts(subgraph, 5, 4); graphProvider.clear(subgraph, config); } + @Test + @LoadGraphWith(CREW) + @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = FEATURE_ADD_VERTICES) + @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = FEATURE_ADD_EDGES) + @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS) + @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS) + public void g_withSideEffectXsgX_V_hasXname_danielXout_capXsgX() throws Exception { + final Configuration config = graphProvider.newGraphConfiguration("subgraph", this.getClass(), name.getMethodName(), CREW); + graphProvider.clear(config); + final Graph subgraph = graphProvider.openTestGraph(config); + ///// + final Traversal<Vertex, Vertex> traversal = get_g_withSideEffectXsgX_V_hasXname_danielX_outE_subgraphXsgX_inV(subgraph); + printTraversalForm(traversal); + traversal.iterate(); + assertVertexEdgeCounts(subgraph, 3, 2); + + final List<String> locations = subgraph.traversal().V().has("name", "daniel").<String>values("location").toList(); + assertThat(locations, contains("spremberg", "kaiserslautern", "aachen")); + + graphProvider.clear(subgraph, config); + } + public static class Traversals extends SubgraphTest { @Override @@ -112,5 +139,10 @@ public abstract class SubgraphTest extends AbstractGremlinProcessTest { public Traversal<Vertex, String> get_g_V_withSideEffectXsgX_repeatXbothEXcreatedX_subgraphXsgX_outVX_timesX5X_name_dedup(final Graph subgraph) { return g.withSideEffect("sg", () -> subgraph).V().repeat(bothE("created").subgraph("sg").outV()).times(5).<String>values("name").dedup(); } + + @Override + public Traversal<Vertex, Vertex> get_g_withSideEffectXsgX_V_hasXname_danielX_outE_subgraphXsgX_inV(final Graph subgraph) { + return g.withSideEffect("sg", () -> subgraph).V().has("name","daniel").outE().subgraph("sg").inV(); + } } }
