Total Pageviews

Showing posts with label Neo4j. Show all posts
Showing posts with label Neo4j. Show all posts

2018/10/08

[Neo4j] How to create / drop unique node property constraints

下圖是目前 graph database 所建立的 nodes 與 relationships:

若希望所建立的 Person 的名字不可重複,需針對 Person.name 增加一個 unique constraint:
// create an unique node property constraints
CREATE CONSTRAINT ON (p:Person) ASSERT p.name IS UNIQUE

於 Neo4j browser 執行畫面如下:


此時,若我又建立一個名為大雄的 node:
// create a node which nameed 大雄
CREATE(p:Person {id:"1", name:"大雄", gender:"男性"})


於 Neo4j browser 執行就會發生錯誤:


若日後想要刪除此 unique constraint:
// drop an unique node property constraints
DROP CONSTRAINT ON (p:Person) ASSERT p.name IS UNIQUE


2018/10/07

[Neo4j] Using Spring data to find nodes and its relationships

假設我要從下圖中,分別找出
(1) 大雄的朋友
(2) 大雄的父母
(3) 大雄的寵物,以及寵物的妹妹

架構規劃如下:

pom.xml 內容
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>neo4j</groupId>
 <artifactId>springdata</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>springdata</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <java.version>1.8</java.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
 </properties>

 <dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-neo4j</artifactId>
      <version>2.0.0.RELEASE</version>
  </dependency>

  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.18</version>
  </dependency>

  <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>23.0</version>
  </dependency>

  <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
  </dependency>
 </dependencies>

 <repositories>
  <repository>
      <id>spring-libs-release</id>
      <name>Spring Releases</name>
      <url>https://repo.spring.io/libs-release</url>
      <snapshots>
   <enabled>false</enabled>
       </snapshots>
  </repository>
 </repositories>
</project>


Value Object - Person
package neo4j.springdata.vo;

import java.util.ArrayList;
import java.util.List;

import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;

import lombok.Data;
import lombok.ToString;

@NodeEntity
@Data
@ToString
public class Person {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String gender;
    
    @Relationship(type = "FRIEND_OF")
    public List<Person> friends = new ArrayList<Person>();
    
}

Value Object - Robot
package neo4j.springdata.vo;

import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;

import lombok.Data;

@NodeEntity
@Data
public class Robot {
    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    private String gender;
    
}

Value Object - PetQueryResult (查詢結果)
package neo4j.springdata.vo.result;

import org.springframework.data.neo4j.annotation.QueryResult;

import lombok.Data;
import lombok.ToString;
import neo4j.springdata.vo.Person;
import neo4j.springdata.vo.Robot;

@QueryResult
@Data
@ToString
public class PetQueryResult {

    private Person person;
    private Robot pet;
    private Robot petSister;

}

Repository class - PersonRepository
package neo4j.springdata.repository;

import java.util.List;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import neo4j.springdata.vo.Person;
import neo4j.springdata.vo.result.PetQueryResult;

@Repository
public interface PersonRepository extends CrudRepository<Person, Long> {

    @Query("match(n) return n")
    List<Person> findAll();

    Person findByName(String name);

    @Query(" match(p:Person) where p.name={name} " +
           " optional match (p)-[:FRIEND_OF]->(p2) " + 
           " return p2")
    List<Person> findFriendsByName(@Param("name") String name);

    @Query(" match(p:Person) where p.name={name} " +
           " optional match (p)-[:FATHER_OF]-(p2) " +
           " return p2 " +
           " union " +
           " match(p:Person) where p.name={name} " +
           " optional match (p)-[:MOTHER_OF]-(p2) " +
           " return p2 ")
    List<Person> findParents(@Param("name") String name);
    
    @Query(" match(p:Person)-[:PET_OF]-(r:Robot)-[:SISTER_OF]-(r2) " +
           " where p.name={name} " +
           " return p as person, r as pet, r2 as petSister ")
    List<PetQueryResult> findPetsAndItsSister(@Param("name") String name);
    
}

Service class - PersonService
package neo4j.springdata.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import neo4j.springdata.repository.PersonRepository;
import neo4j.springdata.vo.Person;
import neo4j.springdata.vo.result.PetQueryResult;

@Service
public class PersonService {

    @Autowired
    private PersonRepository personRepo;

    public List<Person> findAll() {
        return personRepo.findAll();
    }

    public List<Person> findFriendsByName(String name) {
        return personRepo.findFriendsByName(name);
    }

    public List<Person> findParents(String name) {
        return personRepo.findParents(name);
    }

    public List<PetQueryResult> findPetsAndItsSister(String name) {
        return personRepo.findPetsAndItsSister(name);
    }

}

Client class - App
package neo4j.springdata;

import java.util.List;

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;

import lombok.extern.slf4j.Slf4j;
import neo4j.springdata.service.PersonService;
import neo4j.springdata.vo.Person;
import neo4j.springdata.vo.Robot;
import neo4j.springdata.vo.result.PetQueryResult;

@SpringBootApplication
@EnableNeo4jRepositories
@Slf4j
public class App {

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

    @Bean
    CommandLineRunner findFriendsByName(PersonService service) {
        return args -> {
            log.info("find 大雄的朋友:");
            List<Person> friends = service.findFriendsByName("大雄");
            friends.forEach(p -> log.info(p.toString()));

            log.info("find 大雄的父母:");
            List<Person> parents = service.findParents("大雄");
            parents.forEach(p -> log.info(p.toString()));

            List<PetQueryResult> petQueryResult = service.findPetsAndItsSister("大雄");
            petQueryResult.forEach(p -> {
                Robot pet = p.getPet();
                Robot petSister = p.getPetSister();
                log.info("大雄的寵物是[" + pet.getName() + "], 寵物的妹妹是[" + petSister.getName() + "]");
            });
        };
    }

}


