neo4j 実例で学ぶCypher -1-

# はじめに前提的なこと
* 楽天のような店子をたくさん持つプラットフォーマーの立場で考えます
* たくさんのユーザが色々なショップで色々な商品を購入し、その購入履歴データを保持している
* [前回](http://qiita.com/nakamura-tsuyoshi/items/d284ad1eb7ca848d5d79)から引き続きです

# サンプルデータ
## データ構造は下記
![graph.png](https://qiita-image-store.s3.amazonaws.com/0/106937/20f31aeb-d47f-1d5c-d485-99b2b2c47f9a.png)

## CSVとしては下記

```category.csv
category_id:ID,name,:LABEL
cate1,カテゴリ1,category
cate2,カテゴリ2,category
```

```shops.csv
shop_id:ID,name,category_id,:LABEL
shop1,ショップA,cate1,shop
shop2,ショップB,cate1,shop
shop3,ショップC,cate2,shop
```

```item.csv
item_id:ID,name,shop_id,:LABEL
item1,商品A,shop1,item
item2,商品B,shop1,item
item3,商品C,shop2,item
item4,商品D,shop3,item
item5,商品E,shop3,item
```

```orders.csv
order_id:ID,date,user_id,shop_id,category_id,price,item_id,:LABEL
order1,2016-04-02,user1,shop1,cate1,9500,item1,order
order2,2016-04-03,user2,shop1,cate1,1000,item1,order
order3,2016-04-04,user3,shop1,cate1,1200,item2,order
order4,2016-04-05,user4,shop2,cate1,15000,item3,order
order5,2016-03-22,user1,shop3,cate2,2000,item4,order
order6,2016-02-11,user2,shop3,cate2,4000,item4,order
order7,2016-03-25,user1,shop3,cate2,5000,item5,order
```

```users.csv
user_id:ID,name,email,age:int,industry,gender,:LABEL
user1,user_name1,1@example.com,37,サービス業,male,user
user2,user_name2,2@example.com,17,ネットサービス,male,user
user3,user_name3,3@example.com,27,公務員,female,user
user4,user_name4,4@example.com,44,公務員,male,user
```
## データ投入は
こんな感じで

```
neo4j-import --into /usr/local/Cellar/neo4j/2.3.2/libexec/data/graph5.db --nodes category.csv --nodes items.csv --nodes orders.csv --nodes shops.csv --nodes users.csv
```

## リレーション

### ユーザと購入を紐付け
```
MATCH (o:order),(u:user) 
WHERE o.user_id = u.user_id 
CREATE (u)-[:BUY]->(o);
```

### 購入データと商品を紐付け
```
MATCH (o:order),(i:item) 
WHERE o.item_id = i.item_id 
CREATE (o)-[:ORDER]->(i);
```

### お店と商品を紐付け
```
MATCH (s:shop),(i:item)
WHERE s.shop_id = i.shop_id
CREATE (i)-[:PART]->(s);
```

### お店とお店のジャンルを紐付け
```
MATCH (c:category),(s:shop)
WHERE c.category_id = s.category_id
CREATE (s)-[:CATE]->(c);
```

# 抽出したいデータからCypherを考える
## 購入確率の高いユーザを抽出する
* 過去の購入履歴から電化製品カテゴリのショップで購入したことのあるユーザを電化製品好きのユーザとする
* 新しい電化製品の販売が始まってが、まだ購入していない電化製品好きのユーザを抽出する

### サンプルデータから正解を考える
* まず`カテゴリ1`を電化製品を扱ってるショップのカテゴリとする
* 新しい電化製品の販売が始まったお店を`ショップA`とする
* `ショップA`の購入データは無いが、`カテゴリ1`=電化製品カテゴリに分類されるお店での購入履歴のあるユーザを抽出すれば良い
* 図からたどると`user4`が抽出されれば正解


### Cypherで書き正解を出す
```
neo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)-->(s:shop)-->(c:category)
> WHERE  NOT s.name="ショップA" AND c.name="カテゴリ1"
> RETURN u.name;
+--------------+
| u.name       |
+--------------+
| "user_name4" |
+--------------+
```
* 回答が一致


## 購入者の内訳で男女べつにどのくらいの割合かを知りたい
* ショップAに絞って考える

### サンプルデータから正解を考える
* ショップAで購入しているユーザはuser1,user2,user3
* user1はmale,user2はmale,user3はfemale
* なのでmale:2,female:1となる

### Cypherで書き正解を出す
* `UNION ALL`で続けて出してしまう

```
neo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)-->(s:shop)-->(c:category)
> WHERE s.name="ショップA" AND u.gender='male'
> RETURN count(u)
> UNION ALL
> MATCH (u:user)-->(o:order)-->(i:item)-->(s:shop)-->(c:category)
> WHERE s.name="ショップA" AND u.gender='female'
> RETURN count(u)
> ;
+----------+
| count(u) |
+----------+
| 2        |
| 1        |
+----------+
2 rows
21 ms
```
* 回答が一致


## 購入者の内訳で誰が何個購入しているのかを知りたい
* ショップCに絞って考える

### サンプルデータから正解を考える
* ショップAで購入しているユーザはuser1,user2
* user1は商品Dと商品Eを購入
* user2は商品Dを購入
* なのでuser1は２回購入、user2は1回購入となる

### Cypherで書き正解を出す
```
neo4j-sh (?)$ MATCH (u:user)-->(o:order)--(i:item)-->(s:shop)
> WHERE s.name="ショップC"
> RETURN u.name, count(o) as order_cnt;
+--------------------------+
| u.name       | order_cnt |
+--------------------------+
| "user_name1" | 2         |
| "user_name2" | 1         |
+--------------------------+
2 rows
```
* 回答が一致



# まとめ、雑感
* relationshipをもっと貼ってみてCypher考えた方が良さそう
 * relationshipの貼り方次第的な感覚も出てきた
* SQL書くより簡単なのは確か