基本
- ノードは括弧 () で表される。
- ラベルはコロンで表し、例えば (:Person) とします。
- ノード間の関係は2本のダッシュで記述します。 (:Person)--(:Movie)
- リレーションシップの方向は、大なり小なり記号 < または > を用いて示されます。 (:Person)-→(:Movie)
- リレーションシップのタイプは、2つのダッシュの間にある角括弧 [ と ] を使って記述されます。
- プロパティは、JSONのような構文で指定されます。
- ノードを取得したい場合には、コロンの前に値(下記の例では p) を置くことで、変数を代入することができます。
MATCH (p:Person)
- Neo4jのプロパティはキーと値のペアで、例えば {name: 'Tom Hanks'} のようになります。
// example Cypher pattern
(m:Movie {title: 'Cloud Atlas'})<-[:ACTED_IN]-(p:Person)
- dot記法 を使ってプロパティにアクセスできます
MATCH (p:Person {name: 'Tom Hanks'})
RETURN p.born
- Cypherでは、ラベル、プロパティ・キー、変数は、大文字と小文字が区別されます。
- Cypherのキーワードは、大文字と小文字が区別されません
お作法
- ラベルにはCamelCase (先頭の文字を大文字で表記)を使用して名前を付けます。
- プロパティキーと変数にcamelCase (先頭は小文字、後続する単語の先頭は大文字で表記)を使用した名前を付けます。
- Cypherキーワード(MATCH, WHERE 等)には、UPPERCASE(すべて大文字)を使用します。
- ノードのラベルは最低でも1つ、最大でも4つまでとするのがベストプラクティスです。
- Index名は ノード名_プロパティー
index
index作成
# 単体index
CREATE INDEX <インデックス名> IF NOT EXISTS FOR (n:ノード名) ON (n.プロパティー名);
# 複合indexの場合
CREATE INDEX <インデックス名> IF NOT EXISTS FOR (n:ノード名) ON (n.プロパティー名1, n.プロパティー名2, ・・・);
index削除
DROP INDEX インデックス名;
インデックス一覧の取得
show indexes
プロパティー一覧の取得方法(keys)
MATCH (p:Person)
RETURN p.name, keys(p)
グラフに存在するプロパティは何か?
一度定義したプロパティ・キーは、そのプロパティ・キーを使用するノードやリレーションシップが現在存在しない場合でも、グラフ内に残ります。
CALL db.propertyKeys()
グラフに存在するラベル一覧の取得
CALL db.labels()
リレーションの一覧
インデックスが貼れないから重い?
match (a)-[r]->(b) return distinct a.labels, type(r), b.labels
制約一覧の取得
show constraints
MERGE
Cypher の超主力キーワード
MERGE は、まずデータの存在確認を行い、存在していなければ作成し、既に存在していれば作成しない
便利だが、MERGE内で複数ノード、リレーションを作成する場合、一つでも未作成のオブジェクトがあると作成してしまう
(プライマリーキー制約があれば失敗するが、そうでなければ、同じオブジェクトが複数さくせいされてしまう。)
MERGE のカスタマイズ
ノードが作成されたときやノードが見つかったときにプロパティを設定できるように、実行時の振る舞いを指定することができる。
ON CREATE SET や ON MATCH SET 条件、あるいは SET キーワードを使って、任意の追加プロパティを設定することができます。
// 存在しなければ作成、既に存在すれば参照を返す
MERGE (p:Person {name: 'McKenna Grace'})
// ノードが作成された場合 `createdAt` プロパティーを作成
ON CREATE SET p.createdAt = datetime()
// ノードが既に存在していれば `updatedAt` プロパティーを設定
ON MATCH SET p.updatedAt = datetime()
// プロパティーの有無に関わらず `born` プロパティーを設定ト
SET p.born = 2006
RETURN p
検索
書き方色々
MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.title='The Matrix'
RETURN p.name
MATCH (p)-[:ACTED_IN]->(m)
WHERE p:Person AND m:Movie AND m.title='The Matrix'
RETURN p.name
部分一致によるフィルタリング
MATCH (p:Person)-[:ACTED_IN]->()
WHERE toLower(p.name) STARTS WITH 'michael'
RETURN p.name
リストによるフィルタリング
MATCH (p:Person)
WHERE p.born IN [1965, 1970, 1975]
RETURN p.name, p.born
INなら動くけど、=だと動かない
リレーションのプロパティーに対しては条件を指定できない?
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE 'Neo' IN r.roles AND m.title='The Matrix'
RETURN p.name, r.roles
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE 'Neo' = r.roles AND m.title='The Matrix'
RETURN p.name, r.roles
全ノード取得
MATCH (a) RETURN a
with句
購入数が2以上のノード(User、Item)、リレーション数(購入数)を抽出
MATCH (a:User)-[r:BUY]->(b:Item)
WITH a,b,count(r) as cnt
WHERE cnt >= 2
RETURN *
リレーションの情報は取れない模様(下記だヒットしない)
MATCH (a:User)-[r:BUY]->(b:Item)
WITH a,b, r, count(r) as cnt
WHERE cnt >= 2
RETURN *
Index一覧取得
show indexes
制約一覧取得
show constraints
ソート
RETURN の後に ORDER By
MATCH (n)
RETURN n.name, n.age
ORDER BY n.name
複数カラムに対して重複削除
期待通りに distinct が使える
MATCH (n:User) RETURN distinct n.sex , n.age;
ラベルの追加
MATCH (p:Person {name: 'Jane Doe'})
SET p:Developer
RETURN p
カウント
全ノードの件数
MATCH (n) RETURN count(*);
ノードの種類を特定してカウント
MATCH (u:User) RETURN count(*);
リレーションの数
MATCH ()-[r]->() RETURN count(r) as count;
ノード間を特定してカウント
MATCH (a:Company)-[r]->(b:User) RETURN count(r) as count;
リレーションを特定してカウント
MATCH ()-[r:BUY]->() RETURN count(r) as count;
ノードの種類を特定してカウント
MATCH (u:User) RETURN count(*);
削除
全削除
MATCH (n) DETACH DELETE n
オブジェクトの参照を取得してからDELETEで削除
MATCH (p:Person)
WHERE p.name = 'Jane Doe'
DELETE p
リレーションが単体で存在させる事を防ぐため、リレーションが張られているノードを削除しようとするとエラーになる
Cannot delete node<ノードID>, because it still has relationships. To delete this node, you must first delete its relationships.
ノードとリレーションの削除
DETACHを使う
MATCH (p:Person {name: 'Jane Doe'})
DETACH DELETE p
ラベルの削除
MATCH (p:Person {name: 'Jane Doe'})
REMOVE p:Developer
RETURN p
IDを指定して削除
ノードの場合
id=1のノードを削除
MATCH (n) where id(n)=1 DELETE n
リレーションの場合
id=2の BUY リレーション を削除
MATCH ()-[r:BUY]->() where id(r)=1 DELETE r
リレーション削除
ユーザ(user_id=11111)と 商品(item_id: "22222")との関係(購入)を削除
MATCH (a:User{user_id: "11111"})-[r:BUY]->(b:Item{item_id: "22222"}) DELETE r;
プロパティの削除
ノードやリレーションシップからプロパティを削除するには、 REMOVE キーワードを使用するか、プロパティを null に設定する
ノードの主キーとして使用されているプロパティも削除できるが、やってはいけない
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE p.name = 'Michael Cain' AND m.title = 'The Dark Knight'
REMOVE r.roles
RETURN p, r, m
MATCH (p:Person)
WHERE p.name = 'Gene Hackman'
SET p.born = null
RETURN p
indexの削除
DROP INDEX <index_name> IF EXISTS
ノードA-B間で重複しているリレーションを一意にする
apocで用意されている
MATCH (a:User)-[r:BUY]->(b:Item)
WITH collect(r) as cnt
WHERE size(cnt) > 1
CALL apoc.refactor.mergeRelationships(cnt) YIELD rel
RETURN COUNT(*)
DBのクローン
Neo4J Desktopの場合
DBの作成
CREATE DATABASE DB名;
DBの削除
sysytem データベースに切り替えてから実行する必要がある
DROP DATABASE DB名;
DB一覧
SHOW DATABASES;
DBを切り替える
:use <DB名>
DB停止
STOP DATABASE <DB名>
停止確認は
show databases;
から 対象DBが currentStatus=offline となっている事を確認
DB開始
start <DB名>
スキーマ確認
CALL db.schema.visualization()
dumpファイルのロード
sudo -u neo4j /usr/bin/neo4j-admin database load --overwrite-destination=false --from-path=<dumpファイルがか格納されているディレクトリへの絶対パス> <DB名> --verbose
- DBはStopしておく必要あり
- neo4j-adminへのパスが通っていれば /usr/bin/neo4j-admin -> neo4j-admin でOK(通っているはず)
- dumpファイルは <DB名>.dump になっている必要あり
- 既存の中身を差し替えたい場合は -overwrite-destination=true を指定
- DBが既にある状態で -overwrite-destination=false を指定するとエラーになる
- 4.4系で作成したDumpファイルは5.5系にエクスポートできない模様(フォーマット違うらしい)
Cypher ShellにDBを指定してログインする
ローカルのneo4jにポート 17687 でアクセスする場合
/usr/bin/cypher-shell -u <ユーザ名> -p <パスワード> -d <データベース名> -a neo4j://localhost:17687
cypherシェルからログアウト
:exit
confの場所
/etc/neo4j/neo4j.conf
登録・削除処理の途中でメモリ不足の落ちる場合は?
バッチサイズを指定して実行。parallelはTrueにすると速いが、メモリへの負担が大きい
CALL apoc.periodic.iterate(
やりたい処理
{batchSize:5000,parallel:false}
);
例)
明示的にRETURN を使ってやらないとbatchSizeが効かない模様( MATCH (n) DETACH DELETE n だけだと駄目)
CALL apoc.periodic.iterate(
"MATCH (n) RETURN n",
"DETACH DELETE n",
{batchSize:5000, parallel:False});
他で作成した dumpデータをDesktopに認識させる
windowsの場合、下記にdumpファイルを置くと認識してくれる
C:<設定による>\relate-data\projects\プロジェクトのIDっぽいフォルダ名