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/01 17:33:36 UTC

incubator-tinkerpop git commit: fixed a Vertex.remove() bug that showed up in VertexTest for Neo4jGraph. Neo4jGraphStep now relies on the Neo4jTrait for index lookups. Added a WARNING to docs about Neo4j and multi- meta- properties.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master c520013de -> 8250a2f91


fixed a Vertex.remove() bug that showed up in VertexTest for Neo4jGraph. Neo4jGraphStep now relies on the Neo4jTrait for index lookups. Added a WARNING to docs about Neo4j and multi- meta- properties.


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

Branch: refs/heads/master
Commit: 8250a2f9155b20c8132770eef40867ca9722dd47
Parents: c520013
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Mon Jun 1 09:33:38 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Mon Jun 1 09:33:38 2015 -0600

----------------------------------------------------------------------
 docs/src/implementations.asciidoc               |  6 +-
 .../step/sideEffect/Neo4jGraphStep.java         | 52 +--------------
 .../gremlin/neo4j/structure/Neo4jGraph.java     | 22 ++++---
 .../structure/trait/MultiMetaNeo4jTrait.java    | 24 +++++--
 .../neo4j/structure/trait/Neo4jTrait.java       |  8 +++
 .../trait/NoMultiNoMetaNeo4jTrait.java          | 68 ++++++++++++++++++++
 6 files changed, 114 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/docs/src/implementations.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/implementations.asciidoc b/docs/src/implementations.asciidoc
index 3bad2a9..d759742 100644
--- a/docs/src/implementations.asciidoc
+++ b/docs/src/implementations.asciidoc
@@ -556,9 +556,11 @@ gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
 
 For those leveraging Neo4j High Availability, configure `Neo4jGraph` for "HA mode" by setting the `gremlin.neo4j.ha` flag to `true` in the `Configuration` object passed to `Neo4jGraph.open()`.  Note that when the flag is set (by default it is `false`), the `Neo4jGraph` instance expects HA configuration settings to be present.  As with embedded Neo4j, HA configuration keys should be prefixed with `gremlin.neo4j.conf`.  Please consult Neo4j documentation for more information on link:http://docs.neo4j.org/chunked/stable/ha.html[High Availability] configuration.
 
-IMPORTANT: `Neo4jGraph` supports both meta- and multi-properties (see <<_vertex_properties,vertex properties>>). However, these are implemented by making use of "hidden" Neo4j nodes. For example, when a vertex has multiple "name" properties, each property is a new node (multi-properties) which can have properties attached to it (meta-properties). As such, the underlying representation may become difficult to query directly using another graph language such as Cypher. The default setting is to disable multi- and meta-properties. However, if this feature is desired, then it can be activated via `gremlin.neo4j.metaProperties` and `gremlin.neo4j.multiProperties` configurations being set to `true`. Once the configuration is set, it can not be changed for the lifetime of the graph.
+IMPORTANT: `Neo4jGraph` supports both multi- and meta-properties (see <<_vertex_properties,vertex properties>>). This is not a native feature of Neo4j and is implemented by making use of "hidden" Neo4j nodes. For example, when a vertex has multiple "name" properties, each property is a new node (multi-properties) which can have properties attached to it (meta-properties). As such, the native, underlying representation may become difficult to query directly using another graph language such as Cypher. The default setting is to disable multi- and meta-properties. However, if this feature is desired, then it can be activated via `gremlin.neo4j.metaProperties` and `gremlin.neo4j.multiProperties` configurations being set to `true`. Once the configuration is set, it can not be changed for the lifetime of the graph.
 
