DSE Graph、OLTP、およびOLAP

DSE GraphにおけるOLTPとOLAPの関係について説明します。

DSE GraphにおけるOLTPとOLAPの関係について説明します。

オンライン・トランザクション処理(OLTP)

オンライン・トランザクション処理(OLTP)は、短いオンライン・トランザクションが多数あり、クエリー処理が非常に速いという特徴があります。OLTPは通常、データ入力トランザクションおよびデータ取得トランザクション指向のアプリケーションに使用されます。オンライン分析処理(OLAP)は、トランザクションの量が比較的少ないことが特徴です。OLAPは、一般的に、集められた履歴データを対象に複雑な計算を行う、データの多次元分析に使用されます。

OLTPアプリケーションでは、1秒未満の応答速度が求められます。一方、OLAPアプリケーションではクエリー終了まで長くかかります。グラフ・データベースでは、OLTP探索は、グローバル・グラフの特定のサブグラフに局限されます。グラフ・データベースは、ランダム・アクセス・データ・システムです。OLAP探索では、グラフ内のすべての頂点を線形にスキャンします。OLTP探索では、インデックスを利用してグラフの特定の頂点に「ジャンプ」してから、サブグラフに対するスキャンを開始します。

OLTPクエリーは、グラフ全体の限定されたサブセットにアクセスする必要がある問い合わせに最適です。OLTPクエリーでは、フィルターを使用して、回答を見つけるために巡回する頂点の数を制限します。DSE Graphでは、頂点が、そのエッジおよび隣接する頂点と一緒に配置されます。インデックスを使用した探索でサブグラフが指定されている場合、ディスクに対する要求の数は、要求されたサブグラフの位置を特定してメモリーに書き込むために削減されます。メモリーに書き込まれると、エッジに沿って頂点間を巡回します。

オンライン分析処理(OLAP)

OLAPクエリーは、グラフに保存されているデータのかなりの部分にアクセスしなければならない問い合わせに適しています。上記の方法でOLAPクエリーを評価することは効率的ではないため、別のプロセスが使用されます。OLAPクエリーが処理される際、グラフ全体は、それぞれ、単一の頂点とそのプロパティ、インシデント・エッジ、エッジのプロパティから成る星型グラフのシーケンスとして解釈されます。この星型グラフは、すべての星型グラフが処理され、見つかったデータの集計が完了するまで1つの星型グラフから次の星型グラフへと直線的に処理されます。

グラフ探索の作成の原則

これらの基本的原則を理解することが、グラフ・データのクエリーを実行するためのより良いグラフ探索を記述することにつながります。簡単な例でこの違いを説明します。「Julia Childが創作したレシピの数は?」という、食べ物に関するグラフを使用したクエリーを取り上げることにします。

次のグラフ探索を見てみましょう。
g.V().in().has('name','Julia Child').count()
===>6

この探索では、すべての頂点を検索して内向きエッジを巡回し、プロパティ・キーがnameでプロパティ値がJulia Childの隣接頂点を見つけて、頂点の数をカウントします。返されるカウントには、レシピだけでなくJulia Childに対するエッジを持つ頂点がすべて含まれます。後で説明しますが、カウント数は不正確で非常に大きくなります。

このクエリーを完了するために探索しなければならない要素の数を考えてみましょう。DSE Graphには、探索の分析に役立つプロファイリング機能があります。
gremlin> g.V().in().has('name','Julia Child').count().profile()
==>Traversal Metrics
Step                                                               Count  Traversers       Time (ms)    % Dur
=============================================================================================================
DsegGraphStep(vertex,[])                                              61          61          28.932    18.71
  query-optimizer                                                                              0.563
    \_condition=((label = FridgeSensor | label = author | label = book | label = ingredient | label = meal |
                label = recipe | label = reviewer) & (true))
  query-setup                                                                                  0.048
    \_isFitted=true
    \_isSorted=false
    \_isScan=true
  index-query                                                                                  0.979
    \_usesCache=false
    \_statement=SELECT "city_id", "sensor_id" FROM "DSEQuickStart"."FridgeSensor_p" WHERE "~~vertex_exists" =
                 ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.862
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."author_p" WHERE "~~vertex_exists" =
                ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.679
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."book_p" WHERE "~~vertex_exists" = ?
                LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  1.344
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."ingredient_p" WHERE "~~vertex_exists
                " = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 5000
                0
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  1.053
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."meal_p" WHERE "~~vertex_exists" = ?
                LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  4.173
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."recipe_p" WHERE "~~vertex_exists" =
                ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  1.291
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."reviewer_p" WHERE "~~vertex_exists"
                = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
