Graphのアンチパターン

DSE Graphで発生する一般的なミスを検証します。

DSE Graphでは、よくある間違いがいくつかあります。ベスト・プラクティスを検討することで、学習のハードルを下げるとともに、グラフ・アプリケーションのパフォーマンスを改善することができます。

インデックス作成を使用しない

インデックス作成は、分散データベースでのクエリーのレイテンシーを減らす鍵です。DSE Graphは、インデックス作成を利用して複雑なグラフ検索のOLTP読み取りレイテンシーを短縮します。 DSE Graphでのグローバルなインデックス作成には、頂点ラベルとプロパティ・キーの両方が必要です。 頂点ラベルは、基盤となるCassandra データストアの検索をパーティション単位に絞り込み、さらに、クラスター内の1つ、または少数のCassandraノードにまで絞り込みます。複数の頂点ラベルに使用するプロパティ・キーについてインデックスを作成しても、クエリーでこの頂点ラベルを指定しないと、クラスターがほぼ完全スキャンされます。したがって、以下のようなクエリーを使用する場合、
g.V().has('name','James Beard')...
プロパティ・キーnameを使用しているすべての頂点をチェックするように探索で指定する必要があります。このクエリーを以下のように変更すると、
g.V().has('author', 'name', 'James Beard')...
クエリーで著者レコードのすべての名前について作成可能なインデックスを参照し、頂点を1つだけを取得して探索を開始できます。このインデックスは、スキーマ作成時に追加します。
schema.vertexLabel('author').index('byName').secondary().by('name').add()

探索でこのような変更を行った場合、実質的には、OLAPクエリーからOLTPクエリーへの変更となります。

プロパティ・キーの作成

プロパティ・キーの作成は、DSE Graphのパフォーマンスに影響を及ぼす場合があります。一意のプロパティ・キー名を使用するのも良いですが、異なるさまざまな頂点ラベルにプロパティ・キーを再利用すると、グラフのプロパティ・キーのストレージ効率が向上します。たとえば、次の例を見てみましょう。
schema.propertyKey('recipeCreationDate').Timestamp().create()
schema.propertyKey('mealCreationDate').Timestamp().create()
schema.propertyKey('reviewCreationDate').Timestamp().create()
上記のプロパティ・キー名だとコードが読みやすく、グラフ探索における追跡が容易ですが、保存されている追加のプロパティ・キーごとにリソースが必要です。代わりに、次のようなプロパティ・キーを1つ使用すると、
schema.propertyKey('timestamp').Timestamp().create()
オーバーヘッドを減らすことができます。グラフ探索では、プロパティ・キーはほとんどが、頂点ラベルと一緒に使用されるため、timestampは、頂点ラベルとプロパティ・キーの組み合わせによって一意に識別されます。

頂点ラベルの作成

頂点ラベルの作成は、DSE Graphのパフォーマンスに影響を及ぼす場合があります。一意の頂点ラベルを複数使用すると便利そうですが、プロパティ・キーのように、作成する頂点ラベルをできるだけ少なくすると、ストレージ要件を改善することができます。たとえば、次の例を見てみましょう。
schema.vertexLabel('recipeAuthor').create()
schema.vertexLabel('bookAuthor').create()
schema.vertexLabel('mealAuthor').create()
schema.vertexLabel('reviewAuthor').create()
前述したように、これらの頂点ラベルは読みやすさという利点がありますが、頂点ラベルに対して一意にクエリーを行わない限りは、この機能を単一の頂点ラベルにまとめたほうが得策です。たとえば、上記のコードでは、”recipes(レシピ)”、”meals(食事)”、”books(本)”が同じ著者を共有している可能性がある一方、”reviews(書評)”にはさまざまなレビュー担当者とクエリーのタイプがある可能性があります。頂点ラベルは4つではなく2つ使用してください。
schema.vertexLabel('author').create()
schema.vertexLabel('reviewer').create()
実際、これは、著者およびレビュー担当者の重複が十分に大きければ、頂点ラベル、personを1つだけ使用するケースのほうに適しています。場合によっては、personが著者か、レビュー担当者かを識別するプロパティ・キーが有効な選択肢となります。
schema.propertyKey('type').Text().create()
schema.vertexLabel('person').create()
graph.addVertex(label, 'person', 'type', 'author', 'name', 'Jamie Oliver')

スキーマ作成および構成と探索クエリーの混在

次の文を見てみましょう。最初の文は、読み取り整合性のためのグラフ設定を行います。2つ目の文は、すべての頂点について、値がread vertexであるフィールドnameに対してカウントを実行します。
schema.config().option('graph.tx_groups.default.read_consistency').set('ALL');
g.V().has('name', 'read vertex').count()
Gremlin Serverでは、1つのトランザクションで両方の文が実行されます。このトランザクションの実行中に行われる変更は、両方のアクションが正常にコミットされた場合に適用されます。読み取り整合性の変更は、トランザクションが終了されないうちは実際には適用されません。したがって、この変更は、次のトランザクションで初めて有効になります。これらの文は、個別のリクエストとして順次処理されることはありません。

処理中にこのようなエラーが発生しないようにするには、アプリケーションで、スキーマ作成またはスキーマ構成と探索クエリーを混在させないでください。グラフ探索でグラフ・データベースに対してクエリーを実行する前にスキーマを作成して構成しておくことがベスト・プラクティスです。

OLTPクエリーの実行時間が長すぎることを示すInterruptedException

一般的に、このような例外がログに記録されていた場合、OLTPクエリーの実行時間が長すぎることを意味します。 その一般的な原因は、グラフ探索クエリーで使用する要素のインデックスが作成されていないことです。インデックスを作成し、クエリーを再試行してください。