-TIP: To host Neo4j in Gremlin Server, the dependencies must first be "installed" or otherwise copied to the Gremlin Server path.  The automated method for doing this would be to execute `bin/gremlin-server.sh -i org.apache.tinkerpop neo4j-gremlin x.y.z`.
+WARNING: `Neo4jGraph` without multi- and meta-properties is in 1-to-1 correspondence with the native, underlying Neo4j representation. It is recommended that if the user does not require these features, then they should not enable them. Without multi- and meta-properties enabled, Neo4j can be interacted with with other tools and technologies that do not leverage TinkerPop.
+
+TIP: To host Neo4j in Gremlin Server, the dependencies must first be "installed" or otherwise copied to the Gremlin Server path. The automated method for doing this would be to execute `bin/gremlin-server.sh -i org.apache.tinkerpop neo4j-gremlin x.y.z`.
 
 Indices
 ~~~~~~~

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/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 f274e32..4d25c13 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
@@ -19,13 +19,10 @@
 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.process.traversal.Compare;
 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.StringFactory;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -34,7 +31,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
@@ -59,55 +55,9 @@ public final class Neo4jGraphStep<S extends Element> extends GraphStep<S> {
 
     private Iterator<? extends Vertex> vertices() {
         final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
-        // ids are present, filter on them first
-        if (this.ids != null && this.ids.length > 0)
-            return IteratorUtils.filter(graph.vertices(this.ids), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
-        ////// do index lookups //////
-        graph.tx().readWrite();
-        // 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));
-                }
-            }
-        }
-        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 graph.getTrait().lookupVertices(graph, this.hasContainers, this.ids);
     }
 
-    // TODO: move all this to the traits!
-
     public String toString() {
         if (this.hasContainers.isEmpty())
             return super.toString();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/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 8a7060c..c4dac93 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
@@ -109,7 +109,7 @@ public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
             this.neo4jGraphVariables.set(Graph.Hidden.hide(CONFIG_MULTI_PROPERTIES), supportsMultiProperties);
         if (!hasMetaProperties.isPresent())
             this.neo4jGraphVariables.set(Graph.Hidden.hide(CONFIG_META_PROPERTIES), supportsMetaProperties);
-        this.trait = supportsMultiProperties ? new MultiMetaNeo4jTrait() : new NoMultiNoMetaNeo4jTrait();
+        this.trait = supportsMultiProperties ? MultiMetaNeo4jTrait.instance() : NoMultiNoMetaNeo4jTrait.instance();
         this.tx().commit();
     }
 