DsegVertexStep(IN,vertex)                                             78          78          95.721    61.90
  query-optimizer                                                                              0.305
    \_condition=((true) & direction = IN)
  vertex-query                                                                                 4.136
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 588941056, (java.lang.Long) 0, (java.lang.I
                nteger) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  vertex-query                                                                                 0.558
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 1432048000, (java.lang.Long) 1, (java.lang.
                Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  vertex-query                                                                                 1.146
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 153541376, (java.lang.Long) 1, (java.lang.I
                nteger) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.941
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  query-setup                                                                                  0.015
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 1.966
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 138026496, (java.lang.Long) 0, (java.lang.I
                nteger) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.015
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  query-setup                                                                                  0.013
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  query-setup                                                                                  0.016
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
NoOpBarrierStep(2500)                                                 78          25           2.877     1.86
HasStep([name.=(Julia Child)])                                         5           1          25.242    16.32
CountGlobalStep                                                        1           1           1.859     1.20
                                            >TOTAL                     -           -         154.632        -
注: 各ステップに要する時間は、キャッシングおよびその他の要因に左右されます。報告される時間はあくまで解説を目的としたものなので、無視してください。現在、profile()メソッドには、Gremlinコマンドの結果実行されるCQLコマンドが含まれています。
図: Studioによる探索1のプロファイル出力

最初のステップを見ると、グラフ内のすべての頂点が探索されています。このグラフは非常に小規模なため、頂点の数は、実稼働グラフと比べてごく少数です。次のステップでは、頂点に入ってくるすべてのエッジを検出する必要があります。繰り返しになりますが、小規模なグラフの場合、エッジの数はごく少数ですが、実稼働グラフのエッジ数は数百万から数十億になります。ここでは、隣接頂点をフィルター処理して頂点の数を6にまで絞り込むことによって、指定されたプロパティ・キー情報を見つけます。最後の2つのステップでは、カウントおよびプロファイリング測定を完了します。

このグラフ探索は典型的なOLAP探索です。この探索では、すべての頂点に触れる必要があり、インデックスを使用しません。

それでは、内向きエッジのエッジ・ラベルを指定する変更を見てみましょう。
g.V().in('created').has('name','Julia Child').count()
===>3
この変更した探索でも、すべての頂点が探索されますが、内向きエッジの巡回に際しては、createdというラベルが付けられたエッジに制限されます。プロファイルを見ると、画像が改善されている様子がわかります。
gremlin> g.V().in('created').has('name','Julia Child').count().profile()
==>Traversal Metrics
Step                                                               Count  Traversers       Time (ms)    % Dur
=============================================================================================================
DsegGraphStep(vertex,[])                                              61          61          22.251    16.91
  query-optimizer                                                                              1.760
    \_condition=((label = FridgeSensor | label = author | label = book | label = ingredient | label = meal |
                label = recipe | label = reviewer) & (true))
  query-setup                                                                                  0.071
    \_isFitted=true
    \_isSorted=false
    \_isScan=true
  index-query                                                                                  1.139
    \_usesCache=false
    \_statement=SELECT "city_id", "sensor_id" FROM "DSEQuickStart"."FridgeSensor_p" WHERE "~~vertex_exists" =
                 ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  2.012
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."author_p" WHERE "~~vertex_exists" =
                ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.549
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."book_p" WHERE "~~vertex_exists" = ?
                LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.849
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."ingredient_p" WHERE "~~vertex_exists
                " = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 5000
                0
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.887
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."meal_p" WHERE "~~vertex_exists" = ?
                LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.889
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."recipe_p" WHERE "~~vertex_exists" =
                ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
  index-query                                                                                  0.499
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."reviewer_p" WHERE "~~vertex_exists"
                = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
DsegVertexStep(IN,[created],vertex)                                    8           8         103.458    78.62
  query-optimizer                                                                              0.618
    \_condition=(((label = created) & (true)) & direction = IN)
  vertex-query                                                                                 0.261
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 1432048000, (java
                .lang.Long) 1, (java.lang.Integer) 65577, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  vertex-query                                                                                 0.200
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 153541376, (java.
                lang.Long) 1, (java.lang.Integer) 65577, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.017
    \_isFitted=true
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 6.140
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 588941056, (java.
                lang.Long) 0, (java.lang.Integer) 65577, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.017
    \_isFitted=true
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 0.201
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 771301632, (java.
                lang.Long) 0, (java.lang.Integer) 65577, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.012
    \_isFitted=true
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 0.173
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 994194304, (java.
                lang.Long) 0, (java.lang.Integer) 65577, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.012
    \_isFitted=true
    \_isSorted=true
    \_isScan=false
NoOpBarrierStep(2500)                                                  8           4           0.910     0.69
HasStep([name.=(Julia Child)])                                         3           1           4.903     3.73
CountGlobalStep                                                        1           1           0.075     0.06
                                            >TOTAL                     -           -         131.599        -
図: Studioによる探索2のプロファイル出力

最初のステップでは、元の探索と同様にすべての頂点が検出されます。しかし、次のステップで、巡回されるエッジの数は大幅に減ります。ただし、実稼働グラフの場合、グラフ全体のすべての頂点を見つけるには時間がかかります。3番目のステップでは、Julia Childが創作したレシピの数に対する正答が反映されます。最初の探索では、Julia Childの本に対する他の内向きエッジがカウントに含まれています。

このグラフ探索は、依然として、すべての頂点を巡回するOLAP探索であり、インデックスを使用しません。

頂点ラベルを指定することによって、探索改善にどのような影響があるでしょうか?
g.V().hasLabel('recipe').in().has('name','Julia Child').count()
===>3
この変更後の探索はrecipe頂点に制限されるようになりますが、すべての内向きエッジを巡回します。このプロファイルを見ると、画像がいくらか改善されている様子がわかります。
gremlin> g.V().hasLabel('recipe').in().has('name','Julia Child').count().profile()
==>Traversal Metrics
Step                                                               Count  Traversers       Time (ms)    % Dur
=============================================================================================================
DsegGraphStep([~label.=(recipe)])                                      8           8           2.598     9.25
  query-optimizer                                                                              0.241
    \_condition=((label = recipe) & (true))
  query-setup                                                                                  0.187
    \_isFitted=true
    \_isSorted=false
    \_isScan=true
  index-query                                                                                  1.225
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."recipe_p" WHERE "~~vertex_exists" =
                ? LIMIT ? ALLOW FILTERING; with params (java.lang.Boolean) true, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
DsegVertexStep(IN,vertex)                                             15          15           9.668    34.41
  query-optimizer                                                                              0.150
    \_condition=((true) & direction = IN)
  query-setup                                                                                  0.047
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 0.896
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."recipe_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 1315507840, (java.lang.Long) 1, (java.lang.
                Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  vertex-query                                                                                 1.415
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."recipe_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 96517120, (java.lang.Long) 1, (java.lang.In
                teger) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  vertex-query                                                                                 2.846
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."recipe_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 1598713728, (java.lang.Long) 1, (java.lang.
                Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.038
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 0.364
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."recipe_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 1146421632, (java.lang.Long) 1, (java.lang.
                Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.014
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
  vertex-query                                                                                 0.431
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."recipe_e" WHERE "community_id" = ? AND "member_id" = ? LIMIT ?
                 ALLOW FILTERING; with params (java.lang.Integer) 384373760, (java.lang.Long) 2, (java.lang.I
                nteger) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.014
    \_isFitted=false
    \_isSorted=true
    \_isScan=false
