本当はスキーマ全体についての記事を書こうと思ったが、最初のEdge Label Multiplicityだけで文量が嵩みそうだったので、ひとまずこれだけを重点的に解説してみる。
例によって、英語が読めるなら公式のドキュメントに目を通すのをおススメする。
Schema and Data Modeling
Edge Label Multiplicity
エッジ(辺)のラベルについては、Multiplicity(多重度?)という設定を行うことができる。Multiplicityは5種類の中から1つ選択することができ、それぞれ制限の内容が異なる。制限に反する場合、エッジ登録時にエラーが発生して失敗する。
Multiplicity | 説明 |
---|---|
MULTI | [デフォルト]一切の制限なし。あらゆる2頂点間について、方向、エッジ数ともに好きなだけエッジを張ることができる |
SIMPLE | 2頂点間のエッジについてはどちらの方向についても最大1本まで |
MANY2ONE | 頂点に入ってくる方向(incoming)については制限なし。出ていく方向(outgoing)については全ての頂点に対して合計1本まで |
ONE2MANY | 頂点から出ていく方向(outgoing)については制限なし。入ってくる方向(incoming)については全ての頂点に対して合計1本まで |
ONE2ONE | 頂点から出ていく方向は最大1本まで、頂点に入ってくる方向も最大1本まで |
簡単な操作で試してみる。新規のデータベースを立ち上げた状態でGremlinコンソールからリモート接続する(参考)
gremlin> :remote connect tinkerpop.server conf/remote.yaml session
==>Configured localhost/127.0.0.1:8182-[f3e6dcfb-60ab-44d7-aaeb-0f26b01135cc]
gremlin> :> m = graph.openManagement()
==>org.janusgraph.graphdb.database.management.ManagementSystem@146ecc1c
gremlin> :> m.makeEdgeLabel("multi").multiplicity(Multiplicity.MULTI).make()
==>multi
gremlin> :> m.makeEdgeLabel("simple").multiplicity(Multiplicity.SIMPLE).make()
==>simple
gremlin> :> m.makeEdgeLabel("many2one").multiplicity(Multiplicity.MANY2ONE).make()
==>many2one
gremlin> :> m.makeEdgeLabel("one2many").multiplicity(Multiplicity.ONE2MANY).make()
==>one2many
gremlin> :> m.makeEdgeLabel("one2one").multiplicity(Multiplicity.ONE2ONE).make()
==>one2one
gremlin> :> m.commit()
==>null
以上のようにして、5種類それぞれのEdge Labelを登録する。printSchema
を実行すると、以下のような状態になっている。
gremlin> :> m = graph.openManagement()
==>org.janusgraph.graphdb.database.management.ManagementSystem@552c511a
gremlin> :> m.printSchema()
==>------------------------------------------------------------------------------------------------
Edge Label Name | Directed | Unidirected | Multiplicity |
---------------------------------------------------------------------------------------------------
multi | true | false | MULTI |
simple | true | false | SIMPLE |
many2one | true | false | MANY2ONE |
one2many | true | false | ONE2MANY |
one2one | true | false | ONE2ONE |
---------------------------------------------------------------------------------------------------
さらに、グラフに4つほど確認用の頂点を追加する。
:> bob = g.addV("person").property("name", "bob").next()
==>v[4136]
:> james = g.addV("person").property("name", "james").next()
==>v[4184]
:> alice = g.addV("person").property("name", "alice").next()
==>v[8232]
:> ellie = g.addV("person").property("name", "ellie").next()
==>v[4152]
これらに対して、エッジを作成してみる。
MULTI
gremlin> :> g.addE("multi").from(bob).to(alice)
==>e[2rp-36w-6c5-6co][4136-follow->8232]
gremlin> :> g.addE("multi").from(bob).to(alice)
==>e[35x-36w-6c5-6co][4136-follow->8232]
自由にエッジを張ることができる。当然だが、同じ2頂点間に複数エッジを張っても問題ない。
SIMPLE
gremlin> :> g.addE("simple").from(bob).to(alice)
==>e[4qt-36w-1lh-6co][4136-simple->8232]
gremlin> :> g.addE("simple").from(bob).to(alice)
An edge with the given label already exists between the pair of vertices and the label [simple] is simple
Type ':help' or ':h' for help.
Display stack trace? [yN]
同じ2頂点間に複数張ろうとするとエラーになった。Already Exists
と怒られた。
gremlin> :> g.addE("simple").from(alice).to(bob)
==>e[551-6co-1lh-36w][8232-simple->4136]
gremlin> :> g.addE("simple").from(alice).to(bob)
An edge with the given label already exists between the pair of vertices and the label [simple] is simple
Type ':help' or ':h' for help.
Display stack trace? [yN]
向きを逆にして(aliceとbobを入れ替えて)も同じようにエラーとなる。
MANY2ONE
MANY2ONE
はSIMPLE
の制限を含みつつ、さらに厳しい。
gremlin> :> g.addE("many2one").from(bob).to(alice)
==>e[5j9-36w-2dx-6co][4136-many2one->8232]
gremlin> :> g.addE("many2one").from(bob).to(ellie)
An edge with the given label already exists on the out-vertex and the label [many2one] is out-unique
Type ':help' or ':h' for help.
Display stack trace? [yN]
gremlin> :> g.addE("many2one").from(james).to(alice)
==>e[1l7-388-2dx-6co][4184-many2one->8232]
gremlin> :> g.addE("many2one").from(james).to(ellie)
An edge with the given label already exists on the out-vertex and the label [many2one] is out-unique
Type ':help' or ':h' for help.
Display stack trace? [yN]
1本目は問題ないが、2本目は違う頂点に対して張ろうとしてもエラーになる。エラーメッセージのout-unique
が言うとおりに、頂点から出る矢印は1本に限られる。
ONE2MANY
MANY2ONE
もまた、SIMPLE
の制限を含みつつ、さらに厳しい。
gremlin> :> g.addE("one2many").from(alice).to(bob)
==>e[5xh-6co-36d-36w][8232-one2many->4136]
gremlin> :> g.addE("one2many").from(ellie).to(bob)
An edge with the given label already exists on the in-vertex and the label [one2many] is in-unique
Type ':help' or ':h' for help.
Display stack trace? [yN]
gremlin> :> g.addE("one2many").from(alice).to(james)
==>e[6bp-6co-36d-388][8232-one2many->4184]
gremlin> :> g.addE("one2many").from(ellie).to(james)
An edge with the given label already exists on the in-vertex and the label [one2many] is in-unique
Type ':help' or ':h' for help.
Display stack trace? [yN]
ある頂点から、それぞれ違う頂点に対して、何本張っても問題はない。ただし、同じ頂点に対して2本目を張ることは出来ない。エラーメッセージのin-unique
が言うとおりに、頂点に入ってくる矢印は1本に限られる。
ONE2ONE
ONE2ONE
は最も重い制限である。MANY2ONE
とONE2MANY
両方の条件を課される。
gremlin> :> g.addE("one2one").from(bob).to(alice)
==>e[6px-36w-3yt-6co][4136-one2one->8232]
gremlin> :> g.addE("one2one").from(alice).to(james)
==>e[745-6co-3yt-388][8232-one2one->4184]
gremlin> :> g.addE("one2one").from(james).to(ellie)
==>e[1zf-388-3yt-37c][4184-one2one->4152]
gremlin> :> g.addE("one2one").from(ellie).to(alice)
An edge with the given label already exists on the in-vertex and the label [one2one] is in-unique
Type ':help' or ':h' for help.
Display stack trace? [yN]
入ってくるのも1本まで、出ていくのも1本までという、シンプルな形のグラフとなる(線形リストとか、環状ループとか)。
選択方針
不都合がない範囲で、なるべく厳しい制限を課すように設定するのが良い。データ入力時に誤ったエッジを入力してしまうミスを少しだけでも減らすことができる。