Neo4j tutorial 作業記録

#Windows10 に Neo4j を入れて tutorial を実行する

グラフデータベースに少し興味があったのでインストールして動かす
RDBMS の言葉を混ぜつつ自分が理解するための作業記録
私がそもそも NoSQL について初心者なので、NoSQL の概要くらいは知ってることが前提

ぶっちゃけこの方の記事を見たほうが早いですな
https://qiita.com/tikamoto/items/c3a1bba12e9b83aee42a


##インストール
Neo4j 公式サイトよりダウンロード https://neo4j.com/
Desktopではなく、Community Server(Neo4j Community Edition 3.4.9 for windows)
D:\neo4j にインストールした


##DB起動
インストールした場所の readme.txt を読むと
<pre>
1. Open a console and navigate to the install directory.
2. Start the server:
 　　Windows, use: bin\neo4j console
 　　Linux/Mac, use: ./bin/neo4j console
3. In a browser, open http://localhost:7474/
4. From any REST client or browser, open http://localhost:7474/db/data
   in order to get a REST starting point, e.g.
   curl -v http://localhost:7474/db/data
5. Shutdown the server by typing Ctrl-C in the console.
</pre>

ということなのでコマンドプロンプトで `d:\neo4j\bin\neo4j console` で起動する
起動メッセージが出るのでコマンドプロンプトはそのまま
Ctrl+C を押すとDB停止になる


##ブラウザでアクセス
readme.txt にあるようにブラウザで　`http://localhost:7474/`　にアクセス
UserName / Password は neo4j / neo4j


##ブラウザからできること
・Learn about Neo4j : Neo4j の説明
・Jump into code : 実際にデータを追加検索して後始末までを確認できる
・Monitor the system : システム情報
・一番上の入力欄で DML や DSL を入力実行するとその下に結果が表示される
(SQL に相当する Cypher という言語で Neo4j を制御する)


---
#実際に jump into code をやってみる
The Movie Graph という tutorial のシナリオは、映画を題材に監督、役者、プロデューサー等の情報をデータベースにしたもの

##テーブル作成＆データ入れ(Create)
・映画の情報作成
<pre>
CREATE (YouveGotMail:Movie {title:"You've Got Mail", released:1998, tagline:'At odds in life... in love on-line.'})
</pre>

YouveGotMail という映画用の Movie Node を作成。 title 属性 "You've Got Mail"、他に released, tagline, の属性を付加

・役者の情報の作成
<pre>
CREATE (TomH:Person {name:'Tom Hanks', born:1956})
</pre>

TomH という役者用 Person Node を作成。name 属性 に Tom Hanks, Born 属性に 1956 を付加

・映画と役者の関連付け
<pre>
CREATE (TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail)
</pre>

TomH は 'Joe Fox' 役(roles)で YouveGotMail に出演


##ただの検索(Find)
・名前が Tom Hanks のデータを表示
<pre>
MATCH (q1 {name: "Tom Hanks"}) RETURN q1
</pre>

解説：name が Tom Hanks であるデータ(この場合 Person Node にしか name 属性はない) を検索し q1 という変数に格納。q1 の値を返す

・title が "Cloud Atlas" であるデータ(この場合 Movie Node) を返せ
<pre>
MATCH (q2 {title: "Cloud Atlas"}) RETURN q2
</pre>

・Person Node から name を 10 人返せ
<pre>
MATCH (people:Person) RETURN people.name LIMIT 10
</pre>

・90年代にリリースされた映画のタイトルを表示しろ
<pre>
MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties.title
</pre>


##関連付け検索(Query)
・Tom Hanks が出演した映画を全て表示
<pre>
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies) RETURN tom,tomHanksMovies
</pre>

解説：tom:Person {name: "Tom Hanks"}でTom Hanks を限定し tom 変数に格納。tom に ACTED_IN で関連付けされた映画を tomHanksMovies に格納し、tom と tomHanksMovies を RETURN している。

・映画 Cloud Atlas の監督を全員表示
<pre>
MATCH (cloudAtlas {title: "Cloud Atlas"})<-[:DIRECTED]-(directors) RETURN directors.name
</pre>

上もそうだけど、-> や <- のところがちょっと不明。結合と解釈するとちょっと怪しいのでマニュアル参照。後で修正。Cypher の書き方がよくわからないけど、これがグラフデータベースの特徴かな。

・Tom Hanks の相手役を表示
<pre>
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name
</pre>

上と同じく関連付での表示

・Cloud Atlas に関係した人を表示(Type で属性を表示)
<pre>
MATCH (people:Person)-[relatedTo]-(:Movie {title: "Cloud Atlas"}) RETURN people.name, Type(relatedTo), relatedTo
</pre>


##経路検索(Solve)
・Kevin Bacon を中心として1階層～4階層まで関連付けていって重複削除して表示
<pre>
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)
RETURN DISTINCT hollywood
</pre>

