DATAGRAPH-406 Removing Gremlin Dependency

This commit is contained in:
Michael Hunger
2013-11-07 22:08:59 -05:00
parent a186189d2e
commit 0e871e9ae8
39 changed files with 22 additions and 672 deletions

View File

@@ -109,7 +109,7 @@ try {
<li><code>@Indexed([fulltext=true],[indexName=name])</code> Auto-Indexing</li>
<li><code>@RelatedTo([direction=Direction], [type=TYPE])</code> define type and direction of relationship on <code>Entity, Iterable&lt;E>, Set&lt;E></code> fields</li>
<li><code>@RelatedToVia([direction=Direction], [type=TYPE])</code> like <code>@RelatedTo,</code> but targets Relationship-Entities</li>
<li><code>@Query(query, [type=QueryType])</code> computed field, executes graph query in Cypher or Gremlin</li>
<li><code>@Query(query, [type=QueryType])</code> computed field, executes graph query in Cypher</li>
<li><code>@GraphTraversal(traversal=~TraversalBuilder.class, [elementClass=Person.class])</code> computed field, executes traversal starting from entity-node</li>
</ul>
</div>
@@ -160,7 +160,7 @@ interface MovieRepository extends GraphRepository&lt;Movie> {
<div class="note">
<h3>Neo4jTemplate</h3>
<ul><li>convenience methods for graph operations, transaction and exception handling</li>
<li>index lookups, cypher and gremlin queries, traversal execution with fluent result converter API</li>
<li>index lookups, cypher queries, traversal execution with fluent result converter API</li>
<li>preconfigured and customizable conversion of results to a variety of types</li></ul>
</div>
<div class="note">

View File

@@ -42,9 +42,6 @@
<neo4j.spatial.version>0.12-neo4j-2.0.0-M06</neo4j.spatial.version>
<neo4j.graph-collections.version>0.7.1-neo4j-2.0.0-M06</neo4j.graph-collections.version>
<blueprints.version>1.2</blueprints.version>
<gremlin.version>1.5</gremlin.version>
<pipes.version>1.5</pipes.version>
<neo4j-cypher-dsl.version>2.0.0-M06</neo4j-cypher-dsl.version>
</properties>

View File

@@ -147,33 +147,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-core</artifactId>
<version>${blueprints.version}</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-neo4j-graph</artifactId>
<version>${blueprints.version}</version>
<exclusions>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-management</artifactId>
</exclusion>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>

View File

@@ -36,9 +36,6 @@ public interface PersonRepository extends GraphRepository<Person>, NamedIndexRep
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("p_team") Group team);
@Query(value = "g.v(team).out('persons')", type = QueryType.Gremlin)
Iterable<Person> findAllTeamMembersGremlin(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("p_team") Group team);

View File

@@ -60,13 +60,6 @@ public class GraphRepositoryTests extends EntityTestBase {
Iterable<Person> teamMembers = personRepository.findAllTeamMembers(testTeam.sdg);
assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david, testTeam.emil));
}
@Test
@Transactional
@Ignore
public void testFindIterableOfPersonWithQueryAnnotationAndGremlin() {
Iterable<Person> teamMembers = personRepository.findAllTeamMembersGremlin(testTeam.sdg);
assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david, testTeam.emil));
}
@Test
@Transactional

View File

