neo4jをSpring bootで触ってみた
↓のアドベントカレンダーの7日目!(ざわ・・・)
はじめに
今日はneo4jをSpring bootで触ってみたので、その話を少々します。
neo4j
ひょんなことからグラフDBを触る機会ができたので、なにがいいかなーって考えたらやっぱ有名ドコロでしょってことでneo4jを触るようになってます。そんな私です。
neo4jはオープンソースのグラフDBで、Javaで実装されています。
はい、インストール
$ brew install neo4j
はい、起動
neo4j start
ええ、それはもう。
つぎにSpring boot
導入しましょう
Spring Data Neo4jとかいう便利なやつがいるので、 今回はそれを使います。
mavenの定義はこのような感じに・・・
(Gradleで書こうかと思ったけど、まぁ今回はいいかなと・・・)
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>org.springframework</groupId> <artifactId>gs-accessing-data-neo4j</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.2.RELEASE</version> </parent> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-neo4j</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/libs-release</url> </repository> </repositories> </project>
はい、OKです。
ちょちょっと何か作ろう
ひどく簡単(というか↓のチュートリアルそのもの・・・)ですが、サンプルも書いてみました。
人がチームメイトという関係でつながっているサンプルです。
まずは人のクラス
import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.NodeEntity; import org.neo4j.ogm.annotation.Relationship; @NodeEntity public class Person { @GraphId 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", direction = Relationship.UNDIRECTED) 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 -> person.getName()).collect(Collectors.toList()); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
ノードであることは@Relationshipで宣言して、主キーみたいなもんのIDは@GraphIdで宣言して、ノード間の関係は@Relationshipで宣言して、って感じですか。
よくできてますね〜。ええ、はい。
次に人を検索するためのリポジトリ
import org.springframework.data.neo4j.repository.GraphRepository; public interface PersonRepository extends GraphRepository<Person> { Person findByName(String name); }
これで名前での検索が可能になります。
では、実際にノードを定義していきましょう。
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 Application { private final static Logger log = LoggerFactory.getLogger(Application.class); public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } @Bean CommandLineRunner demo(PersonRepository personRepository) { return args -> { personRepository.deleteAll(); Person yamada = new Person("山田 哲人"); Person ogawa = new Person("小川 泰弘"); Person kawabata = new Person("川端 慎吾"); List<Person> team = Arrays.asList(yamada, ogawa, kawabata); log.info("Before linking up with Neo4j..."); team.stream().forEach(person -> log.info("\t" + person.toString())); personRepository.save(yamada); personRepository.save(ogawa); personRepository.save(kawabata); yamada = personRepository.findByName(yamada.getName()); yamada.worksWith(ogawa); yamada.worksWith(kawabata); personRepository.save(yamada); ogawa = personRepository.findByName(ogawa.getName()); ogawa.worksWith(kawabata); // We already know that roy works with greg personRepository.save(ogawa); // 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())); }; } }
実行してみて〜
DBを確認すると、ほれこの通り。ちゃんと山田、ライアン、川端がチームメイトとしてつながっております。メジャーとか行くなよ。
そして、ログをみてもこの通り。 ちゃんと検索されております。
2016-12-20 06:25:05.978 INFO 85511 --- [ main] o.n.o.drivers.http.request.HttpRequest : Thread: 1, url: http://localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Person`) WHERE n.`name` = { `name` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name":"山田 哲人"},"resultDataContents":["graph","row"],"includeStats":false}]} 2016-12-20 06:25:05.989 INFO 85511 --- [ main] stretch.neo4j.Application : 山田 哲人's teammates => [川端 慎吾, 小川 泰弘] 2016-12-20 06:25:05.990 INFO 85511 --- [ main] o.n.o.drivers.http.request.HttpRequest : Thread: 1, url: http://localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Person`) WHERE n.`name` = { `name` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name":"小川 泰弘"},"resultDataContents":["graph","row"],"includeStats":false}]} 2016-12-20 06:25:06.001 INFO 85511 --- [ main] stretch.neo4j.Application : 小川 泰弘's teammates => [山田 哲人, 川端 慎吾] 2016-12-20 06:25:06.002 INFO 85511 --- [ main] o.n.o.drivers.http.request.HttpRequest : Thread: 1, url: http://localhost:7474/db/data/transaction/commit, request: {"statements":[{"statement":"MATCH (n:`Person`) WHERE n.`name` = { `name` } WITH n MATCH p=(n)-[*0..1]-(m) RETURN p, ID(n)","parameters":{"name":"川端 慎吾"},"resultDataContents":["graph","row"],"includeStats":false}]} 2016-12-20 06:25:06.014 INFO 85511 --- [ main] stretch.neo4j.Application : 川端 慎吾's teammates => [山田 哲人, 小川 泰弘]
あら、便利ですねぇ。
最後に
neo4jを導入した。そして、javaを使ってノード作成、検索ができるようになった!
本当に簡単なことしかやってないので、次回はもっと面白いこともやってみよう!
ということで、さようなら。
投稿が遅れたこと、、、、すまないと思っている。