Cypherのリレーションシップ(Relationship)の基本を理解する


Neo4jのCypherクエリ、サンプルは豊富にあるのですが、記法がちょっとわかりづらいです。今回は、ノード(Node)に引き続き、リレーションシップ(Relationship)を見ていきます。ノード編で紹介した記法を理解している前提で説明します。

作成

aとbのノードの間に、タイプがAAAのリレーションシップを作成します。

MATCH (a:....)            // ノードを任意の条件で検索し、aとする
MATCH (b:....)            // ノードを任意の条件で検索し、bとする
CREATE (a)-[:AAA]->(b)

始端終端ノード (必須)

  • MATCHの検索結果を、変数(識別子)で参照させます。
  • ()の中にラベルやプロパティを書くと、ノードが新規に作成されます。
  • ()の中に何も書かないと、IDだけのノードが作成されます。

同じラベルやプロパティのノードが既に存在していても、CREATE文でラベルやプロパティが書かれていると、ノードが作成されてしまいます。ただし、CREATE UNIQUEを使うと、終端に関しては、同じラベルやプロパティのノードは複製されず、既にあるノードにリレーションシップが作成されます。

方向 (必須)

  • -[:AAA]-><-[:AAA]-で記述します。
  • -[:AAA]-と書くと、エラーとなります。

タイプ (必須)

  • []の中に、:に続けて記述します。
  • -->-[]->と書くと、エラーとなります。

プロパティ(任意)

  • ノードと同様、リレーションシップにもデータを持たせることができます。
  • 記法はノードの場合と同じです。
CREATE (a)-[:AAA{name:'bbb'}]->(b)

識別子 (任意)

  • 作成直後にリレーションシップを参照したい場合は、ノードと同様、(の直後に識別子を書きます。
CREATE (a)-[r:AAA]->(b)      // 変数rで参照可能となる

検索

MATCH p=式 RETURN pに入れる部分を抜き出した形で説明します。

最小限

ありとあらゆるノードの間のパスを検索します。

()--()     // (1) 方向関係なし
()-->()    // (2) 左から右
()<--()    // (3) 右から左

()は、「全部のノード」と覚えておきましょう。

(1)の場合、各ノードが始端と終端に設定されて検索されるため、同じパスが2回ずつ検索結果に含まれることになります。

リレーションシップに識別子をつける

リレーションシップ自体を、後から変数rで参照できるようにします。

()-[r]-()

type(r)で、リレーションシップのタイプ(冒頭の例ではAAA)を取得できます。

始端終端ノードを限定する

MATCHで検索した結果に識別子を割り当てるか、()の中に検索条件を直接書くかして、始端終端ノードを限定した状態でパスを検索できます。

(a)--()    // 両方向
()--(a)    // 上とまったく同じ結果
(a)-->()   // aから他へのパス
(a)<--()   // 他からaへのパス

矢印をつけなければ、リレーションシップの方向に関わらず検索できますので、ノード同士が双方向で繋がっている必要はありません。このため、同じ意味(タイプ、プロパティ)の繫がりであれば、どちらか一方向のリレーションシップだけ作成しておけば充分です。データベース領域の節約になります。

リレーションシップのタイプやプロパティで絞り込む

リレーションシップを作成する時に使った記法を使えば、タイプやプロパティで絞り込み検索ができます。

()-[:AAA]->()           // タイプがAAAのリレーションシップ
()-[{name:'bbb’}]->()   // nameプロパティがbbbのリレーションシップ

複数のタイプを一度に検索できます。

()-[:AAA|BBB]->()        // AAAまたはBBBのリレーションシップ

2ホップ以上のリレーションシップ

間に何かが1つ挟まっているパスを検索します。

({title: 'The Matrix'})--()--({title: 'Cloud Atlas'})

ホップが複数になっても、リレーションシップのタイプやプロパティで絞り込みできます。

({title: 'The Matrix'})-[:DIRECTED]-()-[:DIRECTED]-({title: 'Cloud Atlas'})

省略記法

タイプやプロパティを指定しない場合、次のように書けます。

(a)-[*2]-(b)     // (a)--()--(b)
(a)-[*3..4]-(b)  // (a)--()--()--(b)または(a)--()--()--()--(b)
(a)-[*3..]-(b)   // (a)--()--()--(b)以上のホップ数
(a)-[*..3]-(b)   // (a)--()--()--(b)以下のホップ数
(a)-[*]-(b)      // ホップ数無制限
(a)-[*0..]-(b)   // ホップ数無制限 (a)のみというパスも含む

全てのホップで同じ条件で良ければ、省略記法でもタイプやプロパティを指定できます。例えば、少し前に出てきた例を書き換えると、こうなります。

({title: 'The Matrix'})-[:DIRECTED*2]-({title: 'Cloud Atlas'})

識別子、:タイプ、*数字、プロパティの順番です。全部入れると、このような感じになります。

()-[r:TYPE*3..4{key:'value'}]-()