#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 を読むと
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.
ということなのでコマンドプロンプトで 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)
・映画の情報作成
CREATE (YouveGotMail:Movie {title:"You've Got Mail", released:1998, tagline:'At odds in life... in love on-line.'})
YouveGotMail という映画用の Movie Node を作成。 title 属性 "You've Got Mail"、他に released, tagline, の属性を付加
・役者の情報の作成
CREATE (TomH:Person {name:'Tom Hanks', born:1956})
TomH という役者用 Person Node を作成。name 属性 に Tom Hanks, Born 属性に 1956 を付加
・映画と役者の関連付け
CREATE (TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail)
TomH は 'Joe Fox' 役(roles)で YouveGotMail に出演
##ただの検索(Find)
・名前が Tom Hanks のデータを表示
MATCH (q1 {name: "Tom Hanks"}) RETURN q1
解説:name が Tom Hanks であるデータ(この場合 Person Node にしか name 属性はない) を検索し q1 という変数に格納。q1 の値を返す
・title が "Cloud Atlas" であるデータ(この場合 Movie Node) を返せ
MATCH (q2 {title: "Cloud Atlas"}) RETURN q2
・Person Node から name を 10 人返せ
MATCH (people:Person) RETURN people.name LIMIT 10
・90年代にリリースされた映画のタイトルを表示しろ
MATCH (nineties:Movie) WHERE nineties.released >= 1990 AND nineties.released < 2000 RETURN nineties.title
##関連付け検索(Query)
・Tom Hanks が出演した映画を全て表示
MATCH (tom:Person {name: "Tom Hanks"})-[:ACTED_IN]->(tomHanksMovies) RETURN tom,tomHanksMovies
解説:tom:Person {name: "Tom Hanks"}でTom Hanks を限定し tom 変数に格納。tom に ACTED_IN で関連付けされた映画を tomHanksMovies に格納し、tom と tomHanksMovies を RETURN している。
・映画 Cloud Atlas の監督を全員表示
MATCH (cloudAtlas {title: "Cloud Atlas"})<-[:DIRECTED]-(directors) RETURN directors.name
上もそうだけど、-> や <- のところがちょっと不明。結合と解釈するとちょっと怪しいのでマニュアル参照。後で修正。Cypher の書き方がよくわからないけど、これがグラフデータベースの特徴かな。
・Tom Hanks の相手役を表示
MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors) RETURN coActors.name
上と同じく関連付での表示
・Cloud Atlas に関係した人を表示(Type で属性を表示)
MATCH (people:Person)-[relatedTo]-(:Movie {title: "Cloud Atlas"}) RETURN people.name, Type(relatedTo), relatedTo
##経路検索(Solve)
・Kevin Bacon を中心として1階層~4階層まで関連付けていって重複削除して表示
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..4]-(hollywood)
RETURN DISTINCT hollywood
1..4 のところの 4 を 小さくしたり大きくしたりすると関連付けの深さが変わる
1..1 なら映画が 3 つ表示されるだけ
1..2 なら映画 3 つとその関連の人が表示される
1..4 多すぎ
たぶんこっちのほうがわかりやすい
Kevin Baconが出演した映画とその関連者(3つの映画とその映画の監督や役者が出る)
MATCH (bacon:Person {name:"Kevin Bacon"})-[*1..2]-(hollywood)
RETURN DISTINCT bacon,hollywood
・最短経路検索 Kevin Bacon から Meg Ryan への関連付けを辿った時の最短の関連付け
MATCH p=shortestPath(
(bacon:Person {name:"Kevin Bacon"})-[*]-(meg:Person {name:"Meg Ryan"})
)
RETURN p
##レコメンド(Recommend)
・Tom Hanks と仕事をしたことない人を表示
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
・Tom Hanks と仕事をしたことがない Tom Cruise を誰が Tom Hanks に紹介したらいいかを問い合わせ
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
##データのお片付け(Clean Up)
・全部の node を消す前にMATCH (n) RETURN n
で確認
・Person と Movie のノードを消す(実行したら上のコードを実行すると全部消えてることが確認できる)
MATCH (n) DETACH DELETE n
##DB停止
起動したコマンドプロンプトで Ctrl+C を押すとDBが停止する
#最後に
以上で、Getting Started みたいなものの一部が終了
もう一つ RDBMS から Neo4j への移行のtutorialがある
それは別の記事にしようかと思ったけど、面倒なのでこのまま
tutorial その2 RDBMS to Neo4j
tutorial の2つ目はどうやら RDBMS から Neo4j への移行するとどうなるかを確認できるらしい
面倒なので色々端折る
##RDBMSのデータ(CSV)を読み込み Node 作成
・ネットにあるファイルをダウンロードして読み込む
LOAD CSV WITH HEADERS FROM "http://data.neo4j.com/northwind/products.csv" AS row
これで、ネットから CSV をダウンロードしてきて変数 row に打ち込めるらしい
WITH HEADERS をつけるとそれがそのまま属性になるっぽい
・上でロードしたデータを使って Product Node の作成(ついでにデータ型の整形)
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")
整形せずに入れるだけなら SET n = row
だけでいい
・次に進む前に入れたデータを確認してみる
MATCH(n) RETURN n
上でロードした node が全部 Relation なしで存在していることがわかる
##リレーションをはる(関連付ける)
・Category に Product を関連付ける
MATCH (p:Product),(c:Category)
WHERE p.categoryID = c.categoryID
CREATE (p)-[:PART_OF]->(c)
注意:you only need to compare property values like this when first creating relationships
(関連付けは上記のようなプロパティの比較だけでいい)
実行した後 MATCH(n) RETURN n
すると Category に Product が PART_OF で関連づいているのがわかる
・Product に Supplier を関連付ける
MATCH (p:Product),(s:Supplier)
WHERE p.supplierID = s.supplierID
CREATE (s)-[:SUPPLIES]->(p)
実行した後 MATCH(n) RETURN n
すると Product に Supplier が SUPPLIES で関連づいているのがわかる
##問い合わせ
・Supplier 毎に、何の製品カテゴリを扱っているかを表示
MATCH (s:Supplier)-->(:Product)-->(c:Category)
RETURN s.companyName as Company, collect(distinct c.categoryName) as Categories
・Produce 業(category)をしている会社(Supplier)を表示
MATCH (c:Category {categoryName:"Produce"})<--(:Product)<--(s:Supplier)
RETURN DISTINCT s.companyName as ProduceSuppliers
##顧客情報と関連付けて表示
・顧客情報を読み込んで node 作成やら index 作成やら関連付けやらを実行
・製品情報と顧客情報とを絡め、顧客毎に produce 業への注文数を集計して多い順に表示
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
以上