You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2015/06/15 23:49:15 UTC

incubator-tinkerpop git commit: XMatchStep now has the same API as MatchStep -- startKey, traversals and returns Map.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/xmatch c77521cc1 -> 538af16b4


XMatchStep now has the same API as MatchStep -- startKey,traversals and returns Map<String,E>.


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

Branch: refs/heads/xmatch
Commit: 538af16b453090a332f1bf571e55ea21462ac53e
Parents: c77521c
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Jun 15 15:49:04 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Jun 15 15:49:04 2015 -0600

----------------------------------------------------------------------
 .../traversal/dsl/graph/GraphTraversal.java     |  5 +-
 .../gremlin/process/traversal/dsl/graph/__.java |  4 +-
 .../traversal/step/filter/exp/XMatchStep.java   | 94 ++++++++++++++++----
 .../tinkergraph/structure/TinkerGraphTest.java  |  5 +-
 4 files changed, 83 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/538af16b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
index 8b9db86..06a3951 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java
@@ -465,6 +465,7 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
     public default <E2> GraphTraversal<S, Map<String, E2>> match(final String startLabel, final Traversal<?, ?>... traversals) {
         return (GraphTraversal) this.asAdmin().addStep(new MatchStep<E, Map<String, E2>>(this.asAdmin(), startLabel, traversals));
+        //return (GraphTraversal) this.asAdmin().addStep(new XMatchStep(this.asAdmin(), startLabel, XMatchStep.Conjunction.AND, traversals));
     }
 
     /**
@@ -1010,8 +1011,8 @@ public interface GraphTraversal<S, E> extends Traversal<S, E> {
 
     ////
 
-    public default GraphTraversal<S, E> xmatch(final Traversal<?, ?>... andTraversals) {
-        return this.asAdmin().addStep(new XMatchStep<>(this.asAdmin(), XMatchStep.Conjunction.AND, andTraversals));
+    public default <E2> GraphTraversal<S, Map<String,E2>> xmatch(final String startKey, final Traversal<?, ?>... andTraversals) {
+        return this.asAdmin().addStep(new XMatchStep<>(this.asAdmin(), startKey, XMatchStep.Conjunction.AND, andTraversals));
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/538af16b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
index 7011036..af17803 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/__.java
@@ -774,8 +774,8 @@ public class __ {
         return __.<A>start().barrier(maxBarrierSize);
     }
 
-    public static <A> GraphTraversal<A, A> xmatch(final Traversal<?, ?>... andTraversals) {
-        return __.<A>start().xmatch(andTraversals);
+    public static <A,B> GraphTraversal<A, Map<String,B>> xmatch(final String startKey, final Traversal<?, ?>... andTraversals) {
+        return __.<A>start().xmatch(startKey, andTraversals);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/538af16b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
index 9e72bc5..8debce5 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/exp/XMatchStep.java
@@ -27,6 +27,7 @@ import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 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.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.AndStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.ConjunctionStep;
@@ -41,9 +42,11 @@ import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.Set;
@@ -54,19 +57,22 @@ import java.util.stream.Stream;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements TraversalParent {
+public final class XMatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>> implements TraversalParent, Scoping {
 
     public enum Conjunction {AND, OR}
 
     private List<Traversal.Admin<Object, Object>> conjunctionTraversals = new ArrayList<>();
     private boolean first = true;
     private Set<String> matchStartLabels = null;
+    private Set<String> matchEndLabels = null;
     private final Conjunction conjunction;
+    private final String startKey;
     private final MatchAlgorithm matchAlgorithm = new GreedyMatchAlgorithm();
 
-    public XMatchStep(final Traversal.Admin traversal, final Conjunction conjunction, final Traversal... conjunctionTraversals) {
+    public XMatchStep(final Traversal.Admin traversal, final String startKey, final Conjunction conjunction, final Traversal... conjunctionTraversals) {
         super(traversal);
         this.conjunction = conjunction;
+        this.traversal.getEndStep().addLabel(this.startKey = startKey);
         this.conjunctionTraversals = (List) Stream.of(conjunctionTraversals).map(Traversal::asAdmin).map(this::integrateChild).collect(Collectors.toList());
         this.conjunctionTraversals.forEach(this::configureStartAndEndSteps); // recursively convert to SelectOneStep, XMatchStep, or XMatchEndStep
     }
@@ -76,14 +82,17 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
         // START STEP to SelectOneStep OR XMatchStep
         final Step<?, ?> startStep = conjunctionTraversal.getStartStep();
         if (startStep instanceof ConjunctionStep) {
-            final XMatchStep xMatchStep = new XMatchStep(conjunctionTraversal,
+            final XMatchStep xMatchStep = new XMatchStep(conjunctionTraversal, this.startKey,
                     startStep instanceof AndStep ? XMatchStep.Conjunction.AND : XMatchStep.Conjunction.OR,
                     ((ConjunctionStep<?>) startStep).getLocalChildren().toArray(new Traversal[((ConjunctionStep<?>) startStep).getLocalChildren().size()]));
             TraversalHelper.replaceStep(startStep, xMatchStep, conjunctionTraversal);
         } else if (startStep instanceof StartStep && !startStep.getLabels().isEmpty()) {
             if (startStep.getLabels().size() > 1)
                 throw new IllegalArgumentException("The start step of a match()-traversal can only have one label: " + startStep);
-            TraversalHelper.replaceStep(conjunctionTraversal.getStartStep(), new SelectOneStep<>(conjunctionTraversal, Scope.global, Pop.head, startStep.getLabels().iterator().next()), conjunctionTraversal);
+            final String label = startStep.getLabels().iterator().next();
+            final Step selectOneStep = new SelectOneStep<>(conjunctionTraversal, Scope.global, Pop.head, label);
+            selectOneStep.addLabel(label);
+            TraversalHelper.replaceStep(conjunctionTraversal.getStartStep(), selectOneStep, conjunctionTraversal);
         }
         // END STEP to XMatchStep
         final Step<?, ?> endStep = conjunctionTraversal.getEndStep();
@@ -101,21 +110,55 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
     public Set<String> getMatchStartLabels() {
         if (null == this.matchStartLabels) {
             this.matchStartLabels = new HashSet<>();
-            for (final Traversal.Admin<Object, Object> conjunctionTraversals : this.conjunctionTraversals) {
-                this.matchStartLabels.addAll(conjunctionTraversals.getStartStep() instanceof XMatchStep ?
-                        ((XMatchStep) conjunctionTraversals.getStartStep()).getMatchStartLabels() :
-                        ((SelectOneStep) conjunctionTraversals.getStartStep()).getScopeKeys());
+            for (final Traversal.Admin<Object, Object> conjunctionTraversal : this.conjunctionTraversals) {
+                this.matchStartLabels.addAll(conjunctionTraversal.getStartStep() instanceof XMatchStep ?
+                        ((XMatchStep) conjunctionTraversal.getStartStep()).getMatchStartLabels() :
+                        ((SelectOneStep) conjunctionTraversal.getStartStep()).getScopeKeys());
             }
             this.matchStartLabels = Collections.unmodifiableSet(this.matchStartLabels);
         }
         return this.matchStartLabels;
     }
 
+    public Set<String> getMatchEndLabels() {
+        if (null == this.matchEndLabels) {
+            this.matchEndLabels = new HashSet<>();
+            for (final Traversal.Admin<Object, Object> conjunctionTraversal : this.conjunctionTraversals) {
+                if (conjunctionTraversal.getStartStep() instanceof XMatchStep) {
+                    this.matchEndLabels.addAll(((XMatchStep) conjunctionTraversal.getStartStep()).getMatchEndLabels());
+                }
+                this.matchEndLabels.add(((XMatchEndStep) (Step<?, ?>) conjunctionTraversal.getEndStep()).matchKey);
+            }
+            this.matchEndLabels = Collections.unmodifiableSet(this.matchEndLabels);
+        }
+        return this.matchEndLabels;
+    }
+
     public List<Traversal.Admin<Object, Object>> getGlobalChildren() {
         return Collections.unmodifiableList(this.conjunctionTraversals);
     }
 
     @Override
+    public Scope getScope() {
+        return Scope.global;
+    }
+
+    @Override
+    public Scope recommendNextScope() {
+        return Scope.local;
+    }
+
+    @Override
+    public void setScope(final Scope scope) {
+
+    }
+
+    @Override
+    public Set<String> getScopeKeys() {
+        return this.getMatchEndLabels();
+    }
+
+    @Override
     public String toString() {
         return StringFactory.stepString(this, this.conjunction, this.conjunctionTraversals);
     }
@@ -127,8 +170,8 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
     }
 
     @Override
-    public XMatchStep<S> clone() {
-        final XMatchStep<S> clone = (XMatchStep<S>) super.clone();
+    public XMatchStep<S, E> clone() {
+        final XMatchStep<S, E> clone = (XMatchStep<S, E>) super.clone();
         clone.conjunctionTraversals = new ArrayList<>();
         for (final Traversal.Admin<Object, Object> traversal : this.conjunctionTraversals) {
             clone.conjunctionTraversals.add(clone.integrateChild(traversal.clone()));
@@ -146,11 +189,26 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
                 counter++;
             }
         }
+        // if (counter == 0) traverser.path().addLabel(this.startKey); // for computer to add the start key
         return this.conjunctionTraversals.size() == counter;
     }
 
+    private Map<String, E> getBindings(final Traverser<S> traverser) {
+        final Map<String, E> bindings = new HashMap<>();
+        traverser.path().forEach((object, labels) -> {
+            for (final String label : labels) {
+                if (this.getMatchEndLabels().contains(label)) {
+                    bindings.put(label, (E) object);
+                } else if (this.getMatchStartLabels().contains(label)) {
+                    bindings.put(label, (E) object);
+                }
+            }
+        });
+        return bindings;
+    }
+
     @Override
-    protected Iterator<Traverser<S>> standardAlgorithm() throws NoSuchElementException {
+    protected Iterator<Traverser<Map<String, E>>> standardAlgorithm() throws NoSuchElementException {
         while (true) {
             Traverser.Admin traverser = null;
             if (this.first) {
@@ -164,10 +222,10 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
                     }
                 }
             }
-            if (null == traverser)
+            if (null == traverser) {
                 traverser = this.starts.next();
-            else if (hasMatched(this.conjunction, traverser))
-                return IteratorUtils.of(traverser);
+            } else if (hasMatched(this.conjunction, traverser))
+                return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
 
             if (this.conjunction == Conjunction.AND) {
                 final Traversal.Admin<Object, Object> conjunctionTraversal = this.matchAlgorithm.apply(traverser); // determine which sub-pattern the traverser should try next
@@ -184,7 +242,7 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
     }
 
     @Override
-    protected Iterator<Traverser<S>> computerAlgorithm() throws NoSuchElementException {
+    protected Iterator<Traverser<Map<String, E>>> computerAlgorithm() throws NoSuchElementException {
         if (this.first) {
             this.matchAlgorithm.initialize(this.conjunctionTraversals);
             this.first = false;
@@ -192,7 +250,7 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
         final Traverser.Admin traverser = this.starts.next();
         if (hasMatched(this.conjunction, traverser)) {
             traverser.setStepId(this.getNextStep().getId());
-            return IteratorUtils.of(traverser);
+            return IteratorUtils.of(traverser.split(this.getBindings(traverser), this));
         }
 
         if (this.conjunction == Conjunction.AND) {
@@ -201,7 +259,7 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
             traverser.setStepId(conjunctionTraversal.getStartStep().getId()); // go down the traversal match sub-pattern
             return IteratorUtils.of(traverser);
         } else {
-            final List<Traverser<S>> traversers = new ArrayList<>();
+            final List<Traverser<Map<String, E>>> traversers = new ArrayList<>();
             this.conjunctionTraversals.forEach(conjunctionTraversal -> {
                 final Traverser.Admin split = traverser.split();
                 split.path().addLabel(conjunctionTraversal.getStartStep().getId());
@@ -299,7 +357,7 @@ public final class XMatchStep<S> extends ComputerAwareStep<S, S> implements Trav
                     return this.traversals.get(i);
                 }
             }
-            throw new IllegalStateException("The provided match pattern is unsolvable: " + this.traversals);
+            throw new IllegalArgumentException("The provided match pattern is unsolvable: " + this.traversals);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/538af16b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
index de6d55e..12995fe 100644
--- a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
+++ b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraphTest.java
@@ -158,7 +158,7 @@ public class TinkerGraphTest {
     @Ignore
     public void testPlay5() throws Exception {
         GraphTraversalSource g = TinkerFactory.createModern().traversal(GraphTraversalSource.standard());
-        final Supplier<Traversal<?, ?>> traversal = () -> g.V().as("a").xmatch(
+        final Supplier<Traversal<?, ?>> traversal = () -> g.V().xmatch("a",
                 as("a").out("created").as("b"),
                 or(
                         as("a").out("knows").as("c"),
@@ -166,8 +166,7 @@ public class TinkerGraphTest {
                                 as("a").out("created").has("name", "ripple"),
                                 as("a").out().out()
                         )
-                ))
-                .select(Pop.head);
+                ));
         /*
                 g.V().as("a").xmatch(
                         as("a").out("knows").as("b"),