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/05/30 21:45:35 UTC

incubator-tinkerpop git commit: Neo4jGraphStep is now uses Neo4j schema indices appropriately. Much simpler Neo4jGraphStep without having to think about automatic indices.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master 486bc3b01 -> 50bd2973d


Neo4jGraphStep is now uses Neo4j schema indices appropriately. Much simpler Neo4jGraphStep without having to think about automatic indices.


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

Branch: refs/heads/master
Commit: 50bd2973d81d1fd1d478da6ff565f841a542c48a
Parents: 486bc3b
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Sat May 30 13:45:40 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Sat May 30 13:45:40 2015 -0600

----------------------------------------------------------------------
 .../step/sideEffect/Neo4jGraphStep.java         | 111 +++++++------------
 .../gremlin/neo4j/structure/Neo4jGraph.java     |   1 +
 .../neo4j/AbstractNeo4jGraphProvider.java       |  28 +++++
 .../gremlin/neo4j/NativeNeo4jSuite.java         |   8 +-
 .../neo4j/structure/NativeNeo4jIndexTest.java   |  60 ++++++++++
 .../structure/NativeNeo4jStructureTest.java     |   2 -
 6 files changed, 137 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
index 949a22a..f274e32 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
@@ -20,30 +20,21 @@ package org.apache.tinkerpop.gremlin.neo4j.process.traversal.step.sideEffect;
 
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
-import org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait;
 import org.apache.tinkerpop.gremlin.process.traversal.Compare;
-import org.apache.tinkerpop.gremlin.process.traversal.Contains;
 import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
-import org.javatuples.Pair;
-import org.neo4j.tinkerpop.api.Neo4jDirection;
-import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
-import org.neo4j.tinkerpop.api.Neo4jNode;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
+import java.util.Optional;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -73,76 +64,56 @@ public final class Neo4jGraphStep<S extends Element> extends GraphStep<S> {
             return IteratorUtils.filter(graph.vertices(this.ids), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
         ////// do index lookups //////
         graph.tx().readWrite();
-        // a label and a property
-        final Pair<String, HasContainer> labelHasPair = this.getHasContainerForLabelIndex();
-        if (null != labelHasPair)
-            return this.getVerticesUsingLabelAndProperty(labelHasPair.getValue0(), labelHasPair.getValue1())
-                    .filter(vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers)).iterator();
-        // only labels
-        final List<String> labels = this.getInternalLabels();
-        if (null != labels)
-            return this.getVerticesUsingOnlyLabels(labels).filter(vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers)).iterator();
-        // linear scan
-        return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
-    }
-
-
-    private Stream<Neo4jVertex> getVerticesUsingLabelAndProperty(final String label, final HasContainer hasContainer) {
-        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
-        final Iterable<Neo4jNode> iterator1 = graph.getBaseGraph().findNodes(label, hasContainer.getKey(), hasContainer.getValue());
-        final Iterable<Neo4jNode> iterator2 = graph.getBaseGraph().findNodes(hasContainer.getKey(), T.value.getAccessor(), hasContainer.getValue());
-        final Stream<Neo4jVertex> stream1 = IteratorUtils.stream(iterator1)
-                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
-                .map(node -> new Neo4jVertex(node, graph));
-        final Stream<Neo4jVertex> stream2 = IteratorUtils.stream(iterator2)
-                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
-                .filter(node -> node.getProperty(T.key.getAccessor()).equals(hasContainer.getKey()))
-                .map(node -> node.relationships(Neo4jDirection.INCOMING).iterator().next().start())
-                .map(node -> new Neo4jVertex(node, graph));
-        return Stream.concat(stream1, stream2);
-    }
-
-    private Stream<Neo4jVertex> getVerticesUsingOnlyLabels(final List<String> labels) {
-        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
-        final Predicate<Neo4jNode> nodePredicate = graph.getTrait().getNodePredicate();
-        return labels.stream()
-                .flatMap(label -> IteratorUtils.stream(graph.getBaseGraph().findNodes(label)))
-                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
-                .filter(nodePredicate)
-                .map(node -> new Neo4jVertex(node, graph));
-    }
-
-    private Pair<String, HasContainer> getHasContainerForLabelIndex() {
-        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
-        Neo4jGraphAPI baseGraph = graph.getBaseGraph();
-        for (final HasContainer hasContainer : this.hasContainers) {
-            if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Compare.eq)) {
-                if (baseGraph.hasSchemaIndex(
-                        (String) hasContainer.getValue(), hasContainer.getKey())) {
-                    return Pair.with((String) hasContainer.getValue(), hasContainer);
+        // get a label being search on
+        final Optional<String> label = this.hasContainers.stream()
+                .filter(hasContainer -> hasContainer.getKey().equals(T.label.getAccessor()))
+                .filter(hasContainer -> hasContainer.getPredicate().equals(Compare.eq))
+                .map(hasContainer -> (String) hasContainer.getValue())
+                .findAny();
+        if (label.isPresent()) {
+            // find a vertex by label and key/value
+            for (final HasContainer hasContainer : this.hasContainers) {
+                if (hasContainer.getPredicate().equals(Compare.eq)) {
+                    return IteratorUtils.filter(
+                            IteratorUtils.map(
+                                    graph.getBaseGraph().findNodes(label.get(), hasContainer.getKey(), hasContainer.getValue()).iterator(),
+                                    node -> new Neo4jVertex(node, graph)),
+                            vertex -> HasContainer.testAll(vertex, this.hasContainers));
+                }
+            }
+        } else {
+            // find a vertex by key/value
+            for (final HasContainer hasContainer : this.hasContainers) {
+                if (hasContainer.getPredicate().equals(Compare.eq)) {
+                    return IteratorUtils.filter(
+                            IteratorUtils.map(
+                                    graph.getBaseGraph().findNodes(hasContainer.getKey(), hasContainer.getValue()).iterator(),
+                                    node -> new Neo4jVertex(node, graph)),
+                            vertex -> HasContainer.testAll(vertex, this.hasContainers));
                 }
             }
         }
-        return null;
-    }
-
-    private List<String> getInternalLabels() {
-        for (final HasContainer hasContainer : this.hasContainers) {
-            if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Compare.eq))
-                return Arrays.asList(((String) hasContainer.getValue()));
-            else if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Contains.within))
-                return new ArrayList<>((Collection<String>) hasContainer.getValue());
+        if (label.isPresent()) {
+            // find a vertex by label
+            return IteratorUtils.filter(
+                    IteratorUtils.map(
+                            graph.getBaseGraph().findNodes(label.get()).iterator(),
+                            node -> new Neo4jVertex(node, graph)),
+                    vertex -> HasContainer.testAll(vertex, this.hasContainers));
+        } else {
+            // linear scan
+            return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
         }
