GraphDB Neo4j on Docker

- Neo4jを使ってみたのでその時のことをメモしておく

#### 下記のステップで進めます
1. Dockerコンテナの準備
2. Dockerコンテナの起動
3. Neo4j管理画面入室
4. Cyperを利用したデータの操作

#### 1. Dockerコンテナの準備
- [Dockerhub neo4j](https://hub.docker.com/_/neo4j/)
- neo4j のイメージを取得

```
$ mkdir graphdb-neo4j
$ cd graphdb-neo4j
$ docker pull neo4j
```
#### 2. Dockerコンテナの起動
**docker コマンドで起動**

```
$ docker run \
    --detach \
    --publish=7474:7474 --publish=7687:7687 \
    --volume=$HOME/neo4j/data:/data \
    --volume=$HOME/neo4j/logs:/logs \
    --volume=$HOME/neo4j/conf:/conf \
    --ulimit=nofile=40000:40000 \
    neo4j:latest
# 確認
$ docker CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                      NAMES
905109eecfc6        neo4j:latest        "/sbin/tini -g -- /d…"   12 seconds ago      Up 11 seconds       0.0.0.0:7474->7474/tcp, 7473/tcp, 0.0.0.0:7687->7687/tcp   affectionate_elgamal

# コンテナに入る
$ docker exec -it neo4j bin/cypher-shell
username:****
password:****

# 退出
$ :exit
```

**docker-compose.ymlの場合**

```docker-compose.yml
version: '2'

services:
  neo4j:
    image: neo4j:latest
    ports:
      - "7474:7474"
      - "7687:7687"
    volumes:
      - ${HOME}/neo4j/data:/data
      - ${HOME}/neo4j/logs:/logs
      - ${HOME}/neo4j/conf:/conf
    ulimits:
      nofile:
        soft: 40000
        hard: 40000
```

**docker-compose.ymlで起動**

```
$ docker-compsoe up -d
$ docker-compose            Name                         Command               State                            Ports                          
------------------------------------------------------------------------------------------------------------------------------
neo4j_neo4j_1_12ca70742005   /sbin/tini -g -- /docker-e ...   Up      7473/tcp, 0.0.0.0:7474->7474/tcp, 0.0.0.0:7687->7687/tcp

# コンテナに入る
$ docker-compose exec neo4j bin/cypher-shell
username:****
password:****

# 退出
$ :exit
```

#### 3. Neo4j管理画面入室
- 起動が確認できたらブラウザからNeo4jの管理画面に入室します
- 192.168.33.10:7474
- ホストアドレスは自分の環境に合わせて変更
- 初回はusernameとpasswordの初期設定を求められるもよう

#### 4. Cyperを利用したデータの操作
[公式ドキュメント](https://neo4j.com/docs/cypher-manual/current/)

- 公式ドキュメントを参考に軽くテストしてく

##### ノード作成
- ノードとはデータ点のこと

**基本構文**
`CREATE (ParameterName:Label { field1: value1, field2: value2 })`

**一意制約**
`MATCH (ParameterName:Label { field1: value1, field2: value2 }) CREATE UNIQUE (ParameterName)`

**複数のラベルを指定**
`CREATE (ParameterName:Label1:Label2 { field1: value1, field2: value2 })`

*複数ノード作成**
`CREATE (node1),(node2),...`

**結果を取得**
`CREATE (node1) RETURN paramName.field1`

**ノードと一緒にリレーションも作成**
`CREATE (node1:Label{field1:value})-[:relationName]->(node2:label{field1:value})`


```
# ノードを2件作成
$ CREATE (n1:Person:Japanese { name: 'Sato', blood: 'A', age:25}),(n2:Person:Korea {name:'Kim', blood:'O', age:23})

# ノード3件とリレーションも作成
$ CREATE (n1:Person:Japanese { name: 'Endo', blood: 'AB', age:20}),(n2:Person:Japanese {name:'Aoki', blood:'A', age:18}),(n3:Person:Japanese {name:'Takagi', blood:'B', age:30}),(n1)-[:friends]->(n2)-[:friends]->(n3)-[:friends]->(n1)-[:friends]->(n3)
```

##### リレーションを追加
- リレーションとはエッジ（辺）のこと

**基本構文**
`CREATE (node1)-[:Relations]->(node2)`

**相互リレーション**
`CREATE (node1)-[:Relations]->(node2)-[:relation]->(node1)`


```
# SatoさんとKimさんは友達同士という関係を追加
$ MATCH (n1:Person { name: 'Sato'}),(n2:Person {name:'Kim'}) CREATE (n1)-[:friends]->(n2)-[:friends]->(n1)

# SatoさんはAokiさんと友達という関係を追加
$ MATCH (n1 {name:'Sato'}),(n2 {name:'Aoki'}) CREATE (n1)-[:friends]->(n2) 
```

#### データを取得
**基本構文**
`MATCH (n) RETURN n`

```
# 全件取得
$ MATCH (n) RETURN n
```

**ラベル検索**
`MATCH (n:LabelName) RETURN n`

```
# 日本人というラベルで検索
$ MATCH (n:Japanese) RETURN n
```

**属性検索** ※属性検索ではラベルは必須ではありません
`MATCH (n:LabelName { name:'value' }) RETURN n`

```
# Kimさんを検索
$ MATCH (n:Person {name:'Kim'}) RETURN n
```
**WHERE句を使った検索**
`MATCH (n) WHERE n.field=value RETURN n`

```
# Kimさんを検索
$ MATCH (n) WHERE n.name='Kim' RETURN n
```

**前方一致**
`UNWIND list as v
MATCH (n) WHERE left(n.name, size(v))=v return n`

**後方一致**
`UNWIND list as v
MATCH (n) WHERE right(n.name, size(v))=v return n`

```
# Ki,Satで始まるnameを検索さんを検索
$ UNWIND ['Ki','Sat'] as v MATCH (n) WHERE left(n.name, size(v))=v RETURN n
```

#### 関係データを取得
**構文**
`MATCH (node1)-[:Relations]->(node2) return node1, node2`

```
# Satoさんの友達を検索（Satoさんの友達はKimさんとAokiさん
$ MATCH (n1 {name:'Sato'})-[:friends]->(n2) return n2

# Satoさんと友達同士の人を検索（友達同士なのはKimさんだけ）
$ MATCH (n1 {name:'Sato'})-[:friends]->(n2)-[:friends]->(n1) return n1, n2
```

**ノードの階層を指定**
`MATCH (node1)-[:Relation*1..3]-(node2)`

```
# Kimさんの友達の友達の友達を取得
$ MATCH  (n1 {name:'Kim'})-[:friends*1..3]->(n2) RETURN n2

# Kimさんの友達の友達を友達と友達関係にある人物
$ MATCH  (n1 {name:'Kim'})-[:friends*1..3]->(n2)-[:friends*]->(n3)-[:friends*]->(n2) RETURN n3
```

#### データを更新
**ノードのプロパティを更新**
`MATCH (node) SET node.field = value`

```
# Endoさんの年齢を30に更新
$ MATCH (node {name:'Endo'}) SET node.age = 30 return node

# Endoさんの性別、女性を追加
$ MATCH (node {name:'Endo'}) SET node.sex= 'femaile' return node
```
**ノードのラベルを更新**
`MATCH (node1) SET node1:Label`

```
# AokiさんにStudentというラベルを追加
$ MATCH (node1 {name:'Aoki'}) SET node1:Student
```


**リレーションの属性（情報）を更新**
`MATCH (node1)<-[r:Relations]->(node2) SET r.type = 'value'`

```
# SatoさんとKimさんの関係が親密であるという情報（属性）を追加
$ MATCH (node1{name:'Sato'})<-[relation1:friends]->(node2{name:'Kim'}) SET relation1.type = "intimate"
```

#### データを削除
**ノードを削除**
`MATCH (node1) DELETE node1`

**リレーションも含めて削除**
`MATCH (node1) DETACH DELETE node1`

**リレーションだけ削除**
`MATCH (node1)-[r:Relation] DELETE r`

```
# 削除用のデータを作成
$ CREATE (n1 {test:'hogehoge'}) return n1
# テストデータを削除
$ MATCH (node) WHERE node.test='hogehoge' DELETE node RETURN node
```

#### csvファイルからデータ取りこみ
ファイル名：./csv/node.csv
※こんな感じのデータ
1,Taro,20
2,Hanako,18
3,Kenta,22
4,Namihei,58

`LOAD CSV FROM './csv/node.csv' AS line CREATE (:Person { name: line[1], age: toInteger(line[2])})` 

[csv読み込み](https://neo4j.com/docs/cypher-manual/current/clauses/load-csv/)

#### 終わり
ドキュメントを参考にCRUDの使い方だけさらっと、それからリレーションの探索のところもさらっとやってみました。
前方（後方）一致検索について情報が載ってなかったのでメモです。
前方一致はともかく、後方一致や部分一致は検索が遅いであろうことは想像つきますので実用的ではないですが。

**参考**
[neo4j chapter3.Docker](https://neo4j.com/docs/operations-manual/current/docker/introduction/)