Neo4j  1日触ってみた備忘録

Neo4jをインストールしたもののなかなか触ることができていなかったので、夏前？に1日触ってみた備忘録。

Cypherについては、公式で丁寧に解説されているので、そちらを参考にしてください。
<html>https://neo4j.com/docs/cypher-manual/current/</html>


# インストール関連
前に備忘録としてまとめたので、そちらを参照
[グラフDB初心者　Neo4jインストールからサンプル実行まで](https://qiita.com/daisuke_high_185/items/3c924e67c01776e5334c)



# Neo4j ブラウザコマンド備忘録
ブラウザに表示された画面でコマンドが実行できます。
![ブラウザ画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297721/5815ed1f-c61f-4f9d-c74a-fd6339bf6edf.png)

##### ■HELPを表示
HELPコマンドから、コマンドやクエリ、チュートリアルなどを参照することができます。
自分は初心者として、Exampleのチュートリアルを触って、クエリのイメージを掴むのはおすすめです。

```
:help
```
![help画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297721/d042417f-494c-c2af-ef18-0c7b8291d9c7.png)

##### ■cypherを確認
GraphoDBを操作するクエリを確認することができます。

```
:help cypher
```

##### ■画面をクリアする

```
:clear
```
![clear.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297721/ba92bdc7-c719-6989-e7e3-088993f65dc6.png)

詳しくはこちらが参考になります
[Neo4j Webインターフェースを使い倒す](https://qiita.com/awk256/items/4448899663a6aa82e88d)

# Neo4j データ型
- 数値 
integerおよびFloat
- 文字列
`''`もしくは`""`で記載する
- 真偽値
- List型



# Neo4j cypherクエリ備忘録

## node

### 作成関連

#### CREATE

##### ■シンプルにINSERT
label（ラベル）    :person
property(属性)  :中田

```
CREATE(:person{name:'中田'})
```

もちろん、SQLのように見やすく改行しても実行できます！
Neo4j公式の構文記載方法はこちらを参照してください。
[Cypher 構文推奨記載方法](https://neo4j.com/docs/cypher-manual/current/styleguide/#cypher-styleguide-patterns)

```
CREATE (
  :person{
    name:'田中'
  }
)
```

##### ■一度に複数のnodeをINSERT

```
CREATE (
  :person{
    name:'森田'
  }
)
,(
  :person{
    name:'田森'
  }
)
```

##### ■複数のpropertyをINSERT
複数のnodeをINSERTする場合でも、propertyを統一する必要はありません。

```
CREATE (
  :person{
    name:'村田'
    ,age:25
    ,from:'Kyoto'
  }
)
,(
  :person{
    name:'田村'
    ,age:40
    ,job:'engineer'
    ,hobby:['fishing','reading','cooking']
  }
)
```

##### ■やってみての注意点
・データの重複はあり
　例えば`CREATE(:person{name:'中田'})`を複数回実行すれば、中田さんが複数node表示されます。


### 制約関連
制約をしようすれば、データの重複も除外することができます。

#### CONSTRAINT

##### ■ユニーク制約の作成
Lable"Person"のProperty"name"にユニーク制約をつけることで名前が重複する人の登録を防ぐことが可能です。

```
CREATE CONSTRAINT ON (p:person) ASSERT p.name IS UNIQUE
```
ユニークを制約を作成すると、作成したPropertyに対してIndexが作成されます。
以下のクエリで確認できます。

```
CALL db.indexes
```

##### ■（ユニーク）制約の削除
制約の削除は`CREATE`を`DROP`に変更することで実行が行えます。
また、上記で補足したIndexは削除されないため、別で削除が必要になります。

```
DROP CONSTRAINT ON (p:person) ASSERT p.name IS UNIQUE
```

##### ■制約の確認

```
CALL db.constraints
```
他にも"Label"、"Index"などの設定が`CALL`を使用することで確認できます。
<html>https://neo4j.com/docs/cypher-manual/current/clauses/call/</html>

#### Enterprise Editionのみで設定できる制約

##### ■Propertyの制約
Propertyで必ず登録が必要なものには、制約を付与できます。
例えば、Label"person"では、Property"name"の登録を必須にすることで、名前は常にわかる状態とすることができます。
ただし、Enterprise Editionのみ実行可能でした。。。

```
CREATE CONSTRAINT ON (p:person) ASSERT exists(p.name)
```
![CONSTRAINT_exists.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297721/ff9e19f6-e6cd-33d3-7992-7ca7d58d4eb7.png)

##### ■Node Keyの制約

```
CREATE CONSTRAINT ON (p:Person) ASSERT (p.name, p.age) IS NODE KEY
```


### INDEX関連

#### INDEX

##### ■1つのPropertyにINDEXを作成する

```
CREATE INDEX ON :person(name)
```

##### ■複数のPropertyにINDEXを作成する

```
CREATE INDEX ON :person(name, age)
```

##### ■INDEXの確認

```
CALL db.indexes
```

##### ■INDEXの削除
`CREATE`を`DROP`に変更するのみ

```
DROP INDEX ON :person(name, age)
```


### 検索関連

#### MATCH, RETURN
MATCHはSQLでのFROMに相当
RETURNはSQLでのSELECTに相当

##### ■全データを検索する

```
MATCH (n) RETURN n
```
![MATCH全件.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297721/2946c1d1-3ee7-ae3e-ddff-6ad4e69502b6.png)

##### ■対象のラベルに含まるデータを検索する

```
MATCH (
  p:person
) 
RETURN
  p
```

##### ■対象のLabel,Propertyをもつデータを検索する

```
MATCH (
  p_morita:person{
    name:'森田'
  }
) 
RETURN
  p_morita
```

#### WHERE
SQLのWHERE句と同様の使い方ができる。
演算子は`AND/OR/XOR/NOT`が使用可能

##### ■WHEREでlabelを絞り込み

```
MATCH (n)
WHERE n:person
RETURN n.name, n.age
```

##### ■WHERE句での絞り込み（完全一致検索）

```
MATCH (
  p:person
) 
WHERE 
  p.name = '村田'
  AND p.from='Kyoto'
RETURN 
  p
```

##### ■WHERE句での絞り込み（範囲検索）

```
MATCH (
  p:person
) 
WHERE 
  p.age >= 20
  AND p.age < 30
RETURN 
  p
```

##### ■WHERE句での絞り込み（LIKE検索）

```
MATCH (
  p:person
) 
WHERE 
  p.name =~ '.*田'
RETURN 
  p
```

#### ORDER BY

##### ■結果をソートする

```
MATCH (
  p:person
)
RETURN 
  p.name, p.age
ORDER BY 
  p.age, p.name
```

#### UNION

##### ■複数の結果をUNIONで取得する（重複あり）

```
MATCH (
  p_murata:person{
    name:'村田'
  }
) 
RETURN
  p_murata.name AS name
  ,p_murata.age AS age 
UNION ALL 
MATCH (
  p_tamura:person{
    name:'田村'
  }
) 
RETURN
  p_tamura.name AS name
  ,p_tamura.age AS age
```

##### ■複数の結果をUNIONで取得する（重複なし）
`UNION ALL`を`UNION`に変更することで対応ができます

```
MATCH (
  p_murata:person{
    name:'村田'
  }
) 
RETURN
  p_murata.name AS name
  ,p_murata.age AS age 
UNION 
MATCH (
  p_tamura:person{
    name:'田村'
  }
) 
RETURN
  p_tamura.name AS name
  ,p_tamura.age AS age
```


### 削除関連

#### DELETE
削除関連では、検索関連と同様にMATCH句を使用します。
構文としては、`RETURN`を` DETACH DELETE`に変更することで基本的に対応できます。

##### ■全てのnodeを削除する

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

##### ■対象のラベルに含まれるnodeを削除する

```
MATCH (
  p:person
) 
DETACH DELETE
  p
```

##### ■対象のLabel,Propertyを持つnodeを削除する

```
MATCH (
  p_nakata:person{
    name:'中田'
  }
) 
DETACH DELETE
  p_nakata
```

##### ■WHERE句を使用したnode削除
LIKE検索以外にも、検索で紹介したWHERE句が同様に使用できます。

```
MATCH (
  p:person
) 
WHERE 
  p.name =~ '.*田'
DETACH DELETE
  p
```

#### REMOVE

##### ■Labelを削除する
```
MATCH (
  n { name: '村田' }
)
REMOVE 
  n:person
```

##### ■Propertyを削除する

```
MATCH (
  p_nurata:person {
    name:'村田' 
  }
)
REMOVE 
  p_nurata.age
```


### 更新関連
DELETEでは、検索・削除関連と同様にMATCH句を使用します。
構文としては、`RETURN`を`SET`に変更することで基本的に対応できます。

##### ■全てのnodeを更新する
使うことはほぼないですが、全nodeへの更新も可能です。
SETに記載したPropertyが既にあるnodeは値が更新。ないnodeは新規のPropertyが追加させれます。

```
MATCH (n) SET n.test = 'test_val'
```
RETURNを最後に記載することで、更新結果を出力できます。

```
MATCH (n) SET n.test = 'test_val' RETURN n
```

##### ■特定のnodeを更新する
下記の例以外にも検索・削除関連で紹介したコマンドが使用することが可能です。

```
MATCH (
  p:person
) 
SET
  p.group = 'RiceField'
```

##### ■NULLを使用してPropertyを削除する
`REMOVE`以外にも`SET xxx = NULL`でPropertyを削除することができます

```
MATCH (
  p_tamura:person{
    name:'田村'
  }
) 
SET
  p_tamura.age = NULL
```

全てのPropertyを削除する場合

```
MATCH (
  p_murata:person{
    name:'村田'
  }
) 
SET
  p_murata = {}
```

##### ■特定のnodeのLabelを追加する
Labelは追加されるため、既存のLabelを`Remove`で削除

```
MATCH (
  n { 
    name: '村田' 
  }
)
SET
  n:human
```

##### 特定のnodeにpropertyを追加する

```
MATCH (
  p_nakata:person{
    name:'中田'
  }
) 
SET
  p_nakata += {
    age:35
    ,from:'Okinawa'
  }
```



## Relationship

### Relationshipの種類

- 無向性
関係性に向き先がない。例えば「友達」の関係は互いに友達であるため、方向関係がないものに使用が適しています。
`('中田')-[友達]-('田中')`
ただし、<b>Neo4jでは無向性は提供されていません。</b>
そのため、下記の<b>有向性</b>を使用して記載する必要があります。
参考：[グラフの表現パターン](https://www.omotenashi-mind.com/index.php?title=Neo4j%E3%81%A7%E5%AD%A6%E3%81%B6Graph_DB%E5%85%A5%E9%96%80)

- 有向性
関係性に向き先がある。例えば「上司」であれば、片方が上司→片方は部下の立場となる
`('田村')-[上司]->('村田')`


### 作成関連

#### CREATE

##### ■対象のnode間にrelationを作成する
`RETURN xxx`を使用することで、作成したリレーションを確認できます。

```
MATCH (
  p_1:person
)
,(
  p_2:person
)
WHERE
  p_1.name = '中田'
  AND p_2.name = '田中'
CREATE 
  (p_1)-[r:Friend]->(p_2)
RETURN 
  p_1, p_2
```
`RETURN TYPE(r)`に変更するとrelationのみを確認できます。


##### ■relationの重複しない形でCREATEを行う
`CREATE`を`CREATE UNIQUE`に変更するだけで、重複を許さずに作成ができます。

```
MATCH (
  p_1:person
)
,(
  p_2:person
)
WHERE
  p_1.name = '田村'
  AND p_2.name = '村田'
CREATE UNIQUE 
  (p_1)-[:Boss]->(p_2)
RETURN
  p_1, p_2
```

##### ■nodeとrelationを同時に作成する

```
CREATE(
  :person{
    name:'町田'
    ,age:20
  }
)-[:Rival]->(
  :person{
    name:'田町'
  }
)  
```

##### ■relationにpropertyを作成する
relationにもpropertyを0~設定することができます。

```
MATCH(
  p_1:person{
    name:'森田'
  } 
)
,(
  p_2:person{
    name:'田森'
  } 
)
CREATE UNIQUE(
  (p_1)-[:Dinner{
    start_time:'13:00'
    ,end_time:'15:00'
   }]->(p_2)
)
RETURN
  p_1, p_2
```


### 検索関連

#### RETURN

##### ■すべてのnodeとrelationを表示する

```
MATCH (n) RETURN n
```

##### ■すべてのrelationをもつnodeを表示する

```
MATCH (p_1)-[]-(p_2) RETURN p_1, p_2
```

##### ■全てのrelationを表示する

```
MATCH ()-[r]-() RETURN r
```

##### ■対象のnodeを指定して表示する
両方nodeを指定する

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r]-(
  p_2:person{
    name:'中田'
  }
)
RETURN
  p_1, p_2
```

片方のnodeのみを指定する

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r]-(p_2)
RETURN
  p_1, p_2
```

relationの向きを指定して表示する

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r]->(p_2)
RETURN
  p_1, p_2
```

##### ■対象のrelationを指定して表示する

```
MATCH (p_1)-[r:Friend]->(p_2) RETURN p_1, p_2 
```

nodeも指定する

```
MATCH (
  p_1:person{
    name:'中田'
  }
)-[r:Friend]->(p_2)
RETURN
  p_1, p_2
```

##### ■起点からNnodeまでの階層を検索
田中さんの"友達"と"友達の友達"までを検索する場合

```
MATCH (
  p_1:person{
    name:'田中'
  }
)<-[r:Friend*1..2]-(p_2)
RETURN
  p_1, p_2
```

"友達の友達"のみを表示する場合

```
MATCH (
  p_1:person{
    name:'田中'
  }
)<-[r:Friend*2]-(p_2)
RETURN
  p_2
```


### 削除関連

#### DELETE

##### ■nodeを指定してrelationを削除する

```
MATCH(
  p_1:person{
    name:'森田'
  } 
)-[r:Dinner]->(
  p_2:person{
    name:'田森'
  } 
)
DELETE 
  r
```

##### ■propertyを指定してrelationを削除する

```
MATCH(
  p_1:person{
    name:'森田'
  } 
)-[r:Dinner{
    start_time:'13:00'
    ,end_time:'15:00'
}]->(
  p_2:person{
    name:'田森'
  } 
)
DELETE 
  r
```


##### ■片方のnodeのみを指定して該当するRelationを削除する
町田さんを始点にする"Rival"のrelationを全て削除することができます。

```
MATCH (
  p_1:person{
    name:'町田'
  }
)-[r:Rival]->()
DELETE
  r
```

田町さんを終点にする"Rival"のrelationを全て削除することができます。

```
MATCH (
  p_1:person{
    name:'田町'
  }
)<-[r:Rival]-()
DELETE
  r
```

##### ■relationのlabelを指定せずに削除する
nodeを全て指定する

```
MATCH(
  p_1:person{
    name:'森田'
  } 
)-[r]->(
  p_2:person{
    name:'田森'
  } 
)
DELETE 
  r
```
片方のnodeのみを指定する

```
MATCH(
  p_1:person{
    name:'森田'
  } 
)-[r]->()
DELETE 
  r

```


##### ■特定のnodeの持つrelationを全て削除する
田中さんのもつrelationを全て削除する

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r]-()
DELETE
  r
```

##### ■relationを全て削除する

```
MATCH ()-[r]-() DELETE r
```


### 更新関連

#### SET

##### ■relationのpropertyを更新する
propertyを更新する場合　※既存のpropertyは削除される

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r:Friend]-(
  p_2:person{
    name:'中田'
  }
)
SET
  r = {
    where:'Tokyo'
    ,when:'2019/1/1'
  }
RETURN
  p_1, p_2
```

propertyを追加する場合　※既存のpropertyは保持（propertyが同一のものは更新）

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r:Friend]-(
  p_2:person{
    name:'中田'
  }
)
SET
  r += {
    where:'Kanagawa'
    ,How:'Lunch'
  }
RETURN
  p_1, p_2
```

##### ■relationのlabelを変更する

```
MATCH (
  p_1:person{
    name:'田中'
  }
)-[r:Friend]-(
  p_2:person{
    name:'中田'
  }
)
SET
  r:Best_Friend
RETURN
  p_1, p_2
```


### CSV関連

#### LOAD

##### ■CSVファイルを取り込む
localにファイルを配置する場合には、`インストールディレクトリ/neo4j-community-x.x.x/import/`配下に格納する必要があります。

```インストールディレクトリ/neo4j-community-x.x.x/import/person_list.csv
田中,25,Nagoya
中田,50,Kyoto
森田,20,Osaka
田森,60,Sendai
村田,25,Tokyo
田村,40,Hakata
```
```
LOAD CSV FROM
  "file:///person_list.csv" AS line
CREATE(
  p:person {
    name:line[0]
    ,age:toInteger(line[1])
    ,from:line[2]
  }
)
RETURN
  p
```

##### ■HEADER(１行目)を利用してCSVファイルを取り込む

```インストールディレクトリ/neo4j-community-x.x.x/import/person_list_with_header.csv
Name,Age,From
田中,25,Nagoya
中田,,Kyoto
森田,20
田森,60,
村田,,Tokyo
田村,
```
```
LOAD CSV WITH HEADERS FROM
  "file:///person_list_with_header.csv" AS line
CREATE(
  p:person {
    name:line.Name
    ,age:toInteger(line.Age)
    ,from:line.From
  }
)
RETURN
  p
```

##### ■区切り文字を指定してCSVファイルを取り込む

```インストールディレクトリ/neo4j-community-x.x.x/import/person_list_delimiter.csv
田中;25;Nagoya
中田;50;Kyoto
森田;20;Osaka
田森;60;Sendai
村田;25;Tokyo
田村;40;Hakata
```
```
LOAD CSV WITH HEADERS FROM
  "file:///person_list.csv" AS line
FIELDTERMINATOR ';'
CREATE(
  p:person {
    name:line.Name
    ,age:toInteger(line.Age)
    ,from:line.From
  }
)
RETURN
  p
```

##### ■コミットする行数を指定してCSVファイルを取り込む
CSVファイルをLOADする場合は行数が多いため、コミットする行数を指定することができます。
デフォルトでは、コミットは1000行ごとに発生します。
<html>https://neo4j.com/docs/cypher-manual/current/query-tuning/using/#query-using-periodic-commit-hint</html>

```
USING PERIODIC COMMIT 5
LOAD CSV FROM
  "file:///person_list.csv" AS line
CREATE(
  p:person {
    name:line[0]
    ,age:toInteger(line[1])
    ,from:line[2]
  }
)
RETURN
  p
```



# 参考URL
初心者でもCypherがわかりやすい
[neo4j入門 Cypherクエリと使い方の具体例](https://www.deep-rain.com/programming/database/880)
[Neo4j-グラフデータベースとは](https://www.creationline.com/lab/7168)

Cypherについてまとまっており、参照しやすい
[グラフDB - Neo4j のレファレンスをまとめる](https://qiita.com/terakoya76/items/02df304394c445f5801c#merge-statement)

Neo4j公式のCypherマニュアル
[The Neo4j Cypher Manual v3.5](https://neo4j.com/docs/cypher-manual/current/)