-        return null;
     }
 
-    @Override
+    // TODO: move all this to the traits!
+
     public String toString() {
         if (this.hasContainers.isEmpty())
             return super.toString();
         else
             return 0 == this.ids.length ?
-                    StringFactory.stepString(this, this.hasContainers) :
-                    StringFactory.stepString(this, Arrays.toString(this.ids), this.hasContainers);
+                    StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), this.hasContainers) :
+                    StringFactory.stepString(this, this.returnClass.getSimpleName().toLowerCase(), Arrays.toString(this.ids), this.hasContainers);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
index 31aa0c5..8a7060c 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
@@ -68,6 +68,7 @@ import java.util.stream.Stream;
 @Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT)
 @Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT_INTEGRATE)
 @Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT_PERFORMANCE)
+@Graph.OptIn("org.apache.tinkerpop.gremlin.neo4j.NativeNeo4jSuite")
 public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
 
     static {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
index 41b6d0f..c59ad3f 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
@@ -75,6 +75,34 @@ public abstract class AbstractNeo4jGraphProvider extends AbstractGraphProvider {
         super.loadGraphData(graph, loadGraphWith, testClass, testName);
     }
 
+    public static void dropIndices(final Neo4jGraph graph, final LoadGraphWith.GraphData graphData) {
+        if (graphData.equals(LoadGraphWith.GraphData.GRATEFUL)) {
+            graph.tx().readWrite();
+            graph.cypher("DROP INDEX ON :artist(name)").iterate();
+            graph.cypher("DROP INDEX ON :song(name)").iterate();
+            graph.cypher("DROP INDEX ON :song(songType)").iterate();
+            graph.cypher("DROP INDEX ON :song(performances)").iterate();
+            graph.tx().commit();
+        } else if (graphData.equals(LoadGraphWith.GraphData.MODERN)) {
+            graph.tx().readWrite();
+            graph.cypher("DROP INDEX ON :person(name)").iterate();
+            graph.cypher("DROP INDEX ON :person(age)").iterate();
+            graph.cypher("DROP INDEX ON :software(name)").iterate();
+            graph.cypher("DROP INDEX ON :software(lang)").iterate();
+            graph.tx().commit();
+        } else if (graphData.equals(LoadGraphWith.GraphData.CLASSIC)) {
+            graph.tx().readWrite();
+            graph.cypher("DROP INDEX ON :vertex(name)").iterate();
+            graph.cypher("DROP INDEX ON :vertex(age)").iterate();
+            graph.cypher("DROP INDEX ON :vertex(lang)").iterate();
+            graph.tx().commit();
+        } else {
+            // TODO: add CREW work here.
+            // TODO: add meta_property indices when meta_property graph is provided
+            //throw new RuntimeException("Could not load graph with " + graphData);
+        }
+    }
+
     private void createIndices(final Neo4jGraph graph, final LoadGraphWith.GraphData graphData) {
         final Random random = new Random();
         final boolean pick = random.nextBoolean();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NativeNeo4jSuite.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NativeNeo4jSuite.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NativeNeo4jSuite.java
index cf23fda..58da3cf 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NativeNeo4jSuite.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/NativeNeo4jSuite.java
@@ -23,6 +23,7 @@ package org.apache.tinkerpop.gremlin.neo4j;
 
 import org.apache.tinkerpop.gremlin.AbstractGremlinSuite;
 import org.apache.tinkerpop.gremlin.neo4j.process.NativeNeo4jCypherTest;
+import org.apache.tinkerpop.gremlin.neo4j.structure.NativeNeo4jIndexTest;
 import org.apache.tinkerpop.gremlin.neo4j.structure.NativeNeo4jStructureTest;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
 import org.junit.runners.model.InitializationError;
@@ -37,10 +38,15 @@ public class NativeNeo4jSuite extends AbstractGremlinSuite {
         super(klass, builder,
                 new Class<?>[]{
                         NativeNeo4jStructureTest.class,
+                        NativeNeo4jIndexTest.class,
                         NativeNeo4jCypherTest.class,
                 }, new Class<?>[]{
                         NativeNeo4jStructureTest.class,
-                        NativeNeo4jCypherTest.class}, true, TraversalEngine.Type.STANDARD);
+                        NativeNeo4jIndexTest.class,
+                        NativeNeo4jCypherTest.class
+                },
+                false,
+                TraversalEngine.Type.STANDARD);
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexTest.java
new file mode 100644
index 0000000..0df3cf2
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jIndexTest.java
@@ -0,0 +1,60 @@
+/*
+ *
+ *  * 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.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.neo4j.AbstractNeo4jGremlinTest;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.util.TimeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public class NativeNeo4jIndexTest extends AbstractNeo4jGremlinTest {
+
+    @Test
+    public void shouldHaveFasterRuntimeWithLabelKeyValueIndex() throws Exception {
+        final Neo4jGraph neo4j = (Neo4jGraph) this.graph;
+        for (int i = 0; i < 10000; i++) {
+            if (i % 2 == 0)
+                this.graph.addVertex(T.label, "something", "myId", i);
+            else
+                this.graph.addVertex(T.label, "nothing", "myId", i);
+        }
+        this.graph.tx().commit();
+        final Runnable traversal = () -> g.V().hasLabel("something").has("myId", 2000).tryNext().get();
+
+        // no index
+        TimeUtil.clock(10, traversal);
+        final double noIndexTime = TimeUtil.clock(20, traversal);
+        // index time
+        neo4j.cypher("CREATE INDEX ON :something(myId)").iterate();
+        this.graph.tx().commit();
+        Thread.sleep(5000); // wait for index to be build just in case
+        TimeUtil.clock(10, traversal);
+        final double indexTime = TimeUtil.clock(20, traversal);
+        //System.out.println(noIndexTime + "----" + indexTime);
+        assertTrue(noIndexTime > indexTime);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/50bd2973/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureTest.java
index dc29a91..75e5d80 100644
--- a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureTest.java
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/NativeNeo4jStructureTest.java
@@ -21,9 +21,7 @@
 
 package org.apache.tinkerpop.gremlin.neo4j.structure;
 
-import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
-import org.apache.tinkerpop.gremlin.LoadGraphWith;
 import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
 import org.apache.tinkerpop.gremlin.neo4j.AbstractNeo4jGremlinTest;
 import org.apache.tinkerpop.gremlin.neo4j.structure.trait.MultiMetaNeo4jTrait;