fbpx

Cypher Query Language(QL)-構成要素編 #neo4j

この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。

Cypher QL(Cypher:サイファーと読む)は、Neo4jでグラフ構造のデータ処理を行うために開発した宣言型のグラフクエリ言語です。簡単に言うと、あらかじめ決まった機能を遂行する文やひな形のような構文の書式が存在し、それを組み合わせてクエリを作成し、データ処理を実行します。今回は、Cypher QLの全体的な構成要素を網羅的に紹介します。非常に数が多いので、すべてを説明はしていませんが、どのような構成要素があるのかぐらいは、見ておいたほうがいいです。特に、パターン、制約(UNIQUE INDEX)、INDEX、実行計画、ファンクションなどにはぜひ目を通して頂きたいです。関係型データベースの経験者なら、名称だけで機能がイメージできるものもあれば、まったく新しい概念もあります。

詳しく知りたい方は、下記ドキュメントを参照してください。

http://neo4j.com/docs/milestone/cypher-query-lang.html

関連記事-CL-Lab
Neo4j-グラフデータベースとは
Cypher Query Language(QL)-構成要素編
Cypher Query Language(QL)-初級編
Neo4j-大量データの読み込み

関連記事-Qiita
WindowsでNeo4jを使ってみる
MacでNeo4jを使ってみる
SoftLayerでNeo4jを使ってみる
AWSでNeo4jを使ってみる
Neo4jウェブインターフェースを使い倒す

Cypher QLの構成要素

シンタックス


以下は、Cypher QLの核に値する要素です。
バリュー(VALUE)

  • 数字
  • 文字
  • ブール型
  • ノード
  • 関係性
  • パス:ノードとノードを結ぶ関係性の経路、ノードと関係性の一連の繋がりの流れ
  • コレクション:リストやマップ
  • NULL

式(EXPRESSION)
一般式

  • 小数
  • 16進数
  • 8進数
  • 整数
  • 文字列
  • ブーリン型
  • 識別子
  • 識別子.属性: {movie.title}
  • パラメータ:{param},{0}
  • コレクション:["a","b"],[1,2,3]
  • 一般ファンクション:length(識別子), nodes(識別子)
  • 集合ファンクション:avg(識別子.属性),count(*)
  • パスパターン:(識別子1)->()<-(識別子2)
  • 演算:1+2, 3 < 4
  • 述語式(TURN or FALSE): a.prop = "Hello", length(p) > 10, has(a.name)

文字列リテラル

  • \t:タブ
  • \b:バックスペース
  • \n:改行
  • \r:キャリッジリターン。行末から行頭に戻す復帰コード
  • \f:紙送り/改頁
  • \':単一引用符
  • \":二重引用符
  • \\:バックスラッシュ
  • \uxxxx:UTF-16
  • \Uxxxxxxxx:UTF-32

CASE

MATCH n
RETURN
CASE n.eyes
WHEN 'blue'
THEN 1
WHEN 'brown'
THEN 2
ELSE 3 END AS result

識別子
ノードや関係性、処理結果などの値を示す構造体です。書式は、(識別子:ラベル)のように表記します。下記の「person」が識別子です。

(person:Person)

演算子

  • 算術演算子:+, -, *, /, %, ^
  • 比較演算子:=, <>,<,>,<=, >=,IS NULL,IS NOT NULL
  • ブール演算:結果値はTRUE又はFALSE。演算子はAND, OR, XOR, NOT
  • 文字列演算子:文字列+文字列
  • コレクション演算子:IN

パターン
パターンという概念は、Cypher QLの心臓部と言われています。Neo4jは、単純か、複雑かを問わず、すべてのデータをパターンとしてとらえて表現します。データパターン処理は、MATCH、 CREATE 、 MERGEのなかに散在しています。データパターンとか言われるとなぜか、難しく感じてしまうかも知れませんが、「同じデータや類似したデータ」という概念は、どのデータベースにも存在します。パターンと言っているのは、グラフ語だと思えばいいです。

単純なパターン
最も単純なパターンの形状は、1個のノードです。

(person:Person {name:"李"})

複雑なパターン
複雑なパターンは、複数のノードとノード間の関係性の表現です。

(人)-->(映画)

(人)-->(映画)() <--(人)

Neo4jで、2つのノード間の関係性を示す最も単純な方法は、「--」です。これは、方向性やタイプを問わず、何らかの繋がりを持っているデータパターンを意味します。

(person:Person)--(movie:Movie)

Relationship-1

関係性の表現は、方向を持たせることでより具体的で意味ある関係になります。下図のように「Aさん」と「Bさん」は、「お互いに何となく知っている」という関係性を表現したとします。これを果たして意味ある関係性の表現だと言えるでしょうか。

Relationship-2

何となく知っているという関係を掘り下げてみます。まず、[:知っている]というタイプが存在します。そして、2つのパターンが存在するはずです。「Aさん」は「Bさん」を知っている。「Bさん」は「Aさん」を知っている。そして、属性は一致することもあれば、一致しないこともあるはずです。「Aさん」は「Bさん」と面識があり、好感をもっています。「Bさん」は「Aさん」と面識はあるが、好感をもっていません。

