初歩の歩:gremlinでグラフデータ作成
グラフは、頂点(ノード、ドット)とエッジ(関係、線)のコレクションで構成されており、頂点はドメインオブジェクト(例:人物や場所)を表し、エッジは2つの頂点間の関係を表します。
プロパティグラフ
頂点「1」が「person」であり、頂点「3」が「software」の頂点であることが分かります。
これらの頂点は、「created」というエッジによって接続されており、"person created software"という関係を表しています。また、"label"と"id"は頂点とエッジの予約された属性ですが、独自の任意のプロパティを追加することもできます。
このモデルはプロパティグラフと呼ばれ、データをモデリングするための柔軟で直感的な方法を提供します。
データを作成
gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = traversal().withEmbedded(graph)
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> v1 = g.addV("person").property(id, 1).property("name", "marko").property("age", 29).next()
==>v[1]
gremlin> v2 = g.addV("software").property(id, 3).property("name", "lop").property("lang", "java").next()
==>v[3]
gremlin> g.addE("created").from(v1).to(v2).property(id, 9).property("weight", 0.4)
==>e[9][1-created->3]
データを走査
「markoが作成したソフトウェアは何ですか?」
この質問に答えるために、以下のようにグレムリンに指示します。
- グラフ内で「marko」を見つける
- 「created」のエッジに沿って「software」の頂点に移動する
- 「software」の頂点の「name」プロパティを選択する
g.V().has('name','marko')
上記のクエリは、グラフ内のすべての頂点を反復処理して答えを取得します。
gremlin> g.V().has('person','name','marko').outE('created')
==>e[9][1-created->3]
今、グレムリンが「marko」を見つけたので、次のステップである「created」のエッジをたどって「software」の頂点に移動することを考えることができます。
エッジには方向性がありますので、グレムリンにどの方向をたどるかを指示する必要があります。この場合、私たちは「marko」頂点からの出力エッジをたどってほしいので、outEステップ
を使用します。
g.V().has('person','name','marko').outE('created').inV()
==>v[3]
エッジのもう一方の端の頂点に移動するために、Gremlinに対してinV()を使用してエッジから入ってくる頂点に移動するように指示する必要があります。
gremlin> g.V().has('person','name','marko').out('created')
==>v[3]
このコードは、g.V() ですべての頂点をトラバースし、その中から「name」プロパティが「marko」という値を持つ頂点をフィルタリングします。最後に、「created」というラベルの出辺をトラバースします。
g.V().has('person','name','marko').out('created').values('name')
==>lop
最後に、Gremlinが「Markoが作成したソフトウェア」に到達したので、彼は「ソフトウェア」頂点のプロパティにアクセスできます。そのため、以下のようにGremlinに「name」プロパティの値を取得するように依頼することができます。
上よりも、ちょっと複雑なトラバーサル
within
gremlin> g.V().has('person','name',within('vadas','marko')).values('age')
==>29
==>27
mean
もしも「vadas」と「marko」の平均年齢をGremlinに尋ねる場合、mean()ステップを使用できます。例えば以下のようになります:
gremlin> g.V().has('person','name',within('vadas','marko')).values('age').mean()
==>28.0
where
「marko」が作成した「software」を見つける方法
gremlin> g.V().has('person','name','marko').out('created')
==>v[3]
「marko」がソフトウェアを開発している人々は誰ですか?
それをするために、私たちはまず前のクエリで残した場所にいるGremlinを思い浮かべる必要があります。
彼は「software」の頂点に立っていました。その「software」を「created」したのは誰かを知るためには、Gremlinに「created」のエッジに沿って逆方向にトラバースして、「person」の頂点を見つける必要があります。
gremlin> g.V().has('person','name','marko').
out('created').in('created').
values('name')
==>marko
==>josh
==>peter
"peter"、"josh"、"marko"の3人が、"v[3]"という名前が"lop"の"software"頂点の作成に関与していることがわかります
asステップモジュレーター
結果から"marko"を除外するために、トラバーサルに2つの変更を加えました。
まず、as()ステップを追加しました。as()ステップは実際には「ステップ」ではなく、「ステップモジュレーター」です。
ステップやトラバーサルに機能を追加するものです。
ここでは、as('exclude')を使用してhas()ステップに「exclude」という名前のラベルを付け、そのステップを通過するすべての値をそのラベルに保持します。この場合、"marko"頂点はそのポイントを通過する唯一の頂点であり、"exclude"に保持されます。
もう一つの追加は、where()ステップです。where()はhas()と同様のフィルタリングステップです。where()は、"person"頂点を持つin()ステップの後に配置されており、つまりwhere()フィルタは「marko」の共同作業者のリストに対して行われています。where()は、そのステップを通過する「person」頂点が「exclude」ラベルの内容と等しくない(neq())ことを指定しています。"exclude"には"marko"頂点だけが含まれているため、where()は"created"辺を通じて戻るときに取得する"marko"をフィルタリングします。
gremlin> g.V().has('person','name','marko').as('exclude').
out('created').in('created').
where(neq('exclude')).
values('name')
==>josh
==>peter
group()ステップとその関連ステップモジュレーターであるby()
グラフ内のすべての頂点をラベルごとにグループ化するように要求したい場合、以下のように行うことができます。
gremlin> g.V().group().by(label).by('name')
==>[software:[lop,ripple],person:[marko,vadas,josh,peter]]