2018/09/14

[Neo4j] Using Spring Data to create / delete nodes and relationship

假設我想透過 Spring Data API 建立起以下的 graph:


架構規劃如下:

pom.xml 內容:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>neo4j</groupId>
 <artifactId>springdata</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>jar</packaging>

 <name>springdata</name>
 <url>http://maven.apache.org</url>

 <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <java.version>1.8</java.version>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
 </properties>

 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-neo4j</artifactId>
   <version>2.0.0.RELEASE</version>
  </dependency>

  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.16.18</version>
  </dependency>

  <dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>23.0</version>
  </dependency>

  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
 </dependencies>

 <repositories>
  <repository>
   <id>spring-libs-release</id>
   <name>Spring Releases</name>
   <url>https://repo.spring.io/libs-release</url>
   <snapshots>
    <enabled>false</enabled>
   </snapshots>
  </repository>
 </repositories>
</project>

Value objects - Brand
package neo4j.springdata.vo;

import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@NodeEntity
@Data
@ToString
@NoArgsConstructor
@RequiredArgsConstructor
public class Brand {

    @Id
    @GeneratedValue
    private Long id;

    @NonNull
    private String name;

}

Value objects - Product
package neo4j.springdata.vo;

import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@NodeEntity
@Data
@ToString
@NoArgsConstructor
@RequiredArgsConstructor
public class Product {
    
    @Id
    @GeneratedValue
    private Long id;

    @NonNull
    private String name;
    
    @Relationship(type = "MADE_BY")
    private Brand madeBy;
    
}

Repository class - BrandRepository
package neo4j.springdata.repository;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import neo4j.springdata.vo.Brand;

@Repository
public interface BrandRepository extends CrudRepository<Brand, Long>{

    @Query("match(b:Brand) where b.name = {name} return b")
    Brand findByName(@Param("name") String name);
    
    @Query("match(n:Brand) optional match (n)-[r]-() delete r, n")
    void deleteAllBrands();
    
}

Repository class - ProductRepository
package neo4j.springdata.repository;

import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import neo4j.springdata.vo.Product;

@Repository
public interface ProductRepository extends CrudRepository<Product, Long> {

    @Query("match (n:Product) optional match (n)-[r]-() delete r, n")
    void deleteAllProducts();
    
}

Service class - BrandService
package neo4j.springdata.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import neo4j.springdata.repository.BrandRepository;
import neo4j.springdata.vo.Brand;

@Service
public class BrandService {

    @Autowired
    private BrandRepository brandRepo;
    
    public void createBrands(List<Brand> brands) {
        brandRepo.saveAll(brands);
    }
    
    public void deleteAllBrands() {
        brandRepo.deleteAllBrands();
    }

}

Service class - ProductService
package neo4j.springdata.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import neo4j.springdata.repository.BrandRepository;
import neo4j.springdata.repository.ProductRepository;
import neo4j.springdata.vo.Brand;
import neo4j.springdata.vo.Product;

@Service
public class ProductService {

    @Autowired
    private BrandRepository brandRepo;
    
    @Autowired
    private ProductRepository productRepo;
    
    public void createProducts(List<Product> products, String brandName) {
        Brand brand = brandRepo.findByName(brandName);
        products.forEach(p -> p.setMadeBy(brand));
        
        productRepo.saveAll(products);
    }
    
    public void deleteAllProducts() {
        productRepo.deleteAllProducts();
    }
    
}

Client class - App
package neo4j.springdata;

import java.util.List;

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;

import com.google.common.collect.Lists;

import neo4j.springdata.service.BrandService;
import neo4j.springdata.service.ProductService;
import neo4j.springdata.vo.Brand;
import neo4j.springdata.vo.Product;

@SpringBootApplication
@EnableNeo4jRepositories
public class App {

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

    @Bean
    CommandLineRunner createBrands(BrandService brandService) {
        return args -> {
            List<Brand> brands = Lists.newArrayList(new Brand("Apple"), new Brand("Google"), new Brand("Samsung"));
            brandService.createBrands(brands);
        };
    }

    @Bean
    CommandLineRunner createProducts(ProductService productService) {
        return args -> {
            List<Product> appleProducts = Lists.newArrayList(new Product("iPhne"), new Product("iPad"),
                    new Product("iPad Pro"), new Product("MacBook"), new Product("MackBook Pro"));
            productService.createProducts(appleProducts, "Apple");

            List<Product> googleProducts = Lists.newArrayList(new Product("Nexus 6P"), new Product("Nexus 5X"),
                    new Product("Chromecast"));
            productService.createProducts(googleProducts, "Google");

            List<Product> samsungProducts = Lists.newArrayList(new Product("Samsung Galaxy Note 8"),
                    new Product("Samsung Galaxy Note FE"), new Product("Samsung Galaxy S9"),
                    new Product("Samsung Galaxy A8"));
            productService.createProducts(samsungProducts, "Samsung");
        };
    }

    @Bean
    CommandLineRunner deleteProductAndBrands(BrandService brandService, ProductService productService) {
        return args -> {
            brandService.deleteAllBrands();
            productService.deleteAllProducts();
        };
    }

}


application.properties (記錄連線資訊)
spring.data.neo4j.uri=bolt://localhost
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret