/* * 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.process; import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.neo4j.AbstractNeo4jGremlinTest; import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.util.TimeUtil; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Supplier; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.as; import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.where; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** * @author Marko A. Rodriguez (http://markorodriguez.com) * @author Stephen Mallette (http://stephen.genoprime.com) */ public class NativeNeo4jCypherCheck extends AbstractNeo4jGremlinTest { private static final Logger logger = LoggerFactory.getLogger(NativeNeo4jCypherCheck.class); @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteCypher() throws Exception { this.graph.addVertex("name", "marko"); this.graph.tx().commit(); final Iterator<Map<String, Object>> result = this.getGraph().cypher("MATCH (a {name:\"marko\"}) RETURN a", Collections.emptyMap()); assertNotNull(result); assertTrue(result.hasNext()); } @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteCypherWithArgs() throws Exception { this.graph.addVertex("name", "marko"); this.graph.tx().commit(); final Map<String, Object> bindings = new HashMap<>(); bindings.put("n", "marko"); final Iterator<Map<String, Object>> result = this.getGraph().cypher("MATCH (a {name:{n}}) RETURN a", bindings); assertNotNull(result); assertTrue(result.hasNext()); } @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteCypherWithArgsUsingVertexIdList() throws Exception { final Vertex v = this.graph.addVertex("name", "marko"); final List<Object> idList = Arrays.asList(v.id()); this.graph.tx().commit(); final Map<String, Object> bindings = new HashMap<>(); bindings.put("ids", idList); final Iterator<String> result = this.getGraph().cypher("START n=node({ids}) RETURN n", bindings).select("n").values("name"); assertNotNull(result); assertTrue(result.hasNext()); assertEquals("marko", result.next()); } @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteCypherAndBackToGremlin() throws Exception { this.graph.addVertex("name", "marko", "age", 29, "color", "red"); this.graph.addVertex("name", "marko", "age", 30, "color", "yellow"); this.graph.tx().commit(); final Traversal result = this.getGraph().cypher("MATCH (a {name:\"marko\"}) RETURN a").select("a").has("age", 29).values("color"); assertNotNull(result); assertTrue(result.hasNext()); assertEquals("red", result.next().toString()); } @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteMultiIdWhereCypher() throws Exception { this.graph.addVertex("name", "marko", "age", 29, "color", "red"); this.graph.addVertex("name", "marko", "age", 30, "color", "yellow"); this.graph.addVertex("name", "marko", "age", 30, "color", "orange"); this.graph.tx().commit(); final List<Object> result = this.getGraph().cypher("MATCH n WHERE id(n) IN [1,2] RETURN n").select("n").id().toList(); assertNotNull(result); assertEquals(2, result.size()); assertTrue(result.contains(1l)); assertTrue(result.contains(2l)); } @Test @LoadGraphWith(LoadGraphWith.GraphData.MODERN) public void shouldExecuteMultiIdWhereWithParamCypher() throws Exception { final Vertex v1 = this.graph.addVertex("name", "marko", "age", 29, "color", "red"); final Vertex v2 = this.graph.addVertex("name", "marko", "age", 30, "color", "yellow"); this.graph.addVertex("name", "marko", "age", 30, "color", "orange"); this.graph.tx().commit(); final List<Object> ids = Arrays.asList(v1.id(), v2.id()); final Map<String, Object> m = new HashMap<>(); m.put("ids", ids); final List<Object> result = this.getGraph().cypher("MATCH n WHERE id(n) IN {ids} RETURN n", m).select("n").id().toList(); assertNotNull(result); assertEquals(2, result.size()); assertTrue(result.contains(v1.id())); assertTrue(result.contains(v2.id())); } @Test @Ignore @LoadGraphWith(LoadGraphWith.GraphData.GRATEFUL) public void benchmarkCypherAndMatch() throws Exception { final Neo4jGraph n = (Neo4jGraph) graph; final List<Supplier<GraphTraversal<?, ?>>> traversals = Arrays.asList( () -> g.V().match( as("a").in("sungBy").as("b"), as("a").in("writtenBy").as("b")).select("a", "b").by("name"), () -> n.cypher("MATCH (a)<-[:sungBy]-(b), (a)<-[:writtenBy]-(b) RETURN a.name, b.name"), /// () -> g.V().match( as("a").out("followedBy").as("b"), as("b").out("followedBy").as("a")).select("a", "b").by("name"), () -> n.cypher("MATCH (a)-[:followedBy]->(b), (b)-[:followedBy]->(a) RETURN a.name, b.name"), /// () -> g.V().match( as("a").out("followedBy").count().is(P.gt(10)).as("b"), as("a").in("followedBy").count().is(P.gt(10)).as("b")). select("a").by("name"), () -> n.cypher("MATCH (a)-[:followedBy]->(b) WITH a, COUNT(b) AS bc WHERE bc > 10 MATCH (a)<-[:followedBy]-(c) WITH a, bc, COUNT(c) AS cc WHERE bc = cc RETURN a.name"), /// () -> g.V().match( as("a").in("sungBy").count().as("b"), as("a").in("sungBy").as("c"), as("c").out("followedBy").as("d"), as("d").out("sungBy").as("e"), as("e").in("sungBy").count().as("b"), where("a", P.neq("e"))).select("a", "e").by("name"), () -> n.cypher("MATCH (a)<-[:sungBy]-()-[:followedBy]->()-[:sungBy]->(e) WHERE a <> e WITH a, e MATCH (a)<-[:sungBy]-(b) WITH a, e, COUNT(DISTINCT b) as bc MATCH (e)<-[:sungBy]-(f) WITH a, e, bc, COUNT(DISTINCT f) as fc WHERE bc = fc RETURN a.name, e.name"), /// () -> g.V().match( as("a").in("followedBy").as("b"), as("a").out("sungBy").as("c"), as("b").out("sungBy").as("c")).select("a", "b"), () -> n.cypher("MATCH (a)<-[:followedBy]-(b), (a)-[:sungBy]->(c), (b)-[:sungBy]->(c) RETURN a, b"), /// () -> g.V().match( as("a").in("followedBy").as("b"), as("a").out("sungBy").as("c"), as("a").out("writtenBy").as("d"), as("b").out("sungBy").as("c"), as("b").out("writtenBy").as("d"), where("c", P.neq("d"))).select("a", "b").by("name"), () -> n.cypher("MATCH (a)<-[:followedBy]-(b), (a)-[:sungBy]->(c), (a)-[:writtenBy]->(d), (b)-[:sungBy]->(c), (b)-[:writtenBy]->(d) WHERE c <> d RETURN a.name, b.name"), /// () -> g.V().match( as("a").in("sungBy").as("b"), as("a").in("writtenBy").as("b"), as("b").out("followedBy").as("c"), as("c").out("sungBy").as("a"), as("c").out("writtenBy").as("a")).select("a").by("name"), () -> n.cypher("MATCH (a)<-[:sungBy]-(b), (a)<-[:writtenBy]-(b), (b)-[:followedBy]->(c), (c)-[:sungBy]->(a), (c)-[:writtenBy]->(a) RETURN a.name"), /// () -> g.V().match( as("a").has("name", "Garcia").has(T.label, "artist"), as("a").in("writtenBy").as("b"), as("b").out("followedBy").as("c"), as("c").out("writtenBy").as("d"), as("d").where(P.neq("a"))).select("a", "d").by("name"), () -> n.cypher("MATCH (a)<-[:writtenBy]-(b), (b)-[:followedBy]->(c), (c)-[:writtenBy]->(d) WHERE a <> d AND a.name = 'Garcia' AND 'artist' IN labels(a) RETURN a.name, d.name"), /// () -> g.V().match( as("a").out("followedBy").as("b"), as("b").out("followedBy").as("c")).select("a").by("name"), () -> n.cypher("MATCH (a)-[:followedBy]->(b), (b)-[:followedBy]->(c) RETURN a.name"), /// () -> g.V().match( as("a").out("followedBy").as("b"), as("a").has(T.label, "song").has("performances", P.gt(10)), as("a").out("writtenBy").as("c"), as("b").out("writtenBy").as("c")).select("a", "b", "c").by("name"), () -> n.cypher("MATCH (a)-[:followedBy]->(b), (a)-[:writtenBy]->(c), (b)-[:writtenBy]->(c) WHERE a.performances > 10 AND 'song' IN labels(a) RETURN a, b, c").select("a", "b", "c").by("name") ); for (int i = 0; i < traversals.size(); i = i + 2) { final Supplier<GraphTraversal<?, ?>> gremlin = traversals.get(i); final Supplier<GraphTraversal<?, ?>> cypher = traversals.get(i + 1); for (final Supplier<GraphTraversal<?, ?>> sub : Arrays.asList(cypher, gremlin)) { logger.info("pre-strategy: {}", sub.get()); logger.info("post-strategy: {}", sub.get().iterate()); logger.info(TimeUtil.clockWithResult(25, () -> sub.get().count().next()).toString()); logger.info("------------------"); } } } }