Relationship-3

ノード間の関係性の方向のみを示すときは、下記のように「-->」で表現します。これは、関係性のタイプは問わず、(人)から(映画)へと向いているすべての関係を意味します。

(person:Person)-->(movie:Movie)

ノード間の関係性のタイプを示すときは、[:出演した]のように表現します。勿論、人と映画との関係では、より多くのタイプが存在するはずです。[:監督した]、[:主演した]、など、どんな関係性のパターンを表現したいかによってタイプを決めることができます。

(person)-[roles:出演した]->(movie)

関係性のタイプに属性を持たせると、さらに多様なパターンの表現ができるようになります。

(person)-[roles:出演した{"A役に"," B役に","C役に"}]->(movie)

コメント
構文のなかのダブルスラッシュはコメント扱いされます。

MATCH (person:Person)
//これはコメントです
RETURN person

コレクション
一般的なコレクション
Neo4jの構文では、RETURN文単独でデータ処理が可能です。下記のリストは、インデックスを指定していないので、全データが返ってきます。

RETURN [0,1,2,3,4,5,6,7,8,9]
[0,1,2,3,4,5,6,7,8,9]

下記のリストは、0から10の範囲のリストのなかで、[0]から始まる[3]のインデックスの値を意味するので 3が返ってきます。

RETURN range(0,10)[3]
3

下記は、始点をインデックス[0]として、「3番目」までの要素全てを意味し ます。

RETURN range(0,10)[0..3]
[0,1,2]

下記は、インデックスの末尾から「-3番目」の要素を意味します。

RETURN range(0,10)[-3]
8

下記は、始点をインデックス[0]、末尾から「-5番目」までの要素全てを意味 します。

RETURN range(0,10)[0..-5]
[0,1,2,3,4,5]

下記は、始点を末尾から「-5番目」として、末尾までの要素全てを意味します。

RETURN range(0,10)[-5..]
[6,7,8,9,10]

INリスト
[]のなかでリストのFOR EACH処理を行っています。下記は、0からの10までの数字を2で割り算して、余りが0の数字を返します。INの右の0から10までの数字がインデックス順で左の変数xに渡され、WHEREで「x % 2 = 0」の結果値をフィルターして返しています。

RETURN [x IN range(0,10) WHERE x % 2 = 0] AS result
[0,2,4,6,8,10]

リテラルマップ
Cypher QLでは、結果値をマップで受け取ることができます。下記のようなJSON形式です。

RETURN { key : "Value", collectionKey: [{ inner: "Map1" }, { inner: "Map2" }]}
{key -> "Value", collectionKey -> [{inner -> "Map1"},{inner -> "Map2"}]}

NULL
グラフデータベースでNULLの認識は、とても重要です。下記は、論理演算とIN演算の結果です。

論理演算の結果
Logical-oeration-1

IN演算の結果

Logical-oeration-2

一般的な文(General Clauses)


  • RETURN
  • ORDER BY
  • LIMIT
  • SKIP
  • WITH
  • UNWIND:UNWINDは、コレクションの個々の値を行に変換します
  • UNWIND[1,2,3] AS x
    RETURN x
    1
    2
    3

  • UNION
  • USING:ノードに対するラベル検索と属性に対するINDEX検索を誘導します。

MATCH (n:Swedish)
USING INDEX n:Swedish(surname)
WHERE n.surname = 'Taylor'
RETURN n
Node[3]{name:"Andres",age:36,awesome:true,surname:"Taylor"}

MATCH (m:German)
USING SCAN m:German
WHERE m.surname = 'Plantikow'
RETURN m
Node[1]{name:"Stefan",surname:"Plantikow"}

読み取り文


データパターンの検索、フィルター、集計、大量データロードなどを行う文です。

  • MATCH
  • OPTIONAL MATCH
  • WHERE
  • START:インデックスを使ってノードや関係性を検索します
  • AGGREGATION
  • LOAD CSV

書き込み文


データパターンの追加、更新、削除、大量データロードなどを行う文です。

  • CREATE
  • MERGE
  • SET
  • DELETE
  • REMOVE
  • FOREACH
  • CREATE UNIQUE
  • IMPORTING CSV FILES WITH CYPHER
  • USING PERIODIC COMMIT:トラザクション処理件数の制限

ファンクション(FUNCTION)


下記は、Cypher QLのすべてのファンクション情報です。
述語ファンクション

  • ALL
  • ANY
  • NONE
  • SINGLE
  • EXISTS

スカーラファンクション
グラフのメタ情報を表示したりするものが一部含まれています。

  • LENGTH
  • LENGTHのパターン表現
  • TYPE
  • ID
  • COALESCE
  • HEAD
  • LAST
  • TIMESTAMP
  • STARTNODE
  • ENDNODE
  • TOINT
  • TOFLOAT
  • TOSTRING

コレクションファンクション
グラフのメタ情報を表示したりするものが一部含まれています。

  • NODES
  • RELATIONSHIPS
  • LABELS
  • KEYS
  • EXTRACT
  • FILTER
  • TAIL
  • RANGE
  • REDUCE

数学ファンクション

  • ABS
  • ACOS
  • ASIN
  • ATAN
  • ATAN2
  • COS
  • COT
  • DEGREES
  • E
  • EXP
  • FLOOR
  • HAVERSIN
  • LOG
  • LOG10
  • PI
  • RADIANS
  • RAND
  • ROUND
  • SIGN
  • SIN
  • SQRT
  • TAN

文字列ファンクション

  • STR
  • REPLACE
  • SUBSTRING
  • LEFT
  • RIGHT
  • LTRIM
  • RTRIM
  • TRIM
  • LOWER
  • UPPER
  • SPLIT

データ整合性と処理速度


Neo4jでは、下記の3つの要素を「スキーマ」と表現しています。
CONSTRAINTS
制約(CONSTRAINT)は、同ラベルのなかの属性値に対して一意性を保証するために作成します。関係型データベースの言葉に置き換えればプライマリーキーです。例えば、ブックマスターのISBN、社員マスターの社員IDなどが制約宣言の対象になります。1属性に対して1制約しか作成できませんが、同ラベルのなかで制約を複数作成することは可能です。但し、複数の属性で複数キー型の制約を宣言することはできません。

CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE

DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE

下記のような制約を宣言することは出来ません。

CREATE CONSTRAINT ON (book:Book) ASSERT {book.title,book.author} IS UNIQUE

INDEX
検索速度を上げるために、属性に対してインデックスを作成できます。インデックスは、1属性に対して1インデックスしか作成できません。同ラベルのなかの属性を使って複数のインデックスを作成することは可能です。但し、複数の属性で複合キー型のインデックスに宣言することはできません。

CREATE INDEX ON :Movie(title)

DROP INDEX ON :Movie(title)

下記のようなインデックスの宣言は出来ません。

CREATE INDEX ON :Book(title, author)

STATISTICS
Neo4jは、実行計画を作成するために必要な統計値を保持します。Neo4jは、ノードとインデックに対し、別の手法で統計値を収集しています。ノードに対しては、ラベルの属性に変更が起きたときに統計値が更新されます。インデックスに対しては、特定の割合の変更が起きたときにバックグラウンドで統計値を更新します。

  • ラベルとノードの数
  • インデックスの選択制
  • タイプによる関係性の数
  • 特定のラベルのノードから始まるか、終わるか、そのタイプによる関係性の数

Cypher QLのチューニング


実行計画者(Execution planner )

Cypherクエリは、実行計画者(Execution planner)呼ばれる者が作った実行計画によって実行されます。実行計画の作成方法は、次の2つです。

RULE BASE
主にインデックスに頼って実行計画を作成します。統計値は参照しません。

COST BASE
統計値を利用して実行計画の代替案を作成し、コストが最も低い実行計画を使用します。2.2.xからは、デフォルトになっていますが、まだ、開発途上にあり、すべてコストベースが使われているわけではありません。

実行計画

実行計画とは、Cypherクエリの作業順と作業方法のことです。これを見ると作業効率を図ることが出来て、パフォーマンスチューニングに利用することができます。

EXPLAIN
構文を実行せず、実行計画だけをみることができます。使い方は、構文の前にEXPLANを付けて実行します。

EXPLAIN MATCH (p { name:"Tom Hanks" }) RETURN p

PROFILE
構文を実行し、結果値とともに実行計画をみることができます。使い方は、構文の前にPROFILEを付けて実行します。

PROFILE MATCH (p { name:"Tom Hanks" }) RETURN p

実行計画の読み方

下記は、実行計画の例ですが、肝心なことは、下から上に読んでいくことです。

cypher-ql-explain-plan

Operator:演算子の名称
EstimatedRows: コストベースの実行計画で見積した予測の行数。これは、Neo4j 2.2.xから採用されています。古いパージョンは表示されません。
Rows , DbHits:これはPROFILEを実行して実行計画を出力したときに表示されます。Rows(行数)は、演算子によって絞り出された実際のデータの行数を意味します。つまり、最終結果値です。そして「DbHits」は、演算子が実行に使ったデータ行数を意味します。「DbHits」は、Neo4jのIOサブシステムにより、キャッシュやディスクとのやり取りを行います。

EstimatedRowsの行数と、Rowsの行数とは、なるべく近いほうがいいです。

まとめ


今回の記事は、多少退屈だったかも知れません。次回から、本格的なCypher QLの書き方に入ります。

Author

モダンアーキテクチャー基盤のソリューションアーキテクトとして活動しています。

[著書]
・Amazon Cloudテクニカルガイド―EC2/S3からVPCまで徹底解析
・Amazon Elastic MapReduceテクニカルガイド ―クラウド型Hadoopで実現する大規模分散処理
・Cypherクエリー言語の事例で学ぶグラフデータベースNeo4j
・Neo4jを使うグラフ型データベース入門(共著)
・RDB技術者のためのNoSQLガイド(共著)

leeの記事一覧

新規CTA