Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1897 fd4829070 -> a7cb12b6e (forced update)


TINKERPOP-1586 Added checkAdjacentVertices option to SubgraphStrategy

This change allows the user to turn off an aspect of SubgraphStrategy that 
prevents it from working properly in OLAP situations.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/d1121544
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/d1121544
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/d1121544

Branch: refs/heads/TINKERPOP-1897
Commit: d1121544017acf1189f0270f60b5f1f402fec0ea
Parents: bcffaad
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Feb 15 16:22:58 2018 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Feb 15 16:24:54 2018 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../strategy/decoration/SubgraphStrategy.java   | 58 ++++++++++----
 .../decoration/SubgraphStrategyProcessTest.java | 84 ++++++++++++++++++++
 3 files changed, 127 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/d1121544/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index f1519b6..1701342 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -23,6 +23,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 [[release-3-2-8]]
 === TinkerPop 3.2.8 (Release Date: NOT OFFICIALLY RELEASED YET)
 
+* Added `checkAdjacentVertices` option to `SubgraphStrategy`.
 * Modified `GremlinDslProcessor` so that it generated the 
`getAnonymousTraversalClass()` method to return the DSL version of `__`.
 * Added the "Kitchen Sink" test data set.
 * Fixed a bug in `NumberHelper` that led to wrong min/max results if numbers 
exceeded the Integer limits.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/d1121544/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
index 4747cd4..e0d260f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategy.java
@@ -82,13 +82,14 @@ public final class SubgraphStrategy extends 
AbstractTraversalStrategy<TraversalS
 
     private final String MARKER = 
Graph.Hidden.hide("gremlin.subgraphStrategy");
 
