Neo4j ハンズオン
アジェンダ
• はじめに
• グラフDBの概要とNeo4j
• データ要素 of Neo4j
• データ操作 of Neo4j
• CSVアップロード
• ソーシャル・グラフ
• その他の話題
2
はじめに
3
自己紹介
• 名前:宮崎俊郎
• TIS株式会社生産革新本部 生産革新部 生産技術R&D室
• 最近のお仕事• 社内フレームワークの開発
• Xenlonマイグレーターの開発
4
宣伝:Xenlon~神龍 マイグレーションサービス
• 大規模レガシーシステムを短期間で安全確実にアプリケーション移行を実現
5
COBOL Java変換ツール
• 構文解析• 依存関係分析
Neo4jとの出会い
• Neo4j ≔グラフデータベースの一つ
• Xenlonマイグレーターで活用しました• 構文解析結果の格納
• 依存関係や呼び出し関係を保存・検索
• GOTO文の変換の調査• while文+その中で行先へswitchするよう変換するのが常套
• でないと、ループ構造の場合にスタックオーバーフローの恐れ
• ⇒呼び出し関係のうち、ループになるものを見つけその一群を1つのwhile文へ変換
6
グラフDBの概要とNeo4j
10
グラフとは
• 「グラフ(英: Graph)とは、ノード(頂点)群とノード間の連結関係を表すエッジ(枝)群で構成される抽象データ型、and・orその実装である具象データ型である。」(Wikipediaより)
11
ノード
ノード
エッジ
グラフデータベースとは
今回のハンズオンでは、以下とする
• 「ノード」と「エッジ」及びそれらに紐づく"プロパティ"(KV値)を扱うデータベース• Neo4jでは「ノード」をNode、「エッジ」をRelationshipと呼ぶ
12
Node
Node
Relationship
RDBでも"グラフ"を表現できるけど…
• 例えば"友人関係"のグラフをRDBのテーブルで表現できる
• ある人の友人を検索するクエリも書ける
13
personId Name
1 長友
2 平
3 三瓶
personId friendId
1 2
2 3
2 4
RDBでも"グラフ"を表現できるけど…
• ある人の友人の友人を検索する場合は?
14
personId Name
1 長友
2 平
3 三瓶
personId friendId
1 2
2 3
2 4
グラフデータベースの場合
• ある人の友人の友人を検索する場合は?
15
personId Name
1 長友
2 平
3 三瓶
personId friendId
1 2
2 3
2 4
長友
平
三瓶
データ構造の相違による性能差
16
personId Name
1 長友
2 平
3 三瓶
personId friendId
1 2
2 3
2 4
長友
平
三瓶
RDBの場合、隣接Nodeの情報を別テーブルに持つ
グラフDBは隣接Nodeの情報を直接持つ
データ量が増大した場合の性能差
17
personId Name
1 長友
2 平
3 三瓶
personId friendId
1 2
2 3
2 4
長友
平
三瓶
深さが増大した場合の性能差
• リレーショナルデータベースでの友達の検索とNeo4jでの効率的な検索の比較
18
深さ RDBMS
実行時間(秒)
Neo4j
実行時間(秒)
返されたレコード件数
2 0.016 0.01 ~2,500
3 30.267 0.168 ~110,000
4 1543.505 1.359 ~600,000
5 未完了 2.132 ~800,000
『Neo4j In Action』https://www.manning.com/books/neo4j-in-action
ネイティブ・グラフデータベース
• ある起点から関連を辿る操作(検索)に威力を発揮
19
長友
平
三瓶
起点
グラフデータベースについてさらに詳しく…
以下のスライドがおすすめです
• 「GraphDB徹底入門」〜構造や仕組み理解から使いどころ・種々のGraphDBの比較まで幅広く〜• https://www.slideshare.net/doryokujin/graphdbgraphdb
20
Neo4j - グラフデータベース
23
Neo4j - Customers
24
Neo4j - Graph Database Use Case
When Connected Data Matters Most
• Fraud Detection
• Graph-Based Search
• Network & IT Operations
• Real-Time Recommendation Engines
• Master Data Management
• Social Network
• Identity & Access Management
25
Neo4j - Graph Database Features
• ACID for Integrity
• Flexible Schema
• High-Performance Query Execution
• Cypher Query Language
• Scale and Performance
• Built-in Tooling & Visualization
• Advanced Causal Clustering
• Elastic Scalability
• In-Memory Page Cache
• Hot Backups
27
Community版で利用可能
Enterprise版で利用可能
グラフデータベースとは
今回のハンズオンでは、以下とする
• 「ノード」と「エッジ」及びそれらに紐づく"プロパティ"(KV値)を扱うデータベース• Neo4jでは「ノード」をNode、「エッジ」をRelationshipと呼ぶ
28
Node
Node
Relationship
データ要素 of Neo4j
29
Neo4jが扱うデータの例
30
:Person{name:"長友",age:31 }
:Team{name:"インテル",country:"Italy" }
:Person{name:"三瓶",age:41,job:"芸人" }
データ要素(1)- ノード
• Node ≔データレコード• Label ≔ Nodeを分類する
• プロパティ ≔データレコード内の個別データ
31
Node
Node
データ要素(1)- ノード
• Node ≔データレコード• Label ≔ Nodeを分類する
• プロパティ ≔データレコード内の個別データ
32
:Person
:Team
データ要素(1)- ノード
• Node ≔データレコード• Label ≔ Nodeを分類する
• プロパティ ≔データレコード内の個別データ
33
:Person{name:"長友",age:31 }
:Team{name:"インテル",country:Italy }
:Person{name:"三瓶",age:41,job:"芸人" }
データ要素(2)- プロパティ
• Node内の個別データ
• Key-Value値
• 同じラベルのNodeでも異なるKeyセットを持てる
34
:Person{name:"長友",age:31 }
:Team{name:"インテル",country:Italy }
:Person{name:"三瓶",age:41,job:"芸人" }
データ要素(3)-
リレーションシップ
• Relationship ≔ Node間の関係を示す• Type ≔ Relationshipを分類する
• プロパティ ≔ Relationshipへも付与できる
35
Relationship
Relationship
Relationship
データ要素(3)-
リレーションシップ
• Relationship ≔ Node間の関係を示す• Type ≔ Relationshipを分類する
• プロパティ ≔ Relationshipへも付与できる
36
:MARRIED
:KNOWS
:MEMBER_OF
データ要素(3)-
リレーションシップ
• Relationship ≔ Node間の関係を示す• Type ≔ Relationshipを分類する
• プロパティ ≔ Relationshipへも付与できる
37
:MARRIED{at:2017}
:KNOWS
:MEMBER_OF{since:2011}
:MEMBER_OF{at:[2010,2014]}
データ要素 - まとめ
• Node ≔データレコード• Label ≔ Nodeを分類する
• プロパティ ≔データレコード内の個別データ
• Relationship ≔ Node間の関係を示す• Type ≔ Relationshipを分類する
• プロパティ ≔ Relationshipへも付与できる
38
データ操作 of Neo4j
39
データ操作
• NodeとRelationshipのCRUD操作
40
Nodeの・作成・プロパティの追加/更新/削除・削除 Relationshipの
・作成(結合)・プロパティの追加/更新/削除・削除(切断)
検索
Cypher = クエリ言語
• Neo4j独自のデータ操作DSL
• "Being a declarative language, Cypher focuses on the
clarity of expressing what to retrieve from a graph,
not on how to retrieve it."
41
どのように検索するのかではなく、何を検索するかにフォーカスする
=
データ要素の表現
• Node
• Relationship
42
(:Person {name:"長友", age:31})
[:MEMBER_OF {since:2011}]
データ要素の表現
• Node
• Relationship
43
(:Person {name:"長友", age:31})
[:MEMBER_OF {since:2011}]
データ要素の表現
• Node
• Relationship
44
(:Person {name:"長友", age:31})
ラベル名
[:MEMBER_OF {since:2011}]
タイプ名
• アッパーキャメルケースによる記述が多い• Case Sensitive
• スネークケースによる記述が多い• Case Sensitive
データ要素の表現
• Node
• Relationship
45
(:Person {name:"長友", age:31})
プロパティ
[:MEMBER_OF {since:2011}]
プロパティ
• JSON形式に準じた記法
データ要素の表現 - まとめ
• Node…()で括る
• Relationship…[]で括る
46
(:Person {name:"長友", age:31})
ラベル名 プロパティ
[:MEMBER_OF {since:2011}]
タイプ名 プロパティ
パスの表現
• パス…( )-[ ]-( )
• パスの例
47
(:Person {name:"長友"})<-[:MARRIED]-(:Person {name:"平"})
プロパティ
ステートメント - CREATE
• CREATE…Nodeを作成
• 以下のクエリを実行して下さい
48
CREATE (:Person {name:"長友", age:31})
CREATE (:Person {name:"長友", age:31})CREATE (:Person {name:"平", age:32})CREATE (:Person {name:"本田", age:31})CREATE (:Person {name:"三瓶", age:41, job:"芸人"})CREATE (:Person {name:"ガリアルディーニ", age:23})CREATE (:Team {name:"インテル"})CREATE (:Team {name:"日本代表"})
1
Neo4j Browser(1)
• 今回のハンズオンでは、Cypherクエリの実行に「Neo4j Browser」を使います。
• Neo4j Browserの起動手順• Neo4jコンソールアプリケーション(Neo4jサーバ)を起動する
• http://localhost:7474へアクセス• 認証画面が表示された場合は以下を入力
• user ⇒ neo4j
• password ⇒ Neo4jインストール時に設定したパスワード
49
Neo4j Browser(2)
• Neo4j Browserの使い方は、以下を参照してください• GitHubの zackys/handson-neo4j の下の
doc/10_hands-on.md• https://github.com/zackys/handson-neo4j/blob/master/doc/10_hands-on.md
• 「Neo4j Browser(2)」に手順に従って操作して見て下さい
• ハンズオンで入力するCypherクエリは、このページからコピーして下さい。
50
ステートメント - CREATE
• CREATE…Nodeを作成
• 以下のクエリを実行して下さい
51
CREATE (:Person {name:"長友", age:31})
CREATE (:Person {name:"長友", age:31})CREATE (:Person {name:"平", age:32})CREATE (:Person {name:"本田", age:31})CREATE (:Person {name:"三瓶", age:41, job:"芸人"})CREATE (:Person {name:"ガリアルディーニ", age:23})CREATE (:Team {name:"インテル"})CREATE (:Team {name:"日本代表"})
1
クエリ実行後、お気に入りへ登録した「MATCH (n) RETURN n」を実行し、Nodeの登録を確認する
ステートメント -
MATCHとRETURN
• MATCH…パターンを指定して検索
• RETURN…検索結果を返す
52
MATCH (n) RETURN n
MATCH (n:Person) RETURN n
MATCH (n:Person) RETURN n.name, n.age, n.job
MATCH (n:Person {age:32}) RETURN n.name AS name
2
3
4
5
プロパティ値指定 戻り値に名前をつける
ステートメント - WHERE
• WHERE…検索条件を指定する(MATCHの後)
53
MATCH (n:Person)WHERE n.age = 32RETURN n.name AS name, n.age AS age
6
MATCH (n:Person)WHERE n.age > 40RETURN n.name AS name, n.age AS age
7
ステートメント - CREATE(2)
• CREATE…Relationshipを作成• NodeとRelationshipをまとめて作成
• 既存のNode間にRelationshipを作成
54
CREATE (:Person {name:"香川", age:28})-[:MEMBER_OF]->
(:Team {name:"ドルトムント"})
MATCH (x:Person {name:"長友"}),(y:Person {name:"平"})
CREATE (y)-[:MARRIED {at:2017}]->(x)
MATCHの結果を利用する
8
9
ステートメント - CREATE(2)
• CREATE…Relationshipを作成• NodeとRelationshipをまとめて作成
• 既存のNode間にRelationshipを作成
55
CREATE (:Person {name:"香川", age:28})-[:MEMBER_OF]->
(:Team {name:"ドルトムント"})
MATCH (x:Person {name:"長友"}),(y:Person {name:"平"})
CREATE (y)-[:MARRIED {at:2017}]->(x)
MATCHの結果を利用する
8
9
ステートメント - CREATE(3)
• 前ページの と合わせて以下のクエリを実行
56
MATCH (nagatomo:Person {name:"長友"}),(taira:Person {name:"平"}),(sanpei:Person {name:"三瓶"}),(honda:Person {name:"本田"}),(kagawa:Person {name:"香川"}),(gagl:Person {name:"ガリアルディーニ"}),(japan:Team {name:"日本代表"}),(intel:Team {name:"インテル"})
CREATE (taira)-[:KNOWS]->(sanpei)CREATE (nagatomo)-[:MEMBER_OF {since:2011}]->(intel)CREATE (nagatomo)-[:MEMBER_OF {at:[2010,2014]}]->(japan)CREATE (honda)-[:MEMBER_OF {at:[2010,2014]}]->(japan)CREATE (kagawa)-[:MEMBER_OF {at:[2014]}]->(japan)CREATE (gagl)-[:MEMBER_OF {since:2017}]->(intel)
10
8 9
クエリ実行後、お気に入りへ登録した「MATCH (n) RETURN n」を実行し、Relationshipの作成を確認する
ステートメント - SET
• SET…プロパティの追加・更新• 追加
• 更新
57
MATCH (n:Person {name:"香川"})SET n.from = "兵庫"
MATCH (n:Person {name:"香川"})SET n.from = "神戸"
11
12
ステートメント - REMOVE
• REMOVE…プロパティの削除
58
MATCH (n:Person {name:"香川"})REMOVE n.from
13
ステートメント - DELETE
• DELETE…NodeやRelationshipの削除• Relationshipの削除
• Nodeの削除
59
MATCH (n:Team {name:"ドルトムント"})DELETE n
MATCH (x:Person {name:"香川"})-[r]->(y:Team {name:"ドルトムント"})
DELETE r
14
15
MATCHしたRelationshipに名前をつけておく
DELETE時の注意事項
• NodeをDELETEする場合、そのNodeにつながるRelationshipは事前に削除しておく必要がある
• または、DETACH DELETEを使う• DETACH DELETEは、NodeにRelationshipが残っていても、
Relationshipを含め削除してくれる
60
MATCH (n:Person {name:"香川"})DELETE n
16
MATCH (n:Person {name:"香川"})DETACH DELETE n
17
エラー!まだ(日本代表)に属しているので、削除できない
パスをCypherで表現する(1)
【例】
61
()-[]->()
()<-[]-()
()-[]->()<-[]-()
パスをCypherで表現する(1)
【例】
62
()-[]->()
()<-[]-()
()-[]->()<-[]-()
パスをCypherで表現する(1)
【例】
63
()-[]->()
()<-[]-()
()-[]->()<-[]-()
(:Person {name:"長友"})<-[:MARRIED]-(:Person {name:"平"})
・・・「長友と結婚した平愛梨」
パスをCypherで表現する(1)
【例】
64
()-[]->()
()<-[]-()
()-[]->()<-[]-()
パスをCypherで表現する(1)
【例】
65
()-[]->()
()<-[]-()
()-[]->()<-[]-()
・・・「長友が所属するチームに所属する本田」=「長友のチームメイトの本田」
(:Person {name:"長友"})-[:MEMBER_OF]->(:Team)<-[:MEMBER_OF]-(:Person {name="本田"})
パスをCypherで表現する(2)
• パスの長さを指定
• 長さ0のパス=Nodeのみマッチ
• 向きの指定は省略可能
66
()-[:KNOWS*2]->()()-[:KNOWS*1..3]->()()-[*]->()
()-[:KNOWS*0..3]->()
()-[:KNOWS]-()
パスをCypherで表現する(3)
• ループの表現(有向)
• ループの表現(無向)
67
(s)-[:GOTO*1..]->(s)
(s)-[:KNOWS*1..]-(s)
X
WY
Z
x
wy
z
パスをCypherで表現する(4)
• xさんと同じ本とCDを買ったyさんを探す
68
MATCH (x)-[:BOUGHT]->(:Book)<-[:BOUGHT]-(y)-[:BOUGHT]->(:CD)<-[:BOUGHT]-(x)
RETURN y
MATCH (x)-[:BOUGHT]->(:Book)<-[:BOUGHT]-(y),(x)-[:BOUGHT]->(:CD)<-[:BOUGHT]-(y)
RETURN y
x
:Book
:CD
y
or
検索対象:BOUGHT :BOUGHT
:BOUGHT :BOUGHT
パスをCypherで表現する(5)
• xさんと同じ本を買ったyさんにCDをおすすめする
69
MATCH (x)-[:BOUGHT]->(:Book)<-[:BOUGHT]-(y)-[:BOUGHT]->(n:CD)<-[:BOUGHT]-(x)
RETURN n
MATCH (x)-[:BOUGHT]->(:Book)<-[:BOUGHT]-(y),(x)-[:BOUGHT]->(n:CD)<-[:BOUGHT]-(y)
RETURN n
x
:Book
:CD
y
or
:BOUGHT :BOUGHT
:BOUGHT :BOUGHT検索対象
パスを使って検索する(1)
• ⇒ MATCH句にパスを指定して検索する• 「長友の配偶者は?」
70
MATCH (:Person {name:"長友"})-[:MARRIED]-(n)RETURN n.name
18
パスを使って検索する(2)
• ⇒ MATCH句にパスを指定して検索する• 「長友のチームメイトは?」
• 「長友の日本代表のチームメイトは?」
71
MATCH (:Person {name:"長友"})-[:MEMBER_OF]->(:Team)<-[:MEMBER_OF]-(n)
RETURN n.name
MATCH (:Person {name:"長友"})-[:MEMBER_OF]->(:Team {name:"日本代表"})<-[:MEMBER_OF]-(n)
RETURN n.name
19
20
CSVアップロード
72
CSVアップロード
• 用途• RDB上のデータをインポート
• 外部データの取り込み
• など
• 今回は、後の「ソーシャル・グラフ」で使用するデータをアップロードしてみる
73
ステートメント - LOAD CSV
• LOAD CSV…CSVファイルのデータをNeo4jのワークメモリ上に読み込む• ヘッダなし
• ヘッダあり
74
LOAD CSV FROM "https://file.csv"
LOAD CSV WITH HEADERS FROM "https://file.csv"
CSVファイル
CSVファイル
CSVファイル(ヘッダなし)
• 【例】Person.csv
75
LOAD CSV FROM "https://Person.csv"
長友,31平,32三瓶,41本田,32
CSVファイル(ヘッダあり)
• 【例】Person.csv
76
LOAD CSV WITH HEADERS FROM "https://Person.csv"
name,age長友,31平,32三瓶,41本田,32
ヘッダ
ファイルについて
• ローカルディスク上のファイルでもOK
• ただし、$NEO4J_HOME/importディレクトリ直下に置く
• URIは、そこからの相対パス
• デリミタの指定も可能
77
LOAD CSV FROM "file:///social/Person.csv"
$NEO4J_HOME/import/social/Person.csv
LOAD CSV FROM "file:///social/Person.csv"FIELDTERMINATOR "\t"
タブ区切りの場合
ロードしたデータはCypherクエリで操作可能(1)
• パイプライン的に操作できる
78
LOAD CSV WITH HEADERS FROM "https://Person.csv"AS lineRETURN line
LOAD CSV WITH HEADERS FROM "https://Person.csv"AS lineRETURN line.id, line.name
ヘッダ付きでLOADした場合、データ名で参照できる(JSONデータを参照している)
1行単位で、JSON形式で返す(ヘッダありの場合)
ロードしたデータはCypherクエリで操作可能(2)
• パイプライン的に操作できる
79
LOAD CSV WITH HEADERS FROM "https://Person.csv"AS lineMATCH (n:Person {name:line.name})RETURN n.age
LOAD CSV WITH HEADERS FROM "https://Person.csv"AS lineCREATE (:Person {name:line.name, age:line.age})
グラフデータのアップロード戦略(1)
• 各NodeにはユニークなNodeIDを付与した上でCSVファイル化する• Person.csv
• Team.csv
80
id,name,age1,長友,312,平,323,三瓶,414,本田,32
RDBのテーブルデータのイメージ
id,name,age101,日本代表102,インテル
グラフデータのアップロード戦略(2)
• Relationshipは、NodeIDをもとにした関係テーブルとしてCSVファイルを作成する• MARRIED.csv
• MEMBER_OF.csv
81
from,to2,1
personId,teamId1,1011,1024,102
RDBの関係テーブルデータのイメージ
実際のアップロード(1)
• まず、すべてのNodeをアップロード
82
LOAD CSV WITH HEADERS FROM "https://Person.csv"AS lineCREATE (:Person {personId:line.id, name:line.name})
LOAD CSV WITH HEADERS FROM "https://Team.csv"AS lineCREATE (:Team {teamId:line.id, name:line.name})
実際のアップロード(2)
• その後、Node間を結ぶRelationshipを生成
83
LOAD CSV WITH HEADERS FROM "https://MEMBER_OF.csv"AS lineMATCH (x:Person {personId:line.personId}),
(y:Team {teamId:line.teamId})CREATE (x)-[:MEMBER_OF]->(y)
LOAD CSV を試す
• GitHub上のPerson.csvの内容を確認する
• https://github.com/zackys/handson-neo4j/blob/master/import/social/Person.csv
• ヘッダ付きCSVファイルのLOADと、列要素へのアクセス
• 【参考】ヘッダなしCSVファイルとして読み込んだ場合
84
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Person.csv" AS lineRETURN line
21
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Person.csv" AS lineRETURN line.id, line.name, line.age
LOAD CSV FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Person.csv" AS lineRETURN line[0], line[1], line[2]
LOAD CSV FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Person.csv" AS lineRETURN line
22
23
次章で使うデータのアップロード
• データを全削除(MATCH (n) DETACH DELETE n)してから実行
85
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Person.csv" AS lineCREATE (:Person {personId:line.id, name:line.name, age:line.age})UNIONLOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Company.csv" AS lineCREATE (:Company {companyId:line.id, name:line.name})UNIONLOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Project.csv" AS lineCREATE (:Project {projectId:line.id, name:line.name})UNIONLOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/Interest.csv" AS lineCREATE (:Interest {interestId:line.id, name:line.name})
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/WORKS_FOR.csv" AS lineMATCH (n1:Person {personId:line.personId}), (n2:Company {companyId:line.companyId})CREATE (n1)-[:WORKS_FOR]->(n2)UNIONLOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/WORKED_ON.csv" AS lineMATCH (n1:Person {personId:line.personId}), (n2:Project {projectId:line.projectId})CREATE (n1)-[:WORKED_ON]->(n2)UNIONLOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/zackys/handson-neo4j/master/import/social/INTERESTED_IN.csv" AS lineMATCH (n1:Person {personId:line.personId}), (n2:Interest {interestId:line.interestId})CREATE (n1)-[:INTERESTED_IN]->(n2)
24
25
ソーシャル・グラフ
86
サンプル・データの説明
• from O'reilly "Graph Databases"(邦訳:『グラフデータベース』)
87
サンプル・データの説明
• from O'reilly "Graph Databases"(邦訳:『グラフデータベース』)
88
:Person
サンプル・データの説明
• from O'reilly "Graph Databases"(邦訳:『グラフデータベース』)
89
:Company
:WORKS_FOR
サンプル・データの説明
• from O'reilly "Graph Databases"(邦訳:『グラフデータベース』)
90
:Project
:WORKED_ON
サンプル・データの説明
• from O'reilly "Graph Databases"(邦訳:『グラフデータベース』)
91
:Interest
:INTERESTED_IN
Warm Up
①「Benの年齢は?」
②「Benの関心事は?」
③「Benと同じプロジェクトで働く人は?」
92
:Interest
:Project
Warm Up - 解答例
①「Benの年齢は?」
②「Benの関心事は?」
③「Benと同じプロジェクトで働く人は?」
93
MATCH (n:Person {name:"Ben"}) RETURN n.name, n.age
MATCH (:Person {name:"Ben"})-[:INTERESTED_IN]->(i) RETURN i.name
MATCH (:Person {name:"Ben"})-[:WORKED_ON]->()<-[:WORKED_ON]-(coworker:Person)
RETURN coworker.name
人気のある"関心事"は?
⇒
としても、登録済みのすべての関心事が返るだけ
94
MATCH (n:Interest) RETURN n.name
人気のある"関心事"は?⇒考え方:
①パス を検索する
② "関心事"ごとにパス数を集計する
③パス数の多い関心事
= 人気の関心事
95
(関心事)<-[:INTERESTED_IN]-(:Person)
①パスの検索
• パス を検索する
• 今回は、パスの代わりに両端ノードを返す
96
(関心事)<-[:INTERESTED_IN]-(:Person)
MATCH p=(i:Interest)<--(n:Person) RETURN p
MATCH (i:Interest)<--(n:Person) RETURN i.name, n.name
1
0
集約関数 - COLLECT
• COLLECT…検索結果について集約し、集約結果を1つの配列にして返す
97
MATCH (i:Interest)<--(n:Person)RETURN i.name, n.name
MATCH (i:Interest)<--(n:Person)RETURN i.name, n.name, COLLECT(n.name)
MATCH (i:Interest)<--(n:Person)RETURN i.name, COLLECT(n.name)
1
2
3
i.nameとn.nameでgroup byされ、各部分集合に対してCOLLECTが実行される
i.nameでgroup byされ、各部分集合に対してCOLLECTが実行される
全パスが返る
集約関数 - COUNT
• COUNT…検索結果について集約し、要素数を返す
98
MATCH (i:Interest)<--(n:Person)RETURN i.name, COLLECT(n.name), COUNT(n.name)
MATCH (i:Interest)<--(n:Person)RETURN i.name, COLLECT(n.name), COUNT(i.name)
MATCH (i:Interest)<--(n:Person)RETURN i.name, COLLECT(n.name)
3
4
5
COUNT()の場合はnとiを入れ替えても結果は変わらない(後々のためiにする)
②"関心事"ごとにパス数を集計
• COUNTを使い、趣味ごとにパス数を集計
99
MATCH (i:Interest)<--(n:Person)RETURN i.name, n.name
MATCH (i:Interest)<--(n:Person)RETURN i.name, COUNT(i.name)
1
6
ORDER BY 句
• ORDER BY…検索結果をソートする
100
MATCH (i:Interest)<--(n:Person)RETURN i.name, COUNT(i.name)
MATCH (i:Interest)<--(n:Person)RETURN i.name, COUNT(i.name)
ORDER BY COUNT(i.name) DESC
MATCH (i:Interest)<--(n:Person)RETURN i.name AS intr, COUNT(i.name) AS rank
ORDER BY rank DESC
6
7
8
LIMIT 句
• LIMIT…検索結果数を制限する
101
MATCH (i:Interest)<--(n:Person)RETURN i.name AS intr, COUNT(i.name) AS rank
ORDER BY rank DESCLIMIT 3
9
MATCH (i:Interest)<--(n:Person)RETURN i.name AS intr, COUNT(i.name) AS rank
ORDER BY rank DESC
8
WITH 句を使い、クエリを整理
• WITH…中間結果を次のクエリへパイプする
102
MATCH (i:Interest)<--(n:Person)RETURN i.name AS intr, COUNT(i.name) AS rank
ORDER BY rank DESCLIMIT 3
MATCH (i:Interest)<--(n:Person)WITH i.name AS intrRETURN intr, COUNT(intr) AS rank
ORDER BY rank DESCLIMIT 3
9
10
共通の関心事を持つ同僚は?
① "Ben"と共通の関心事を持つ同僚は?
②その中で、より多く共通の関心事を持つ同僚は?(①の結果を、共通の関心事の数でランク付ける)
103
共通の関心事を持つ同僚は?
① "Ben"と共通の関心事を持つ同僚は?
②その中で、より多く共通の関心事を持つ同僚は?(①の結果を、共通の関心事の数でランク付ける)
104
MATCH (n:Person {name:"Ben"})WITH n
MATCH (n)
MATCH (n:Person {name:"Ben"})WITH n
MATCH (n)
共通の関心事を持つ同僚は?- 解答例
① "Ben"と共通の関心事を持つ同僚は?
②その中で、より多く共通の関心事を持つ同僚は?(①の結果を、共通の関心事の数でランク付ける)
105
MATCH (n:Person {name:"Ben"})WITH n
MATCH (n)-[:INTERESTED_IN]->()<-[:INTERESTED_IN]-(x),(n)-[:WORKED_ON]->()<-[:WORKED_ON]-(x)
RETURN x
MATCH (n:Person {name:"Ben"})WITH n
MATCH (n)-[:INTERESTED_IN]->(i)<-[:INTERESTED_IN]-(x),(n)-[:WORKED_ON]->(p)<-[:WORKED_ON]-(x)
WITH i.name AS intr, x.name AS nameRETURN name, COUNT(intr) AS rank, COLLECT(intr)
その他の話題
106
アプリケーションによるNeo4jのデータ操作
• 以下の言語向けにAPIが提供されている• C#
• Java
• JavaScript
• Python
• REST APIも提供
107
Javaアプリケーション
• OGM(= Object-Graph Mapping) Libraryが利用可能• like ORMapper(Object-Relational Mapper)
• OGMを使ったサンプルアプリケーション• https://github.com/zackys/handson-neo4j/tree/master/sample02
108
サンプル・アプリケーション
• メールユーザの送信記録を行う
109
ログ
Neo4j
ドメインモデルとグラフデータの対応
JavaBeans(POJO) ⇔ Node
JavaBeans間の参照 ⇔ Relationship
110
dpt
BELONG_TO
▼
from
to
1
1..* ◀ SENT TO
◀ SENT BY
UseruserIdnameaddress
EmailmailIdtitle
Dptname
113
ありがとうございました
Top Related