Spring Certification Guide: how to persist objects and relationships in Neo4j's NoSQL data store

Original title: Spring certified China Education Management Center - learn how to persist objects and relationships in Neo4j's NoSQL data store. (spring China Education Management Center)

This guide will guide you through the process of building an application using Spring Data Neo4j, which stores and retrieves data in Neo4j, a graphics based database.

What will you build

You will use Neo4j's NoSQL graph based data storage to build embedded Neo4j servers, store entities and relationships, and develop queries.

What do you need?

  • About 15 minutes
  • Favorite text editor or IDE
  • JDK 1.8 or later
  • Gradle 4 + or Maven 3.2+
  • You can also import the code directly into the IDE: spring tool kit (STS)IntelliJ IDEA

How to complete this guide

Like most Spring getting started guides, you can start from scratch and complete each step, or you can bypass the basic setup steps you are already familiar with. Either way, you'll end up with working code.

To start from scratch, continue with Spring Initializr.

To skip the basics:

  • Download and unzip the source code base of this guide, or clone it with Git: git clone https://github.com/spring-guides/gs-accessing-data-neo4j.git
  • The CD goes to GS accessing data neo4j / initial
  • Jump to defining a simple entity.

When you are finished, you can check the results against the code in gs-accessing-data-neo4j/complete.

Start with Spring Initializr

You can use this pre initialized project and click Generate to download the ZIP file. This project is configured to fit the examples in this tutorial.

Manually initialize the project:

  1. Navigate to https://start.spring.io . The service extracts all the dependencies required by the application and completes most of the settings for you.
  2. Select Gradle or Maven and the language you want to use. This guide assumes that you have chosen Java.
  3. Click Dependencies and select Spring Data Neo4j.
  4. Click generate.
  5. Download the generated ZIP file, which is an archive of the Web application configured according to your choice.

If your IDE has spring initializer integration, you can complete this process from your IDE.

You can also fork the project from Github and open it in your IDE or other editor.

Set up Neo4j server

Before building this application, you need to set up the Neo4j server.

Neo4j has an open source server that you can install for free.

On a Mac with Homebrew installed, run the following command:

$Brewing installation neo4j

For additional options, visit https://neo4j.com/download/community-edition/.

After installation, start it with the default settings by running the following command:

$ neo4j start

You should see output similar to the following:

start-up Neo4j. 
start-up neo4j (pid 96416). By default, it is located in http://localhost:7474/
There may be a short delay before the server is ready.
For the current status, see /usr/local/Cellar/neo4j/3.0.6/libexec/logs/neo4j.log. 

By default, the user name and password of Neo4j is neo4jand neo4j. It requires a new password, but it needs to be changed. To do this, run the following command:

curl -v -u neo4j:neo4j POST localhost:7474/user/neo4j/password -H "Content-type:application/json" -d "{\"password\":\"secret\"}"

This will change the password from neo4j to secret   - what not to do in production! After completing this step, you should be ready to run the rest of this guide.

Define a simple entity

Neo4j captures entities and their relationships, both of which are equally important. Imagine that you are modeling a system in which you store everyone's records. However, you also want to track a person's colleagues (teammates in this case). With Spring Data Neo4j, you can capture all of this with a few simple comments, as shown in listing (in src/main/java/com/example/accessingdataneo4j/Person.java):

package com.example.accessingdataneo4j;

import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.schema.GeneratedValue;

@Node
public class Person {

  @Id @GeneratedValue private Long id;

  private String name;

  private Person() {
    // Empty constructor required as of Neo4j API 2.0.5
  };

  public Person(String name) {
    this.name = name;
  }

  /**
   * Neo4j doesn't REALLY have bi-directional relationships. It just means when querying
   * to ignore the direction of the relationship.
   * https://dzone.com/articles/modelling-data-neo4j
   */
  @Relationship(type = "TEAMMATE")
  public Set<Person> teammates;

  public void worksWith(Person person) {
    if (teammates == null) {
      teammates = new HashSet<>();
    }
    teammates.add(person);
  }