-    private SubgraphStrategy(final Traversal<Vertex, ?> vertexCriterion, final 
Traversal<Edge, ?> edgeCriterion, final Traversal<VertexProperty, ?> 
vertexPropertyCriterion) {
+    private SubgraphStrategy(final Builder builder) {
 
-        this.vertexCriterion = null == vertexCriterion ? null : 
vertexCriterion.asAdmin().clone();
+        this.vertexCriterion = null == builder.vertexCriterion ? null : 
builder.vertexCriterion.asAdmin().clone();
 
-        // if there is no vertex predicate there is no need to test either 
side of the edge
-        if (null == this.vertexCriterion) {
-            this.edgeCriterion = null == edgeCriterion ? null : 
edgeCriterion.asAdmin().clone();
+        // if there is no vertex predicate there is no need to test either 
side of the edge - also this option can
+        // be simply configured in the builder to not be used
+        if (null == this.vertexCriterion || !builder.checkAdjacentVertices) {
+            this.edgeCriterion = null == builder.edgeCriterion ? null : 
builder.edgeCriterion.asAdmin().clone();
         } else {
             final Traversal.Admin<Edge, ?> vertexPredicate;
             vertexPredicate = __.<Edge>and(
@@ -97,12 +98,12 @@ public final class SubgraphStrategy extends 
AbstractTraversalStrategy<TraversalS
 
             // if there is a vertex predicate then there is an implied edge 
filter on vertices even if there is no
             // edge predicate provided by the user.
-            this.edgeCriterion = null == edgeCriterion ?
+            this.edgeCriterion = null == builder.edgeCriterion ?
                     vertexPredicate :
-                    edgeCriterion.asAdmin().clone().addStep(new 
TraversalFilterStep<>(edgeCriterion.asAdmin(), vertexPredicate));
+                    builder.edgeCriterion.asAdmin().clone().addStep(new 
TraversalFilterStep<>(builder.edgeCriterion.asAdmin(), vertexPredicate));
         }
 
-        this.vertexPropertyCriterion = null == vertexPropertyCriterion ? null 
: vertexPropertyCriterion.asAdmin().clone();
+        this.vertexPropertyCriterion = null == builder.vertexPropertyCriterion 
? null : builder.vertexPropertyCriterion.asAdmin().clone();
 
         if (null != this.vertexCriterion)
             TraversalHelper.applyTraversalRecursively(t -> 
t.getStartStep().addLabel(MARKER), this.vertexCriterion);
@@ -316,25 +317,50 @@ public final class SubgraphStrategy extends 
AbstractTraversalStrategy<TraversalS
 
     public final static class Builder {
 
-        private Traversal<Vertex, ?> vertexPredicate = null;
-        private Traversal<Edge, ?> edgePredicate = null;
-        private Traversal<VertexProperty, ?> vertexPropertyPredicate = null;
+        private Traversal<Vertex, ?> vertexCriterion = null;
+        private Traversal<Edge, ?> edgeCriterion = null;
+        private Traversal<VertexProperty, ?> vertexPropertyCriterion = null;
+        private boolean checkAdjacentVertices = true;
 
         private Builder() {
         }
 
+        /**
+         * Enables the strategy to apply the {@link #vertices(Traversal)} 
filter to the adjacent vertices of an edge.
+         * If using this strategy for OLAP then this value should be set to 
{@code false} as checking adjacent vertices
+         * will force the traversal to leave the local star graph (which is 
not possible in OLAP) and will cause an
+         * error. By default, this value is {@code true}.
+         */
+        public Builder checkAdjacentVertices(final boolean enable) {
+            this.checkAdjacentVertices = enable;
+            return this;
+        }
+
+        /**
+         * The traversal predicate that defines the vertices to include in the 
subgraph. If
+         * {@link #checkAdjacentVertices(boolean)} is {@code true} then this 
predicate will also be applied to the
+         * adjacent vertices of edges. Take care when setting this value for 
OLAP based traversals as the traversal
+         * predicate cannot be written in such a way as to leave the local 
star graph and can thus only evaluate the
+         * current vertex and its related edges.
+         */
         public Builder vertices(final Traversal<Vertex, ?> vertexPredicate) {
-            this.vertexPredicate = vertexPredicate;
+            this.vertexCriterion = vertexPredicate;
             return this;
         }
 
+        /**
+         * The traversal predicate that defines the edges to include in the 
subgraph.
+         */
         public Builder edges(final Traversal<Edge, ?> edgePredicate) {
-            this.edgePredicate = edgePredicate;
+            this.edgeCriterion = edgePredicate;
             return this;
         }
 
+        /**
+         * The traversal predicate that defines the vertex properties to 
include in the subgraph.
+         */
         public Builder vertexProperties(final Traversal<VertexProperty, ?> 
vertexPropertyPredicate) {
-            this.vertexPropertyPredicate = vertexPropertyPredicate;
+            this.vertexPropertyCriterion = vertexPropertyPredicate;
             return this;
         }
 
@@ -355,9 +381,9 @@ public final class SubgraphStrategy extends 
AbstractTraversalStrategy<TraversalS
         }
 
         public SubgraphStrategy create() {
-            if (null == this.vertexPredicate && null == this.edgePredicate && 
null == this.vertexPropertyPredicate)
+            if (null == this.vertexCriterion && null == this.edgeCriterion && 
null == this.vertexPropertyCriterion)
                 throw new IllegalStateException("A subgraph must be filtered 
by a vertex, edge, or vertex property criterion");
-            return new SubgraphStrategy(this.vertexPredicate, 
this.edgePredicate, this.vertexPropertyPredicate);
+            return new SubgraphStrategy(this);
         }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/d1121544/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
----------------------------------------------------------------------
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
index ad2501d..2565770 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SubgraphStrategyProcessTest.java
@@ -252,6 +252,90 @@ public class SubgraphStrategyProcessTest extends 
AbstractGremlinProcessTest {
 
     @Test
     @LoadGraphWith(MODERN)
+    public void shouldFilterMixedCriteriaButNotCheckAdjacentVertices() {
+        final Traversal<Vertex, ?> vertexCriterion = has("name", 
P.within("josh", "lop", "ripple"));
+
+        // 9 isn't present because marko is not in the vertex list
+        final Traversal<Edge, ?> edgeCriterion = __.or(
+                has("weight", 0.4d).hasLabel("created"), // 11
+                has("weight", 1.0d).hasLabel("created") // 10
+        );
+
+        final SubgraphStrategy strategy = SubgraphStrategy.build().
+                checkAdjacentVertices(false).
+                edges(edgeCriterion).vertices(vertexCriterion).create();
+        final GraphTraversalSource sg = g.withStrategies(strategy);
+
+        // three vertices are included in the subgraph
+        assertEquals(6, g.V().count().next().longValue());
+        assertEquals(3, sg.V().count().next().longValue());
+
+        // three edges are explicitly included as we ignore checking of 
adjacent vertices
+        assertEquals(6, g.E().count().next().longValue());
+        assertEquals(3, sg.E().count().next().longValue());
+
+        // from vertex
+
+        assertEquals(2, 
g.V(convertToVertexId("josh")).outE().count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).outE().count().next().longValue());
+        assertEquals(2, 
g.V(convertToVertexId("josh")).out().count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).out().count().next().longValue());
+
+        assertEquals(1, 
g.V(convertToVertexId("josh")).inE().count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).inE().count().next().longValue());
+        assertEquals(1, 
g.V(convertToVertexId("josh")).in().count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).in().count().next().longValue());
+
+        assertEquals(3, 
g.V(convertToVertexId("josh")).bothE().count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).bothE().count().next().longValue());
+        assertEquals(3, 
g.V(convertToVertexId("josh")).both().count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).both().count().next().longValue());
+
+        // marko not present directly because of vertexCriterion - only 
accessible via vertices in the subgraph
+        assertEquals(1, 
g.V(convertToVertexId("marko")).count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("marko")).count().next().longValue());
+
+        // with label
+
+        assertEquals(2, 
g.V(convertToVertexId("josh")).outE("created").count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).outE("created").count().next().longValue());
+        assertEquals(2, 
g.V(convertToVertexId("josh")).out("created").count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).out("created").count().next().longValue());
+        assertEquals(2, 
g.V(convertToVertexId("josh")).bothE("created").count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).bothE("created").count().next().longValue());
+        assertEquals(2, 
g.V(convertToVertexId("josh")).both("created").count().next().longValue());
+        assertEquals(2, 
sg.V(convertToVertexId("josh")).both("created").count().next().longValue());
+
+        assertEquals(1, 
g.V(convertToVertexId("josh")).inE("knows").count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).inE("knows").count().next().longValue());
+        assertEquals(1, 
g.V(convertToVertexId("josh")).in("knows").count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).in("knows").count().next().longValue());
+        assertEquals(1, 
g.V(convertToVertexId("josh")).bothE("knows").count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).bothE("knows").count().next().longValue());
+        assertEquals(1, 
g.V(convertToVertexId("josh")).both("knows").count().next().longValue());
+        assertEquals(0, 
sg.V(convertToVertexId("josh")).both("knows").count().next().longValue());
+
+        // with branch factor
+
+        assertEquals(1, 
g.V(convertToVertexId("josh")).local(bothE().limit(1)).count().next().longValue());
+        assertEquals(1, 
sg.V(convertToVertexId("josh")).local(bothE().limit(1)).count().next().longValue());
+        assertEquals(1, 
g.V(convertToVertexId("josh")).local(bothE().limit(1)).inV().count().next().longValue());
+        assertEquals(1, 
sg.V(convertToVertexId("josh")).local(bothE().limit(1)).inV().count().next().longValue());
+        assertEquals(1, g.V(convertToVertexId("josh")).local(bothE("knows", 
"created").limit(1)).count().next().longValue());
+        assertEquals(1, sg.V(convertToVertexId("josh")).local(bothE("knows", 
"created").limit(1)).count().next().longValue());
+        assertEquals(1, g.V(convertToVertexId("josh")).local(bothE("knows", 
"created").limit(1)).inV().count().next().longValue());
+        assertEquals(1, sg.V(convertToVertexId("josh")).local(bothE("knows", 
"created").limit(1)).inV().count().next().longValue());
+
+        // from edge
+
+        // marko is not accessible from the edge
+        assertEquals(2, g.E(convertToEdgeId("marko", "created", 
"lop")).bothV().count().next().longValue());
+        assertEquals(1, sg.E(convertToEdgeId("marko", "created", 
"lop")).bothV().count().next().longValue());
+    }
+
+
+    @Test
+    @LoadGraphWith(MODERN)
     public void shouldFilterMixedCriteria() throws Exception {
         final Traversal<Vertex, ?> vertexCriterion = has("name", 
P.within("josh", "lop", "ripple"));
 

Reply via email to