この記事ではグラフデータベースのNeoj4を操作するための基本的なCypherクエリについて学習していきます。Cypherとはグラフデータベースに対する問い合わせ言語で、Noej4社によって開発されたものです。Cypherに限らずデータベースへの基本操作はCRUDと呼ばれ、データベースへの操作クエリ(問い合わせ)の頭文字をとったものです。
- Create(新規作成)
- Read(読み取り)
- Update(更新)
- Delete(削除)
本記事はAWSのEC2インスタンスにNeo4jがインストールされていてブラウザから管理画面にアクセスできることを前提として解説していきます。インストールがまだの方は「EC2インスタンスにNeo4jをインストールする」の学習を終えてからこちらの記事に戻ってきてください。
基本操作のCRUD
ノード指定の構文
Cypherクエリで使用するノードの指定は以下のフォーマットになります。
(識別子:ラベル名 {プロパティーキー:値, ...})
識別子とは同じクエリ内で該当するノードを表す別名(エイリアス)になります。識別子は任意の文字、名前を付けることができます。
ノードのラベル名は頭文字は大文字にすることが慣例となっています。また、リレーション名は全体を大文字でワード間はアンダースコア(_)で繋ぐのが慣例となっています。
MERGE/CREATE
MERGE文、またはCREATE文ではデータの作成を行います。データの作成時、Neo4jのノードデータには自動的に一意のIDが割り振られます。CREATE文は全く同じデータであってもID違いの重複データが作成されます。MERGE文は既存データがなければ作成、あれば上書き更新を行います。ただし、ノード内に指定されるプロパティーが同じである必要があります。MERGE/CREATEは一意のデータのみの更新なので複数データの更新には後述のMATCH-SET構文を使用する必要があります。
下記のCREATEの例では、2回実行するとuser_id=1のデータが2つ作成されます。ただし、Neo4jから自動採番されるノードIDは異なります。後述のユニーク制約をuser_idに付与することで同じuser_idのデータは作成できなくすることが可能になります。
【CREATEの例】
CREATE (u:User {user_id: 1})
SET u.name = 'Mike'
, u.age = 19
, u.favorite_fruits = ['banana', 'apple']
RETURN u
以下のMERGEの例ではCREATEで作成されたデータがなければ新規にデータが作成され、既にCREATEで作成されたuser_id=1のデータがあれば上書き更新します。ここではデータ内容は全く同じなので変化はありませんが、ノードは新規には作成されません。
【MERGEの例】
MERGE (u:User {user_id: 1})
SET u.name = 'Sally'
, u.age = 20
, u.favorite_fruits = ['orange', 'melon']
RETURN u
以下のMERGEではuser_id=1はそのままで、SET句で指定しているプロパティーの値をそれぞれ変えてみます。データが更新されたのがわかります。
MERGE (u:User {user_id: 1})
SET u.name = 'Sally'
, u.age = 20
, u.favorite_fruits = ['orange', 'melon']
RETURN u
以下のMERGEではノード内のプロパティーに hair: ‘red’ を追加してみます。それ以外は同じままにしておきます。user_id=1であるのに別のデータが作成されてしまったことが分かります。
MERGE (u:User {user_id: 1, hair: 'red'})
SET u.name = 'Sally'
, u.age = 20
, u.favorite_fruits = ['orange', 'melon']
RETURN u
この挙動は後述する一意制約をつけておくことで制御することができます。MERGE文のノード内のプロパティーの追加がある場合はデータ作成にエラーを発生させて (u:User {user_id: 1}) のノードとプロパティーのみの場合にデータの更新ができるように強制することができます。
ベストプラクティスとして、特別な理由がない場合はCREATEよりMERGEを使用するようにしましょう。
MERGEでの上書き作成を試す場合は後述の一意制約を作成してください。
MATCH
MATCH文では条件にマッチするデータの取得を行います。データのフィルタリングを行って最後にRETURN文でデータを返します。
【全データ取得(ノードのラベルに関係なく全ノードを取得する場合)】
MATCH (n)
RETURN n
【Userラベルの付いた全ノードの特定のプロパティーのみを取得する場合】
MATCH (n:User)
RETURN n.user_id, n.name
【取得条件を追加する場合】
MATCH (n:User)
WHERE n.hair = 'red'
RETURN n
リレーションの作成
ノードが作成できるようになったので、今度はノード間のリレーションを作成してみましょう。
【ノードを作成】
MERGE (p:Person {name: 'Mike'})
MERGE (m:Movie {title: 'Titanic'})
【作成したノードを選択して関連付けを作成】
MATCH (p:Person {name: 'Mike'}), (m:Movie {title:'Titanic'})
MERGE (p)-[:WATCHED_EXCITEDLY]->(m)
RETURN p,m
MATCH – (DETACH) DELETE
ノードとリレーションの作成ができるようになったので、今度はそれらを削除する方法を確認しましょう。
リレーションのついていないノードはMATCH-DELETE構文で選択したデータを削除することができます。
MATCH (n:User)
WHERE n.hair = 'red'
DELETE n
リレーションが付いているノードはノードだけを消すことはできません。リレーションの削除とノードの削除を同時に行う必要があります。DELETEの前にDETACHが付いていることに注意してください。
MATCH (m:Movie)
WHERE m.title = 'Titanic'
DETACH DELETE m
MATCH – SET
MATCH – SET構文でデータの更新を行います。WHERE句が使えるので条件にマッチしたデータの更新を行う事ができます。以下の例では新規のプロパティーを追加しています。
MATCH (p:Person)
WHERE p.name = 'Mike'
SET p.age = 22
RETURN p.name, p.age
データの更新はMERGEの上書き更新とこのMATCH-SET構文の2つの方法があります。
特に更新・削除のクエリを書く際は、WHERE句を忘れないようにしてください。全データの更新・削除が行われてしまいますので、十分注意しましょう。
制約の作成
ユニーク制約
ユニーク制約をつけることでMERGE文による一意のデータの更新が正確にできるようになります。
【設定されている制約の確認】
SHOW CONSTRAINTS
【ユニーク制約の作成】
CREATE CONSTRAINT ConstraintUniqueUserUserId FOR (n:User) REQUIRE n.user_id IS UNIQUE
【ユニーク制約が作成されたことを確認】
SHOW CONSTRAINTS
制約名はConstraintUnique+ノードラベル名+プロパティー名にすると重複なく作成できます。
ON-ASSERTは古い構文になります。FOR-REQUIREの新しい構文を使用するようにしましょう。
制約の削除
DROP CONSTRAINT ConstraintUniqueUserUserId
インデックスの作成
インデックスはクエリのパフォーマンスに大きく影響します。WHERE句で指定されるプロパティーにはインデックスをつけるようにします、インデックスを作成することでデータの保存時に検索に最適化された状態で保存されることになります。
【設定されているインデックスの確認】
SHOW INDEX
【インデックスの作成(ノードに対して)】
CREATE INDEX IndexNodeUserAge FOR (n:User) ON (n.age)
【インデックスの作成(リレーションに対して)】
CREATE INDEX IndexRelWatchedExcitedlyRank FOR ()-[r:WATCHED_EXCITEDLY]-() ON (r.rank)
【インデックスが作成されたことを確認】
SHOW INDEX
インデックスの削除
DROP INDEX IndexRelWatchedExcitedlyRank
まとめ
今回の記事ではNeo4jでのCypherクエリの基本操作について学習しました。CRUDはCreat、Read、Update、Deleteの頭文字でした。CREATE文もありましたが、作成と更新にはMERGE文を使った方がよいという事でしたね。MATCH文を用いてDELETE句でデータの削除をしました。リレーションが付いている場合はDETACH DELETEにしないといけませんでした。ノードに対するユニーク制約の作成と削除、またクエリのパフォーマンスのためにインデックスの作成と削除の方法も学びました。今後もCypherの学習を一緒に続けていきましょう。
コメント