Improving the Flavour- Upgrading to Spring Data Neo4j 4.1

· 6 min read

Our previous article demonstrated how easy it was to build an application using Spring Data Neo4j 4.

The first milestone of Spring Data Neo4j 4.1 has just been released (based on Neo4j OGM 2.0), and it delivers significant performance improvements for write operations, the ability to map nodes and relationships returned in custom Cypher queries to domain entities, as well as the much awaited support for embedded Neo4j.

The new Components framework in Neo4j OGM 2.0 allows you to configure your application by specifying which driver you want to use to connect to Neo4j. Currently supported are the Http and Embedded drivers. A Bolt driver will be available in the near future when Neo4j 3.0 is released. The great news is that swapping drivers in your application is trivial!

Upgrading Flavorwocky to use Spring Data Neo4j 4.1 requires us to use one of these Drivers instead of the RemoteServer provided in SDN 4.0. We’re still using a remote Neo4j server so the Http Driver is appropriate.

The source code discussed in this article is available on Github.

Dependencies

First, let us update the versions of Spring Data Neo4j and Spring Data Commons -

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-neo4j</artifactId>
    <version>4.1.0.M1</version>
</dependency>

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
    <version>1.12.0.M1</version>
</dependency>

Include the milestone repository too -

<repository>
    <id>spring-milestones</id>
    <url>http://repo.spring.io/milestone</url>
</repository>

Configuring the HTTP Driver

There are two ways to configure our application. The easiest way is to have the OGM auto-configure itself by providing a properties file called ogm.properties in the classpath. This file contains the driver to use and the URI of the Neo4j database. An example of this is

driver=org.neo4j.ogm.drivers.http.driver.HttpDriver
URI=http://user:password@localhost:7474

We’re not going to use this because Flavorwocky is deployed on Heroku and uses the GrapheneDB add-on. Our Neo4j connection URI is conveniently available in an environment variable called GRAPHENEDB_URL which looks like http://<neo4j-server-username>:<neo4j-server-password@<neo4j-host>:<neo4j-port>

Hence, we will configure the driver programmatically and not embed our credentials in the properties file.

Recall that Application.java must extend Neo4jConfiguration. We do not need neo4jServer() any more and instead create a Configuration bean. The Configuration is supplied with the driver class name, which in our case is org.neo4j.ogm.drivers.http.driver.HttpDriver, as well as the URI of the remote Neo4j server. This is provided by the GRAPHENEDB_URL environment variable as discussed earlier.


import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan("com.flavorwocky")
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableNeo4jRepositories("com.flavorwocky.repository")
public class Application extends Neo4jConfiguration {

	final String grapheneUrl;

	public Application() {
		grapheneUrl = System.getenv("GRAPHENEDB_URL");
	}

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Bean
	public org.neo4j.ogm.config.Configuration getConfiguration() {
		org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
		config.driverConfiguration()
				.setDriverClassName
						("org.neo4j.ogm.drivers.http.driver.HttpDriver")
				.setURI(grapheneUrl);
		return config;
	}

	@Override
	@Bean
	public SessionFactory getSessionFactory() {
		return new SessionFactory(getConfiguration(), "com.flavorwocky.domain" );
	}

	@Override
	@Bean
	@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
	public Session getSession() throws Exception {
		return super.getSession();
	}
}

The Configuration we set up is now passed as the first argument to the SessionFactory constructor.

That’s it, we’ve successfully configured the application to use Spring Data Neo4j 4.1.

Mapped entities in custom queries

Nodes and relationships returned by custom queries i.e. @Query are now automatically mapped to domain entities. This is a huge benefit - earlier the only option was to return node and relationship entity IDs and load the entities by ID via a separate API call. Returning paths are not supported- instead, we return nodes and relationships in the path and this will map and wire up all our domain objects represented by those returned entities.

Recall that we defined this custom query to help us build a tree of flavour pairings as the input to the D3.js visualization-

	@Query("match p=(i:Ingredient {name:{0}})-[r:PAIRS_WITH*0..3]-(i2)-[:HAS_CATEGORY]->(cat) return p;")
	Iterable<Map<String, Object>> getFlavorPaths(String ingredientName);

This query represented each row as a List<Map<String, Object>>; each map contained properties of nodes or relations in the path, it did not contain the ID’s or labels or relationship types. We can no longer return paths, but instead, Spring Data Neo4j 4.1 will map each node and relationship entity to domain objects, so we’ll change our query to return those instead-

    @Query("match p=(ingredient:Ingredient {name:{0}})-[pairsWith:PAIRS_WITH*0..3]-(otherIngredient)-[r:HAS_CATEGORY]->(cat) return nodes(p) as nodes, rels(p) as rels")
	Iterable<Map<String, Object>> getFlavorPaths(String ingredientName);

We still have every element in the path, only now they are represented as easy-to-work-with domain objects.

Testing

In SDN 4.1, the InProcessServer we used in our tests earlier has been deprecated. Instead, we will use an impermanent embedded database.

The test dependencies required are

 <dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-neo4j</artifactId>
   <version>4.1.0.RELEASE</version>
   <type>test-jar</type>
</dependency>

<dependency>
   <groupId>org.neo4j</groupId>
    <artifactId>neo4j-kernel</artifactId>
    <version>2.3.2</version>
    <type>test-jar</type>
</dependency>

<dependency>
    <groupId>org.neo4j.app</groupId>
    <artifactId>neo4j-server</artifactId>
    <version>2.3.2</version>
    <type>test-jar</type>
</dependency>

 <dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-ogm-test</artifactId>
    <version>2.0.0-M02</version>
    <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.neo4j.test</groupId>
  <artifactId>neo4j-harness</artifactId>
  <version>2.3.2</version>
  <scope>test</scope>
</dependency>

We’ll have the OGM auto-configure itself to use the embedded driver for tests by including an ogm.properties file in the test classpath.

driver=org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver

Note that we want to use the impermanent graph database so the URI is omitted from the properties. As with Application.java, the neo4jServer() method is not relevant any more and it’s been removed.

Conclusion

Pretty straightforward!

We strongly recommend that you upgrade from Spring Data Neo4j 4.0 to Spring Data Neo4j 4.1, or from Neo4j OGM 1.x to Neo4j OGM 2.0

The documentation for Spring Data Neo4j 4.1 is available at https://docs.spring.io/spring-data/neo4j/docs/4.1.0.M1/reference/html/

If you prefer to use Neo4j OGM directly, the reference guide is published to https://neo4j.com/docs/ogm/java/stable/

The source code for Flavorwocky is available on Github and instructions on how to run it locally are documented in the README.

If you need help, please post a question on StackOverflow and tag it with spring-data-neo4j-4

Luanne Misquitta

Engineering | Neo4j certification

Luanne Misquitta is an engineering leader with over 20 years of experience in start-ups and enterprises, both consulting and product oriented. She is widely recognised as one of the world's most experienced Neo4j consultants, having successfully implemented numerous projects in the field. Luanne has a track record of growing customer-focused, high-performing engineering teams and believes in lean principles driving engineering excellence.