【ハンズオン】Graph DB(Neo4j)入門

# この記事について

こんにちは！株式会社プラハ CPO兼エンジニアの [@shino_tp](https://twitter.com/shino_tp) です。

Graph DB アドベントカレンダー1日目です！（※アドベントカレンダーは2019年12月17日に作成）

弊社では、自社サービス開発にGraph DB（Neo4j）を採用しています。

恐らくGraph DBを知らない方も多いと思いますので、新規参画者向けにハンズオン記事を書いてみました。

そもそもGraph DBとは？な方は、以下の記事を読むことをおすすめします。
[【初心者向け】(随時更新)グラフデータベースについて学んだ事をまとめていく](https://qiita.com/osapiii/items/64982bb84f1ccf389ad2)

今回の記事では、

- DockerでNeo4jを立ち上げ
- Graph DBを操作するクエリ(cypher: サイファー)を入力して、Neo4jを操作

について書いていきます。
実際に手を動かしながら読み進めていただき、Graph DBとはなんぞや、Graph DBってこんな感じなんだな、を
知っていただけたら幸いです。

では、ハンズオン開始！

# 環境構築
本稿では、`docker-compose` コマンドを使いますので、予めDockerをインストールしておいて下さい。

## Neo4jをDockerで立ち上げる
まずは、DockerでNeo4jを起動しましょう。

```docker-compose.yml
version: '3'
services:
  neo4j:
    container_name: neo4j
    image: neo4j:3.5
    ports:
      - 7474:7474
      - 7687:7687
    volumes:
      - neo4j-store:/data
    environment:
      NEO4J_AUTH: neo4j/test

volumes:
  neo4j-store:
    driver: local
```

公式のリファレンスを貼っておきます。
https://neo4j.com/developer/docker-run-neo4j/

では、docker-compose upでNeo4jを起動してみましょう。

```bash:bash
$ docker-compose up
Creating network "hands-on-neo4j_default" with the default driver
Creating volume "hands-on-neo4j_neo4j-store" with local driver
Creating neo4j ... done
Attaching to neo4j
neo4j    | Changed password for user 'neo4j'.
neo4j    | Active database: graph.db
neo4j    | Directories in use:
neo4j    |   home:         /var/lib/neo4j
neo4j    |   config:       /var/lib/neo4j/conf
neo4j    |   logs:         /logs
neo4j    |   plugins:      /var/lib/neo4j/plugins
neo4j    |   import:       /var/lib/neo4j/import
neo4j    |   data:         /var/lib/neo4j/data
neo4j    |   certificates: /var/lib/neo4j/certificates
neo4j    |   run:          /var/lib/neo4j/run
neo4j    | Starting Neo4j.
neo4j    | 2019-12-22 15:08:58.461+0000 WARN  Unknown config option: causal_clustering.discovery_listen_address
neo4j    | 2019-12-22 15:08:58.471+0000 WARN  Unknown config option: causal_clustering.raft_advertised_address
neo4j    | 2019-12-22 15:08:58.471+0000 WARN  Unknown config option: causal_clustering.raft_listen_address
neo4j    | 2019-12-22 15:08:58.472+0000 WARN  Unknown config option: ha.host.coordination
neo4j    | 2019-12-22 15:08:58.472+0000 WARN  Unknown config option: causal_clustering.transaction_advertised_address
neo4j    | 2019-12-22 15:08:58.473+0000 WARN  Unknown config option: causal_clustering.discovery_advertised_address
neo4j    | 2019-12-22 15:08:58.473+0000 WARN  Unknown config option: ha.host.data
neo4j    | 2019-12-22 15:08:58.473+0000 WARN  Unknown config option: causal_clustering.transaction_listen_address
neo4j    | 2019-12-22 15:08:58.513+0000 INFO  ======== Neo4j 3.5.8 ========
neo4j    | 2019-12-22 15:08:58.546+0000 INFO  Starting...
neo4j    | 2019-12-22 15:09:05.621+0000 INFO  Bolt enabled on 0.0.0.0:7687.
```

## Neo4j Desktopのインストール

今回のハンズオンでは、Neo4j Desktopを使ってNeo4jにアクセスします。
Neo4j Desktopを採用する理由としては

- Neo4j Browser（Neo4jをブラウザから操作する）よりも動作が軽い
- cypherクエリの補完入力機能がある
- cypherクエリの結果を視覚的に描画する

などありますので、ぜひインストールしてみて下さい。

下記のURLからNeo4j Desktopをインストールして下さい。
https://neo4j.com/download-center/#desktop

インストールが完了し、立ち上げると以下のような画面が表示されます。
<img width="1677" alt="スクリーンショット 2019-12-23 0.14.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/c0efb7ee-eee0-1935-75c0-cd99fb291304.png">

この画面から、`Add Graph > Connect to Remote Graph > (デフォルト値)でNext > Username/Password` を押下。

```
Username: neo4j
Password: test
```

を入力し、Connectを押下。

`Activate > Open Browser` を押下して立ち上がり、以下の画面が表示されれば接続完了です。:tada:

<img width="1677" alt="スクリーンショット 2019-12-23 0.43.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/c70eb73a-a2d3-09a5-1b94-cd605612fbce.png">

具体的な操作方法は、以降の章で説明します。

# Neo4jをcypherクエリで操作する
この章では、実際にcypherクエリでNeo4jを操作します。
GraphDBの世界での登場人物は主に2つあります。
**ノード**と**リレーション**です。
詳細は後述しますので、簡単に説明すると、
ノードは、「ユーザ」や、「本」、「犬」、などの実体の情報を表現し、
リレーションは、ノードとの関係を表現します。

## ノードとは？
先程も説明したように、ノードは、「ユーザ」や、「本」、「犬」、などの実体の情報を表現します。

ノードは2つの概念を持っています。

- **ラベル**
- **プロパティ**

です。

ラベルは、「ユーザ」などの実体の名前を表現し、
プロパティは、実体の属性情報を表現します。

cypherクエリでは以下のように記述します。

```cypher:ノードの定義
(:User)
(:Book)
(:Dog)
```

`(:User)` 括弧でノードを表現し、`:`(コロン）の後に続いて記述した文字列を **ラベル**といいます。
また、ラベルは**複数付与**することができます。
複数付与する場合は、以下のようなクエリになります。

```
(:User:Admin)
```

先程のノードをプロパティ付きで表現してみましょう。

```cypher:ノードの定義+プロパティ
(:User{name: "taro", age: 17})
(:Book{title: "book", isbn: "978-3-16-148410-0"})
(:Dog{name: "pochi", age: 3})
```

見てわかる通り、波括弧で囲うことでプロパティを表現します。直感的ですね。

## ノードを作成する
では、Neo4j Desktopを立ち上げて、実際にノードを作成してみましょう！

以下のクエリを、Neo4j Desktop上部のコンソールに入力し、Enterを押下してみて下さい。

```
CREATE 
　(u:User{name: "taro", age: 17}) 
RETURN 
  u
```

ここで新しい構文がでましたね。
ラベル名の `:` (コロン) の前に定義した `u` は、cypherクエリ上で扱う変数です。
変数uには、新たに作成したUserの情報が格納されます。
この変数 `u` を使い、`RETURN u` を呼び出すことで、Neo4j Desktop上に描画することができます。

### 実行結果
name: "taro"、age: 17 のプロパティを持つUserノードが作成できました。
<img width="1577" alt="スクリーンショット 2019-12-23 0.45.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/fed5d887-825d-681a-c7e9-811b24d13461.png">

## ノードを検索する
検索をする場合は、`MATCH` 句を使います。

以下のクエリをNeo4j Desktopに入力してみましょう。

```
MATCH 
  (u:User) 
RETURN 
  u
```

このクエリで、Userラベルがついた全てのノードを取得することができます。

### 実行結果

<img width="1559" alt="スクリーンショット 2019-12-23 0.56.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/5e47a49c-5ffd-805d-50c9-1bf258135437.png">



## ノードを更新する
では、検索ができるようになったのでノードを更新してみましょう。

```
MATCH
  (u:User)
SET
  u.name = "jiro",
  u.age = 20
RETURN
  u
```

ただし、このクエリはUserラベルのついた全てのノードを更新してしまうので注意が必要です。
(SQL文のUPDATE文を実行し、テーブル内の全てのデータを更新してしまうのと同様です）
name: "taro" プロパティを持ち、Userラベルが付与されているノードのみ更新したい場合は、
以下のように、プロパティを指定してクエリを書くと良いでしょう。

```
MATCH
  (u:User{name: "taro"})
SET
  u.name = "jiro",
  u.age = 20
RETURN
  u
```

### 実行結果
<img width="1569" alt="スクリーンショット 2019-12-23 0.59.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/8af98ca4-0159-042d-e342-25a1e343385e.png">

## コラム：UUIDを生成したい
Neo4jが新しいノードを生成するとインクリメンタルなIDを付与しますが、
それ以外のランダムなUUIDを付与したい場合がありますよね。
こういう場合は、cypherのスカラ関数を用いることが可能です。

```
(u:User{id: randomUUID(), name: "taro"})
```

このクエリで、idプロパティにユニークなIDを振ることができます。
他にも、タイムスタンプを付与する `timestamp()` があります。


公式リファレンスはこちらです。
https://neo4j.com/docs/cypher-manual/current/functions/scalar/



## ノードを削除する
ノードを削除する場合は、DELETE句を使います。

```
MATCH 
  (u:User)
DELETE
  u
```

### 実行結果
<img width="1563" alt="スクリーンショット 2019-12-23 1.09.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/43dec184-3f02-ccf6-11d4-c25af5ccc51c.png">

ノードの操作方法は以上です。
次の章では、グラフデータベースの醍醐味、リレーションのハンズオンについて記載します。

## リレーションを作成する
グラフデータベースは、リレーションのみ生成することはできません。
リレーションを生成する場合は、対応するノードが必要です。
ノードを生成すると同時にリレーションを生成してみましょう。

```
CREATE 
  (u1:User{name: "taro"})-[r:FRIEND]->(u2:User{name: "jiro"}) 
RETURN 
  u1, r, u2 
```

リレーションは、`[]` (角括弧) で表現し、リレーションもノードと同様に、ラベルとプロパティを持ちます。
また、リレーションの方向を `-` または `->`、`<-` で方向を表現することができます。

この場合、taroはjiroの友達であることを表現しています。

### 実行結果
<img width="1568" alt="スクリーンショット 2019-12-23 2.05.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/9f4289e0-3170-1c10-cb01-a4c5a86c6c98.png">

## リレーションを更新する
リレーションのプロパティの更新方法は、ノードと同じです。

リレーションを変更したい（付け替えたい）場合は、
一度リレーションを削除し、再度リレーションを生成する必要があります。

## リレーションを削除する

```
MATCH (u:User{ name: "taro" })-[r:FRIEND]->()
DELETE r
```

## ノード、リレーションを全て削除

### サンプルデータの投入

サンプルデータを投入しましょう。

```
CREATE 
  (u1:User{name: "taro"})-[r:FRIEND]->(u2:User{name: "jiro"}) 
RETURN 
  u1, r, u2 
```

#### 実行結果
<img width="1568" alt="スクリーンショット 2019-12-23 2.05.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/a959a2ab-47e6-f971-c35e-8c18ae1cdd08.png">

### 全て削除する
ノードとリレーションを削除する場合は、`DETACH DELETE` 句を使います。

```
MATCH (n) DETACH DELETE n
```

#### 実行結果
<img width="1563" alt="スクリーンショット 2019-12-23 2.17.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32950/57e5f97e-be10-7e8d-fdf2-6560adf48594.png">

## もっと検索する

ラベルを指定しない検索も可能です。

### 全てのノードを検索する
```
MATCH (n) RETURN n
```

### 何かしらリレーションが付与されているノードを検索する
```
MATCH (n)-[]->() RETURN n
```

# まとめ
今回は、Neo4j入門者向けにハンズオン記事を書きました。いかがでしたでしょうか？

今回のハンズオンを経て、より複雑な内容に踏み込んでいただけるような記事も執筆予定です。

- cypherでページネーションをするクエリを書く
- Node.js/GoでNeo4jを操作してみる

# 参考
The Neo4j Cypher Manual v3.5
https://neo4j.com/docs/cypher-manual/current/

# おすすめ書籍
グラフデータベース――Neo4jによるグラフデータモデルとグラフデータベース入門
https://www.oreilly.co.jp/books/9784873117140/

※英語版はインターネットで無料配布されているそうです

# 宣伝

弊社ではエンジニアを募集しています！！ご応募お待ちしております。
https://www.wantedly.com/companies/praha-inc