HasStep([name.=(Julia Child)])                                         3           3          15.765    56.10
CountGlobalStep                                                        1           1           0.068     0.24
                                            >TOTAL                     -           -          28.100        -
図: Studioによる探索3のプロファイル出力

最初のステップで検出される頂点の数は限られており、多数のエッジが巡回されました。ただし実稼働グラフでは、インデックスを使用しないと、限られた数の頂点の探索であっても時間がかかり、また、巡回されるエッジの数も膨大になる可能性があります。

このグラフ探索は、依然として、インデックス作成を使用しないOLAP探索です。次の例で説明するように、インデックスは頂点ラベルとプロパティ・キーによって識別されます。この探索は、まず、頂点ラベルを制限することによってクエリーを絞り込みますが、探索の開始点の検出にインデックスは使用されません。

次のグラフ探索では、クエリーの方向が変更されています。
g.V().has('author', 'name', 'Julia Child').outE('created').count()
===>3
頂点ラベルauthorおよび具体的なプロパティ・キーの両方と値Julia Childを指定することによって、この探索は1つの頂点から開始され、エッジ・ラベルcreatedを持つ外向きエッジのみを巡回します。
gremlin> g.V().has('author','name','Julia Child').outE('created').count().profile()
==>Traversal Metrics
Step                                                               Count  Traversers       Time (ms)    % Dur
=============================================================================================================
DsegGraphStep([~label.=(author), name.=(Julia C...                     1           1          29.049    84.45
  query-optimizer                                                                              7.673
    \_condition=(((label = author) & (true)) & name = Julia Child)
  query-setup                                                                                  0.033
    \_isFitted=true
    \_isSorted=false
    \_isScan=false
  index-query                                                                                 17.694
    \_indexType=Secondary
    \_usesCache=false
    \_statement=SELECT "community_id", "member_id" FROM "DSEQuickStart"."author_p" WHERE "name" = ? LIMIT ?;
                with params (java.lang.String) Julia Child, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
DsegVertexStep(OUT,[created],edge)                                     3           3           5.265    15.31
  query-optimizer                                                                              0.200
    \_condition=(((label = created) & (true)) & direction = OUT)
  vertex-query                                                                                 0.586
    \_usesCache=false
    \_statement=SELECT * FROM "DSEQuickStart"."author_e" WHERE "community_id" = ? AND "member_id" = ? AND "~~
                edge_label_id" = ? LIMIT ? ALLOW FILTERING; with params (java.lang.Integer) 1535517312, (java
                .lang.Long) 0, (java.lang.Integer) 65576, (java.lang.Integer) 50000
    \_options=Options{consistency=Optional[ONE], serialConsistency=Optional.empty, fallbackConsistency=Option
              al.empty, pagingState=null, pageSize=-1, user=Optional.empty, waitForSchemaAgreement=true, asyn
              c=true}
    \_isPartitioned=false
    \_usesIndex=false
  query-setup                                                                                  0.057
    \_isFitted=true
    \_isSorted=true
    \_isScan=false
CountGlobalStep                                                        1           1           0.081     0.24
                                            >TOTAL                     -           -          34.397        -
図: Studioによる探索4のプロファイル出力

単一の頂点から探索が開始されます。エッジは、エッジ・ラベルの使用によってフィルターされます。

このグラフ探索はOLTP探索です。頂点ラベルauthorおよびプロパティ・キーnameに対するインデックスを使用すると、インデックスが付けられた頂点から探索を直接開始できます。この例の結果は単一の頂点ですが、インデックス作成を使用して開始点を複数の頂点に制限するクエリーは、グラフ内のすべての頂点をチェックしなければならない線形スキャンよりも効率的です。したがって、サブグラフ(グラフの一部)を探索します。

OLTPグラフ探索を作成する際に重要なことは、グラフの探索方法を検討することです。インデックス作成の使用は、トランザクション処理を高速で行ううえで不可欠です。DSE Graphに付属しているプロファイリング・ツールは、探索のパフォーマンスの分析に役立ちます。

Sparkを使用したOLAPクエリーの実行については、「DSE GraphおよびGraph Analytics」を参照してください。