neo4j 実例で学ぶCypher -2-
はじめに前提的なこと
サンプルデータの用意
データ構造
データ構造
CSVにすると
category.csv
category_id:ID,name,:LABEL
cate1,カテゴリ1,category
shops.csv
shop_id:ID,name,category_id,:LABEL
shop1,ショップA,cate1,shop
shop2,ショップB,cate1,shop
items.csv
tem_id:ID,name,shop_id,:LABEL
item1,商品A,shop1,item
item2,商品B,shop1,item
item3,商品C,shop2,item
item4,商品D,shop2,item
item5,商品E,shop2,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
users.csv
user_id:ID,name,email,age:int,industry,gender,:LABEL
user1,user_name1,[email protected],37,サービス業,male,user
user2,user_name2,[email protected],17,ネットサービス,male,user
user3,user_name3,[email protected],27,公務員,female,user
user4,user_name4,[email protected],44,公務員,male,user
user5,user_name5,[email protected],55,公務員,male,user
owner.csv
owner_id:ID,name,:LABEL
owner1,owner1,owner
owner2,owner2,owner
サンプルデータの投入
➜ neo4j neo4j-import --into /usr/local/Cellar/neo4j/2.3.2/libexec/data/graph9.db --nodes category.csv --nodes items.csv --nodes orders.csv --nodes shops.csv --nodes users.csv --nodes owner.csv
Unable to find any JVMs matching version "1.7".
Importing the contents of these files into /usr/local/Cellar/neo4j/2.3.2/libexec/data/graph9.db:
Nodes:
/Users/a12091/neo4j/category.csv
/Users/a12091/neo4j/items.csv
/Users/a12091/neo4j/orders.csv
/Users/a12091/neo4j/shops.csv
/Users/a12091/neo4j/users.csv
/Users/a12091/neo4j/owner.csv
Available memory:
Free machine memory: 18.05 MB
Max heap memory : 1.78 GB
Nodes
[*>:??-------------------------------------------------------------------------------------|P||] 10k
Done in 594ms
Prepare node index
[*DETECT:7.63 MB-------------------------------------------------------------------------------] 0
Done in 24ms
Calculate dense nodes
[*>:??-----------------------------------------------------------------------------------------] 0
Done in 12ms
Relationships
[*>:??-----------------------------------------------------------------------------------------] 0
Done in 10ms
Node --> Relationship
[*>:??------------------------------------------|LINK-------------------|v:??------------------] 10k
Done in 11ms
Relationship --> Relationship
[*>:??-----------------------------------------------------------------------------------------] 0
Done in 12ms
Node counts
[*COUNT:76.29 MB-------------------------------------------------------------------------------] 10k
Done in 133ms
Relationship counts
[*>:??-----------------------------------------------------------------------------------------] 0
Done in 1ms
IMPORT DONE in 2s 345ms. Imported:
19 nodes
0 relationships
85 properties
リレーションをはる
buy
- 注文とuserを紐付ける
MATCH (o:order),(u:user)
WHERE o.user_id = u.user_id
CREATE (u)-[:BUY]->(o);
order
- 注文データと商品を紐付ける
MATCH (o:order),(i:item)
WHERE o.item_id = i.item_id
CREATE (o)-[:ORDER]->(i);
part of
- 商品とショップを紐付ける
MATCH (s:shop),(i:item)
WHERE s.shop_id = i.shop_id
CREATE (i)-[:PART]->(s);
categorize
- ショップとカテゴリーを紐付ける
MATCH (c:category),(s:shop)
WHERE c.category_id = s.category_id
CREATE (s)-[:CATE]->(c);
frend
- ショップオーナーと友人ユーザを紐付ける
MATCH (ow:owner),(u:user)
WHERE ow.owner_id = "owner1" AND u.user_id = "user1"
CREATE (ow)-[:FREND]->(u);
MATCH (ow:owner),(u:user)
WHERE ow.owner_id = "owner1" AND u.user_id = "user2"
CREATE (ow)-[:FREND]->(u);
recommend
- ショップオーナーのおすすめ商品を紐付け
MATCH (ow:owner),(i:item)
WHERE ow.owner_id = "owner1" AND i.item_id = "item1"
CREATE (ow)-[:RECCOMEND]->(i);
favorite
- ユーザとお気に入り商品を紐付ける
MATCH (u:user),(i:item)
WHERE u.user_id = "user3" AND i.item_id = "item2"
CREATE (u)-[:FAVORITE]->(i);
MATCH (u:user),(i:item)
WHERE u.user_id = "user3" AND i.item_id = "item3"
CREATE (u)-[:FAVORITE]->(i);
MATCH (u:user),(i:item)
WHERE u.user_id = "user4" AND i.item_id = "item2"
CREATE (u)-[:FAVORITE]->(i);
MATCH (u:user),(i:item)
WHERE u.user_id = "user4" AND i.item_id = "item4"
CREATE (u)-[:FAVORITE]->(i);
MATCH (u:user),(i:item)
WHERE u.user_id = "user5" AND i.item_id = "item5"
CREATE (u)-[:FAVORITE]->(i);
owner
- ショップオーナーとショップを紐付ける
MATCH (ow:owner),(s:shop)
WHERE ow.owner_id = "owner1" AND s.shop_id = "shop1"
CREATE (ow)-[:OWMER]->(s);
MATCH (ow:owner),(s:shop)
WHERE ow.owner_id = "owner2" AND s.shop_id = "shop2"
CREATE (ow)-[:OWMER]->(s);
抽出したいデータ(ここからがメイン)
1:内訳としてショップAの購入者でオーナーの知人とそうでない人はどのくらいのか
サンプルデータから自分でデータを追うと
- user1とuser2の2名が知人でuser3は知人ではない人からの購入
-
:FREND
というリレーションが貼られてるのはuser1とuser3のみ
- なので知人が2でその他は1となる
Cypherで書いてみる
neo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)-->(shop {name:"ショップA"})<--(ow:owner)-[:FREND]->(user)
> RETURN count(DISTINCT user) as frend_of_owner , count(DISTINCT u) - count(DISTINCT user) as other
> ;
+------------------------+
| frend_of_owner | other |
+------------------------+
| 2 | 1 |
+------------------------+
- 知人が2でその他は1となり一致
2:favorite(お気に入り)が多い商品は
サンプルデータから表にまとめてみると
:FREND
というリレーションが貼られてるのはuser1とuser3のみneo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)-->(shop {name:"ショップA"})<--(ow:owner)-[:FREND]->(user)
> RETURN count(DISTINCT user) as frend_of_owner , count(DISTINCT u) - count(DISTINCT user) as other
> ;
+------------------------+
| frend_of_owner | other |
+------------------------+
| 2 | 1 |
+------------------------+
user | favorite item |
---|---|
user3 | 商品B |
user3 | 商品C |
user4 | 商品B |
user4 | 商品D |
user5 | 商品E |
- 商品Bがuser3とuser4からお気に入り登録されているので2ユーザがfavorite
- 商品Cがuser3からお気に入り登録されているので1ユーザがfavorite
- 商品Dがuser4からお気に入り登録されているので1ユーザがfavorite
- 商品Eがuser5からお気に入り登録されているので1ユーザがfavorite
が答え
Cypherで書いてみる
neo4j-sh (?)$ MATCH (u:user)-[:FAVORITE]->(i:item)
> RETURN i.name,count(*)
> ;
+-------------------+
| i.name | count(*) |
+-------------------+
| "商品E" | 1 |
| "商品B" | 2 |
| "商品D" | 1 |
| "商品C" | 1 |
+-------------------+
4 rows
37 ms
-
count(*)
はユーザ数を表す - それぞれ一致
3:商品をfavorite(お気に入り)をして該当の商品を購入したユーザ数は?
サンプルデータから表にまとめてみると
商品 | favorite | 購入したか | 購入user |
---|---|---|---|
商品A | x | ○ | user1 |
商品A | x | ○ | user2 |
商品B | ○ | ○ | user3 |
商品B | ○ | x | user4 |
商品C | ○ | x | user3 |
商品C | x | ○ | user4 |
商品D | ○ | x | user4 |
商品E | ○ | x | user5 |
-
favorite=○
で且つ購入したか=○
を探す - user3だけが商品Bをfavoriteして購入しているので1ユーザが答え
ビジュアライズしてみる
Cypherで書いてみる パターン1
neo4j-sh (?)$ MATCH (u:user)-[:FAVORITE]->(i:item)<--(o:order)<--(u:user)
> RETURN count(*);
+----------+
| count(*) |
+----------+
| 1 |
+----------+
Cypherで書いてみる パターン2
neo4j-sh (?)$ MATCH (u:user)-[:FAVORITE]->(i:item),(u:user)-->(o:order)-->(i:item)
> RETURN COUNT(*);
+----------+
| COUNT(*) |
+----------+
| 1 |
+----------+
1 row
82 ms
Cypherで書いてみる パターン3
neo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)
> WHERE u-[:FAVORITE]->i
> RETURN count(*);
+----------+
| count(*) |
+----------+
| 1 |
+----------+
1 row
109 ms
-
count(*)
はユーザ数を表す - 1ユーザとなり一致。色々と書き方がある
4:商品をfavoite(お気に入り)をしてないけど購入したユーザ数は?
サンプルデータから表にまとめてみると
商品 | favorite | 購入したか | 購入user |
---|---|---|---|
商品A | x | ○ | user1 |
商品A | x | ○ | user2 |
商品B | ○ | ○ | user3 |
商品B | ○ | x | user4 |
商品C | ○ | x | user3 |
商品C | x | ○ | user4 |
商品D | ○ | x | user4 |
商品E | ○ | x | user5 |
-
購入したか=○
で且つfavorite=x
を探す - ユーザはuser1,user2,user4はfavoriteしていなが購入しているので3ユーザが答え
ビジュアライズしてみる
Cypherで書いてみる
neo4j-sh (?)$ MATCH (u:user)-->(o:order)-->(i:item)
> WHERE NOT u-[:FAVORITE]->i
> RETURN count(*)
> ;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row
81 ms
-
count(*)
はユーザ数を表す - 3ユーザとなり一致
5:商品をfavorite(お気に入り)をしたが該当の商品を買わなかったユーザ数は?
サンプルデータから表にまとめてみると
商品 | favorite | 購入したか | 購入user |
---|---|---|---|
商品A | x | ○ | user1 |
商品A | x | ○ | user2 |
商品B | ○ | ○ | user3 |
商品B | ○ | x | user4 |
商品C | ○ | x | user3 |
商品C | x | ○ | user4 |
商品D | ○ | x | user4 |
商品E | ○ | x | user5 |
-
favorite=○
で且つ購入したか=x
を探す - favorite(お気に入り)をしたが、購入していないユニークユーザはuser3,user4,user5で3ユーザが答え
ビジュアライズしてみる
- 注意)商品Bはuser3からfavoriteされ、購入しているが、user4からfavoriteされて購入されていない
Cypherで書いてみる
neo4j-sh (?)$ MATCH (u:user)-[:FAVORITE]->(i:item),(o:order)
> WHERE NOT o<--u
> RETURN count(DISTINCT u);
+-------------------+
| count(DISTINCT u) |
+-------------------+
| 3 |
+-------------------+
1 row
89 ms
-
count(*)
はユーザ数を表す - 3ユーザとなり一致
まとめ、雑感的なもの
- ちょっと複雑めにリレーションを張って色々な条件で抽出してみたが、まぁなんとなくできた
- Webインターフェースがあったおかげで理解がスムーズだった
- チュートリアルもわかりやすかった
- グラフDBを使うことで割と欲しい集計データが簡単に抽出できるとわかった
- プロダクジョンではmysqlを使ってて、どういう方法、タイミングでneo4jへ連携する部分でまだ考えなきゃいけないなぁと感じた
- 夜間バッチかなぁ。。。毎晩夜間バッチでslaveのmysqlのデータをneo4jへ突っ込む的な
- Cypherでサブクエリ的なものが使えないっぽいのでリレーションが重要だと感じた
- Cypherには
EXPLAIN
,PROFILE
があるので自分のQLの計測が出来る。プロダクジョンとかの大量のデータを扱う際に必要になってくるだろうな
- スケールに関するものも一通りあるっぽいなぁ http://neo4j.com/docs/stable/ha.html
- 可能性はいろいろあるね
- ただ負荷に対するノウハウ等が少ないのでいきなりユーザが使うサービスには使うのは怖いかな
- 社内的な分析にまずは使ってみるが良いんじゃないかなと
- チュートリアルもわかりやすかった
- 夜間バッチかなぁ。。。毎晩夜間バッチでslaveのmysqlのデータをneo4jへ突っ込む的な
EXPLAIN
,PROFILE
があるので自分のQLの計測が出来る。プロダクジョンとかの大量のデータを扱う際に必要になってくるだろうな- ただ負荷に対するノウハウ等が少ないのでいきなりユーザが使うサービスには使うのは怖いかな
- 社内的な分析にまずは使ってみるが良いんじゃないかなと
Author And Source
この問題について(neo4j 実例で学ぶCypher -2-), 我々は、より多くの情報をここで見つけました https://qiita.com/nakamura-tsuyoshi/items/5ae38b04373a224d9a34著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .