電脳世界のケーキ屋さん

考えの甘い甘党エンジニアがいろいろ書くブログ

neo4j の MERGE クエリを知った

はじめに

MERGE クエリは neo4j でノードが存在しない場合は新規にノードを作成し, 存在する場合は何も行わないという処理を行いたい時に使う.

MERGEの基本

単一ノードを作成する場合は簡単で, CREATEMERGE に置き換えるだけでよい.
下記のクエリを二回実行すると, 1回目は指定したノードが作成されるが, 2回目は何も変更はないと通知されるはずである.

MERGE (testNode:test {description: "this is test"})

MERGE はプロパティによるマッチングでは全プロパティをマッチさせる必要はない.
ただし, 指定したプロパティが存在しなかった場合は新規にそのプロパティを持つノードの作成を行う.

下記の2クエリをそれぞれ実行するケースを考える.

  1. MERGE (testNode1:test {first: 1})
  2. MERGE (testNode2:test {first: 1, second: 2})

  3. 1, 2 と実行した場合

    • ノードは2つ作成されることになる
    • 後に実行する2のクエリでは対象ノードが存在しないと判定される
  4. 2, 1 と実行した場合
    • ノードは1つ作成される
    • 後に実行する1のクエリでは対象ノードが既に存在していることになる

ちなみに, CREATE はカンマ区切りで複数ノードを同時に作成できるが, MERGE は構文エラーとなって実行できない.

リレーションも作成する時

この場合は少々複雑になる.
下記のクエリを実行してノードを2つ作成した状態にする.

MERGE (testNode1:test {description: "this is test1"})
MERGE (testNode2:test {description: "this is test2"})

この状態で以下の MERGE クエリを実行するとどうなるだろうか.

MERGE (testNode1:test {description: "this is test1"}) - [:relation] -> (testNode2:test {description: "this is test2"})

結果としては :relation で接続されたノード2つが 新規に 作成される.
これは自分にとっては少し予想外であった.
てっきりリレーションだけ新規に作成されると考えていたからである.
MERGE:relationtestNode2 に接続された testNode1 というのは存在しないと判断されたと考えれば納得は行くが, 直感的ではなかった(自分の直感が単純過ぎるだろうか)

さて, リレーションだけを新規に作成したい場合は少し工夫が必要となる.
下記のように実行すると想定通りの動きをした(スペルミスなどで何度もやりなおすはめになったが…).

MERGE (testNode1:test {description: "this is test1"})
MERGE (testNode2:test {description: "this is test2"})
MERGE (testNode1) - [:relation] -> (testNode2)

おわりに

CREATE UNIQUE 句というのも存在するらしいが MERGE 句を使えと wiki には書いてある.

参考文献

http://neo4j.com/docs/developer-manual/current/cypher/clauses/create-unique/