@@ -1,77 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.aspects.support.query;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.helpers.collection.MapUtil;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.aspects.Person;
import org.springframework.data.neo4j.aspects.support.EntityTestBase;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.support.DelegatingGraphDatabase;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
/**
* @author mh
* @since 13.06.11
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/aspects/support/Neo4jGraphPersistenceTests-context.xml"})
@Transactional
@Ignore
public class GremlinQueryEngineTests extends EntityTestBase {
private QueryEngine<Object> queryEngine;
private Person michael;
@Before
public void setUp() throws Exception {
GraphDatabase graphDatabase = createGraphDatabase();
testTeam.createSDGTeam();
queryEngine = graphDatabase.queryEngineFor(QueryType.Gremlin);
michael = testTeam.michael;
}
protected GraphDatabase createGraphDatabase() throws Exception {
final DelegatingGraphDatabase graphDatabase = new DelegatingGraphDatabase(neo4jTemplate.getGraphDatabaseService());
graphDatabase.setConversionService(conversionService);
return graphDatabase;
}
@SuppressWarnings("unchecked")
@Test
@Transactional
public void testQueryList() throws Exception {
final String queryString = "t = new Table(); [g.v(michael),g.v(david)].each{ n -> n.as('person.name').as('person.age').table(t,['person.name','person.age']){ it.age }{ it.name }.iterate()}; t;" ;
final Collection<Object> result = IteratorUtil.asCollection(queryEngine.query(queryString, MapUtil.map("michael", getNodeId(michael), "david", getNodeId(testTeam.david))));
assertEquals(asList(testTeam.simpleRowFor(michael, "person"), testTeam.simpleRowFor(testTeam.david, "person")), result);
}
}

View File

@@ -29,10 +29,7 @@ Import-Template:
javax.persistence.*;version="[1.0.0, 3.0.0)";resolution:=optional,
javax.persistence.spi.*;version="[1.0.0, 3.0.0)";resolution:=optional,
javax.transaction.*;version="[1.0.1, 2.0.0)";resolution:=optional,
com.tinkerpop.blueprints.*;version="[0.8,1.0)";resolution:=optional,
com.tinkerpop.gremlin.*;version="[1.1,2.0)";resolution:=optional,
com.tinkerpop.pipes.util.*;version="[0.8,1.0)";resolution:=optional
Import-Package:
Import-Package:
sun.reflect;version="0";resolution:=optional,
net.sf.cglib.proxy;version="[2.2.0,3.0.0)",
net.sf.cglib.core;version="[2.2.0,3.0.0)",

View File

@@ -124,13 +124,6 @@
</exclusions>
</dependency>
<!--dependency>
<groupId>org.neo4j.server.plugin</groupId>
<artifactId>neo4j-gremlin-plugin</artifactId>
<version>1.9.2</version>
<optional>true</optional>
<scope>test</scope>
</dependency-->
<dependency>
<groupId>org.neo4j.app</groupId>
<artifactId>neo4j-server</artifactId>
@@ -185,36 +178,6 @@
</exclusions>
</dependency>
<!--dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-core</artifactId>
<version>${blueprints.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-neo4j-graph</artifactId>
<version>${blueprints.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-management</artifactId>
</exclusion>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.tinkerpop.gremlin</groupId>
<artifactId>gremlin-groovy</artifactId>
<version>${gremlin.version}</version>
<optional>true</optional>
</dependency-->
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>

View File

@@ -17,17 +17,14 @@ package org.springframework.data.neo4j.rest;
import org.neo4j.graphdb.*;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.traversal.TraversalDescription;
import org.neo4j.rest.graphdb.RestAPI;
import org.neo4j.rest.graphdb.RestAPIFacade;
import org.neo4j.rest.graphdb.entity.RestNode;
import org.neo4j.rest.graphdb.index.RestIndex;
import org.neo4j.rest.graphdb.index.RestIndexManager;
import org.neo4j.rest.graphdb.query.RestCypherQueryEngine;
import org.neo4j.rest.graphdb.query.RestGremlinQueryEngine;
import org.neo4j.rest.graphdb.transaction.NullTransaction;
import org.neo4j.rest.graphdb.transaction.NullTransactionManager;
import org.neo4j.rest.graphdb.traversal.RestTraversalDescription;
import org.neo4j.rest.graphdb.util.Config;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.neo4j.annotation.QueryType;
@@ -114,7 +111,6 @@ public class SpringRestGraphDatabase extends org.neo4j.rest.graphdb.RestGraphDat
public <T> QueryEngine<T> queryEngineFor(QueryType type, final ResultConverter resultConverter) {
switch (type) {
case Cypher: return (QueryEngine<T>)new SpringRestCypherQueryEngine(new RestCypherQueryEngine(getRestAPI(), new SpringResultConverter(resultConverter)));
case Gremlin: return (QueryEngine<T>)new SpringRestGremlinQueryEngine(new RestGremlinQueryEngine(getRestAPI(),new SpringResultConverter(resultConverter)));
}
throw new IllegalArgumentException("Unknown Query Engine Type "+type);
}

View File

@@ -1,44 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.rest;
import org.neo4j.rest.graphdb.query.RestGremlinQueryEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.neo4j.support.query.QueryEngine;
import java.util.Map;
public class SpringRestGremlinQueryEngine implements QueryEngine<Object> {
public static final Logger log = LoggerFactory.getLogger(SpringRestGremlinQueryEngine.class);
private final RestGremlinQueryEngine restGremlinQueryEngine;
public SpringRestGremlinQueryEngine(RestGremlinQueryEngine restGremlinQueryEngine) {
this.restGremlinQueryEngine = restGremlinQueryEngine;
}
@Override
public SpringRestResult<Object> query(String statement, Map<String, Object> params) {
if (log.isDebugEnabled()) log.debug(String.format("Executing remote gremlin query: %s params %s",statement,params));
return new SpringRestResult<Object>(restGremlinQueryEngine.query(statement, params));
}
}

View File

@@ -1,69 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.rest.support;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.aspects.support.query.GremlinQueryEngineTests;
import org.springframework.data.neo4j.core.GraphDatabase;
import org.springframework.data.neo4j.rest.SpringRestGraphDatabase;
import org.springframework.test.context.CleanContextCacheTestExecutionListener;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
/**
* @author mh
* @since 23.06.11
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:org/springframework/data/neo4j/aspects/support/Neo4jGraphPersistenceTests-context.xml",
"classpath:RestTests-context.xml"})
@TestExecutionListeners({CleanContextCacheTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, TransactionalTestExecutionListener.class})
@Ignore
public class RestGremlinQueryEngineTests extends GremlinQueryEngineTests {
@Autowired
SpringRestGraphDatabase restGraphDatabase;
@BeforeClass
public static void startDb() throws Exception {
RestTestBase.startDb();
}
@BeforeTransaction
public void cleanDb() {
RestTestBase.cleanDb();
}
@AfterClass
public static void shutdownDb() {
RestTestBase.shutdownDb();
}
@Override
protected GraphDatabase createGraphDatabase() throws Exception {
restGraphDatabase.setConversionService(conversionService);
return restGraphDatabase;
}
}

View File

@@ -219,37 +219,6 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-core</artifactId>
<version>${blueprints.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-neo4j-graph</artifactId>
<version>${blueprints.version}</version>
<exclusions>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-management</artifactId>
</exclusion>
<exclusion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
</exclusion>
</exclusions>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tinkerpop.gremlin</groupId>
<artifactId>gremlin-groovy</artifactId>
<version>${gremlin.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>

View File

@@ -21,5 +21,5 @@ package org.springframework.data.neo4j.annotation;
* @since 25.07.11
*/
public enum QueryType {
Cypher, Gremlin
Cypher
}