1..4 のところの 4 を 小さくしたり大きくしたりすると関連付けの深さが変わる
1..1 なら映画が 3 つ表示されるだけ
1..2 なら映画 3 つとその関連の人が表示される
1..4 多すぎ

たぶんこっちのほうがわかりやすい
Kevin Baconが出演した映画とその関連者(3つの映画とその映画の監督や役者が出る）
<pre>
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..2]-(hollywood)
RETURN DISTINCT bacon,hollywood
</pre>

・最短経路検索 Kevin Bacon から Meg Ryan への関連付けを辿った時の最短の関連付け
<pre>
MATCH p=shortestPath(
  (bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"})
)
RETURN p
</pre>


##レコメンド(Recommend)
・Tom Hanks と仕事をしたことない人を表示
<pre>
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),
      (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cocoActors)
WHERE NOT (tom)-[:ACTED_IN]->()<-[:ACTED_IN]-(cocoActors) AND tom <> cocoActors
RETURN cocoActors.name AS Recommended, count(*) AS Strength ORDER BY Strength DESC
</pre>

・Tom Hanks と仕事をしたことがない Tom Cruise を誰が Tom Hanks に紹介したらいいかを問い合わせ
<pre>
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),
      (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cruise:Person {name:"Tom Cruise"})
RETURN tom, m, coActors, m2, cruise
</pre>


##データのお片付け(Clean Up)
・全部の node を消す前に`MATCH (n) RETURN n`で確認
・Person と Movie のノードを消す(実行したら上のコードを実行すると全部消えてることが確認できる)
<pre>MATCH (n) DETACH DELETE n</pre>


##DB停止
起動したコマンドプロンプトで Ctrl+C を押すとDBが停止する


#最後に
以上で、Getting Started みたいなものの一部が終了
---

もう一つ RDBMS から Neo4j への移行のtutorialがある
それは別の記事にしようかと思ったけど、面倒なのでこのまま

# tutorial その2 RDBMS to Neo4j
tutorial の2つ目はどうやら RDBMS から Neo4j への移行するとどうなるかを確認できるらしい
面倒なので色々端折る

##RDBMSのデータ(CSV)を読み込み Node 作成
・ネットにあるファイルをダウンロードして読み込む
<pre>LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/products.csv" AS row</pre>

これで、ネットから CSV をダウンロードしてきて変数 row に打ち込めるらしい
WITH HEADERS をつけるとそれがそのまま属性になるっぽい

・上でロードしたデータを使って Product Node の作成（ついでにデータ型の整形)
<pre>
CREATE (n:Product)
SET n = row,
  n.unitPrice = toFloat(row.unitPrice),
  n.unitsInStock = toInteger(row.unitsInStock),
　n.unitsOnOrder = toInteger(row.unitsOnOrder),
  n.reorderLevel = toInteger(row.reorderLevel),
　n.discontinued = (row.discontinued <> "0")
</pre>

整形せずに入れるだけなら `SET n = row` だけでいい

・次に進む前に入れたデータを確認してみる
<pre>MATCH(n) RETURN n</pre>

上でロードした node が全部 Relation なしで存在していることがわかる

##リレーションをはる(関連付ける)
・Category に Product を関連付ける
<pre>
MATCH (p:Product),(c:Category)
WHERE p.categoryID = c.categoryID
CREATE (p)-[:PART_OF]->(c)
</pre>

注意：you only need to compare property values like this when first creating relationships
（関連付けは上記のようなプロパティの比較だけでいい）
実行した後 `MATCH(n) RETURN n` すると Category に Product が PART_OF で関連づいているのがわかる

・Product に Supplier を関連付ける
<pre>
MATCH (p:Product),(s:Supplier)
WHERE p.supplierID = s.supplierID
CREATE (s)-[:SUPPLIES]->(p)
</pre>

実行した後 `MATCH(n) RETURN n` すると Product に Supplier が SUPPLIES で関連づいているのがわかる

##問い合わせ
・Supplier 毎に、何の製品カテゴリを扱っているかを表示
<pre>
MATCH (s:Supplier)-->(:Product)-->(c:Category)
RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories
</pre>

・Produce 業(category)をしている会社(Supplier)を表示
<pre>
MATCH (c:Category {categoryName:"Produce"})<--(:Product)<--(s:Supplier)
RETURN DISTINCT s.companyName as ProduceSuppliers
</pre>

##顧客情報と関連付けて表示
・顧客情報を読み込んで node 作成やら index 作成やら関連付けやらを実行
・製品情報と顧客情報とを絡め、顧客毎に produce 業への注文数を集計して多い順に表示
<pre>
MATCH (cust:Customer)-[:PURCHASED]->(:Order)-[o:ORDERS]->(p:Product),
      (p)-[:PART_OF]->(c:Category {categoryName:"Produce"})
RETURN DISTINCT cust.contactName as CustomerName, SUM(o.quantity) AS TotalProductsPurchased
ORDER BY TotalProductsPurchased DESC
</pre>

以上