  public String toString() {

    return this.name + "'s teammates => "
      + Optional.ofNullable(this.teammates).orElse(
          Collections.emptySet()).stream()
            .map(Person::getName)
            .collect(Collectors.toList());
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

Here, you have a class whose Person has only one attribute: name

This class of Person is annotated with @ NodeEntity. When neo4j stores it, a new node is created. This class also has an id tag @ graphid. Neo4j@GraphId Use internally to track data.

The next important part is teammates It's simple set < Person >, but it's marked @ Relationship. This means that each member of the collection should exist as a separate Person node. Notice how the direction is set to UNDIRECTED. This means that when you query the TEAMMATE Relationship, Spring Data Neo4j ignores the direction of the Relationship.

Using this worksWith() method, you can easily connect people together.

Finally, you have a convenient toString() method that prints out the person's name and the person's colleagues.

Create simple query

Spring Data Neo4j focuses on storing data in Neo4j. However, it inherits the functions of the Spring Data Commons project, including the ability to derive queries. Essentially, you don't need to learn Neo4j's query language. Instead, you can write some methods and let the query write for you.

To understand how it works, create an interface to query the Person node. Following list (in) src/main/java/com/example/accessingdataneo4j/PersonRepository.java) shows such a query:

package com.example.accessingdataneo4j;

import java.util.List;
import org.springframework.data.neo4j.repository.Neo4jRepository;

public interface PersonRepository extends Neo4jRepository<Person, Long> {

  Person findByName(String name);
  List<Person> findByTeammatesName(String name);
}

PersonRepository extends the neo4jreposition interface and inserts the type of its operation: Person The interface has many operations, including standard CRUD (create, read, update, and delete) operations.

However, you can define other queries by declaring their method signatures. In this case, you add findByName, which looks up the type node Person and finds the node name matching the. You also have findbyteammates name, which will look for a Person node, drill down to each entry in the teammates field, and according to the name of the teammate

Access to Neo4j

Neo4j Community Edition requires credentials to access it. You can set several properties in src/main/resources/application.properties), as shown in the following listing:

spring.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret

This includes the default user name (neo4j) and the newly set password (secret) we previously selected.

Do not store real credentials in your source repository. Instead, use Spring Boot's property overrides to configure them at run time.

Create application class

Spring Initializr creates a simple class for the application. The following listing shows the class that Initializr created for this example (in) src/main/java/com/example/accessingdataneo4j/AccessingDataNeo4jApplication.java):

package com.example.accessingdataneo4j;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AccessingDataNeo4jApplication {

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

}

@SpringBootApplication is a convenient annotation that adds all of the following:

  • @Configuration: marks the class as the bean definition source of the application context.
  • @EnableAutoConfiguration: Tell Spring Boot to start adding beans according to classpath settings, other beans and various property settings. For example, if spring webmvc is on the classpath, this annotation marks the application as a Web application and activates key behaviors, such as setting DispatcherServlet
  • @ComponentScan: Tell Spring to find other components, configurations and services com/example in the package and let it find the controller.

The main() method uses springapplication. Of Spring Boot Run () method to start the application. Have you noticed that there is no single line of XML? There is no Web XML file. This Web application is 100% pure Java, and you don't have to deal with any pipeline or infrastructure configuration.

As long as they are contained in the same package (or sub package) of the @ SpringBootApplication class, Spring Boot will automatically process these repositories. To better control the registration process, you can use the @ enableneo4jrepositions annotation.

By default, @ enableneo4jrepositions scans the current package for any interface that extends one of the Spring Data repository interfaces. basePackageClasses=MyRepository.class if your project layout has multiple projects and your repository cannot be found, you can use it to safely tell Spring Data Neo4j to scan different root packages by type.

Display record output. The service should start and run in a few seconds.

The PersonRepository now automatically assembles the instances you defined earlier. Spring Data Neo4j dynamically implements the interface and inserts the required query code to meet the obligations of the interface.

The main method uses spring bootspringapplication Run () starts the application and calls the CommandLineRunner method to build the relationship.