View File

@@ -104,12 +104,12 @@ public interface GraphDatabase {
TraversalDescription traversalDescription();
/**
* returns a query engine for the provided type (Cypher or Gremlin) which is initialized with the default result converter
* returns a query engine for the provided type (Cypher) which is initialized with the default result converter
*/
<T> QueryEngine<T> queryEngineFor(QueryType type);
/**
* returns a query engine for the provided type (Cypher or Gremlin) which is initialized with the provided result converter
* returns a query engine for the provided type (Cypher) which is initialized with the provided result converter
*/
<T> QueryEngine<T> queryEngineFor(QueryType type, ResultConverter resultConverter);

View File

@@ -149,10 +149,8 @@ public class GraphQueryMethod extends QueryMethod {
switch (queryAnnotation.type()) {
case Cypher:
return new CypherGraphRepositoryQuery(this, template);
case Gremlin:
return new GremlinGraphRepositoryQuery(this, template);
default:
throw new IllegalStateException("@Query Annotation has to be configured as Cypher or Gremlin Query");
throw new IllegalStateException("@Query Annotation has to be configured as Cypher Query");
}
}

View File

@@ -1,44 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.repository.query;
import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.annotation.QueryType;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.ParameterAccessor;
import java.util.Map;
/**
* @author mh
* @since 31.10.11
*/
class GremlinGraphRepositoryQuery extends GraphRepositoryQuery {
private QueryEngine queryEngine;
public GremlinGraphRepositoryQuery(GraphQueryMethod queryMethod, final Neo4jTemplate template) {
super(queryMethod, template);
}
protected QueryEngine getQueryEngine() {
if (this.queryEngine !=null) return queryEngine;
this.queryEngine = getTemplate().queryEngineFor(QueryType.Gremlin);
return this.queryEngine;
}
}

View File

@@ -37,7 +37,6 @@ import org.springframework.data.neo4j.support.index.IndexType;
import org.springframework.data.neo4j.support.index.NoSuchIndexException;
import org.springframework.data.neo4j.support.query.ConversionServiceQueryResultConverter;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.data.neo4j.support.query.GremlinQueryEngine;
import org.springframework.data.neo4j.support.query.QueryEngine;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -59,7 +58,6 @@ public class DelegatingGraphDatabase implements GraphDatabase {
private ConversionService conversionService;
private ResultConverter resultConverter;
private volatile QueryEngine<Object> cypherQueryEngine;
private volatile QueryEngine<Object> gremlinQueryEngine;
public DelegatingGraphDatabase(final GraphDatabaseService delegate) {
this(delegate,null);
@@ -90,7 +88,6 @@ public class DelegatingGraphDatabase implements GraphDatabase {
private void reinitQueryEngines() {
if (cypherQueryEngine != null) this.cypherQueryEngine = queryEngineFor(QueryType.Cypher, resultConverter, true);
if (gremlinQueryEngine != null) this.gremlinQueryEngine = queryEngineFor(QueryType.Gremlin, resultConverter, true);
}
@Override
@@ -211,14 +208,6 @@ public class DelegatingGraphDatabase implements GraphDatabase {
}
return (QueryEngine<T>) cypherQueryEngine;
}
case Gremlin: {
if (reinit || gremlinQueryEngine==null) {
synchronized (this) {
if (reinit || gremlinQueryEngine==null) gremlinQueryEngine=createGremlinQueryEngine(resultConverter);
}
}
return (QueryEngine<T>) gremlinQueryEngine;
}
}
throw new IllegalArgumentException("Unknown Query Engine Type "+type);
}
@@ -228,13 +217,6 @@ public class DelegatingGraphDatabase implements GraphDatabase {
return queryEngineFor(type,resultConverter,false);
}
private <T> QueryEngine<T> createGremlinQueryEngine(ResultConverter resultConverter) {
if (!ClassUtils.isPresent("com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph", getClass().getClassLoader())) {
return new FailingQueryEngine<T>("Gremlin");
}
return (QueryEngine<T>) new GremlinQueryEngine(delegate,resultConverter);
}
private <T> QueryEngine<T> createCypherQueryEngine(ResultConverter resultConverter) {
if (!ClassUtils.isPresent("org.neo4j.cypher.javacompat.ExecutionEngine", getClass().getClassLoader())) {
return new FailingQueryEngine<T>("Cypher");

View File

@@ -528,13 +528,6 @@ public class Neo4jTemplate implements Neo4jOperations, ApplicationContextAware {
return queryEngine.query(statement, params);
}
@Override
@SuppressWarnings("unchecked")
public Result<Object> execute(String statement, Map<String, Object> params) {
notNull(statement, "statement");
return queryEngineFor(QueryType.Gremlin).query(statement, params);
}
@Override
public Result<Path> traverse(Object start, TraversalDescription traversal) {
return traverse((Node) getPersistentState(start), traversal);

View File

@@ -1,126 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.support.query;
import com.tinkerpop.blueprints.pgm.Edge;
import com.tinkerpop.blueprints.pgm.Vertex;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jEdge;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jGraph;
import com.tinkerpop.blueprints.pgm.impls.neo4j.Neo4jVertex;
import com.tinkerpop.pipes.util.structures.Row;
import com.tinkerpop.pipes.util.structures.Table;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.helpers.collection.IterableWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class GremlinExecutor {
public static final Logger log = LoggerFactory.getLogger(GremlinExecutor.class);
public static final int REFRESH_ENGINE_COUNT = 10000;
private static final String GRAPH_VARIABLE = "g";
private volatile ScriptEngine engine;
private ScriptEngine createScriptEngine() {
return new ScriptEngineManager().getEngineByName("gremlin-groovy");
}
private static final AtomicInteger executionCount = new AtomicInteger();
private final GraphDatabaseService graphDatabaseService;
public GremlinExecutor(GraphDatabaseService graphDatabaseService) {
this.graphDatabaseService = graphDatabaseService;
}
@SuppressWarnings("unchecked")
public Iterable<Object> query(String statement, Map<String,Object> params) {
try {
if (log.isDebugEnabled()) log.debug(String.format("Executing gremlin query: %s params %s",statement,params));
final Bindings bindings = createBindings(params);
final ScriptEngine engine = engine();
final Object result = engine.eval(statement, bindings);
return getRepresentation(result);
} catch (final ScriptException e) {
throw new RuntimeException("Error executing statement " + statement, e);
}
}
private Bindings createBindings(Map<String, Object> params) {
final Bindings bindings = new SimpleBindings();
bindings.put(GRAPH_VARIABLE, new Neo4jGraph(graphDatabaseService,false));
if (params==null) return bindings;
for (Map.Entry<String, Object> entry : params.entrySet()) {
bindings.put(entry.getKey(),entry.getValue());
}
return bindings;
}
private ScriptEngine engine() {
if (engine == null || executionCount.incrementAndGet() > REFRESH_ENGINE_COUNT) {
executionCount.set(0);
this.engine = createScriptEngine();
}
return this.engine;
}
@SuppressWarnings("unchecked")
public static Iterable getRepresentation(final Object result) {
if (result instanceof Iterable) {
if (result instanceof Table) {
final Table table = (Table) result;
return new IterableWrapper<Map<String,Object>,Row>(table) {
@Override
protected Map<String, Object> underlyingObjectToObject(Row row) {
Map<String,Object> result=new LinkedHashMap<String, Object>();
for (String column : table.getColumnNames()) {
result.put(column, row.getColumn(column));
}
return result;
}
};
}
return new IterableWrapper((Iterable) result) {
@Override
protected Object underlyingObjectToObject(Object object) {
return getSingleResult(object);
}
};
} else {
return Collections.singleton(getSingleResult(result));
}
}
private static Object getSingleResult(Object result) {
if (result instanceof Vertex) {
return ((Neo4jVertex) result).getRawVertex();
} else if (result instanceof Edge) {
return ((Neo4jEdge) result).getRawEdge();
} else if (result instanceof Neo4jGraph) {
return ((Neo4jGraph) result).getRawGraph();
} else {
return result;
}
}
}

View File

@@ -1,53 +0,0 @@
/**
* Copyright 2011 the original author or authors.
*
* Licensed 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.springframework.data.neo4j.support.query;
import org.neo4j.graphdb.GraphDatabaseService;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.data.neo4j.conversion.DefaultConverter;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.conversion.QueryResultBuilder;
import org.springframework.data.neo4j.conversion.ResultConverter;
import java.util.Map;
public class GremlinQueryEngine implements QueryEngine<Object> {
private final GremlinExecutor gremlinExecutor;
private final ResultConverter resultConverter;
public GremlinQueryEngine(GraphDatabaseService graphDatabaseService) {
this(graphDatabaseService, new DefaultConverter());
}
public GremlinQueryEngine(GraphDatabaseService graphDatabaseService, ResultConverter resultConverter) {
this.resultConverter = resultConverter != null ? resultConverter : new DefaultConverter();
this.gremlinExecutor = new GremlinExecutor(graphDatabaseService);
}
@SuppressWarnings("unchecked")
@Override
public Result<Object> query(String statement, Map<String, Object> params) {
try {
Iterable<Object> result = gremlinExecutor.query(statement, params);
return new QueryResultBuilder<Object>(result,resultConverter);
} catch (Exception e) {
throw new InvalidDataAccessResourceUsageException("Error executing statement " + statement, e);
}
}
}

View File

@@ -189,7 +189,7 @@ public interface Neo4jOperations {
<T extends PropertyContainer> Result<T> lookup(String indexName, Object query);
/**
* Provides a cypher or gremlin query engine set up with a default entity converter.
* Provides a cypher query engine set up with a default entity converter.
*/
<T> QueryEngine<T> queryEngineFor(QueryType type);
@@ -199,12 +199,6 @@ public interface Neo4jOperations {
*/
Result<Map<String, Object>> query(String statement, Map<String, Object> params);
/**
* Executes the given Gremlin statement and returns the result packaged as Result as Neo4j types, not
* Gremlin types. The Neo4j-Graph is provided as variable "g". Table rows are converted to Map<String,Object>.
*/
Result<Object> execute(String statement, Map<String, Object> params);
/**
* Traverses the graph starting at the given node with the provided traversal description. The Path's of the
* traversal will be packaged into a Result which can be easily converted into Nodes, Relationships or

View File

@@ -36,9 +36,6 @@ public interface PersonRepository extends GraphRepository<Person>, NamedIndexRep
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("p_team") Group team);
@Query(value = "g.v(team).out('persons')", type = QueryType.Gremlin)
Iterable<Person> findAllTeamMembersGremlin(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String,Object>> findAllTeamMemberData(@Param("p_team") Group team);

View File

@@ -216,12 +216,6 @@ public class GraphRepositoryTests {
assertThat(asCollection(teamMembers), hasItems(testTeam.michael, testTeam.david));
}
@Test @Transactional
public void testFindIterableOfPersonWithQueryAnnotationAndGremlin() {
Iterable<Person> teamMembers = personRepository.findAllTeamMembersGremlin(testTeam.sdg);
assertThat( asCollection( teamMembers ), hasItems(testTeam.michael, testTeam.david, testTeam.emil) );
}
@Test @Transactional
public void testFindPersonWithQueryAnnotation() {
Person boss = personRepository.findBoss( testTeam.michael );

View File

@@ -43,9 +43,6 @@ public interface PersonRepository extends GraphRepository<Person>, NamedIndexRep
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member")
Iterable<Person> findAllTeamMembers(@Param("p_team") Group team);
@Query(value = "g.v(team).out('persons')", type = QueryType.Gremlin)
Iterable<Person> findAllTeamMembersGremlin(@Param("team") Group team);
@Query("start team=node({p_team}) match (team)-[:persons]->(member) return member.name,member.age")
Iterable<Map<String, Object>> findAllTeamMemberData(@Param("p_team") Group team);

View File

@@ -371,12 +371,6 @@ public class EntityNeo4jTemplateTests extends EntityTestBase {
final Person result = engine.query("start n=node({self}) return n", map("self", testTeam.michael.getId())).to(Person.class).single();
assertEquals(testTeam.michael.getId(), result.getId());
}
@Test @Transactional
public void testQueryEngineForGremlin() throws Exception {
final QueryEngine<Result<Object>> engine = neo4jOperations.queryEngineFor(QueryType.Gremlin);
final Person result = engine.query("g.v(self)", map("self", testTeam.michael.getId())).to(Person.class).single();
assertEquals(testTeam.michael.getId(), result.getId());
}
@Test @Transactional
public void testTraverse() throws Exception {

View File

@@ -328,12 +328,6 @@ public class FullNeo4jTemplateTests {
assertSingleResult(node1, neo4jTemplate.query("start n=node(0) match n-[:knows]->m return m", null).to(Node.class));
}
@Test
@Transactional
public void shouldFindNextNodeViaGremlin() throws Exception {
assertSingleResult(node1, neo4jTemplate.execute("g.v(0).outE.filter{it.label=='knows'}.inV", null).to(Node.class));
}
@Test
@Transactional
public void shouldGetDirectRelationship() throws Exception {

View File

@@ -188,12 +188,6 @@ public class Neo4jTemplateApiTests {
assertSingleResult(node1, template.query("start n=node(0) match n-->m return m", null).to(Node.class));
}
@Test
@Ignore
public void shouldFindNextNodeViaGremlin() throws Exception {
assertSingleResult(node1, template.execute("g.v(0).out", null).to(Node.class));
}
@Test
public void shouldGetDirectRelationship() throws Exception {
assertSingleResult("rel1", template.convert(referenceNode.getRelationships()).to(String.class, new RelationshipNameConverter()));

View File

@@ -84,10 +84,6 @@ public class SnippetNeo4jTemplateMethodsTests extends DocumentingTestBase {
// SNIPPET template
// Gremlin
assertEquals(thomas, neo.execute("g.v(person).out('WORKS_WITH')",
map("person", mark.getId())).to(Node.class).single());
// Index lookup
assertEquals(thomas, neo.lookup("devs", "name", "Thomas").to(Node.class).single());

View File

@@ -37,10 +37,7 @@ Import-Template:
com.mysema.query.annotations.*;version="0";resolution:=optional,
com.mysema.query.apt.*;version="0";resolution:=optional,
com.mysema.query.types.*;version="0";resolution:=optional,
com.tinkerpop.blueprints.*;version="[0.8,1.0)";resolution:=optional,
com.tinkerpop.gremlin.*;version="[1.1,2.0)";resolution:=optional,
com.tinkerpop.pipes.util.*;version="[0.8,1.0)";resolution:=optional
Import-Package:
Import-Package:
sun.reflect;version="0";resolution:=optional,
scala.collection;version="0";resolution:=optional,
net.sf.cglib.proxy;version="[2.2.0,3.0.0)",

View File

@@ -3,20 +3,17 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<!-- TODO
* Gremlin @Query on fields
* Gremlin @Query on repository methods
* variables in gremlin queries
* variables in cypher queries
* New Template Query API
* Spring Roo Addon, Intro, Example Session
* Update tutorial to include some of the new features (cypher, gremlin)
* Update tutorial to include some of the new features (cypher)
* eclipse / STS setup with m2e, AspectJConfigurator and Weaving enabled etc. https://jira.springsource.org/browse/DATAGRAPH-104
* fetch-strategies / behaviour
* cascading persist/save
* @Indexed(level)
*
* more on Gremlin / Cypher over REST
* more on Cypher over REST
-->
<bookinfo>
<title>Good Relationships</title>

View File

@@ -95,7 +95,7 @@ public void foo( @Context WorldRepository repo ) {
<para>
Please also keep in mind that performing graph operations via the REST-API is about one order of
magnitude slower than local operations. Try to use the Neo4j Cypher query language,
server-side traversals (<code>RestTraversal</code>) or Gremlin expressions whenever possible for retrieving large sets of data.
or server-side traversals (<code>RestTraversal</code>) whenever possible for retrieving large sets of data.
Future versions of Spring Data Neo4j will use the more performant batch API as well as a binary protocol.
</para>
<para>
@@ -128,7 +128,7 @@ public void foo( @Context WorldRepository repo ) {
Your project is now set up to work against a remote Neo4j Server.
</para>
<para>
For traversals and Cypher and Gremlin graph queries it is sensible to forward those to the remote endpoint and execute them there
For traversals and Cypher graph queries it is sensible to forward those to the remote endpoint and execute them there
instead of walking the graph over the wire. SpringRestGraphDatabase already supports that by providing methods that forward
to the remote instance. (e.g. <code>queryEngineFor(), index() and createTraversalDescription()</code>).
Please use those methods when interacting with a remote server for optimal performance. Those methods are also

View File

@@ -205,35 +205,6 @@ start lucy=node(1000) match lucy-[:ACTS_IN]->movie<-[:ACTS_IN]-co_actor
// Recommendations including counts, grouping and sorting
start user=node:User(login='micha') match user-[:FRIEND]-()-[r:RATED]->movie
return movie.title, AVG(r.stars), count(*) order by AVG(r.stars) desc, count(*) desc
]]></programlisting>
</example>
</section>
<section>
<title>Gremlin - a Graph Traversal DSL</title>
<para>
Gremlin is an expressive Groovy DSL developed by <ulink url="http://markorodriguez.com">Marko Rodriguez</ulink>
as part of the <ulink url="http://tinkerpop.com">Tinkerpop</ulink> stack. It builds on top of a pipe implementation
(Blueprints Pipes) that uses connected operations to traverse a graph. Gremlin has a concise syntax but is
Turing complete.
</para>
<para>Gremlin can be executed by including the Tinkerpop and Blueprints dependencies and then requesting a <code>ScriptEngine</code>
of type "gremlin" from the <code>javax.Script*</code> facilities. In Spring Data Neo4j this is encapsulated in
<code>GremlinQueryEngine</code>. The Neo4j-REST-Server also comes with a Gremlin-Plugin that is accessible remotely and is
available in the Spring Data Neo4j REST-Binding.
</para>
<example>
<title>Sample Gremlin Queries</title>
<programlisting><![CDATA[
// Vertex with id 1
v = g.v(1)
// determine the name of the vertices that vertex 1 knows and that are older than 30 years of age
v.outE{it.label=='knows'}.inV{it.age > 30}.name
// calculate basic collaborative filtering for vertex 1
m = [:]
g.v(1).out('likes').in('likes').out('likes').groupCount(m)
m.sort{a,b -> a.value <=> b.value}
]]></programlisting>
</example>
</section>

View File

@@ -52,7 +52,7 @@
references to other entities this is straightforward.
</para>
<para>
To use advanced functionality like traversals, Cypher and Gremlin, a basic understanding of the graph data model is required.
To use advanced functionality like traversals and Cypher, a basic understanding of the graph data model is required.
The graph data model is explained in the chapter about Neo4j, see <xref linkend="neo4j" />.
</para>
<para>
@@ -70,7 +70,7 @@
(<xref linkend="reference_template"/>) for interacting with
the mapped entities and the Neo4j graph database. The operations provided by Spring Data Neo4j - Repositories
per mapped entity class are based on the API offered by the Neo4j-Template. It also provides the operations of the Neo4j Core API
in a more convenient way. Especially the querying (Indexes, Cypher, Gremlin and Traversals) and result conversion
in a more convenient way. Especially the querying (Indexes, Cypher and Traversals) and result conversion
facilities allow writing very concise code.
</para>
@@ -94,7 +94,7 @@
</para>
<para>
Using computed fields that are dynamically backed by graph operations is a bit more involved. First you should know
about traversals, Cypher queries and Gremlin expressions.
about traversals and Cypher queries.
Those are explained in <xref linkend="neo4j" />. Then you can start using virtual, computed fields
in your entities <xref linkend="reference_programming-model_projection"/> .
</para>

View File

@@ -5,7 +5,7 @@
<para>
Indexing is used in Neo4j to quickly find nodes and relationships to start graph operations from.
Either for manually traversing the graph, using the traversal framework, cypher or gremlin queries
Either for manually traversing the graph, using the traversal framework, cypher queries
or for "global" graph operations. Indexes are also employed to ensure uniqueness of elements with
certain properties.
</para>
@@ -226,7 +226,7 @@ personFulltextIndex.query("{name:*cha*}");
from the approach used in Spring Data Neo4j because it only updates the indexes when the transaction is committed. So the
index modifications will only be available after the successful commit.
It is possible to use the specific index names <code>node_auto_index</code> and <code>relationship_auto_index</code> when
querying indexes in Spring Data Neo4j either with the query methods in template and repositories or via Cypher and Gremlin.
querying indexes in Spring Data Neo4j either with the query methods in template and repositories or via Cypher.
</para>
</section>
<section>

View File

@@ -10,8 +10,7 @@
</para>
<para>
Spring Data Neo4j repositories support annotated and named queries for the Neo4j
<ulink url="http://docs.neo4j.org/chunked/milestone/query-lang.html">Cypher</ulink> query-language and
<code>Gremlin</code> graph DSL.
<ulink url="http://docs.neo4j.org/chunked/milestone/query-lang.html">Cypher</ulink> query-language.
</para>
<para>
Spring Data Neo4j comes with typed repository implementations that provide methods for
@@ -136,10 +135,6 @@
If it is required that paged results return the correct total count, the <code>@Query</code> annotation can be supplied with a count query in the <code>countQuery</code>
attribute. This query is executed separately after the result query and its result is used to populate the <code>totalCount</code> property of the returned Page.
</para>
<para>
Gremlin queries can be used similarly, the <code>@Query</code> annotation would just need a <code>type=QueryType.GREMLIN</code> attribute.
Parameters are supported in the same way.
</para>
</section>
<section>

View File

@@ -44,10 +44,6 @@
// Gremlin
assertEquals(thomas, neo.execute("g.v(person).out('WORKS_WITH')",
map("person", mark.getId())).to(Node.class).single());
// Index lookup
assertEquals(thomas, neo.lookup("devs", "name", "Thomas").to(Node.class).single());
@@ -123,14 +119,6 @@
or converted as needed.
</para>
</section>
<section>
<title>Gremlin Scripts</title>
<para>
Gremlin Scripts can run with the <code>execute</code> method, which also takes the parameters that will be
available as variables inside the script. The result of the executions is a generic
<code>Result&lt;Object&gt;</code> fit for conversion or usage.
</para>
</section>
<section>
<title>Transactions</title>
<para>

View File

@@ -120,8 +120,6 @@ repositories {
Spring Framework (core, context, aop, aspects, tx), AspectJ, Neo4j, and Spring Data Commons. If you
already use these (or different versions of these) in your project, then include those dependencies
on your own. In this case, please make sure that the versions match.
If you want to use Gremlin, please add the dependency (which is optional in SDN)
accordingly.
</para>
<example>
<title>Maven dependencies</title>

View File

@@ -83,8 +83,8 @@
<!-- So the first step would be moving away from the aspectj-direct mapping to loading and storing the
entities via the repositories which would manage.
-->
We looked into the different modes of remotely executed operations and found traversals, Cypher and Gremlin queries
and index lookups. Most of them already matched our needs but the Cypher and Gremlin approaches were best
We looked into the different modes of remotely executed operations and found traversals, Cypher queries
and index lookups. Most of them already matched our needs but the Cypher approaches were best
suited, because they also handled index operations and allowed to return partial attribute sets and subgraphs.
</para>
<para>

View File

@@ -18,8 +18,7 @@
the core API, and declaratively using a query-like
<ulink url="http://docs.neo4j.org/chunked/milestone/tutorials-java-embedded-traversal.html">Traversal Description</ulink>. Besides
those programmatic traversals there was the powerful graph query language called
<ulink url="http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html">Cypher</ulink> and an interesting
looking DSL named <ulink url="https://github.com/tinkerpop/gremlin/wiki">Gremlin</ulink>. So lots of ways of working with the graph.
<ulink url="http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html">Cypher</ulink>. So lots of ways of working with the graph.
</para>
<para>
We also learned that Neo4j is fully transactional and therefore upholds