@@ -168,14 +168,14 @@ public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
     @Override
     public Iterator<Vertex> vertices(final Object... vertexIds) {
         this.tx().readWrite();
+        final Predicate<Neo4jNode> nodePredicate = this.trait.getNodePredicate();
         if (0 == vertexIds.length) {
-            final Predicate<Neo4jNode> nodePredicate = this.trait.getNodePredicate();
             return IteratorUtils.stream(this.getBaseGraph().allNodes())
                     .filter(nodePredicate)
                     .map(node -> (Vertex) new Neo4jVertex(node, this)).iterator();
         } else {
             ElementHelper.validateMixedElementIds(Vertex.class, vertexIds);
-            return Stream.of(vertexIds)
+            return (Iterator) Stream.of(vertexIds)
                     .map(id -> {
                         if (id instanceof Number)
                             return ((Number) id).longValue();
@@ -188,26 +188,28 @@ public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
                     })
                     .flatMap(id -> {
                         try {
-                            return Stream.of((Vertex) new Neo4jVertex(this.baseGraph.getNodeById(id), this));
+                            return Stream.of(this.baseGraph.getNodeById(id));
                         } catch (final RuntimeException e) {
                             if (Neo4jHelper.isNotFound(e)) return Stream.empty();
                             throw e;
                         }
-                    }).iterator();
+                    })
+                    .filter(nodePredicate)
+                    .map(node -> new Neo4jVertex(node, this)).iterator();
         }
     }
 
     @Override
     public Iterator<Edge> edges(final Object... edgeIds) {
         this.tx().readWrite();
+        final Predicate<Neo4jRelationship> relationshipPredicate = this.trait.getRelationshipPredicate();
         if (0 == edgeIds.length) {
-            final Predicate<Neo4jRelationship> relationshipPredicate = this.trait.getRelationshipPredicate();
             return IteratorUtils.stream(this.getBaseGraph().allRelationships())
                     .filter(relationshipPredicate)
                     .map(relationship -> (Edge) new Neo4jEdge(relationship, this)).iterator();
         } else {
             ElementHelper.validateMixedElementIds(Edge.class, edgeIds);
-            return Stream.of(edgeIds)
+            return (Iterator) Stream.of(edgeIds)
                     .map(id -> {
                         if (id instanceof Number)
                             return ((Number) id).longValue();
@@ -220,12 +222,14 @@ public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
                     })
                     .flatMap(id -> {
                         try {
-                            return Stream.of((Edge) new Neo4jEdge(this.baseGraph.getRelationshipById(id), this));
+                            return Stream.of(this.baseGraph.getRelationshipById(id));
                         } catch (final RuntimeException e) {
                             if (Neo4jHelper.isNotFound(e)) return Stream.empty();
                             throw e;
                         }
-                    }).iterator();
+                    })
+                    .filter(relationshipPredicate)
+                    .map(relationship -> new Neo4jEdge(relationship, this)).iterator();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
index 336858c..bd6142d 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/MultiMetaNeo4jTrait.java
@@ -26,6 +26,7 @@ import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jHelper;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jProperty;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.Property;
@@ -42,6 +43,7 @@ import org.neo4j.tinkerpop.api.Neo4jRelationship;
 
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
@@ -51,6 +53,8 @@ import java.util.stream.Stream;
  */
 public class MultiMetaNeo4jTrait implements Neo4jTrait {
 
+    private static final MultiMetaNeo4jTrait INSTANCE = new MultiMetaNeo4jTrait();
+
     public static final String VERTEX_PROPERTY_LABEL = "vertexProperty";
     public static final String VERTEX_PROPERTY_PREFIX = Graph.Hidden.hide("");
     public static final String VERTEX_PROPERTY_TOKEN = Graph.Hidden.hide("vertexProperty");
@@ -58,6 +62,14 @@ public class MultiMetaNeo4jTrait implements Neo4jTrait {
     private static final Predicate<Neo4jNode> NODE_PREDICATE = node -> !node.hasLabel(VERTEX_PROPERTY_LABEL);
     private static final Predicate<Neo4jRelationship> RELATIONSHIP_PREDICATE = relationship -> !relationship.type().startsWith(VERTEX_PROPERTY_PREFIX);
 
+    private MultiMetaNeo4jTrait() {
+
+    }
+
+    public static MultiMetaNeo4jTrait instance() {
+        return INSTANCE;
+    }
+
     @Override
     public Predicate<Neo4jNode> getNodePredicate() {
         return NODE_PREDICATE;
@@ -72,13 +84,12 @@ public class MultiMetaNeo4jTrait implements Neo4jTrait {
     public void removeVertex(final Neo4jVertex vertex) {
         try {
             final Neo4jNode node = vertex.getBaseVertex();
-            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.OUTGOING)) {
+            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.BOTH)) {
                 final Neo4jNode otherNode = relationship.other(node);
                 if (otherNode.hasLabel(VERTEX_PROPERTY_LABEL)) {
-                    otherNode.relationships(Neo4jDirection.BOTH).forEach(Neo4jRelationship::delete);
                     otherNode.delete(); // meta property node
-                } else
-                    relationship.delete();
+                }
+                relationship.delete();
             }
             node.delete();
         } catch (final IllegalStateException ignored) {
@@ -247,6 +258,11 @@ public class MultiMetaNeo4jTrait implements Neo4jTrait {
                     key -> (Property<V>) new Neo4jProperty<>(vertexProperty, key, (V) vertexPropertyNode.getProperty(key)));
     }
 
+    @Override
+    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids) {
+        return NoMultiNoMetaNeo4jTrait.instance().lookupVertices(graph, hasContainers, ids);
+    }
+
     /*
      @Override
     public Set<String> keys() {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
index 9bb79ec..acfa0c6 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/Neo4jTrait.java
@@ -21,14 +21,18 @@
 
 package org.apache.tinkerpop.gremlin.neo4j.structure.trait;
 
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.neo4j.tinkerpop.api.Neo4jNode;
 import org.neo4j.tinkerpop.api.Neo4jRelationship;
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.function.Predicate;
 
 /**
@@ -64,4 +68,8 @@ public interface Neo4jTrait {
 
     public <V> Iterator<Property<V>> getProperties(final Neo4jVertexProperty vertexProperty, final String... keys);
 
+    ////
+
+    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids);
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/8250a2f9/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
index d1647ad..8961dba 100644
--- a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/trait/NoMultiNoMetaNeo4jTrait.java
@@ -21,10 +21,15 @@
 
 package org.apache.tinkerpop.gremlin.neo4j.structure.trait;
 
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jHelper;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
 import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
+import org.apache.tinkerpop.gremlin.process.traversal.Compare;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
 import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -33,6 +38,8 @@ import org.neo4j.tinkerpop.api.Neo4jNode;
 import org.neo4j.tinkerpop.api.Neo4jRelationship;
 
 import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
 import java.util.function.Predicate;
 
 /**
@@ -40,8 +47,18 @@ import java.util.function.Predicate;
  */
 public class NoMultiNoMetaNeo4jTrait implements Neo4jTrait {
 
+    private static final NoMultiNoMetaNeo4jTrait INSTANCE = new NoMultiNoMetaNeo4jTrait();
+
     private final static Predicate TRUE_PREDICATE = x -> true;
 
+    public static NoMultiNoMetaNeo4jTrait instance() {
+        return INSTANCE;
+    }
+
+    private NoMultiNoMetaNeo4jTrait() {
+
+    }
+
     @Override
     public Predicate<Neo4jNode> getNodePredicate() {
         return TRUE_PREDICATE;
@@ -130,4 +147,55 @@ public class NoMultiNoMetaNeo4jTrait implements Neo4jTrait {
     public <V> Iterator<Property<V>> getProperties(final Neo4jVertexProperty vertexProperty, final String... keys) {
         throw VertexProperty.Exceptions.metaPropertiesNotSupported();
     }
+
+    @Override
+    public Iterator<Vertex> lookupVertices(final Neo4jGraph graph, final List<HasContainer> hasContainers, final Object... ids) {
+        // ids are present, filter on them first
+        if (ids.length > 0)
+            return IteratorUtils.filter(graph.vertices(ids), vertex -> HasContainer.testAll(vertex, hasContainers));
+        ////// do index lookups //////
+        graph.tx().readWrite();
+        // get a label being search on
+        final Optional<String> label = 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 : hasContainers) {
+                if (hasContainer.getPredicate().equals(Compare.eq)) {
+                    if (graph.getBaseGraph().hasSchemaIndex(label.get(), hasContainer.getKey())) {
+                        return IteratorUtils.filter(
+                                IteratorUtils.map(
+                                        IteratorUtils.filter(graph.getBaseGraph().findNodes(label.get(), hasContainer.getKey(), hasContainer.getValue()).iterator(), getNodePredicate()),
+                                        node -> new Neo4jVertex(node, graph)),
+                                vertex -> HasContainer.testAll(vertex, hasContainers));
+                    }
+                }
+            }
+        } else {
+            // find a vertex by key/value
+            for (final HasContainer hasContainer : hasContainers) {
+                if (hasContainer.getPredicate().equals(Compare.eq)) {
+                    return IteratorUtils.filter(
+                            IteratorUtils.map(
+                                    IteratorUtils.filter(graph.getBaseGraph().findNodes(hasContainer.getKey(), hasContainer.getValue()).iterator(), getNodePredicate()),
+                                    node -> new Neo4jVertex(node, graph)),
+                            vertex -> HasContainer.testAll(vertex, hasContainers));
+                }
+            }
+        }
+        if (label.isPresent()) {
+            // find a vertex by label
+            return IteratorUtils.filter(
+                    IteratorUtils.map(
+                            IteratorUtils.filter(graph.getBaseGraph().findNodes(label.get()).iterator(), getNodePredicate()),
+                            node -> new Neo4jVertex(node, graph)),
+                    vertex -> HasContainer.testAll(vertex, hasContainers));
+        } else {
+            // linear scan
+            return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll(vertex, hasContainers));
+        }
+    }
 }