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;