In this example, you will create three local Person instances: Greg, Roy, and Craig. Initially, they existed only in memory. Please note that no one is anyone's teammate (currently).

At first, you find Greg, show him that he works with Roy and Craig, and then stick to him again. Remember that teammate relationships are marked UNDIRECTED. This means Roy and Craig have also been updated.

That's why when you need to update Roy. It is important to get this record from Neo4j first. Before adding Craig to the list, you need to know the latest status of Roy's teammates.

Why is there no code to get Craig and add any relationships? Because you already have it! Greg earlier marked Craig as a teammate, as did Roy. This means that Craig's relationship does not need to be updated again. You can see it as you traverse each team member and print their information to the console.

Finally, look back at your other queries and answer "who works with whom?" Problems.

The following listing shows the completed AccessingDataNeo4jApplication class (at) src/main/java/com/example/accessingdataneo4j/AccessingDataNeo4jApplication.java):

package com.example.accessingdataneo4j;

import java.util.Arrays;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;

@SpringBootApplication
@EnableNeo4jRepositories
public class AccessingDataNeo4jApplication {

	private final static Logger log = LoggerFactory.getLogger(AccessingDataNeo4jApplication.class);

	public static void main(String[] args) throws Exception {
		SpringApplication.run(AccessingDataNeo4jApplication.class, args);
		System.exit(0);
	}

	@Bean
	CommandLineRunner demo(PersonRepository personRepository) {
		return args -> {

			personRepository.deleteAll();

			Person greg = new Person("Greg");
			Person roy = new Person("Roy");
			Person craig = new Person("Craig");

			List<Person> team = Arrays.asList(greg, roy, craig);

			log.info("Before linking up with Neo4j...");

			team.stream().forEach(person -> log.info("\t" + person.toString()));

			personRepository.save(greg);
			personRepository.save(roy);
			personRepository.save(craig);

			greg = personRepository.findByName(greg.getName());
			greg.worksWith(roy);
			greg.worksWith(craig);
			personRepository.save(greg);

			roy = personRepository.findByName(roy.getName());
			roy.worksWith(craig);
			// We already know that roy works with greg
			personRepository.save(roy);

			// We already know craig works with roy and greg

			log.info("Lookup each person by name...");
			team.stream().forEach(person -> log.info(
					"\t" + personRepository.findByName(person.getName()).toString()));

			List<Person> teammates = personRepository.findByTeammatesName(greg.getName());
			log.info("The following have Greg as a teammate...");
			teammates.stream().forEach(person -> log.info("\t" + person.getName()));
		};
	}

}

Build an executable JAR

You can run the application from the command line using Gradle or Maven. You can also build and run a single executable jar file that contains all the necessary dependencies, classes, and resources. Building executable jars can easily deliver, versione and deploy services as applications throughout the development life cycle, across different environments, and so on.

If you use Gradle, you can use/ gradlew bootRun. Alternatively, you can use to build JAR files/ gradlew build, and then run the} JAR file as follows:

java -jar build/libs/gs-accessing-data-neo4j-0.1.0.jar

If you use Maven, you can use/ mvnw spring-boot:run. Alternatively, you can use the build JAR file/ mvnw clean package and run the JAR file as follows:

java -jar target/gs-accessing-data-neo4j-0.1.0.jar

The steps described here create a runnable JAR. You can also build classic WAR files.

You should see something similar to the following list (and other things, such as queries):

In and Neo4j Before connection...
	Greg's teammates => []
	Roy's teammates => []
	Craig's teammates => []

Find everyone by name...
	Greg's teammates => [Roy, Craig]
	Roy's teammates => [Greg, Craig]
	Craig's teammates => [Roy, Greg]

You can see from the output that (initially) no one is connected through any relationship. Then, after you add people, they are tied together. Finally, you can see the convenient query of finding personnel according to teammates.

summary

congratulations! You just set up an embedded Neo4j server to store some simple related entities and develop some fast queries.

Added by mdmann on Fri, 11 Feb 2022 08:51:15 +0200