アークスのためのNeo4j Cypher入門

# TL;DR

PSO2のギャザリングを題材にNeo4jの使い方を練習してみたので勘所を書いておく。
ざっくり言うと、素材から料理を作って、料理で素材取得などのブーストを掛けるシステム。
RDBだと辛そうだけどグラフDBなら見通し良さそうなので試した。

# Node

## 粒度

* RDBで検索の主キーに使うものは片っ端からノードにすると楽な印象。
* ノードは「ラベル」という大分類を持つので、種別ごとに整理できる。
* 今回は4種類のラベルを作った(Category, Dish, Fish, Pick)

## 種類ごとのノード作成例

* Dish (料理)

```
create (dish:Dish {name:"森林トマトのサラダ"})
create (dish:Dish {name:"森林アユのトマト煮"})
```

※Webインターフェースを使って入力する場合、createは1行ごとに実行すること。

* Category

```
create (category:Category {name:"野菜"})
create (category:Category {name:"大型"})
create (category:Category {name:"魚類"})
create (category:Category {name:"小型"})
```

* Pick (採取)

```
create (pick:Pick {name:"森林トマト"})
```

* Fish (釣り)

※ゲーム内の扱いは「採取」で採れるものと同格。採るときにタイミング判定がある程度。なので同じ感じで用意しておく。

```
create (pick:Fish {name:"森林アユ"})
```

ここまでで出来るグラフ

```
MATCH (n) RETURN n LIMIT 25
```

![make_nodes.png](https://qiita-image-store.s3.amazonaws.com/0/31245/8695551d-3460-3c9d-8bb9-23fd17c677da.png)


# Relationship

RelationshipにはPropertyを設定できる。

## 料理(Dish)と材料(Pick,Fish)

ひとまず「USE」として紐付けする。
材料ごとに使う個数を設定する。

* 材料1種類の場合

```
match (dish:Dish {name:"森林トマトのサラダ"}),(pick:Pick {name:"森林トマト"})
merge (dish)-[roles:USE{number:10}]->(pick)
return dish,pick
```

![relationship_1resource.png](https://qiita-image-store.s3.amazonaws.com/0/31245/2323778e-4947-1652-4e3e-dc4fe16b33f3.png)


* 材料2種類の場合

```
match (dish:Dish {name:"森林アユのトマト煮"}),(pick:Pick {name:"森林トマト"}),(fish:Fish {name:"森林アユ"})
merge (dish)-[roles1:USE{number:10}]->(pick)
merge (dish)-[roles2:USE{number:10}]->(fish)
return dish,pick,fish
```

relationshipの仮引数の名称さえ分ければ何個でも書ける。

![relationship_2resource.png](https://qiita-image-store.s3.amazonaws.com/0/31245/2a8f1f10-d097-e650-8b29-ff09b08645fc.png)

## 材料(Pick,Fish)と種類(Category)

* 森林トマト

「野菜」で「大型」

```
match (pick:Pick {name:"森林トマト"}),(category1:Category {name:"野菜"}),(category2:Category {name:"大型"})
merge (pick)-[belong1:BELONG]->(category1)
merge (pick)-[belong2:BELONG]->(category2)
return pick,category1,category2
```

![relationship_tomato.png](https://qiita-image-store.s3.amazonaws.com/0/31245/96d14c54-9bac-76c7-e53e-9f87a0130ffa.png)

* 森林アユ

「魚類」で「小型」

```
match (fish:Fish {name:"森林アユ"}),(category1:Category {name:"魚類"}),(category2:Category {name:"小型"})
merge (fish)-[belong1:BELONG]->(category1)
merge (fish)-[belong2:BELONG]->(category2)
return fish,category1,category2
```

![relationship_ayu.png](https://qiita-image-store.s3.amazonaws.com/0/31245/7573c1e2-83c2-6a63-2ff1-12a9290128c2.png)

# 料理(Dish)と種類(Category)

料理を食べると採取や釣りなどの材料に種類別ブーストが掛かる。
ブーストの効果時間や、追加効果をどう処理するかは未定なので今回は記載しない。でも恐らくノードにすると見やすそう。

* 森林トマトのサラダ

```
match (dish:Dish {name:"森林トマトのサラダ"}),(category:Category {name:"野菜"})
merge (dish)-[boost:BOOST]->(category)
return dish,boost
```

![relationship_boost_yasai.png](https://qiita-image-store.s3.amazonaws.com/0/31245/f25871dd-c676-12d6-2697-65b7817bfc0c.png)

* 森林アユのトマト煮

```
match (dish:Dish {name:"森林アユのトマト煮"}),(category:Category {name:"大型"})
merge (dish)-[boost:BOOST]->(category)
return dish,boost
```

![relationship_tomatoni.png](https://qiita-image-store.s3.amazonaws.com/0/31245/066743f9-318f-29f6-a982-e8202bbec18e.png)


# まとめて表示

```
MATCH ()-[r]->() RETURN r LIMIT 25
```

![summary.png](https://qiita-image-store.s3.amazonaws.com/0/31245/1d4499f3-f6b2-03df-87b5-b567887a5e78.png)

Wikiだとテーブル表現になってしまうので有機的な繋がりが見えないが、グラフDBならこんなに見やすくなる。

# 参考文献

Cypher Query Language(QL)-初級編 #neo4j https://www.creationline.com/lab/7685
PSO2ギャザリング(swiki) http://pso2.swiki.jp/index.php?%E3%82%AE%E3%83%A3%E3%82%B6%E3%83%AA%E3%83%B3%E3%82%B0#u614ae64
Relationship with Properties with Existing Nodes https://www.tutorialspoint.com/neo4j/neo4j_create_relationship_with_properties_with_existing_nodes.htm
is there a way to add multiple nodes with properties in Neo4j with Cypher https://stackoverflow.com/questions/21605388/is-there-a-way-to-add-multiple-nodes-with-properties-in-neo4j-with-cypher