【SDN Architecture】
A high level look of the architecture looks like:
-
Drivers are used to connect to the database. At the moment these come in 3 variants: Embedded, HTTP and the binary protocol Bolt.
-
The Object Graph Mapper (OGM): This is similar to an ORM in that it maps database nodes to java objects. This library is agnostic of any framework (including Spring).
-
Spring Data Neo4j 4: Provides syntactic sugar and code on top of the OGM to help quickly build Spring Based Neo4j/OGM apps.
Keyword | Sample | Cypher snippet |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
【Annotated queries】
public interface MovieRepository extends Neo4jRepository<Movie, Long> {
// returns the node with id equal to idOfMovie parameter
@Query("MATCH (n) WHERE id(n)={0} RETURN n")
Movie getMovieFromId(Integer idOfMovie);
// returns the nodes which have a title according to the movieTitle parameter
@Query("MATCH (movie:Movie {title={0}}) RETURN movie")
Movie getMovieFromTitle(String movieTitle);
// same with optional result
@Query("MATCH (movie:Movie {title={0}}) RETURN movie")
Optional<Movie> getMovieFromTitle(String movieTitle);
// returns a Page of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter.
@Query(value = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor", countQuery= "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN count(actor)")
Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, PageRequest page);
// returns a Page of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter with an accurate total count
@Query(value = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor", countQuery = "MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN count(*)")
Page<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Pageable page);
// returns a Slice of Actors that have a ACTS_IN relationship to the movie node with the title equal to movieTitle parameter.
@Query("MATCH (movie:Movie {title={0}})<-[:ACTS_IN]-(actor) RETURN actor")
Slice<Actor> getActorsThatActInMovieFromTitle(String movieTitle, Pageable page);
// returns users who rated a movie (movie parameter) higher than rating (rating parameter)
@Query("MATCH (movie:Movie)<-[r:RATED]-(user) " +
"WHERE id(movie)={movieId} AND r.stars > {rating} " +
"RETURN user")
Iterable<User> getUsersWhoRatedMovieFromTitle(@Param("movieId") Movie movie, @Param("rating") Integer rating);
// returns users who rated a movie based on movie title (movieTitle parameter) higher than rating (rating parameter)
@Query("MATCH (movie:Movie {title:{0}})<-[r:RATED]-(user) " +
"WHERE r.stars > {1} " +
"RETURN user")
Iterable<User> getUsersWhoRatedMovieFromTitle(String movieTitle, Integer rating);
@Query(value = "MATCH (movie:Movie) RETURN movie;")
Stream<Movie> getAllMovies();
}
public interface PersonRepository extends Neo4jRepository<Person, Long> {
// MATCH (person:Person {name={0}}) RETURN person
Person findByName(String name);
// MATCH (person:Person)
// WHERE person.age = {0} AND person.married = {1}
// RETURN person
Iterable<Person> findByAgeAndMarried(int age, boolean married);
// MATCH (person:Person)
// WHERE person.age = {0}
// RETURN person ORDER BY person.name SKIP {skip} LIMIT {limit}
Page<Person> findByAge(int age, Pageable pageable);
// MATCH (person:Person)
// WHERE person.age = {0}
// RETURN person ORDER BY person.name
List<Person> findByAge(int age, Sort sort);
//Allow a custom depth as a parameter
Person findByName(String name, @Depth int depth);
//Fix the depth for the query
@Depth(value = 0)
Person findBySurname(String surname);
}
public interface MovieRepository extends Neo4jRepository<Movie, Long> {
@Query("MATCH (movie:Movie)-[r:RATING]\->(), (movie)<-[:ACTS_IN]-(actor:Actor) " +
"WHERE movie.id={0} " +
"RETURN movie as movie, COLLECT(actor) AS 'cast', AVG(r.stars) AS 'averageRating'")
MovieData getMovieData(String movieId);
@QueryResult
public class MovieData {
Movie movie;
Double averageRating;
Set<Actor> cast;
}
}
引入依赖
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
</dependencies>
...
org.springframework.data.rest.level=DEBUG
debug: true
spring.data.neo4j.uri=bolt://localhost
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=199611@liu
【bean】
define projections to serve up simplified and reduced views of resources.
/**
* @author ldd
* @version v1.0
* @function movie 节点
*/
@NodeEntity
public class Movie {
@Id
@GeneratedValue
private Long id;
private String title;
private int released;
private String tagline;
@JsonIgnoreProperties("movie")
@Relationship(type = "ACTED_IN", direction = Relationship.INCOMING)
private List<Role> roles;
}
@RelationshipEntity(type = "ACTED_IN")
public class Role {
@Id
@GeneratedValue
private Long id;
private List<String> roles = new ArrayList<>();
@StartNode
private Person person;
@EndNode
private Movie movie;
}
@RepositoryRestResource(collectionResourceRel = "movies", path = "movies")
public interface MovieRepository extends Neo4jRepository<Movie, Long> {
Movie findByTitle(@Param("title") String title);
Collection<Movie> findByTitleLike(@Param("title") String title);
@Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m,r,a LIMIT {limit}")
// @Query("MATCH (m:Movie)<-[r:ACTED_IN]-(a:Person) RETURN m LIMIT {limit}")
Collection<Movie> graph(@Param("limit") int limit);
}
Then add to your Spring Boot configuration class these annotations:
@SpringBootApplication
@EnableNeo4jRepositories("com.example.demo.repositories")
/*NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.repositories Repository'*/
public class Neo4jPracticeApplication {
public static void main(String[] args) {
SpringApplication.run(Neo4jPracticeApplication.class, args);
}
}
https://docs.spring.io/spring-data/neo4j/docs/5.0.x/reference/html/#reference