翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
ラベル付きプロパティグラフのプールモデル
Amazon Neptune の LPGsには 3 つの異なるアプローチがあります。
-
プロパティ戦略 - Apache TinkerPop Gremlin 言語の PartitionStrategy
など、確立されたライブラリコンストラクトの使用をパフォーマンスよりも優先する必要がある場合は、プロパティ戦略を選択します。 -
プレフィックスラベル戦略 ‒ パフォーマンスとノイズの多い近隣効果の制限に基づいて、ほとんどのシナリオでプレフィックスラベル戦略をお勧めします。
-
マルチラベル戦略 ‒ マルチラベル戦略では、プレフィックスラベル戦略のパフォーマンスが向上しています。また、クラスター上のすべてのテナントにまたがるクエリの実行もサポートされています (たとえば、すべてのテナントでレポートまたはモニタリングするための ISV クエリ)。
プロパティ戦略
LPGs、ユーザーはキーと値のペアのプロパティをノード、頂点、エッジに追加できます。論理的な分離を実現するために、ほとんどのお客様は、これをすべてのノードとエッジで共通のテナントプロパティキーを持つ一意のプロパティとして直感的にモデル化します。テナントプロパティキーは、ノードを所有するすべてのテナントを表します。テナント識別子は、個々のテナントを識別する一意の値です。
次の図は、このモデルを示しています。切断された 2 つのサブグラフには、さまざまなラベル付きノードとエッジがあり、テナントプロパティキーは で表されますTId。1 つのサブグラフのすべてのノードとエッジのTId値は です1。もう 1 つのサブグラフでは、すべてのノードとエッジのTId値は です2。
ラベル付きプロパティグラフ内では、これを管理する方法が 2 つあります。Gremlin クエリ言語は、 データのデータパーティショニングの管理に役立つ PartitionStrategyTId。
strategy1 = new PartitionStrategy(partitionKey: "TId", writePartition: "1", readPartitions: ["1"]) strategy2 = new PartitionStrategy(partitionKey: "TId", writePartition: "2", readPartitions: ["2"])
新しいノードまたはエッジが書き込まれると、 プロパティ"TId"は、 "1" または のどちらが選択されたかに応じて"2"、 strategy1または の値で追加strategy2されます。が "TId"のお客様は"1"、 を使用しますstrategy1。次の例は、その顧客のデータの書き込みを示しています。
g.withStrategies(strategy1).addV("Label1").property("Value", "123456").property(id, "Item_1")
読み取りクエリの場合、 "TId == '1'" または のフィルタ"TId == '2'"はstrategy2、それぞれ strategy1または を使用してすべてのノードまたはエッジトラバーサルに追加されます。これらのパーティション戦略はコードを簡素化しますが、必須ではありません。戦略を使用する利点は、認可レベルで挿入し、クエリを形成する下位レベルのコードに渡すことができることです。これにより、顧客識別子 (TId) を決定するコードとクエリのロジックが分離されます。
次のコード例は、データを読み取るための Gremlin クエリを示しています。
g.withStrategies(strategy1).V().hasLabel("Label1")
上記のコードは、次の例と同等です。
g.V().hasLabel("Label1").has("TId", "1")
同様に、Gremlin を使用してデータを書き込む場合は、次のクエリを使用できます。
g.withStrategies(strategy1).addV("Label1").property("Value").property(id, "Item_1")
上記のコードは、パーティション戦略を使用しないため、 "TId"プロパティを明示的に記述する必要がある次の例と同等です。
g.addV("Label1").property("TId", "1").property("Value").property(id, "Item_1")
openCypher では、これらのライブラリは存在しません。テナント識別子をノードとエッジのプロパティとして追加するには、クエリを記述して変更する必要があります。例えば、次のようになります。
CREATE (n:Item {`~id`: 'Item_1', Value: '123456', TId: '1'}) CREATE (n:Item {`~id`: 'Item_2', Value: '123456', TId: '2'})
パーティション戦略を使用しない Gremlin コード間の類似性に注意してください。その後、次のコードを使用して、最初のCREATEステートメントから書き込まれたノードを読み取ることができます。
MATCH (n:Item {TId: '1'}) RETURN n --or MATCH (n:Item) WHERE n.TId == '1' RETURN n
PartitionStrategy などのネイティブ TinkerPop Gremlin コンストラクトを使用する場合は、プロパティ戦略を選択できます。ただし、このモデルには、プレフィックスラベル戦略と比較して、Amazon Neptune のパフォーマンス上の欠点があります。これらのパフォーマンスの欠点については、「LPG モデルのパフォーマンスへの影響」セクションを参照してください。
次の条件が適用される場合は、プロパティ戦略をエッジではなくノードでのみモデリングすることを検討してください。
-
グラフのエッジはラベルよりも大幅に多くなります。
-
各テナントは切断されたグラフです。
-
グラフにアクセスするには、ラベルではなくノードを開始点として使用します。
プレフィックスラベル戦略
パフォーマンスが最大の懸念事項である場合は、プロパティ戦略よりもプレフィックスラベル戦略を検討することを強くお勧めします。
プレフィックスラベル戦略では、各ノードにテナント識別子とノードラベルの組み合わせでラベル付けします。たとえば、テナントの識別子が "1"で、ノードラベルが の場合"Label1"、ノードラベルを として指定します"1-Label1"。次の図は、このモデルを使用する 2 つの切断されたサブグラフを示しています。
Gremlin でデータを書き込むときは、任意のノードのラベルに識別番号を追加できます。
g.addV("1-Label1") g.addV("2-Label6")
このグラフをクエリするときは、ノードにこのプレフィックスが存在するかどうかを確認できます。
g.V().hasLabel("1-Label1")
openCypher では、 CREATEステートメントを使用してデータを書き込むことができます。
CREATE (n:`1-Label1` {`~id`: 'Item_1', Value: 'XYZ123456'})
openCypher で書き込んだデータをクエリするには、次のコードを使用します。
MATCH n= (:`1-Label1`) RETURN n
プレフィックスラベル戦略では、すべてのノードが 1 つ以上のテナントに割り当てられ、アクセス許可がエッジスコープに割り当てられていないことを前提としています。多数の述語を引き起こし、Neptune のパフォーマンスに悪影響を及ぼすため、エッジラベルにこの戦略を使用しないでください。
プレフィックスラベルアプローチには 2 つの主な欠点があります。まず、テナント間でクエリを実行することは困難です。一例は、レポートまたはモニタリングのために特定のラベルのすべてのノードをカウントするクエリです。これがユースケースである場合は、この戦略を複数ラベル戦略と組み合わせることを検討してください。戦略の組み合わせの詳細については、「ハイブリッドモデル」セクションを参照してください。
次に、プレフィックスラベル戦略では、データ漏洩を防ぐために、すべてのクエリに適切なプレフィックスを適切に適用するコントロールが必要です。ただし、この戦略は低レイテンシーのクエリを必要とするワークロードにとって最も効率的なオプションであり、強くお勧めします。LPG モデルのパフォーマンスへの影響セクションでは、これが最も効率的な戦略である理由の例を示します。
マルチラベル戦略
3 番目のオプションは、複数ラベル戦略を使用することです。このアプローチでは、グラフ上のすべてのノードにラベルを追加します。たとえば、特定のテナントのすべてのデータをフィルタリングする必要がある場合は、テナント ID ラベルを追加します。テナントに関係なく、特定のラベルのすべてのデータをフィルタリングする必要がある場合は、そのラベルを追加します。次の図は、ノードごとに 3 つのラベルを使用して適用される複数ラベル戦略を示しています。
次の 3 つの異なるパターンを使用してグラフにアクセスできるようになりました。
-
をフィルタリング
Label1して、すべてのテナントLabel1で を持つすべてのノードを返します。 -
をフィルタリング
1して、テナント 1 のすべてのノードを返します。 -
をフィルタリング
1-Label1して、ラベルが のテナント 1 のみのすべてのノードを返しますLabel1。
LPGs、これを実装する方法は 2 つあります。
Gremlin では、SubgraphStrategy"Label1"。
g.withStrategies( new SubgraphStrategy( vertices=hasLabel("Label1") ) )
PartitionStrategy とは異なり、SubgraphStrategy はデータの読み取りにのみ影響し、データの書き込みには影響しません。データを書き込むには、各クエリにラベルを手動で割り当てます。
g.addV("Label1").property("Value","XYZ123456") .addV("Label2").property("Value","XYZ123456")
データを読み取るときは、SubgraphStrategy を使用して ですべてのノードをクエリできます"Label1"。
g.withStrategies( new SubgraphStrategy(vertices=.hasLabel("Label1")) ). V().has("Value","XYZ123456")
Neptune は、 "Label1"と の値を持つ最初のレコードのみを返します"XYZ123456"。これは、SubgraphStrategy を使用しない次のクエリに相当します。
g.V().hasLabel("Label1").hasValue("XYZ123456")
この基本的なクエリでは、SubgraphStrategy の使用がより複雑であるように見えます。ライブラリは、既に定義された戦略gで のインスタンスを提供できることに注意してください。開発者は、適切なフィルターが適用されていることを確認する必要はありません。
def getGraphTraversal(): return g.withStrategies(new SubgraphStrategy(vertices=.hasLabel("Label1")) getGraphTraversal().has("Value","XYZ123456")
openCypher ライブラリにはこれらのコンストラクトがないため、ノードごとに複数のラベルを作成する必要があります。
CREATE (n:`1`:`Label1`:`1-Label1` {`~id`: 'Item_1', Value: '12345'})
これらのラベルを使用してサブグラフをフィルタリングする場合、探している顧客ラベルを持つノード、またはそのラベルを持つ別のノードとの関係を共有するノードを返すことができます。
MATCH n=(:Label1:`1`) // or MATCH n=(:`1-Label1`)
マルチラベル戦略を使用すると、ノードをタイプ (Label1) またはテナント () でクエリしたり、パフォーマンスが最も重要である場合により効率的なプレフィックスラベル戦略 (1) を使用したりする柔軟性が高まります1-Label1。
この戦略の主な欠点は、各ラベルがグラフに保存されている追加のオブジェクトであることです。オブジェクトは、LPGs。取り込み速度は 1 秒あたりのオブジェクトによって測定され、バインドされます。ストレージコストは消費されたギガバイト数によって異なります。つまり、追加のオブジェクトは大規模な測定可能な影響を与える可能性があります。
LPG モデルのパフォーマンスへの影響
Amazon Neptune AWS のスキルビルダーコースのデータモデリングでは、Neptune データモデルの内部とモデリングの影響について詳しく説明しますが、これらの設計に関する重要な考慮事項をここで要約します。 Amazon Neptune
-
テナント 1 (T1) には合計 1 億のノードがあり、1,000 万のノードは Item 型です。
-
テナント 2 (T2) には合計 1,000 万ノードがあり、100 万ノードは Item 型です。
-
Tenant 3 (T3) には合計 1 億のノードがあり、100 万のノードは Item 型です。
プロパティ戦略を使用して、テナント 3 の項目を取得するクエリを実行します。Neptune は、2 つのインデックス呼び出しの統計を検査します。
-
tenant property key=T3に 1 億件の結果がある -
label = Itemに 1,200 万件の結果がある (T1 から T1,000 万件 + T2 から 100 万件 + T3 から 100 万件)
Neptune クエリオプティマイザは、後者のクエリが最初に適用されるのが最適であると判断し (1,200 万の結果)、各項目で を検査しますtenant property key=T3。1,200 万件の項目を取得して、100 万件の結果を見つけます。
このクエリのノイズの多い近隣の影響に注目してください。テナントあたり 1 億のアイテムノードがある場合、最初のクエリの結果は 1,200 万ではなく 3 億になります (これは説明のために過度に単純化されています。 Neptune オプティマイザは、異なる順序のオペレーションを適用した可能性があります)。
次に、プレフィックスラベル戦略を検討します。100 万件の結果を 返す で label=T3-Item1 回のインデックス呼び出しを行います。これにより、プロパティ戦略と同じ結果が得られますが、取得するレコードは 1,100 万件少なくなります。さらに、ラベルがインデックス内で重複しないため、ノイズの多い近隣の懸念がなくなりました。
マルチラベル戦略では、プロパティ戦略よりもクエリパフォーマンスが直接向上することはありません。プロパティ値によるフィルタリングは、検索スペースが比較可能な場合、ラベル値によるフィルタリングと同等です。代わりに、複数ラベル戦略はより柔軟性をサポートします。 マルチラベル戦略は、 label=T3または ラベル のプレフィックスラベル戦略と同等のパフォーマンスを提供しますT3-Item。マルチラベル戦略は、 のプロパティ戦略と同等のパフォーマンスを提供しますlabel=Item。利点は、さまざまなアクセスパターンをサポートすることです。