

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Neptune Graph のクエリ
<a name="access-graph-queries"></a>

Neptune では、グラフにアクセスするための次のグラフクエリ言語がサポートされています。
+ [Gremlin](https://tinkerpop.apache.org/gremlin.html) は [Apache TinkerPop](https://tinkerpop.apache.org/) で定義され、プロパティグラフの作成とクエリに使用します。

  Gremlin のクエリは個別のステップで構成されたトラバーサルで、各ステップはエッジからノードに従います。

  Neptune での Gremlin の使用については [Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md) を参照し、[Amazon Neptune の Gremlin 標準への準拠](access-graph-gremlin-differences.md) Gremlin の Neptune 実装に関する具体的な詳細をご覧ください。
+ [openCypher](access-graph-opencypher.md) は、プロパティグラフの宣言型クエリ言語です。当初は Neo4j が開発し、その後 2015 年にオープンソース化され、Apache 2 オープンソースライセンスの下で [opencyPher](http://www.opencypher.org/) プロジェクトで活用されました。その構文は [openCypher 仕様書](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf)に記載されています。
+ [SPARQL](https://www.w3.org/TR/sparql11-overview/) は、[RDF](https://www.w3.org/2001/sw/wiki/RDF) データクエリ用のグラフパターンマッチングに基づく宣言型言語です。これは、[ワールド・ワイド・ウェブ・コンソーシアム](https://www.w3.org/)が対応しています。

  Neptune で SPARQL を使用する方法について、[SPARQL を使用した Neptune グラフへのアクセス](access-graph-sparql.md) を参照してください。また、SPARQL の Neptune 実装に関する具体的な詳細については [Amazon Neptune の SPARQL 標準準拠](feature-sparql-compliance.md) ご覧ください。

**注記**  
Gremlin と openCypher はどちらも、ロード方法に関係なく、Neptune に保存されているプロパティグラフデータのクエリに使用できます。

**Topics**
+ [Amazon Neptune でのクエリキューイング](access-graph-queuing.md)
+ [Amazon Neptune のクエリプランキャッシュ](access-graph-qpc.md)
+ [Neptune Gremlin または SPARQL クエリにカスタム ID を挿入する](features-query-id.md)
+ [Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)
+ [openCypher でNeptune グラフにアクセスする](access-graph-opencypher.md)
+ [SPARQL を使用した Neptune グラフへのアクセス](access-graph-sparql.md)

# Amazon Neptune でのクエリキューイング
<a name="access-graph-queuing"></a>

グラフアプリケーションを開発およびチューニングするときは、データベースによってクエリがキューに入れられる方法の意味を知っておくと便利です。Amazon Neptune では、クエリキューイングは次のように実行されます。
+ インスタンスのサイズに関係なく、インスタンスごとにキューに入れることができるクエリの最大数は 8,192 です。その数を超えるクエリは拒否され、`ThrottlingException` で失敗します。
+ 一度に実行できるクエリの最大数は、割り当てられたワーカースレッドの数によって決まります。通常、使用可能な仮想 CPU コア (vCPU) の数の 2 倍に設定されます。
+ クエリのレイテンシーには、クエリがキューに費やす時間、ネットワークのラウンドトリップ、および実際に実行に要する時間が含まれます。

## 特定の瞬間にキューにあるクエリの数を調べる
<a name="access-graph-queuing-count"></a>

`MainRequestQueuePendingRequests` メトリクスは、入力キューで待機しているリクエストの数を 5 分単位で記録します ([Neptune CloudWatch メトリクス](cw-metrics.md) を参照)。

Gremlin の場合、`acceptedQueryCount` により返された [Gremlin クエリステータス API](gremlin-api-status.md) 値を使用して、キュー内の現在のクエリ数を取得できます。ただし、`acceptedQueryCount` により返される [SPARQL クエリステータス API](sparql-api-status.md) 値には、完了したクエリを含め、サーバーの起動後に受け入れられたすべてのクエリが含まれます。

## クエリキューイングがタイムアウトに与える影響
<a name="access-graph-queuing-timeouts"></a>

前述のように、クエリのレイテンシーには、クエリがキューで費やす時間と、実行に要する時間が含まれます。

通常、クエリのタイムアウト期間はキューに入った時点から測定されるため、キューの動きが遅い場合、キューから出されると多くのクエリがすぐにタイムアウトになる可能性があります。これは明らかに望ましくないため、迅速に実行できる場合を除き、多数のクエリをキューに入れることは避けてください。

# Amazon Neptune のクエリプランキャッシュ
<a name="access-graph-qpc"></a>

 クエリが Neptune に送信されると、クエリ文字列が解析、最適化され、クエリプランに変換されて、エンジンによって実行されます。アプリケーションは、多くの場合に、異なる値でインスタンス化された一般的なクエリパターンによってバックアップされます。クエリプランキャッシュは、クエリプランをキャッシュすることで全体的なレイテンシーを低減し、このような繰り返しパターンの解析と最適化を回避できます。

 クエリプランキャッシュは、パラメータ化されていないクエリとパラメータ化されたクエリの両方の **OpenCypher** クエリに使用できます。READ では、HTTP と Bolt に対して有効になっています。OC ミューテーションクエリではサポート**されていません**。Gremlin または SPARQL クエリではサポート**されていません**。

## クエリプランキャッシュを強制的に有効または無効にする方法
<a name="access-graph-qpc-enable"></a>

 クエリプランキャッシュは、低レイテンシーのパラメータ化されたクエリに対してデフォルトで有効になっています。パラメータ化されたクエリのプランは、レイテンシーがしきい値の **100 ミリ秒**を下回った場合にのみキャッシュに保存されます。この動作は、クエリレベルのクエリヒント `QUERY:PLANCACHE` によって、クエリごとに (パラメータ化されているかどうかにかかわらず) 上書きできます。`USING` 句と併用する必要があります。クエリヒントは、値として `enabled` または `disabled` を受け入れます。

```
# Forcing plan to be cached or reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
  
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  -d "parameters={\"arg\": 123}"
  
# Forcing plan to be neither cached nor reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

## プランがキャッシュに保存されているかどうかを判断する方法
<a name="access-graph-qpc-status"></a>

 HTTP READ の場合は、クエリが送信され、プランがキャッシュに保存されると、`explain` はクエリプランのキャッシュに関連する詳細を表示します。

```
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1" \
  -d "explain=[static|details]"

Query: <QUERY STRING>
Plan cached by request: <REQUEST ID OF FIRST TIME EXECUTION>
Plan cached at: <TIMESTAMP OF FIRST TIME EXECUTION>
Parameters: <PARAMETERS, IF QUERY IS PARAMETERIZED QUERY>
Plan cache hits: <NUMBER OF CACHE HITS FOR CACHED PLAN>
First query evaluation time: <LATENCY OF FIRST TIME EXECUTION>

The query has been executed based on a cached query plan. Detailed explain with operator runtime statistics can be obtained by running the query with plan cache disabled (using HTTP parameter planCache=disabled).
```

 Bolt を使用する場合について、説明機能はサポートされていません。

## エビクション
<a name="access-graph-qpc-eviction"></a>

 クエリプランは、キャッシュの有効期限 (TTL) またはキャッシュに保存されたクエリプランの最大数に達したときにエビクトされます。クエリプランがヒットすると、TTL が更新されます。デフォルトは次のとおりです。
+  1,000 – インスタンスごとにキャッシュに保存できるプランの最大数。
+  TTL – 300,000 ミリ秒または 5 分。キャッシュヒットは TTL を再起動し、5 分にリセットします。

## プランがキャッシュに保存されない原因となる条件
<a name="access-graph-qpc-conditions"></a>

 クエリプランキャッシュは、次の条件下では使用されません。

1.  クエリヒント `QUERY:PLANCACHE "disabled"` を使用してクエリが送信された場合。クエリを再実行して `QUERY:PLANCACHE "disabled"` を削除し、クエリプランキャッシュを有効にできます。

1.  送信されたクエリがパラメータ化されたクエリではなく、ヒント `QUERY:PLANCACHE "enabled"` が含まれていない場合。

1.  クエリ評価時間がレイテンシーのしきい値より長い場合、クエリはキャッシュに保存されず、クエリプランキャッシュのメリットが得られない長時間実行クエリであるとみなされます。

1.  クエリに結果を返さないパターンが含まれている場合。
   +  つまり、指定されたラベルを持つノードがゼロの `MATCH (n:nonexistentLabel) return n` の場合です。
   +  つまり、`name=abcde` を含むノードがゼロ個の場合は、`parameters={"param": "abcde"}` で `MATCH (n {name: $param}) return n` を使用します。

1.  クエリパラメータが `list` や `map` などの複合型である場合。

   ```
   curl -k https://<endpoint>:<port>/opencypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": [1, 2, 3]}"
   
   curl -k https://<endpoint>:<port>/opencypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": {\"a\": 1}}"
   ```

1.  クエリパラメータがデータロードまたはデータ挿入オペレーションに含まれていない文字列である場合。例えば、`CREATE (n {name: "X"})` が `"X"` を挿入するために実行されている場合、`RETURN "X"` はキャッシュに保存されますが、`"Y"` が挿入されておらずデータベースに存在しないため `RETURN "Y"` はキャッシュに保存されません。

# Neptune Gremlin または SPARQL クエリにカスタム ID を挿入する
<a name="features-query-id"></a>

デフォルトでは、Neptune はすべてのクエリに一意の `queryId` 値を割り当てます。この ID を使用して、実行中のクエリに関する情報を取得する (「[Gremlin クエリステータス API](gremlin-api-status.md)」または「[SPARQL クエリステータス API](sparql-api-status.md)」を参照) か、キャンセル (「[Gremlin クエリのキャンセル](gremlin-api-status-cancel.md)」または「[SPARQL クエリのキャンセル](sparql-api-status-cancel.md)」を参照) できます。

また、Neptune では、`queryId` クエリヒントを使用して、HTTP ヘッダーまたは SPARQL クエリのいずれかで、Gremlin または SPARQL クエリに独自 `queryId` の値を指定することもできます。独自の `queryID` を割り当てると、クエリを簡単に追跡してステータスの取得やキャンセルを行えます。

## HTTP ヘッダーを使用してカスタム `queryId` 値を挿入する
<a name="features-query-id-header"></a>

Gremlin と SPARQL の両方で、HTTP ヘッダーを使用して独自の `queryId` 値をクエリに挿入できます。

**Gremlin の例**

```
curl -XPOST https://your-neptune-endpoint:port \
    -d "{\"gremlin\": \
        \"g.V().limit(1).count()\" , \
        \"queryId\":\"4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47\"  }"
```

**SPARQL の例**

```
curl https://your-neptune-endpoint:port/sparql \
    -d "query=SELECT * WHERE { ?s ?p ?o } " \
       --data-urlencode \
       "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

## SPARQL クエリヒントを使用してカスタム `queryId` 値を挿入する
<a name="features-query-id-hint"></a>

SPARQL `queryId` クエリヒントを使用して SPARQL クエリにカスタム `queryId` 値を挿入する方法の例を次に示します。

```
curl https://your-neptune-endpoint:port/sparql \
    -d "query=PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#> \
       SELECT * WHERE { hint:Query hint:queryId \"4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47\" \
       {?s ?p ?o}}"
```

## `queryId` 値を使用してクエリステータスを確認する
<a name="features-query-id-check-status"></a>

**Gremlin の例**

```
curl https://your-neptune-endpoint:port/gremlin/status \
    -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

**SPARQL の例**

```
curl https://your-neptune-endpoint:port/sparql/status \
    -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

# Gremlin を使用した Neptune グラフへのアクセス
<a name="access-graph-gremlin"></a>

Amazon Neptune は Apache TinkerPop および Gremlin と互換性があります。つまり、Neptune DB インスタンスに接続し、Gremlin トラバーサル言語を使用してグラフをクエリできます (Apache TinkerPop [ドキュメント](https://tinkerpop.apache.org/docs/current/reference/#graph)の「グラフ」を参照）。Gremlin の Neptune 実装の相違点については、[Gremlin の標準コンプライアンス](access-graph-gremlin-differences.md)を参照してください。

 Gremlin の*トラバーサル*は、一連の連鎖ステップです。頂点 (またはエッジ) で始まります。各頂点から出ていくエッジに沿って、さらに、これらの頂点から出ていくエッジをたどってグラフを描きます。各ステップはトラバーサルの操作です。詳細については、TinkerPop [ドキュメントの「トラバーサル](https://tinkerpop.apache.org/docs/current/reference/#traversal)」を参照してください。

Neptune エンジンのバージョンによって、サポートされる Gremlin のバージョンは異なります。実行中の Neptune バージョンの[エンジンリリースページ](engine-releases.md)をチェックして、サポートされている Gremlin リリースを確認するか、次の表を参照してください。この表には、さまざまな Neptune エンジンバージョンでサポートされている TinkerPop の最も古いバージョンと最新バージョンが一覧表示されています。


| Neptune エンジンバージョン | 最小 TinkerPop バージョン | 最小 TinkerPop バージョン | 
| --- | --- | --- | 
| `1.3.2.0 and newer` | `3.7.1` | `3.7.3` | 
| `1.3.1.0` | `3.6.2` | `3.6.5` | 
| `1.3.0.0` | `3.6.2` | `3.6.4` | 
| `1.2.1.0 <= 1.2.1.2` | `3.6.2` | `3.6.2` | 
| `1.1.1.0 <= 1.2.0.2` | `3.5.5` | `3.5.6` | 
| `1.1.0.0 and older` | `(deprecated)` | `(deprecated)` | 

TinkerPop クライアントは通常、シリーズ ( `3.6.x`や など`3.7.x`) 内で下位互換性があります。多くの場合、これらの境界を越えて動作しますが、上記の表では、可能な限り最高のエクスペリエンスと互換性を得るために バージョンの組み合わせを推奨しています。特に明記されていない限り、これらのガイドラインに従い、使用している TinkerPop のバージョンに合わせてクライアントアプリケーションをアップグレードすることをお勧めします。

TinkerPop バージョンをアップグレードするときは、[TinkerPop のアップグレードドキュメント](http://tinkerpop.apache.org/docs/current/upgrade/)を参照することが常に重要です。このドキュメントは、利用できる新機能を特定するだけでなく、アップグレードに近づいたときに注意が必要な問題を特定するのに役立ちます。特に考慮すべき問題として呼び出されない限り、通常はアップグレード後に既存のクエリと機能が機能することを想定する必要があります。最後に、新しい機能を持つようにアップグレードしたバージョンは、Neptune がサポートするバージョン以降のバージョンでは使用できない場合があることに注意してください。

さまざまなプログラミング言語による Gremlin 言語バリアントおよび Gremlin アクセスのサポートがあります。詳細については、TinkerPop [ドキュメントの「Gremlin 言語バリアント](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants)」を参照してください。

このドキュメントでは、以下のバリアントとプログラミング言語で Neptune にアクセスする方法について説明します。
+ [Gremlin コンソールをセットアップして Neptune DB インスタンスに接続する](access-graph-gremlin-console.md)
+ [HTTPS REST エンドポイントを使用して Neptune DB インスタンスに接続する](access-graph-gremlin-rest.md)
+ [Amazon Neptune で使用する Java ベースの Gremlin クライアント](access-graph-gremlin-client.md)
+ [Python を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-python.md)
+ [.NET を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-dotnet.md)
+ [Node.js を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-node-js.md)
+ [Go を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-go.md)

[SSL/HTTPS を使用した Amazon Neptune データベースへの接続の暗号化](security-ssl.md) で説明されているように、すべての AWS リージョンで Neptune に接続するときには、Transport Layer Security/Secure Sockets Layer (TLS/SSL) を使用する必要があります。

始めるには以下のものが必要です。
+ Neptune DB インスタンス。Neptune DB インスタンスの作成については、[Amazon Neptune クラスターの作成](get-started-create-cluster.md) を参照してください。
+ Neptune DB インスタンスと同じ Virtual Private Cloud (VPC) にある Amazon EC2; インスタンス。

前提条件、ロード形式、およびロードパラメータを含む Neptune へのデータのロードの詳細については、[Amazon Neptune にデータをロードする](load-data.md)を参照してください。

**Topics**
+ [Gremlin コンソールをセットアップして Neptune DB インスタンスに接続する](access-graph-gremlin-console.md)
+ [HTTPS REST エンドポイントを使用して Neptune DB インスタンスに接続する](access-graph-gremlin-rest.md)
+ [Amazon Neptune で使用する Java ベースの Gremlin クライアント](access-graph-gremlin-client.md)
+ [Python を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-python.md)
+ [.NET を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-dotnet.md)
+ [Node.js を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-node-js.md)
+ [Go を使用して Neptune DB インスタンスに接続する](access-graph-gremlin-go.md)
+ [AWS SDK を使用して Gremlin クエリを実行する](access-graph-gremlin-sdk.md)
+ [Gremlin クエリヒント](gremlin-query-hints.md)
+ [Gremlin クエリステータス API](gremlin-api-status.md)
+ [Gremlin クエリのキャンセル](gremlin-api-status-cancel.md)
+ [Gremlin スクリプトベースのセッションのサポート](access-graph-gremlin-sessions.md)
+ [Neptune での Gremlin トランザクション](access-graph-gremlin-transactions.md)
+ [Amazon Neptune で Gremlin API を使用する](gremlin-api-reference.md)
+ [Amazon Neptune Gremlin でクエリ結果をキャッシュする](gremlin-results-cache.md)
+ [Gremlin `mergeV()` および `mergeE()` ステップによる効率的なアップサートの実行](gremlin-efficient-upserts.md)
+ [`fold()/coalesce()/unfold()` による効率的な Gremlin アップサートの実行](gremlin-efficient-upserts-pre-3.6.md)
+ [Gremlin を使用して Neptune クエリ実行を分析する`explain`](gremlin-explain.md)
+ [Gremlin と Neptune DFE クエリエンジンを使用する](gremlin-with-dfe.md)

# Gremlin コンソールをセットアップして Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-console"></a>

Gremlin Console により、REPL (read-eval-print loop) 環境で TinkerPop グラフおよびクエリを試してみることができます。

## Gremlin コンソールをインストールし、通常の方法で接続する
<a name="access-graph-gremlin-console-usual-connect"></a>

Gremlin Console を使用して、リモートグラフデータベースに接続できます。次のセクションでは、Neptune DB インスタンスにリモートで接続するための Gremlin Console のインストールと設定について説明します。Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

SSL/TLS (必須) で Neptune に接続する方法については、「[SSL/TLS 設定](access-graph-gremlin-java.md#access-graph-gremlin-java-ssl)」を参照してください。

**注記**  
[IAM 認証の有効化](iam-auth-enable.md)を Neptune DB クラスターで行った場合、ここでの手順ではなく [Gremlin コンソールでの IAM 認証を使用した Amazon Neptune データベースへの接続](iam-auth-connecting-gremlin-console.md) の手順に従い、Gremlin Console をインストールします。

**Gremlin Console をインストールして Neptune に接続するには**

1. Gremlin Console バイナリには Java 8 または Java 11 が必要です。これらの手順は Java 11 の使用を前提としています。次のように EC2 インスタンスに Java 11 をインストールできます。
   + [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2) を使用している場合:

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + [Amazon Linux 2023 (AL2023)](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html) を使用している場合:

     ```
     sudo yum install java-11-amazon-corretto-devel
     ```
   + 他のディストリビューションでは、以下のうち適切なものを使用してください。

     ```
     sudo yum install java-11-openjdk-devel
     ```

     または

     ```
     sudo apt-get install openjdk-11-jdk
     ```

1. 次のように入力して、EC2 インスタンスで Java 11 をデフォルトのランタイムとして設定します。

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   プロンプトが表示されたら、Java 11 の数を入力します。

1. Apache ウェブサイトから適切なバージョンの Gremlin コンソールをダウンロードします。Neptune のバージョンでサポートされている [Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md) Gremlin バージョンを確認できます。たとえば、バージョン 3.7.2 が必要な場合は、[次のように Apache Tinkerpop](https://tinkerpop.apache.org/download.html) ウェブサイトから EC2 インスタンスに [Gremlin コンソール](https://archive.apache.org/dist/tinkerpop/3.7.2/apache-tinkerpop-gremlin-console-3.7.2-bin.zip)をダウンロードできます。

   ```
   wget https://archive.apache.org/dist/tinkerpop/3.7.2/apache-tinkerpop-gremlin-console-3.7.2-bin.zip
   ```

1. Gremlin Console zip ファイルを解凍します。

   ```
   unzip apache-tinkerpop-gremlin-console-3.7.2-bin.zip
   ```

1. ディレクトリを解凍ディレクトリに変更します。

   ```
   cd apache-tinkerpop-gremlin-console-3.7.2
   ```

1. 抽出されたディレクトリにある `conf` サブディレクトリで、以下のテキストを含む `neptune-remote.yaml` という名前のファイルを作成します。*your-neptune-endpoint*を Neptune DB インスタンスのホスト名または IP アドレスで置き換えます。角括弧 (`[ ]`) が必要です。
**注記**  
Neptune DB インスタンスのホスト名を見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   ```
   hosts: [your-neptune-endpoint]
   port: 8182
   connectionPool: { enableSsl: true }
   serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1,
                 config: { serializeResultToString: true }}
   ```
**注記**  
 バージョン 3.7.0 では、シリアライザーが `gremlin-driver` モジュールから新しい `gremlin-util` モジュールに移動されました。パッケージが org.apache.tinkerpop.gremlin.driver.ser から org.apache.tinkerpop.gremlin.util.ser に変更されました。

1. ターミナルで Gremlin コンソールディレクトリ (`apache-tinkerpop-gremlin-console-3.7.2`) に移動し、次のコマンドを入力して Gremlin コンソールを実行します。

   ```
   bin/gremlin.sh
   ```

   以下の出力が表示されます。

   ```
            \,,,/
            (o o)
   -----oOOo-(3)-oOOo-----
   plugin activated: tinkerpop.server
   plugin activated: tinkerpop.utilities
   plugin activated: tinkerpop.tinkergraph
   gremlin>
   ```

   `gremlin>` プロンプトが表示されます。このプロンプトで残りのステップを入力します。

1. `gremlin>` プロンプトで、次のように入力して Neptune DB インスタンスに接続します。

   ```
   :remote connect tinkerpop.server conf/neptune-remote.yaml
   ```

1. `gremlin>` プロンプトで、次のように入力してリモートモードに切り替えます。これにより、すべての Gremlin クエリがリモート接続に送信されます。

   ```
   :remote console
   ```

1. Gremlin グラフにクエリを送信するには、次のように入力します。

   ```
   g.V().limit(1)
   ```

1. 完了したら、次のように入力して Gremlin コンソールを終了します。

   ```
   :exit
   ```

**注記**  
各ステートメントを区切るには、セミコロン (`;`) または改行文字 (`\n`) を使用します。  
最終的なトラバーサルに先行する各トラバーサルは、`next()` を実行して終わる必要があります。最終的なトラバーサルからのデータのみが返されます。

Gremlin の Neptune 実装の詳細については、[Amazon Neptune の Gremlin 標準への準拠](access-graph-gremlin-differences.md)を参照してください。

# Gremlin コンソールに接続する別の方法
<a name="access-graph-gremlin-console-connect"></a>

**通常の接続方法の欠点**

Gremlin コンソールに接続する最も一般的な方法は上で説明したものであり、`gremlin>` プロンプトで次のようなコマンドを使用します。

```
gremlin> :remote connect tinkerpop.server conf/(file name).yaml
gremlin> :remote console
```

これはうまく機能し、Neptune にクエリを送信できます。ただし、Groovy スクリプトエンジンがループから外れるため、Neptune はすべてのクエリを純粋な Gremlin として扱います。つまり、以下のクエリフォームは失敗します。

```
gremlin> 1 + 1
gremlin> x = g.V().count()
```

このように接続したときに変数を使うのに一番近いのは、コンソールに保持されている `result` 変数を使用し、次のようにして `:>` を使用してクエリを送信することです。

```
gremlin> :remote console
==>All scripts will now be evaluated locally - type ':remote console' to return to remote mode for Gremlin Server - [krl-1-cluster.cluster-ro-cm9t6tfwbtsr.us-east-1.neptune.amazonaws.com/172.31.19.217:8182]
gremlin> :> g.V().count()
==>4249

gremlin> println(result)
[result{object=4249 class=java.lang.Long}]

gremlin> println(result['object'])
[4249]
```

 

**別の接続方法**

次のように、別の方法で Gremlin コンソールに接続することもできます。

```
gremlin> g = traversal().withRemote('conf/neptune.properties')
```

ここでは、`neptune.properties` は次の形式です。

```
gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
gremlin.remote.driver.clusterFile=conf/my-cluster.yaml
gremlin.remote.driver.sourceName=g
```

`my-cluster.yaml` ファイル名は次のようになります。

```
hosts: [my-cluster-abcdefghijk.us-east-1.neptune.amazonaws.com]
port: 8182
serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1,
              config: { serializeResultToString: false } }
connectionPool: { enableSsl: true }
```

**注記**  
 バージョン 3.7.0 では、シリアライザーが `gremlin-driver` モジュールから新しい `gremlin-util` モジュールに移動されました。パッケージが org.apache.tinkerpop.gremlin.driver.ser から org.apache.tinkerpop.gremlin.util.ser に変更されました。

Gremlin コンソール接続をこのように設定すると、以下の種類のクエリを正常に実行できます。

```
gremlin> 1+1
==>2

gremlin> x=g.V().count().next()
==>4249

gremlin> println("The answer was ${x}")
The answer was 4249
```

次のように、結果を表示せずに済みます。

```
gremlin> x=g.V().count().next();[]
gremlin> println(x)
4249
```

通常のクエリ方法 (ターミナルステップなし) はすべて引き続き機能します。例えば、次のようになります。

```
gremlin> g.V().count()
==>4249
```

[https://tinkerpop.apache.org/docs/current/reference/#io-step](https://tinkerpop.apache.org/docs/current/reference/#io-step) ステップを使用して、このような接続でファイルを読み込むこともできます。

## IAM 認証
<a name="access-graph-gremlin-console-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。Gremlin コンソールから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin コンソールでの IAM 認証を使用した Amazon Neptune データベースへの接続](iam-auth-connecting-gremlin-console.md)。

# HTTPS REST エンドポイントを使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-rest"></a>

Amazon Neptune では、Gremlin クエリ用の HTTPS エンドポイントが用意されています。REST インターフェイスは、DB クラスターが使用している Gremlin バージョンすべてと互換性があります (サポートしている Gremlin リリースを特定するには、実行中の Neptune エンジンバージョンの[エンジンリリースページ](engine-releases.md)を参照してください)。

**注記**  
[SSL/HTTPS を使用した Amazon Neptune データベースへの接続の暗号化](security-ssl.md) で説明したように、現在 Neptune では、HTTP ではなく HTTPS を使用して接続する必要があります。さらに、Neptune は現在 REST API リクエストの HTTP/2 をサポートしていません。クライアントは、エンドポイントに接続するときに HTTP/1.1 を使用する必要があります。

次の手順は、`curl` コマンドおよび HTTPS を使用して Gremlin エンドポイントに接続する方法について説明します。Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

Neptune DB インスタンスへの Gremlin クエリ用の HTTPS エンドポイントは `https://your-neptune-endpoint:port/gremlin` です。

**注記**  
Neptune DB インスタンスのホスト名を見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) を参照してください。

## HTTP REST エンドポイントを使用して Neptune に接続するには
<a name="access-graph-gremlin-rest-connect"></a>

次の例では、**curl** を使用して、HTTP **POST** を通じて Gremlin クエリを送信します。クエリは、投稿の本文にある JSON 形式で `gremlin` プロパティとして送信されます。

```
curl -X POST -d '{"gremlin":"g.V().limit(1)"}' https://your-neptune-endpoint:port/gremlin
```

この例では、`g.V().limit(1)` トラバーサルを使用してグラフの最初の頂点を返します。その他の対象にクエリを実行するには、別の Gremlin トラバーサルで置き換えます。

**重要**  
デフォルトでは、REST エンドポイントは、単一の JSON 結果セットですべての結果を返します。この結果セットが大きすぎる場合、Neptune DB インスタンスで`OutOfMemoryError` 例外が発生する可能性があります。  
これを回避するには、チャンク化応答 (結果は一連の個別の応答で返される) を有効にします。[オプションの HTTP 末尾ヘッダーを使用して、複数パートの Gremlin 応答を有効にする](access-graph-gremlin-rest-trailing-headers.md)を参照してください。

Gremlin クエリの送信には HTTP **POST** リクエストが推奨されますが、HTTP **GET**リクエストを使用することもできます。

```
curl -G "https://your-neptune-endpoint:port?gremlin=g.V().count()"
```

**注記**  
Neptune は、`bindings` プロパティをサポートしていません。

# オプションの HTTP 末尾ヘッダーを使用して、複数パートの Gremlin 応答を有効にする
<a name="access-graph-gremlin-rest-trailing-headers"></a>

デフォルトでは、Gremlin クエリに対する HTTP 応答は、単一の JSON 結果セットで返されます。結果セットが非常に大きい場合、これにより DB インスタンスの `OutOfMemoryError` 例外が生じます。

ただし、*チャンク化*応答 (複数の別々のパートで返される応答) を有効にすることができます。これを行うには、転送エンコーディング (TE) トレーラーのヘッダー (`te: trailers`) をリクエストします。TE ヘッダーの詳細については、[TE リクエストヘッダーに関する MDN ページ」](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)を参照してください。

応答が複数のパートで返された場合、最初のパートが受信された後に発生する問題を診断するのは難しい場合があります。これは、最初のパートが `200` (OK)の HTTP ステータスコードで到着するためです。その後は、通常、メッセージ本文に破損した応答が含まれるというエラー状態となり、その最後に Neptune はエラーメッセージを追加します。

この種の障害の検出と診断を容易にするために、Neptune では各応答チャンクの末尾ヘッダー内に 2 つの新しいヘッダーフィールドも含まれます。
+ `X-Neptune-Status`— 応答コードの後ろに短い名前が続きます。たとえば、成功した場合、末尾ヘッダーは次のようになります。`X-Neptune-Status: 200 OK`。失敗の場合、応答コードは、`X-Neptune-Status: 500 TimeLimitExceededException` といった[ Neptune エンジンのエラーコード](errors-engine-codes.md)となる可能性があります。
+ `X-Neptune-Detail`— 成功したリクエストでは空です。エラーの場合は、JSON エラーメッセージが含まれます。HTTP ヘッダー値には ASCII 文字しか使用できないため、JSON 文字列は URL 符号化されます。

**注記**  
Neptune はチャンク化応答の `gzip` 圧縮は現在サポートしていません。クライアントがチャンクエンコーディングと圧縮の両方を同時に要求すると、Neptune は圧縮をスキップします。

# Amazon Neptune で使用する Java ベースの Gremlin クライアント
<a name="access-graph-gremlin-client"></a>

Amazon Neptune では、次の 2 つのオープンソース Java ベースの Gremlin クライアントのいずれかを使用できます。[Apache TinkerPop Java Gremlin クライアント](https://search.maven.org/artifact/org.apache.tinkerpop/gremlin-driver)、または[Amazon Neptune Gremlin クライアント](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client)。

## Apache TinkerPop Java Gremlin クライアント
<a name="access-graph-gremlin-java-driver"></a>

Apache TinkerPop Java [gremlin-driver](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java) は、TinkerPop 対応グラフデータベースで動作する標準の公式 Gremlin クライアントです。このクライアントは、より広範な TinkerPop 開発スペースとの最大限の互換性が必要な場合、複数のグラフデータベースシステムを使用する場合、または Neptune に固有の高度なクラスター管理およびロードバランシング機能を必要としない場合に使用します。このクライアントは、単一の Neptune インスタンスに接続する単純なアプリケーションや、クライアント内ではなくインフラストラクチャレベルで負荷分散を処理する場合にも適しています。

**重要**  
Neptune エンジンバージョンとの互換性を保つには、正しい Apache TinkerPop Gremlin ドライバーバージョンを選択することが重要です。互換性のないバージョンを使用すると、接続の失敗や予期しない動作が発生する可能性があります。バージョンの互換性の詳細については、「」を参照してください[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。

**注記**  
Neptune で使用する正しい Apache TinkerPop バージョンを決定するのに役立つテーブルが に移動されました[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。この表は、以前はこのページに長年保存されており、TinkerPop がサポートするすべてのプログラミング言語の参照用に一元管理されています。

## Amazon Neptune 用 Gremlin Java クライアント
<a name="access-graph-neptune-gremlin-client"></a>

Amazon Neptune の Gremlin クライアントは、[オープンソースの Java ベースの Gremlin クライアント](https://github.com/aws/neptune-gremlin-client)で、標準的な TinkerPop Java クライアントのドロップインリプレースメントとして機能します。

Neptune Gremlin クライアントは Neptune クラスター用に最適化されています。これにより、クラスター内の複数のインスタンス間のトラフィックディストリビューションを管理し、レプリカを追加または削除するときに、クラスタートポロジの変更に適応できます。ロール、インスタンスタイプ、アベイラビリティーゾーン (AZ)、またはインスタンスに関連付けられたタグに基づいて、クラスター内のインスタンスのサブセットにリクエストを分散するようにクライアントを構成することもできます。

[Neptune Gremlin Java クライアントの最新バージョン](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client)は Maven Central で利用できます。

Neptune Gremlin Java クライアントの詳細については、[このブログ投稿](https://aws.amazon.com/blogs/database/load-balance-graph-queries-using-the-amazon-neptune-gremlin-client/)を参照してください。。コードサンプルとデモについては、[クライアントの GitHub プロジェクト](https://github.com/aws/neptune-gremlin-client)をご確認ください。

Neptune Gremlin クライアントのバージョンを選択するときは、Neptune エンジンバージョンに関連して基盤となる TinkerPop バージョンを考慮する必要があります。の互換性表を参照して Neptune エンジンの正しい TinkerPop バージョン[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)を確認し、次の表を使用して適切な Neptune Gremlin クライアントバージョンを選択します。


**Neptune Gremlin クライアントバージョンの互換性**  

| Neptune Gremlin クライアントバージョン | TinkerPop バージョン | 
| --- | --- | 
| 3.x | 3.7.x (AWS SDK for Java 2.x/1.x) | 
| 2.1.x | 3.7.x (AWS SDK for Java 1.x) | 
| 2.0.x | 3.6.x | 
| 1.12 | 3.5.x | 

# Java クライアントを使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-java"></a>

次のセクションでは、Neptune DB インスタンスに接続し、Apache TinkerPop Gremlin を使用して Gremlin トラバーサルを実行する完全な Java サンプルを実行する方法について説明します。

Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

**Java を使用して Neptune に接続するには**

1. Apache Maven を EC2 インスタンスにインストールします。Amazon Linux 2023 (推奨) を使用している場合は、以下の対象を使用します。

   ```
   sudo dnf update -y
   sudo dnf install maven -y
   ```

   Amazon Linux 2 を使用している場合は、[https://maven.apache.org/download.cgi:](https://maven.apache.org/download.cgi:) から最新のバイナリをダウンロードします。

   ```
   sudo yum remove maven -y
   wget https://dlcdn.apache.org/maven/maven-3/ <version>/binaries/apache-maven-<version>-bin.tar.gz
   sudo tar -xzf apache-maven-<version>-bin.tar.gz -C /opt/
   sudo ln -sf /opt/apache-maven-<version> /opt/maven
   echo 'export MAVEN_HOME=/opt/maven' >> ~/.bashrc
   echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> ~/.bashrc
   source ~/.bashrc
   ```

1. **Java をインストールします。**Gremlin ライブラリには Java 8 または 11 が必要です。Java 11 は以下のようにインストールできます。
   + [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2) を使用している場合:

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + [Amazon Linux 2023 (AL2023)](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html) を使用している場合:

     ```
     sudo yum install java-11-amazon-corretto-devel
     ```
   + 他のディストリビューションでは、以下のうち適切なものを使用してください。

     ```
     sudo yum install java-11-openjdk-devel
     ```

     または

     ```
     sudo apt-get install openjdk-11-jdk
     ```

1. **Java 11 を EC2 インスタンスのデフォルトランタイムとして設定:** 以下を入力して、Java 8 を EC2 インスタンスのデフォルトランタイムとして設定します。

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   プロンプトが表示されたら、Java 11 の数を入力します。

1. **`gremlinjava` という名前の新しいディレクトリを作成します。**

   ```
   mkdir gremlinjava
   cd gremlinjava
   ```

1.  `gremlinjava` ディレクトリで `pom.xml` ファイルを作成してから、テキストエディタで開きます。

   ```
   nano pom.xml
   ```

1. 以下の内容を `pom.xml` ファイルにコピーして保存します。

   ```
   <project xmlns="https://maven.apache.org/POM/4.0.0"
            xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
     <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.amazonaws</groupId>
     <artifactId>GremlinExample</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>GremlinExample</name>
     <url>https://maven.apache.org</url>
     <dependencies>
       <dependency>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-driver</artifactId>
         <version>3.7.2</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-jdk14</artifactId>
         <version>1.7.25</version>
       </dependency>
     </dependencies>
     <build>
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.5.1</version>
           <configuration>
             <source>11</source>
             <target>11</target>
           </configuration>
         </plugin>
           <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>exec-maven-plugin</artifactId>
             <version>1.3</version>
             <configuration>
               <executable>java</executable>
               <arguments>
                 <argument>-classpath</argument>
                 <classpath/>
                 <argument>com.amazonaws.App</argument>
               </arguments>
               <mainClass>com.amazonaws.App</mainClass>
               <complianceLevel>1.11</complianceLevel>
               <killAfter>-1</killAfter>
             </configuration>
           </plugin>
       </plugins>
     </build>
   </project>
   ```
**注記**  
既存の Maven プロジェクトを変更する場合、必要な依存関係が前述のコードにおいて強調表示されます。

1. コマンドラインで次のように入力して、ソースコード例 (`src/main/java/com/amazonaws/`) のサブディレクトリを作成します。

   ```
   mkdir -p src/main/java/com/amazonaws/
   ```

1. `src/main/java/com/amazonaws/` ディレクトリで `App.java` という名前のファイルを作成してから、テキストエディタで開きます。

   ```
   nano src/main/java/com/amazonaws/App.java
   ```

1. `App.java` ファイルに次の内容をコピーします。*your-neptune-endpoint* を Neptune DB インスタンスのアドレスで置き換えます。`addContactPoint` メソッドに `https://` プレフィックスを含めることは*できません*。
**注記**  
Neptune DB インスタンスのホスト名を見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) を参照してください。

   ```
   package com.amazonaws;
   import org.apache.tinkerpop.gremlin.driver.Cluster;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
   import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
   import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
   import org.apache.tinkerpop.gremlin.structure.T;
   
   public class App
   {
     public static void main( String[] args )
     {
       Cluster.Builder builder = Cluster.build();
       builder.addContactPoint("your-neptune-endpoint");
       builder.port(8182);
       builder.enableSsl(true);
   
       Cluster cluster = builder.create();
   
       GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
   
       // Add a vertex.
       // Note that a Gremlin terminal step, e.g. iterate(), is required to make a request to the remote server.
       // The full list of Gremlin terminal steps is at https://tinkerpop.apache.org/docs/current/reference/#terminal-steps
       g.addV("Person").property("Name", "Justin").iterate();
   
       // Add a vertex with a user-supplied ID.
       g.addV("Custom Label").property(T.id, "CustomId1").property("name", "Custom id vertex 1").iterate();
       g.addV("Custom Label").property(T.id, "CustomId2").property("name", "Custom id vertex 2").iterate();
   
       g.addE("Edge Label").from(__.V("CustomId1")).to(__.V("CustomId2")).iterate();
   
       // This gets the vertices, only.
       GraphTraversal t = g.V().limit(3).elementMap();
   
       t.forEachRemaining(
         e ->  System.out.println(t.toList())
       );
   
       cluster.close();
     }
   }
   ```

   SSL/TLS (必須) で Neptune に接続する方法については、「[SSL/TLS 設定](#access-graph-gremlin-java-ssl)」を参照してください。

1. 次の Maven コマンドを使用してサンプルをコンパイルおよび実行します。

   ```
   mvn compile exec:exec
   ```

前述の例では、`g.V().limit(3).elementMap()` トラバーサルを使用して最初の 2 つの頂点の各プロパティのキーと値のマップを返します。その他の対象にクエリを実行するには、いずれかの適切な終了メソッドを持つ Gremlin トラバーサルで置き換えます。

**注記**  
Gremlin クエリの最後の部分、`.toList()` では、評価のためにトラバーサルをサーバーに送信する必要があります。そのメソッドまたは別の同等のメソッドを含めない場合、クエリは Neptune DB インスタンスに送信されません。  
`addV( )` ステップの使用時などの頂点またはエッジを追加するときに、適切な終点を追加する必要もあります。

以下のメソッドは Neptune DB インスタンスにクエリを送信します。
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

## Gremlin Java クライアントの SSL/TLS 設定
<a name="access-graph-gremlin-java-ssl"></a>

Neptune では、SSL/TLS をデフォルトで有効にする必要があります。通常、Java ドライバーが `enableSsl(true)` で設定されている場合、証明書のローカルコピーで `trustStore()` または `keyStore()` を設定しなくても、Neptune に接続できます。

ただし、接続先のインスタンスがパブリック証明書を検証するためのインターネット接続を持っていない場合や、使用している証明書がパブリックでない場合は、次の手順を実行してローカル証明書のコピーを設定できます。

**SSL/TLS を有効にするためのローカル証明書コピーの設定**

1. Oracle から [keytool](https://docs.oracle.com/javase/9/tools/keytool.htm#JSWOR-GUID-5990A2E4-78E3-47B7-AE75-6D1826259549) をダウンロードしてインストールします。これにより、ローカルキーストアのセットアップが大幅に簡単になります。

1. `SFSRootCAG2.pem` CA 証明書をダウンロードします (Gremlin Java SDK には、リモート証明書を検証する証明書が必要です)。

   ```
   wget https://www.amazontrust.com/repository/SFSRootCAG2.pem
   ```

1. JKS 形式または PKCS12 形式でキーストアを作成します。この例では JKS を使用します。プロンプトが表示されたら、次の質問に答えます。ここで作成したパスワードは後で必要になります。

   ```
   keytool -genkey -alias (host name) -keyalg RSA -keystore server.jks
   ```

1. ダウンロードした `SFSRootCAG2.pem` ファイルを、新しく作成したキーストアにインポートします。

   ```
   keytool -import -keystore server.jks -file .pem
   ```

1. `Cluster` オブジェクトをプログラムで設定します。

   ```
   Cluster cluster = Cluster.build("(your neptune endpoint)")
                            .port(8182)
                            .enableSSL(true)
                            .keyStore(‘server.jks’)
                            .keyStorePassword("(the password from step 2)")
                            .create();
   ```

   Gremlin コンソールの場合と同じように、必要に応じて設定ファイルでも同じことを行うことができます。

   ```
   hosts: [(your neptune endpoint)]
   port: 8182
   connectionPool: { enableSsl: true, keyStore: server.jks, keyStorePassword: (the password from step 2) }
   serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
   ```

## IAM 認証
<a name="access-graph-gremlin-java-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。Java クライアントから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin Java による IAM を使用した Amazon Neptune データベースへの接続](iam-auth-connecting-gremlin-java.md)。

# 再接続ロジックを使用して Neptune DB インスタンスに接続する Java の例
<a name="access-graph-gremlin-java-reconnect-example"></a>

次の Java の例は、再接続ロジックを使用して Gremlin クライアントに接続して、予期しない切断から回復する方法を示しています。

これには、以下の依存関係があります。

```
<dependency>
    <groupId>org.apache.tinkerpop</groupId>
    <artifactId>gremlin-driver</artifactId>
    <version>${gremlin.version}</version>
</dependency>

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>amazon-neptune-sigv4-signer</artifactId>
    <version>${sig4.signer.version}</version>
</dependency>

<dependency>
    <groupId>com.evanlennick</groupId>
    <artifactId>retry4j</artifactId>
    <version>0.15.0</version>
</dependency>
```

サンプルコードは次のとおりです。

**重要**  
 Retry4J からの `CallExecutor` はスレッドセーフではないことがあります。各スレッドで独自の `CallExecutor` インスタンスを使用するか、別の再試行ライブラリを使用することを検討してください。

**注記**  
 次の例が更新され、requestInterceptor() の使用が追加されました。これは TinkerPop 3.6.6 で追加されました。TinkerPop バージョン 3.6.6 以前では、コード例では handshakeInterceptor() を使用していましたが、このリリースで廃止されました。

```
public static void main(String args[]) {
  boolean useIam = true;

  // Create Gremlin cluster and traversal source
  Cluster.Builder builder = Cluster.build()
         .addContactPoint(System.getenv("neptuneEndpoint"))
         .port(Integer.parseInt(System.getenv("neptunePort")))
         .enableSsl(true)
         .minConnectionPoolSize(1)
         .maxConnectionPoolSize(1)
         .serializer(Serializers.GRAPHBINARY_V1D0)
         .reconnectInterval(2000);

  if (useIam) {
      builder.requestInterceptor( r -> {
         try {
            NeptuneNettyHttpSigV4Signer sigV4Signer =
                        new NeptuneNettyHttpSigV4Signer("(your region)", new DefaultAWSCredentialsProviderChain());
            sigV4Signer.signRequest(r);
         } catch (NeptuneSigV4SignerException e) {
            throw new RuntimeException("Exception occurred while signing the request", e);
         }
         return r;
      });
   }

  Cluster cluster = builder.create();

  GraphTraversalSource g = AnonymousTraversalSource
      .traversal()
      .withRemote(DriverRemoteConnection.using(cluster));

  // Configure retries
  RetryConfig retryConfig = new RetryConfigBuilder()
      .retryOnCustomExceptionLogic(getRetryLogic())
      .withDelayBetweenTries(1000, ChronoUnit.MILLIS)
      .withMaxNumberOfTries(5)
      .withFixedBackoff()
      .build();

  @SuppressWarnings("unchecked")
  CallExecutor<Object> retryExecutor = new CallExecutorBuilder<Object>()
      .config(retryConfig)
      .build();

  // Do lots of queries
  for (int i = 0; i < 100; i++){
    String id = String.valueOf(i);

    @SuppressWarnings("unchecked")
    Callable<Object> query = () -> g.V(id)
        .fold()
        .coalesce(
            unfold(),
            addV("Person").property(T.id, id))
        .id().next();

    // Retry query
    // If there are connection failures, the Java Gremlin client will automatically
    // attempt to reconnect in the background, so all we have to do is wait and retry.
    Status<Object> status = retryExecutor.execute(query);

    System.out.println(status.getResult().toString());
  }

  cluster.close();
}

private static Function<Exception, Boolean> getRetryLogic() {

  return e -> {

    Class<? extends Exception> exceptionClass = e.getClass();

    StringWriter stringWriter = new StringWriter();
    String message = stringWriter.toString();


    if (RemoteConnectionException.class.isAssignableFrom(exceptionClass)){
      System.out.println("Retrying because RemoteConnectionException");
      return true;
    }

    // Check for connection issues
    if (message.contains("Timed out while waiting for an available host") ||
        message.contains("Timed-out") && message.contains("waiting for connection on Host") ||
        message.contains("Connection to server is no longer active") ||
        message.contains("Connection reset by peer") ||
        message.contains("SSLEngine closed already") ||
        message.contains("Pool is shutdown") ||
        message.contains("ExtendedClosedChannelException") ||
        message.contains("Broken pipe") ||
        message.contains(System.getenv("neptuneEndpoint")))
    {
      System.out.println("Retrying because connection issue");
      return true;
    };

    // Concurrent writes can sometimes trigger a ConcurrentModificationException.
    // In these circumstances you may want to backoff and retry.
    if (message.contains("ConcurrentModificationException")) {
      System.out.println("Retrying because ConcurrentModificationException");
      return true;
    }

    // If the primary fails over to a new instance, existing connections to the old primary will
    // throw a ReadOnlyViolationException. You may want to back and retry.
    if (message.contains("ReadOnlyViolationException")) {
      System.out.println("Retrying because ReadOnlyViolationException");
      return true;
    }

    System.out.println("Not a retriable error");
    return false;
  };
}
```

# Python を使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-python"></a>

**重要**  
Neptune エンジンバージョンとの互換性を保つには、正しい Apache TinkerPop Gremlin ドライバーバージョンを選択することが重要です。互換性のないバージョンを使用すると、接続の失敗や予期しない動作が発生する可能性があります。バージョンの互換性の詳細については、「」を参照してください[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。

次のセクションでは、Amazon Neptune DB インスタンスに接続し、Gremlin トラバーサルを実施する Python サンプル実行方法について説明します。

Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

開始する前に、以下を実行します。
+ [Python.org ウェブサイト](https://www.python.org/downloads/)から Python 3.6 以降をダウンロードしてインストールします。
+ **pip** がインストールされていることを確認します。**pip** がインストールされていないか、または不明な場合は、**pip** ドキュメンテーション内の[pip をインストールする必要がありますか?](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip)を参照してください。
+ Python のインストールにない場合は、次に示すように `futures` をダウンロードします。`pip install futures`



**Python を使用して Neptune に接続するには**

1. `gremlinpython` パッケージをインストールするには、次のように入力します。

   ```
   pip install --user gremlinpython
   ```

1. `gremlinexample.py` という名前のファイルを作成して、テキストエディタで開きます。

1. `gremlinexample.py` ファイルに次の内容をコピーします。*your-neptune-endpoint* を Neptune DB クラスターのアドレスに、*your-neptune-port* を Neptune DB クラスターのポート (デフォルト: 8182) に置き換えます。

   Neptune DB インスタンスのアドレスを見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

    以下の例は、Gremlin Python を使用して接続する方法を示しています。

   ```
   import boto3
   import os
   from botocore.auth import SigV4Auth
   from botocore.awsrequest import AWSRequest
   from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
   from gremlin_python.process.anonymous_traversal import traversal
   
   database_url = "wss://your-neptune-endpoint:your-neptune-port/gremlin"
   
   remoteConn = DriverRemoteConnection(database_url, "g")
   
   g = traversal().withRemote(remoteConn)
   
   print(g.inject(1).toList())
   remoteConn.close()
   ```

1. サンプルを実行するには、次のコマンドを入力します。

   ```
   python gremlinexample.py
   ```

   この例の最後にある Gremlin クエリは、リストの頂点 (`g.V().limit(2)`) を返します。次に、このリストは標準の Python `print` 関数で表示されます。
**注記**  
Gremlin クエリの最後の部分、`toList()` では、評価のためにトラバーサルをサーバーに送信する必要があります。そのメソッドまたは別の同等のメソッドを含めない場合、クエリは Neptune DB インスタンスに送信されません。

   以下のメソッドは Neptune DB インスタンスにクエリを送信します。
   + `toList()`
   + `toSet()`
   + `next()`
   + `nextTraverser()`
   + `iterate()`

   

   前述の例では、`g.V().limit(2).toList()` トラバーサルを使用してグラフの最初の 2 つの頂点を返します。その他の対象にクエリを実行するには、いずれかの適切な終了メソッドを持つ Gremlin トラバーサルで置き換えます。

## IAM 認証
<a name="access-graph-gremlin-python-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。Python クライアントから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin Python による IAM 認証を使用した Amazon Neptune データベースへの接続](gremlin-python-iam-auth.md)。

# .NET を使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-dotnet"></a>

**重要**  
Neptune エンジンバージョンとの互換性を保つには、正しい Apache TinkerPop Gremlin ドライバーバージョンを選択することが重要です。互換性のないバージョンを使用すると、接続の失敗や予期しない動作が発生する可能性があります。バージョンの互換性の詳細については、「」を参照してください[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。

次のセクションには、Neptune DB インスタンスに接続して Gremlin トラバーサルを実行する、C\$1 で記述されたサンプルコードが含まれています。

Amazon Neptune への接続は、Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスから行ってください。このサンプルコードは Ubuntu を実行する Amazon EC2 インスタンスでテスト済みです。

開始する前に、以下を実行します。
+ Amazon EC2 インスタンスに .NET をインストールします。Windows、Linux、および macOS を含む複数のオペレーティングシステムで .NET をインストールする手順については、「[.NET の開始方法](https://www.microsoft.com/net/learn/get-started/)」を参照してください。
+ `dotnet add package gremlin.net` を実行して、パッケージに Gremlin.NET をインストールします。詳細については、TinkerPop ドキュメントの「[Gremlin.NET](https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet)」を参照してください。



**Gremlin.NET を使用して Neptune に接続するには**

1. 新しい .NET プロジェクトを作成します。

   ```
   dotnet new console -o gremlinExample
   ```

1. ディレクトリを、新しいプロジェクトディレクトリに変更します。

   ```
   cd gremlinExample
   ```

1. `Program.cs` ファイルに次の内容をコピーします。*your-neptune-endpoint* を Neptune DB インスタンスのアドレスで置き換えます。

   Neptune DB インスタンスのアドレスを見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   ```
   using System;
   using System.Threading.Tasks;
   using System.Collections.Generic;
   using Gremlin.Net;
   using Gremlin.Net.Driver;
   using Gremlin.Net.Driver.Remote;
   using Gremlin.Net.Structure;
   using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
   namespace gremlinExample
   {
     class Program
     {
       static void Main(string[] args)
       {
         try
         {
           var endpoint = "your-neptune-endpoint";
           // This uses the default Neptune and Gremlin port, 8182
           var gremlinServer = new GremlinServer(endpoint, 8182, enableSsl: true );
           var gremlinClient = new GremlinClient(gremlinServer);
           var remoteConnection = new DriverRemoteConnection(gremlinClient, "g");
           var g = Traversal().WithRemote(remoteConnection);
           g.AddV("Person").Property("Name", "Justin").Iterate();
           g.AddV("Custom Label").Property("name", "Custom id vertex 1").Iterate();
           g.AddV("Custom Label").Property("name", "Custom id vertex 2").Iterate();
           var output = g.V().Limit<Vertex>(3).ToList();
           foreach(var item in output) {
               Console.WriteLine(item);
           }
         }
         catch (Exception e)
         {
             Console.WriteLine("{0}", e);
         }
       }
     }
   }
   ```

1. サンプルを実行するには、次のコマンドを入力します。

   ```
   dotnet run
   ```

   この例の最後にある Gremlin クエリは、テスト目的で単一の頂点の数を返します。その後、コンソールに表示されます。
**注記**  
Gremlin クエリの最後の部分、`Next()` では、評価のためにトラバーサルをサーバーに送信する必要があります。そのメソッドまたは別の同等のメソッドを含めない場合、クエリは Neptune DB インスタンスに送信されません。

   以下のメソッドは Neptune DB インスタンスにクエリを送信します。
   + `ToList()`
   + `ToSet()`
   + `Next()`
   + `NextTraverser()`
   + `Iterate()`

   クエリ結果をシリアル化して返す必要がある場合、`Next()` を、そうでない場合は `Iterate()` を使用します。

   前述の例では、`g.V().Limit(3).ToList()` トラバーサルを使用してリストを返します。その他の対象にクエリを実行するには、いずれかの適切な終了メソッドを持つ Gremlin トラバーサルで置き換えます。

## IAM 認証
<a name="access-graph-gremlin-dotnet-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。.NET クライアントから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin .NET による IAM 認証を使用した Amazon Neptune データベースへの接続](gremlin-dotnet-iam-auth.md)。

# Node.js を使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-node-js"></a>

**重要**  
Neptune エンジンバージョンとの互換性を保つには、正しい Apache TinkerPop Gremlin ドライバーバージョンを選択することが重要です。互換性のないバージョンを使用すると、接続の失敗や予期しない動作が発生する可能性があります。バージョンの互換性の詳細については、「」を参照してください[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。

次のセクションでは、Amazon Neptune DB インスタンスに接続し、Gremlin トラバーサルを実施する Node.js サンプル実行方法について説明します。

Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

開始する前に、以下を実行します。
+ Node.js バージョン 8.11 以降がインストールされていることを確認します。そうでない場合、[Nodejs.org ウェブサイト](https://nodejs.org)から Node.js をダウンロードしてインストールします。

**Node.js を使用して Neptune に接続するには**

1. `gremlin-javascript` パッケージをインストールするには、次のように入力します。

   ```
   npm install gremlin
   ```

1. `gremlinexample.js` という名前のファイルを作成して、テキストエディタで開きます。

1. `gremlinexample.js` ファイルに次の内容をコピーします。*your-neptune-endpoint* を Neptune DB インスタンスのアドレスで置き換えます。

   Neptune DB インスタンスのアドレスを見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   ```
   const gremlin = require('gremlin');
   const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
   const Graph = gremlin.structure.Graph;
   
   dc = new DriverRemoteConnection('wss://your-neptune-endpoint:8182/gremlin',{});
   
   const graph = new Graph();
   const g = graph.traversal().withRemote(dc);
   
   g.V().limit(1).count().next().
       then(data => {
           console.log(data);
           dc.close();
       }).catch(error => {
           console.log('ERROR', error);
           dc.close();
       });
   ```

1. サンプルを実行するには、次のコマンドを入力します。

   ```
   node gremlinexample.js
   ```

前述の例では、`g.V().limit(1).count().next()` トラバーサルを使用してグラフの単一の頂点の数を返します。その他の対象にクエリを実行するには、いずれかの適切な終了メソッドを持つ Gremlin トラバーサルで置き換えます。

**注記**  
Gremlin クエリの最後の部分、`next()` では、評価のためにトラバーサルをサーバーに送信する必要があります。そのメソッドまたは別の同等のメソッドを含めない場合、クエリは Neptune DB インスタンスに送信されません。

以下のメソッドは Neptune DB インスタンスにクエリを送信します。
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

クエリ結果をシリアル化して返す必要がある場合、`next()` を、そうでない場合は `iterate()` を使用します。

**重要**  
これは、スタンドアロンの Node.js 例です。 AWS Lambda 関数でこのようなコードを実行する予定がある場合は、Neptune Lambda 関数で JavaScript を効率的に使用する方法の詳細については、[Lambda 関数の例](lambda-functions-examples.md)「」を参照してください。

## IAM 認証
<a name="access-graph-gremlin-nodejs-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。JavaScript クライアントから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin JavaScript による IAM 認証を使用した Amazon Neptune データベースへの接続](gremlin-javascript-iam-auth.md)。

# Go を使用して Neptune DB インスタンスに接続する
<a name="access-graph-gremlin-go"></a>

**重要**  
Neptune エンジンバージョンとの互換性を保つには、正しい Apache TinkerPop Gremlin ドライバーバージョンを選択することが重要です。互換性のないバージョンを使用すると、接続の失敗や予期しない動作が発生する可能性があります。バージョンの互換性の詳細については、「」を参照してください[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)。

**注記**  
gremlingo 3.5.x バージョンは TinkerPop 3.4.x バージョンと下位互換性があります。ただし、記述する Gremlin クエリで 3.4.x の機能のみを使用する場合に限ります。

次のセクションでは、Amazon Neptune DB インスタンスに接続して、Gremlin トラバーサルを実行する Go サンプルの実行方法について説明します。

Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

開始する前に、以下を実行します。
+ [go.dev](https://go.dev/dl/) ウェブサイトから Go 1.17 以降をダウンロードしてインストールします。

**Go を使用して Neptune に接続するには**

1. 空のディレクトリから始めて、新しい Go モジュールを初期化します。

   ```
   go mod init example.com/gremlinExample
   ```

1. gremlin-go を新しいモジュールの依存関係として追加します。

   ```
   go get github.com/apache/tinkerpop/gremlin-go/v3/driver
   ```

1. 「`gremlinExample.go`」という名前のファイルを作成し、テキストエディタで開きます。

1. 以下を `gremlinExample.go` ファイルにコピーし、*`(your neptune endpoint)`* を Neptune DB インスタンスのアドレスに置き換えます。

   ```
   package main
   
   import (
     "fmt"
     gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
   )
   
   func main() {
     // Creating the connection to the server.
     driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("wss://(your neptune endpoint):8182/gremlin",
       func(settings *gremlingo.DriverRemoteConnectionSettings) {
         settings.TraversalSource = "g"
       })
     if err != nil {
       fmt.Println(err)
       return
     }
     // Cleanup
     defer driverRemoteConnection.Close()
   
     // Creating graph traversal
     g := gremlingo.Traversal_().WithRemote(driverRemoteConnection)
   
     // Perform traversal
     results, err := g.V().Limit(2).ToList()
     if err != nil {
       fmt.Println(err)
       return
     }
     // Print results
     for _, r := range results {
       fmt.Println(r.GetString())
     }
   }
   ```
**注記**  
Neptune TLS 証明書形式は、現在、macOS 搭載の Go 1.18\$1 ではサポートされていないため、接続を開始しようとすると 509 エラーが発生する可能性があります。ローカルテストでは、インポートに「crypto/tls」を追加し、`DriverRemoteConnection` 設定を次のように変更することで、これをスキップできます。  

   ```
   // Creating the connection to the server.
   driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("wss://your-neptune-endpoint:8182/gremlin",
     func(settings *gremlingo.DriverRemoteConnectionSettings) {
         settings.TraversalSource = "g"
         settings.TlsConfig = &tls.Config{InsecureSkipVerify: true}
     })
   ```

1. サンプルを実行するには、次のコマンドを入力します。

   ```
   go run gremlinExample.go
   ```

この例の最後にある Gremlin クエリは、頂点 `(g.V().Limit(2))` をスライスで返します。このスライスは、標準の `fmt.Println` 関数で繰り返され、出力されます。

**注記**  
Gremlin クエリの最後の部分、`ToList()` では、評価のためにトラバーサルをサーバーに送信する必要があります。そのメソッドまたは別の同等のメソッドを含めない場合、クエリは Neptune DB インスタンスに送信されません。

以下のメソッドは Neptune DB インスタンスにクエリを送信します。
+ `ToList()`
+ `ToSet()`
+ `Next()`
+ `GetResultSet()`
+ `Iterate()`

前述の例では、`g.V().Limit(2).ToList()` トラバーサルを使用してグラフの最初の 2 つの頂点を返します。その他の対象にクエリを実行するには、いずれかの適切な終了メソッドを持つ Gremlin トラバーサルで置き換えます。

## IAM 認証
<a name="access-graph-gremlin-go-iam"></a>

Neptune は、DB クラスターへのアクセスを制御するための [IAM 認証](iam-auth-enable.md)をサポートしています。IAM 認証が有効になっている場合は、署名バージョン 4 の署名を使用してリクエストを認証する必要があります。Go クライアントから接続するための詳細な手順とコード例については、「」を参照してください[Gremlin Go による IAM 認証を使用した Amazon Neptune データベースへの接続](gremlin-go-iam-auth.md)。

# AWS SDK を使用して Gremlin クエリを実行する
<a name="access-graph-gremlin-sdk"></a>

 AWS SDK を使用すると、任意のプログラミング言語を使用して Neptune グラフに対して Gremlin クエリを実行できます。Neptune データ API SDK (サービス名 `neptunedata`) は、Gremlin クエリを送信するための [ExecuteGremlinQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteGremlinQuery.html) アクションを提供します。

これらの例は、Neptune DB クラスターと同じ Virtual Private Cloud (VPC) の Amazon EC2 インスタンス、またはクラスターエンドポイントへのネットワーク接続がある場所から実行する必要があります。

各 SDK 言語の`neptunedata`サービスの API リファレンスドキュメントへの直接リンクは、以下にあります。


| プログラミング言語 | Neptunedata API リファレンス | 
| --- | --- | 
| C\$1\$1 | [https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html](https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html) | 
| Go | [https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/](https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/) | 
| Java | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html) | 
| JavaScript | [https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/) | 
| Kotlin | [https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html](https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html) | 
| .NET | [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html) | 
| PHP | [https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html](https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html) | 
| Python | [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html) | 
| Ruby | [https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html) | 
| Rust | [https://crates.io/crates/aws-sdk-neptunedata](https://crates.io/crates/aws-sdk-neptunedata) | 
| CLI | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

## Gremlin AWS SDK の例
<a name="access-graph-gremlin-sdk-examples"></a>

次の例は、`neptunedata`クライアントをセットアップし、Gremlin クエリを実行し、結果を出力する方法を示しています。*YOUR\$1NEPTUNE\$1HOST* と *YOUR\$1NEPTUNE\$1PORT* を Neptune DB クラスターのエンドポイントとポートに置き換えます。

**クライアント側のタイムアウトと再試行の設定**  
SDK クライアントのタイムアウトは、*クライアント*がレスポンスを待機する時間を制御します。クエリがサーバー上で実行される時間は制御されません。サーバーが終了する前にクライアントがタイムアウトした場合、クライアントが結果を取得する方法がない間、クエリは Neptune で実行し続ける可能性があります。  
クライアント側の読み取りタイムアウトを `0` (タイムアウトなし) に設定するか、Neptune DB クラスターのサーバー側の [neptune\$1query\$1timeout](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) 設定よりも少なくとも数秒長い値に設定することをお勧めします。これにより、Neptune はクエリのタイムアウトを制御できます。  
また、最大再試行回数を設定することをお勧めします `1` (再試行なし）。SDK がサーバーでまだ実行されているクエリを再試行すると、オペレーションが重複する可能性があります。これは、再試行によって意図しない重複書き込みが発生する可能性があるミューテーションクエリでは特に重要です。

------
#### [ Python ]

1. Boto3 をインストールするには、[インストール手順に従い](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)ます。

1. という名前のファイルを作成し`gremlinExample.py`、次のコードを貼り付けます。

   ```
   import boto3
   import json
   from botocore.config import Config
   
   # Disable the client-side read timeout and retries so that
   # Neptune's server-side neptune_query_timeout controls query duration.
   client = boto3.client(
       'neptunedata',
       endpoint_url=f'https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT',
       config=Config(read_timeout=None, retries={'total_max_attempts': 1})
   )
   
   # Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   response = client.execute_gremlin_query(
       gremlinQuery='g.V().limit(1)',
       serializer='application/vnd.gremlin-v3.0+json;types=false'
   )
   
   print(json.dumps(response['result'], indent=2))
   ```

1. 例を実行します。 `python gremlinExample.py`

------
#### [ Java ]

1. [インストール手順に従って](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) AWS SDK for Java をセットアップします。

1. 次のコードを使用して をセットアップし`NeptunedataClient`、Gremlin クエリを実行して結果を出力します。

   ```
   import java.net.URI;
   import java.time.Duration;
   import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
   import software.amazon.awssdk.core.retry.RetryPolicy;
   import software.amazon.awssdk.services.neptunedata.NeptunedataClient;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteGremlinQueryRequest;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteGremlinQueryResponse;
   
   // Disable the client-side timeout and retries so that
   // Neptune's server-side neptune_query_timeout controls query duration.
   NeptunedataClient client = NeptunedataClient.builder()
       .endpointOverride(URI.create("https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT"))
       .overrideConfiguration(ClientOverrideConfiguration.builder()
           .apiCallTimeout(Duration.ZERO)
           .retryPolicy(RetryPolicy.none())
           .build())
       .build();
   
   // Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   ExecuteGremlinQueryRequest request = ExecuteGremlinQueryRequest.builder()
       .gremlinQuery("g.V().limit(1)")
       .serializer("application/vnd.gremlin-v3.0+json;types=false")
       .build();
   
   ExecuteGremlinQueryResponse response = client.executeGremlinQuery(request);
   
   System.out.println(response.result().toString());
   ```

------
#### [ JavaScript ]

1. [インストール手順に従って](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) AWS SDK for JavaScript をセットアップします。neptunedata クライアントパッケージをインストールします: `npm install @aws-sdk/client-neptunedata`。

1. という名前のファイルを作成し`gremlinExample.js`、次のコードを貼り付けます。

   ```
   import { NeptunedataClient, ExecuteGremlinQueryCommand } from "@aws-sdk/client-neptunedata";
   import { NodeHttpHandler } from "@smithy/node-http-handler";
   
   const config = {
       endpoint: "https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT",
       // Disable the client-side request timeout so that
       // Neptune's server-side neptune_query_timeout controls query duration.
       requestHandler: new NodeHttpHandler({
           requestTimeout: 0
       }),
       maxAttempts: 1
   };
   
   const client = new NeptunedataClient(config);
   
   // Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   const input = {
       gremlinQuery: "g.V().limit(1)",
       serializer: "application/vnd.gremlin-v3.0+json;types=false"
   };
   
   const command = new ExecuteGremlinQueryCommand(input);
   const response = await client.send(command);
   
   console.log(JSON.stringify(response, null, 2));
   ```

1. 例を実行します。 `node gremlinExample.js`

------

# Gremlin クエリヒント
<a name="gremlin-query-hints"></a>

クエリヒントを使用して Amazon Neptune の特定の Gremlin クエリの最適化と評価戦略を指定することができます。

クエリヒントは、次の構文を使用して `withSideEffect` ステップをクエリに追加することによって指定されます。

```
g.withSideEffect(hint, value)
```
+ *hint* – 適用するヒントのタイプを特定します。
+ *value* – 検討中のシステムアスペクトの動作を決めます。

たとえば、以下は Gremlin トラバーサルに `repeatMode` ヒントを含める方法を示します。

**注記**  
すべての Gremlin クエリヒントの副作用にはプレフィックス `Neptune#` が付けられます。

```
g.withSideEffect('Neptune#repeatMode', 'DFS').V("3").repeat(out()).times(10).limit(1).path()
```

前述のクエリは、Neptune エンジンにデフォルトの Neptune *幅優先*(`BFS`)ではなく、*深さ優先*(`DFS`) グラフをトラバースするように指示します。

以下のセクションでは、使用可能なクエリヒントとその使用方法に関する詳しい情報が記載されています。

**Topics**
+ [Gremlin repeatMode クエリヒント](gremlin-query-hints-repeatMode.md)
+ [Gremlin noReordering クエリヒント](gremlin-query-hints-noReordering.md)
+ [Gremlin typePromotion クエリヒント](gremlin-query-hints-typePromotion.md)
+ [Gremlin useDFE クエリヒント](gremlin-query-hints-useDFE.md)
+ [結果キャッシュを使用する Gremlin クエリヒント](gremlin-query-hints-results-cache.md)

# Gremlin repeatMode クエリヒント
<a name="gremlin-query-hints-repeatMode"></a>

Neptune`repeatMode` クエリヒントは、Neptune エンジンが Gremlin トラバーサル (幅優先、深さ優先、チャンク深さ優先) の`repeat()` ステップを評価する方法を指定します。

`repeat()` ステップの評価モードは、パスを探したりパスに従ったりするために使用される場合、単に制限回数までステップを繰り返すことよりも重要です。

## 構文
<a name="gremlin-query-hints-repeatMode-syntax"></a>

`repeatMode` クエリヒントは、クエリに `withSideEffect` ステップを追加して指定します。

```
g.withSideEffect('Neptune#repeatMode', 'mode').gremlin-traversal
```

**注記**  
すべての Gremlin クエリヒントの副作用にはプレフィックス `Neptune#` が付けられます。

**利用可能なモード**
+ `BFS`

  幅優先検索

  `repeat()` ステップのデフォルトの実行モードです。これにより、パスに沿って深くなる前にすべての兄弟ノードを取得します。

  このバージョンはメモリを大量に消費し、領域が非常に大きくなる可能性があります。クエリがメモリ不足になって、Neptune エンジンによりキャンセルされるリスクが高くなります。これは他の Gremlin 実装に最も適合します。
+ `DFS`

  深さ優先検索

  次のソリューションに移る前に最大深度への各パスに従います。

  メモリ使用量は少なくなります。複数のホップ外の開始点から単一のパスを検索するような状況では、パフォーマンスが向上する可能性があります。
+ `CHUNKED_DFS`

  チャンク深さ優先検索

  1 個のノード (`DFS`) またはすべてのノード (`BFS)` ではなく、1,000 個のノードのチャンクでグラフ深さ優先を調べるハイブリッドアプローチです。

  Neptune エンジンは、より深くパスに従う前に各レベルで最大 1,000 個のノードを取得します。

  これは、速度とメモリ使用量のバランスが取れたアプローチです。

  また、`BFS` を使用する場合に便利ですが、このクエリはメモリを過度に使用しています。



## 例
<a name="gremlin-query-hints-repeatMode-example"></a>

次のセクションでは、Gremlin トラバーサルに対する繰り返しモードの効果について説明します。

Neptune では、`repeat()` ステップのデフォルトモードは、すべてのトラバーサルに対して幅優先 (`BFS`) 実行戦略を行うことになっています。

ほとんどの場合、TinkerGraph 実装では同じ実行戦略が使用されますが、場合によってトラバーサルの実行は変更されます。

たとえば、TinkerGraph 実装によって次のクエリが変更されます。

```
g.V("3").repeat(out()).times(10).limit(1).path()
```

このトラバーサルの `repeat()` ステップは次のトラバーサルに「アンロール」され、深さ優先 (`DFS`) 戦略になります。

```
g.V(<id>).out().out().out().out().out().out().out().out().out().out().limit(1).path()
```

**重要**  
Neptune クエリエンジンでは、これは自動的に実行されません。

Breadth-first (`BFS`) はデフォルトの実行方法で、ほとんどの場合 TinkerGraph に似ています。ただし、深さ優先 (`DFS`) 戦略が望ましい場合があります。

 

**BFS (デフォルト)**  
幅優先 (BFS) は、`repeat()` 演算子のデフォルトの実行戦略です。

```
g.V("3").repeat(out()).times(10).limit(1).path()
```

Neptune エンジンは、10 のホップまでソリューションを見つける前に、最初の 9 つのホップ領域を完全に探します。これは、最短パスのクエリなど多くの場合で効果的です。

ただし、前述の例では、`repeat()` 演算子の深さ優先 (`DFS`) モードを使用するとトラバーサルははるかに高速になります。

**DFS**  
次のクエリでは、`repeat()` 演算子の深さ優先 (`DFS`) モードを使用します。

```
g.withSideEffect("Neptune#repeatMode", "DFS").V("3").repeat(out()).times(10).limit(1)
```

ここでは、次のソリューションを探す前に、最大深度まで個別のソリューションに従います。

# Gremlin noReordering クエリヒント
<a name="gremlin-query-hints-noReordering"></a>

Gremlin トラバーサルを送信するとき、Neptune クエリエンジンは、評価に必要な作業の量とクエリ応答時間を最小限にしようとするために、トラバーサルの構造を調査し、クエリの各パートの順序を変更します。たとえば、複数の `has()` ステップなど、複数の制約を持つトラバーサルは通常、指定された順序では評価されません。代わりに、クエリが静的分析でチェックされた後に順序が変更されます。

Neptune クエリエンジンは、より細かく選択される制約を特定しようと試み、その 1 つを最初に実行します。多くの場合、これによりパフォーマンスが向上しますが、Neptune で選択されるクエリの評価の順序は常に最適であるとは限りません。

データの正確な特性がわかっていて、クエリ実行の順序を手動で指定する場合は、Neptune `noReordering` クエリヒントを使用して特定の順序でトラバーサルが評価されるように指定できます。

## 構文
<a name="gremlin-query-hints-noReordering-syntax"></a>

`noReordering` クエリヒントは、クエリに `withSideEffect` ステップを追加して指定します。

```
g.withSideEffect('Neptune#noReordering', true or false).gremlin-traversal
```

**注記**  
すべての Gremlin クエリヒントの副作用にはプレフィックス `Neptune#` が付けられます。

**指定できる値**
+ `true`
+ `false`

# Gremlin typePromotion クエリヒント
<a name="gremlin-query-hints-typePromotion"></a>

数値または範囲でフィルタリングする Gremlin トラバーサルを送信する場合、Neptune クエリエンジンは通常、クエリの実行時に型の上位変換を使用する必要があります。つまり、フィルタリングする値を保持できるすべてのタイプの値を調べる必要があります。

たとえば、55 に等しい値をフィルタリングする場合、エンジンは 55 に等しい整数、55L に等しい長整数、55.0 に等しい浮動小数点数などを探す必要があります。各型の上位変換では、ストレージに対する追加のルックアップが必要なため、単純なクエリの完了に予期せず長い時間がかかることがあります。

たとえば、顧客年齢プロパティが 5 より大きいすべての頂点を検索するとします。

```
g.V().has('customerAge', gt(5))
```

この探索を徹底的に実行するには、Neptune はクエリを展開して、クエリ対象の値を上位変換できるすべての数値型を調べる必要があります。この場合は、`gt`フィルターは、5 を超える任意の整数、5 L を超える任意の長整数、5.0 を超える任意の浮動小数点数、5.0 を超える任意の倍数に適用する必要があります。これらの型の上位変換はそれぞれ、ストレージに関する追加のルックアップを必要とするため、数値フィルターごとに複数のフィルターが表示されます。[Gremlin `profile` API](gremlin-profile-api.md)このクエリでは、完了までに予想よりもかなり長い時間がかかります。

多くの場合、特定のタイプの値を見つけるだけで済むことが事前にわかっているため、型の上位変換は不要です。この場合、クエリを劇的に高速化するには、型の上位変換をオフにする `typePromotion` クエリヒントを使います。

## 構文
<a name="gremlin-query-hints-typePromotion-syntax"></a>

`typePromotion` クエリヒントは、クエリに `withSideEffect` ステップを追加して指定します。

```
g.withSideEffect('Neptune#typePromotion', true or false).gremlin-traversal
```

**注記**  
すべての Gremlin クエリヒントの副作用にはプレフィックス `Neptune#` が付けられます。

**指定できる値**
+ `true`
+ `false`

上記のクエリの型の上位変換をオフにするには、以下を使用します。

```
g.withSideEffect('Neptune#typePromotion', false).V().has('customerAge', gt(5))
```

# Gremlin useDFE クエリヒント
<a name="gremlin-query-hints-useDFE"></a>

このクエリヒントを使用して、クエリを実行するための DFE の使用を有効にします。[neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) インスタンスパラメータはデフォルトでは `viaQueryHint` に設定されるため、デフォルトでは、このクエリヒントが `true` に設定されていないと、Neptune は DFE を使用しません。このインスタンスパラメータを `enabled` に設定した場合、`useDFE` クエリヒントが `false` に設定されているクエリを除き、すべてのクエリに DFE エンジンが使用されます。

クエリの DFE を有効にする例:

```
g.withSideEffect('Neptune#useDFE', true).V().out()
```

# 結果キャッシュを使用する Gremlin クエリヒント
<a name="gremlin-query-hints-results-cache"></a>

次のクエリヒントは、[クエリ結果のキャッシュ](gremlin-results-cache.md)が有効である場合に使用できます。

## Gremlin `enableResultCache`クエリヒント
<a name="gremlin-query-hints-results-cache-enableResultCache"></a>

`enableResultCache` の値を持つ `true` クエリヒントは、クエリ結果が既にキャッシュされている場合、キャッシュから返されます。そうでない場合は、新しい結果を返し、キャッシュからクリアされるまでキャッシュします。例えば、次のようになります。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

後で、まったく同じクエリを再度発行することで、キャッシュされた結果にアクセスできます。

このクエリヒントの値が `false` または、存在しない場合、クエリ結果はキャッシュされません。ただし、それを`false` に設定すると、既存のキャッシュされた結果をクリアしません。キャッシュされた結果をクリアするには、`invalidateResultCache`または`invalidateResultCachekey`ヒントを使用します。

## Gremlin `enableResultCacheWithTTL`クエリヒント
<a name="gremlin-query-hints-results-cache-enableResultCacheWithTTL"></a>

`enableResultCacheWithTTL`クエリヒントは、キャッシュされた結果がある場合、キャッシュ内に既にある結果の TTL に影響を与えずに、キャッシュされた結果を返します。キャッシュされた結果が現在存在しない場合、クエリは`enableResultCacheWithTTL`クエリヒントにより指定される有効期限(TTL) に対して新しい結果を返し、それをキャッシュします。その有効期限は秒単位で指定します。たとえば、次のクエリでは 60 秒の有効期限を指定します。

```
g.with('Neptune#enableResultCacheWithTTL', 60)
 .V().has('genre','drama').in('likes')
```

60 秒の有効期限が終了する前に、キャッシュされた結果にアクセスするための`enableResultCache`または`enableResultCacheWithTTL`クエリヒントのいずれかで同じクエリを使用できます (ここでは、`g.V().has('genre','drama').in('likes')`) 。

**注記**  
指定される有効期限`enableResultCacheWithTTL`は、既にキャッシュされている結果には影響しません。  
結果が `enableResultCache` を使って以前にキャッシュされていた場合、`enableResultCacheWithTTL` 新しい結果を生成し、指定した TTL 用にキャッシュする前に、まずキャッシュを明示的にクリアする必要があります。
結果が `enableResultCachewithTTL` を使って以前にキャッシュされていた場合、`enableResultCacheWithTTL` が新しい結果を生成し、指定した TTL 用にキャッシュする前に、まず前の TTL を期限切れとする必要があります。

有効期限が過ぎると、クエリのキャッシュされた結果がクリアされ、同じクエリの後続のインスタンスが新しい結果を返します。後続のクエリに `enableResultCacheWithTTL` がアタッチされている場合、新しい結果は指定された TTL でキャッシュされます。

## Gremlin `invalidateResultCacheKey`クエリヒント
<a name="gremlin-query-hints-results-cache-invalidateResultCacheKey"></a>

`invalidateResultCacheKey` クエリヒントは、`true` または `false` 値を取ることができます。ある`true` 値を指定すると、`invalidateResultCacheKey` がアタッチされてクリアされるクエリに対してキャッシュされた結果が発生します。たとえば、次の例では、クエリキー `g.V().has('genre','drama').in('likes')` のキャッシュされた結果がクリアされます。

```
g.with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

上記のクエリ例では、新しい結果がキャッシュされることはありません。既存のキャッシュされた結果をクリアした後に新しい結果をキャッシュする場合は、同じクエリで、`enableResultCache` (または`enableResultCacheWithTTL`) を含めることができます。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

## Gremlin `invalidateResultCache`クエリヒント
<a name="gremlin-query-hints-results-cache-invalidateResultCache"></a>

`invalidateResultCache` クエリヒントは、`true` または `false` 値を取ることができます。ある `true` 値を指定すると、結果キャッシュ内のすべての結果がクリアされます。例えば、次のようになります。

```
g.with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

上記のクエリ例では、結果がキャッシュされることはありません。既存のキャッシュを完全にクリアした後に新しい結果をキャッシュする場合は、同じクエリで、`enableResultCache` (または`enableResultCacheWithTTL`) を含めることができます。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

## Gremlin `numResultsCached`クエリヒント
<a name="gremlin-query-hints-results-cache-numResultsCached"></a>

`numResultsCached` クエリヒントは、`iterate()` を含むクエリでのみ使用でき、アタッチ先のクエリに対してキャッシュする結果の最大数を指定します。`numResultsCached` が存在する場合にキャッシュされる結果は返されず、キャッシュされるだけであることに注意してください。

たとえば、次のクエリでは、結果のうち最大 100 個をキャッシュするよう指定していますが、キャッシュされた結果は返されません。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#numResultsCached', 100)
 .V().has('genre','drama').in('likes').iterate()
```

次のようなクエリを使用して、キャッシュされた結果の範囲 (ここでは最初の 10 件) を取得できます。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#numResultsCached', 100)
 .V().has('genre','drama').in('likes').range(0, 10)
```

## Gremlin `noCacheExceptions`クエリヒント
<a name="gremlin-query-hints-results-cache-noCacheExceptions"></a>

`noCacheExceptions` クエリヒントは、`true` または `false` 値を取ることができます。ある `true` 値を指定すると、結果キャッシュに関連するすべての例外が抑制されます。例えば、次のようになります。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#noCacheExceptions', true)
 .V().has('genre','drama').in('likes')
```

特に、これは `QueryLimitExceededException` を抑制し、これはクエリの結果が大きすぎて結果キャッシュに収まらない場合に発生します。

# Gremlin クエリステータス API
<a name="gremlin-api-status"></a>

Gremlin クエリのステータスを取得するには、HTTP `GET` または `POST` を使用して、`https://your-neptune-endpoint:port/gremlin/status` エンドポイントにリクエストを送信します。

## Gremlin クエリステータスのリクエストパラメータ
<a name="gremlin-api-status-get-request"></a>
+ **queryId** (*オプショナル*) — 実行中の Gremlin クエリの ID。指定したクエリのステータスのみを表示します。
+ **includeWaiting** (*オプショナル*) — 待機中のすべてのクエリのステータスを返します。

  通常、実行中のクエリだけが応答に含まれますが、`includeWaiting` パラメータを指定すると、待機中のすべてのクエリのステータスも返されます。

## Gremlin クエリステータスのレスポンスの構文
<a name="gremlin-api-status-get-response-syntax"></a>

```
{
  "acceptedQueryCount": integer,
  "runningQueryCount": integer,
  "queries": [
    {
      "queryId":"guid",
      "queryEvalStats":
        {
          "waited": integer,
          "elapsed": integer,
          "cancelled": boolean
        },
      "queryString": "string"
    }
  ]
}
```

## Gremlin クエリステータスのレスポンス値
<a name="gremlin-api-status-get-response-values"></a>
+ **acceptedQueryCount**   –   受け入れられながらもまだ完了していないクエリの数 (キュー内のクエリを含む)。
+ **runningQueryCount**   –   現在実行されている Gremlin クエリの数。
+ **queries**   –   現在の Gremlin クエリのリスト。
+ **queryId**   –   クエリの GUID ID。Neptune は、この ID 値を各クエリに自動的に割り当てます。または、独自の ID を割り当てることもできます ([Neptune Gremlin または SPARQL クエリにカスタム ID を挿入する](features-query-id.md)を参照)。
+ **queryEvalStats** — このクエリの統計情報。
+ **subqueries** — このクエリのサブクエリの数。
+ **elapsed**   –   これまでクエリが実行されていた時間 (マイクロ秒)。
+ **cancelled**   –   True はクエリがキャンセルされたことを示します。
+ **queryString**   –   送信されたクエリ。それより長い場合、これは 1024 文字に切り捨てられます。
+ **waited** - クエリが待機していた時間をミリ秒単位で示します。

## Gremlin クエリステータスの例
<a name="gremlin-api-status-get-example"></a>

以下は、`curl` と HTTP `GET` を使用したステータスコマンドの例です。

```
curl https://your-neptune-endpoint:port/gremlin/status
```

この出力には、実行中の単一のクエリが表示されます。

```
{
  "acceptedQueryCount":9,
  "runningQueryCount":1,
  "queries": [
    {
      "queryId":"fb34cd3e-f37c-4d12-9cf2-03bb741bf54f",
      "queryEvalStats":
        {
          "waited": 0,
          "elapsed": 23,
          "cancelled": false
        },
      "queryString": "g.V().out().count()"
    }
  ]
}
```

# Gremlin クエリのキャンセル
<a name="gremlin-api-status-cancel"></a>

Gremlin クエリのステータスを取得するには、HTTP `GET` または `POST` を使用して、`https://your-neptune-endpoint:port/gremlin/status` エンドポイントにリクエストを送信します。

## Gremlin クエリのキャンセルリクエストパラメータ
<a name="gremlin-api-status-cancel-request"></a>
+ **cancelQuery**   –   キャンセルで必須です。このパラメータには対応する値がありません。
+ **queryId**   –   キャンセルする実行中の Gremlin クエリの ID。

## Gremlin クエリのキャンセルの例
<a name="gremlin-api-status-cancel-example"></a>

以下は、クエリのキャンセルする `curl` コマンドの例です。

```
curl https://your-neptune-endpoint:port/gremlin/status \
  --data-urlencode "cancelQuery" \
  --data-urlencode "queryId=fb34cd3e-f37c-4d12-9cf2-03bb741bf54f"
```

正常にキャンセルされると、HTTP `200` OK が返されます。

# Gremlin スクリプトベースのセッションのサポート
<a name="access-graph-gremlin-sessions"></a>

Amazon Neptune で暗示的なトランザクションを伴う Gremlin セッションを使用できます。Gremlin セッションについては、Apache TinkerPop のドキュメントの[セッションの検討](http://tinkerpop.apache.org/docs/current/reference/#sessions)を参照してください。以下のセクションでは、Java で Gremlin セッションを使用する方法について説明します。

**重要**  
現在、Neptune がスクリプトベースのセッションを開いたままにできる最長時間は 10 分です。それ以前にセッションを閉じないと、セッションはタイムアウトし、その中のすべてがロールバックされます。

**Topics**
+ [Gremlin コンソール上の Gremlin セッション](#access-graph-gremlin-sessions-console)
+ [Gremlin 言語バリアントの Gremlin セッション](#access-graph-gremlin-sessions-glv)

## Gremlin コンソール上の Gremlin セッション
<a name="access-graph-gremlin-sessions-console"></a>

`session` パラメータを指定せずに Gremlin コンソールでリモート接続を作成すると、リモート接続は*セッションレス*モードで作成されます。このモードでは、サーバーに送信される各リクエストはそれ自体で完全なトランザクションとして扱われ、リクエスト間の状態は保存されません。リクエストが失敗すると、そのリクエストのみがロールバックされます。

`session` パラメータを使用*する*リモート接続を作成した場合、リモート接続を閉じるまで続くスクリプトベースのセッションを作成します。すべてのセッションは、コンソールが生成してユーザーに返す固有の UUID によって識別されます。

次に示すのは、セッションを作成する 1 つのコンソール呼び出しの例です。クエリが送信されると、別の呼び出しによってセッションが閉じられ、クエリがコミットされます。

**注記**  
サーバー側のリソースを解放するには、Gremlin クライアントを常に閉じておく必要があります。

```
gremlin> :remote connect tinkerpop.server conf/neptune-remote.yaml session
  . . .
  . . .
gremlin> :remote close
```

詳細と例については、TinkerPop ドキュメントの「[セッション](http://tinkerpop.apache.org/docs/current/reference/#console-sessions)」を参照してください。

セッション中に実行するすべてのクエリは、単一のトランザクションを形成します。そのトランザクションは、クエリがすべて成功してリモート接続を閉じるまでコミットされません。クエリが失敗した場合、または Neptune でサポートされるセッションの最大有効期間内に接続を閉じなかった場合、セッショントランザクションはコミットされず、その中のすべてのクエリがロールバックされます。

## Gremlin 言語バリアントの Gremlin セッション
<a name="access-graph-gremlin-sessions-glv"></a>

次の例のように、Gremlin 言語バリアント (GLV) では、単一のトランザクションで複数のクエリを発行するための `SessionedClient` オブジェクトを作成する必要があります。

```
try {                              // line 1
  Cluster cluster = Cluster.open();                    // line 2
  Client client = cluster.connect("sessionName");      // line 3
   ...
   ...
} finally {
  // Always close. If there are no errors, the transaction is committed; otherwise, it's rolled back.
  client.close();
}
```

前の例の行 3 は、問題のクラスターについて設定されている設定オプションに従って `SessionedClient` オブジェクトを作成します。接続メソッドに渡す *sessionName* 文字列は、セッションの一意の名前になります。競合を避けるために、名前に UUID を使用してください。

クライアントは初期化されると、セッショントランザクションを開始します。セッションの形成中に実行したすべてのクエリは、`client.close( )` を呼び出すときにのみコミットされます。繰り返しますが、単一のクエリが失敗した場合、または Neptune でサポートされるセッションの最大有効期間内に接続を閉じなかった場合、セッショントランザクションは失敗し、その中のすべてのクエリがロールバックされます。

**注記**  
サーバー側のリソースを解放するには、Gremlin クライアントを常に閉じておく必要があります。

```
GraphTraversalSource g = traversal().withRemote(conn);

Transaction tx = g.tx();

// Spawn a GraphTraversalSource from the Transaction.
// Traversals spawned from gtx are executed within a single transaction.
GraphTraversalSource gtx = tx.begin();
try {
  gtx.addV('person').iterate();
  gtx.addV('software').iterate();

  tx.commit();
} finally {
    if (tx.isOpen()) {
        tx.rollback();
    }
}
```

# Neptune での Gremlin トランザクション
<a name="access-graph-gremlin-transactions"></a>

Gremlin [トランザクション](transactions.md)が実行されるコンテキストはいくつかあります。Gremlin を使用する際には、作業対象となるコンテキストとその意味を理解することが重要です。
+ **`Script-based`** — リクエストは、次のようなテキストベースの Gremlin 文字列を使用して行われます。
  + Java ドライバーと `Client.submit(string)` の使用。
  + Gremlin コンソールと `:remote connect` の使用。
  + バルク API の使用。
+ **`Bytecode-based`** — リクエストは、[Gremlin 言語バリアント](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants) (GLV) のシリアル化された Gremlin バイトコードを使用して行われます。

  例えば、Java ドライバー `g = traversal().withRemote(...)` を使用する場合などです。

上記のコンテキストのどちらでも、リクエストがセッションレスまたはセッションにバインドされた状態で送信されるという追加のコンテキストがあります。

**注記**  
 Gremlin トランザクションは、サーバー側のリソースを解放できるように、常にコミットまたはロールバックする必要があります。トランザクション中にエラーが発生した場合は、失敗した特定のリクエストだけでなく、トランザクション全体を再試行することが重要です。

## セッションレスリクエスト
<a name="access-graph-gremlin-transactions-sessionless"></a>

 セッションレスの場合、リクエストは 1 回のトランザクションに相当します。

スクリプトの場合、1 回のリクエストで送信された 1 つ以上の Gremlin ステートメントが 1 つのトランザクションとしてコミットまたはロールバックされることを意味します。例えば、次のようになります。

```
Cluster cluster = Cluster.open();
Client client = cluster.connect(); // sessionless
// 3 vertex additions in one request/transaction:
client.submit("g.addV();g.addV();g.addV()").all().get();
```

バイトコードの場合、`g` からトラバーサルが生成され実行されるたびに、セッションレスリクエストが行われます。

```
GraphTraversalSource g = traversal().withRemote(...);

// 3 vertex additions in three individual requests/transactions:
g.addV().iterate();
g.addV().iterate();
g.addV().iterate();

// 3 vertex additions in one single request/transaction:
g.addV().addV().addV().iterate();
```

## セッションにバインドされたリクエスト
<a name="access-graph-gremlin-transactions-session-bound"></a>

セッションにバインドすると、1 つのトランザクションのコンテキスト内で複数のリクエストを適用できます。

スクリプトの場合、すべてのグラフ操作を連結して 1 つの埋め込み文字列値にする必要がないということです。

```
Cluster cluster = Cluster.open();
Client client = cluster.connect(sessionName); // session
try {
    // 3 vertex additions in one request/transaction:
    client.submit("g.addV();g.addV();g.addV()").all().get();
} finally {
    client.close();
}

try {
    // 3 vertex additions in three requests, but one transaction:
    client.submit("g.addV()").all().get(); // starts a new transaction with the same sessionName
    client.submit("g.addV()").all().get();
    client.submit("g.addV()").all().get();
} finally {
    client.close();
}
```

バイトコードの場合、TinkerPop `3.5.x` 以降、トランザクションを明示的に制御し、セッションを透過的に管理できます。Gremlin 言語バリアント (GLV) は、以下のように Gremlin の `tx()` 構文をサポートして、トランザクションを `commit()` または `rollback()` します。

```
GraphTraversalSource g = traversal().withRemote(conn);

Transaction tx = g.tx();

// Spawn a GraphTraversalSource from the Transaction.
// Traversals spawned from gtx are executed within a single transaction.
GraphTraversalSource gtx = tx.begin();
try {
    gtx.addV('person').iterate();
    gtx.addV('software').iterate();

    tx.commit();
} finally {
    if (tx.isOpen()) {
        tx.rollback();
    }
}
```

上記の例は Java で記述されていますが、この `tx()` 構文は、Python、Javascript、.NET でも使用できます。

**警告**  
セッションレス読み取り専用クエリは [SNAPSHOT](transactions-isolation-levels.md) 分離下で実行されますが、明示的なトランザクション内で実行される読み取り専用クエリは [SERIALIZABLE](transactions-isolation-levels.md) 分離下で実行されます。`SERIALIZABLE` 分離下で実行される読み取り専用クエリは、`SNAPSHOT` 分離下で実行されるクエリとは異なり、オーバーヘッドが大きくなり、同時書き込みによってブロックしたり、ブロックされたりする可能性があります。

# Amazon Neptune で Gremlin API を使用する
<a name="gremlin-api-reference"></a>

**注記**  
Amazon Neptune は、`bindings` プロパティをサポートしていません。

Gremlin HTTPS では、すべて単一のエンドポイント `https://your-neptune-endpoint:port/gremlin` を使用する必要があります。すべての Neptune 接続は HTTPS を使用する必要があります。

Gremlin コンソールから Neptune グラフには、WebSockets を介して直接接続できます。

Gremlin エンドポイントへの接続の詳細については、「[Gremlin を使用した Neptune グラフへのアクセス](access-graph-gremlin.md)」を参照してください。

Gremlin の Amazon Neptune 実装には、考慮する必要がある特定の詳細と相違点があります。詳細については、「[Amazon Neptune の Gremlin 標準への準拠](access-graph-gremlin-differences.md)」を参照してください。

Gremlin 言語およびトラバーサルについては、Apache TinkerPop ドキュメントの「[トラバーサル](https://tinkerpop.apache.org/docs/current/reference/#traversal)」を参照してください。

# Amazon Neptune Gremlin でクエリ結果をキャッシュする
<a name="gremlin-results-cache"></a>

Amazon Neptune は、Gremlin クエリの結果キャッシュをサポートしています。

クエリ結果キャッシュを有効にし、クエリヒントを使用して Gremlin 読み取り専用クエリの結果をキャッシュできます。

クエリを再実行すると、キャッシュ内に残っている限り、低レイテンシーで I/O コストなしでキャッシュされた結果を取得します。これは、HTTP エンドポイントと WebSocket を使用して、バイトコードまたは文字列形式で送信されたクエリに対して機能します。

**注記**  
プロファイルエンドポイントに送信されたクエリは、クエリキャッシュが有効になっていてもキャッシュされません。

Neptune クエリ結果キャッシュの動作は、いくつかの方法で制御できます。例えば、次のようになります。
+ キャッシュされた結果をブロック単位でページ分割できます。
+ 指定したクエリの有効期限 (TTL) を指定できます。
+ 指定したクエリのキャッシュをクリアすることができます。
+ キャッシュ全体をクリアできます。
+ 結果がキャッシュサイズを超えた場合に通知されるように設定できます。

キャッシュは、LRU (least-recently-used) ポリシーを使用して維持されます。つまり、キャッシュに割り当てられた領域がいっぱいになると、新しい結果がキャッシュされるときに参照される頻度が最も低い結果が削除され、スペースが確保されます。

**重要**  
クエリ結果キャッシュは、`t3.medium` または `t4.medium` インスタンスタイプでは使用できません。

## Neptune でクエリ結果キャッシュを有効にする
<a name="gremlin-results-cache-enabling"></a>

 クエリ結果のキャッシュは、クラスター内のすべてのインスタンスに対して、またはインスタンスごとに有効にできます。クラスター内のすべてのインスタンスで結果のキャッシュを有効にするには、クラスターの `cluster-parameter-group` の `neptune_result_cache` パラメータを `1` に設定します。特定のインスタンスでこれを有効にするには、インスタンスの `instance-parameter-group` の `neptune_result_cache` パラメータを `1` に設定します。クラスターパラメータグループ設定は、インスタンスパラメータグループ値を上書きします。

 結果のキャッシュパラメータ設定を適用するには、影響を受けるインスタンスで再起動が必要です。`cluster-parameter-group` を介してクラスター内のすべてのインスタンスで結果のキャッシュを有効にできますが、各インスタンスは独自のキャッシュを保持します。クエリ結果のキャッシュ機能は、クラスター全体のキャッシュではありません。

結果キャッシュを有効にすると、Neptune は現在のメモリの一部をクエリ結果をキャッシュするために確保します。使用しているインスタンスタイプが大きくなり、使用可能なメモリが多いほど、Neptune がキャッシュに割り当てるメモリが多くなります。

結果キャッシュメモリがいっぱいになると、Neptune は参照される頻度が最も低い (LRU) キャッシュされた結果を自動的に減らし、新しい結果のための場所を空けます。

結果キャッシュの現在のステータスを確認するには、[インスタンスのステータス](access-graph-status.md) コマンドを使います。

## ヒントを使用してクエリ結果をキャッシュする
<a name="gremlin-results-cache-using"></a>

クエリ結果キャッシュを有効にすると、クエリヒントを使用してクエリキャッシュを制御します。以下の例はすべて、同じクエリトラバーサルに適用されます。

```
g.V().has('genre','drama').in('likes')
```

### `enableResultCache`の使用
<a name="using-enableResultCache"></a>

クエリ結果キャッシュを有効にした状態で、Gremlin クエリの結果をキャッシュするには、次のように `enableResultCache` クエリヒントを使います。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Neptune はクエリ結果を返し、キャッシュします。後で、まったく同じクエリを再度発行することで、キャッシュされた結果にアクセスできます。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

キャッシュされた結果を識別するキャッシュキーは、クエリ文字列そのものです。

```
g.V().has('genre','drama').in('likes')
```

### `enableResultCacheWithTTL`の使用
<a name="using-enableResultCacheWithTTL"></a>

クエリ結果をキャッシュする期間を指定するには、`enableResultCacheWithTTL` クエリヒントを使います。たとえば、次のクエリでは、クエリ結果が 120 秒後に期限切れになるよう指定しています。

```
g.with('Neptune#enableResultCacheWithTTL', 120)
 .V().has('genre','drama').in('likes')
```

ここでもキャッシュされた結果を識別するキャッシュキーは、ベースクエリ文字列そのものです。

```
g.V().has('genre','drama').in('likes')
```

また、`enableResultCache` クエリヒントでそのクエリ文字列を使用して、キャッシュされた結果にアクセスできます。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

結果がキャッシュされてから 120 秒以上経過すると、そのクエリは新しい結果を返し、有効期限 (TTL)なしでキャッシュします。

キャッシュされた結果にアクセスするには、`enableResultCacheWithTTL` クエリヒントで同じクエリを発行します。例えば、次のようになります。

```
g.with('Neptune#enableResultCacheWithTTL', 140)
 .V().has('genre','drama').in('likes')
```

120 秒が経過するまで (つまり、現在有効になっている TTL)、`enableResultCacheWithTTL` クエリヒントを使うこの新しいクエリは、キャッシュされた結果を返します。120 秒後、新しい結果が返され、有効期限 (TTL) 140 秒でキャッシュされます。

**注記**  
クエリキーの結果が既にキャッシュされている場合は、`enableResultCacheWithTTL` とともに同じクエリキーは、新しい結果を生成せず、現在キャッシュされている結果の有効期限 (TTL)には影響しません。  
結果が `enableResultCache` を使って以前にキャッシュされていた場合、`enableResultCacheWithTTL` が新しい結果を生成し、指定した TTL 用にキャッシュする前に、まずキャッシュをクリアする必要があります。
結果が `enableResultCachewithTTL` を使って以前にキャッシュされていた場合、`enableResultCacheWithTTL` が新しい結果を生成し、指定した TTL 用にキャッシュする前に、まず前の TTL を期限切れとする必要があります。

### `invalidateResultCacheKey`の使用
<a name="using-invalidateResultCacheKey"></a>

`invalidateResultCacheKey` クエリヒントを使って特定のクエリのキャッシュされた結果をクリアできます。例えば、次のようになります。

```
g.with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

このクエリは、クエリキー、`g.V().has('genre','drama').in('likes')`、のキャッシュをクリアし、そのクエリの新しい結果を返します。

また、`invalidateResultCacheKey` と `enableResultCache` または `enableResultCacheWithTTL` を組み合わせることもできます。たとえば、次のクエリは、現在のキャッシュされた結果をクリアし、新しい結果をキャッシュして返します。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

### `invalidateResultCache`の使用
<a name="using-invalidateResultCache"></a>

`invalidateResultCache` クエリヒントを使ってクエリ結果キャッシュのすべてのキャッシュされた結果をクリアできます。例えば、次のようになります。

```
g.with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

このクエリは、結果キャッシュ全体をクリアし、そのクエリの新しい結果を返します。

また、`invalidateResultCache` と `enableResultCache` または `enableResultCacheWithTTL` を組み合わせることもできます。たとえば、次のクエリは、結果キャッシュ全体をクリアし、このクエリの新しい結果をキャッシュして返します。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

## キャッシュされたクエリ結果のページ割り
<a name="gremlin-results-cache-paginating"></a>

次のような多数の結果を既にキャッシュしているとします。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

それから、次の範囲クエリを発行するとします。

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes').range(0,10)
```

Neptune は最初に完全なキャッシュキーを探します。つまり `g.V().has('genre','drama').in('likes').range(0,10)` です。そのキーが存在しない場合、Neptune は次に範囲のないクエリ文字列のキーがあるかどうかを調べます (すなわち`g.V().has('genre','drama').in('likes')`)。そのキーが見つかると、Neptune は範囲が指定しているように、キャッシュから最初の 10 個の結果を取得します。

**注記**  
末尾に範囲があるクエリの `invalidateResultCacheKey` クエリヒントを使うと、Neptune は、範囲とクエリと完全に一致するものが見つからない場合、範囲のないクエリのキャッシュをクリアします。

### `numResultsCached`と使用する`.iterate()`
<a name="gremlin-results-cache-paginating-numResultsCached"></a>

`numResultsCached` クエリヒントを使用すると、キャッシュされているすべての結果を返さずに結果キャッシュに入力できます。これは、多数の結果をページ分割したい場合に便利です。

`numResultsCached` クエリヒントは、`iterate()` で終わるクエリでのみ機能します。

たとえば、サンプルクエリの最初の 50 の結果をキャッシュする場合は、次のようにします。

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

この場合、キャッシュ内のクエリキーは次のようになります。`g.with("Neptune#numResultsCached", 50).V().has('genre','drama').in('likes')`。このクエリを使用して、キャッシュされた結果の最初の 10 個を取得できます。

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(0, 10)
```

また、次のように、クエリから次の 10 個の結果を取得できます。

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(10, 20)
```

忘れずに `numResultsCached` ヒントを含めます！これはクエリキーの不可欠な部分であるため、キャッシュされた結果にアクセスするには、これが存在していなければなりません。

**`numResultsCached` 使用時には、心に留めておくべきことがいくつかあります。**
+ **`numResultsCached` で入力する番号がクエリの最後に適用されます。**  これは、たとえば、次のクエリが実際に結果を `(1000, 1500)` 範囲内にキャッシュしていることを意味します。

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```
+ **`numResultsCached` で入力する番号はキャッシュする結果の最大数を指定します。**  これは、たとえば、次のクエリが実際に結果を `(1000, 2000)` 範囲内にキャッシュしていることを意味します。

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 100000)
   .V().range(1000, 2000).iterate()
  ```
+ **`.range().iterate()` で終わるクエリによってキャッシュされる結果には独自の範囲があります。**  たとえば、次のようなクエリを使用して結果をキャッシュするとします。

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```

  キャッシュから最初の 100 個の結果を取得するには、次のようなクエリを記述します。

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).range(0, 100)
  ```

  この100の結果は、範囲 `(1000, 1100)` 内の基本クエリの結果と同等になります。

## キャッシュされた結果を検索するために使用されるクエリキャッシュキー
<a name="gremlin-results-cache-query-keys"></a>

クエリの結果がキャッシュされた後、後続のクエリは新しい結果を生成するのではなく、キャッシュからの*クエリキャッシュキー*検索結果と同じものになります。クエリのクエリキャッシュキーは、次のように評価されます。

1. `numResultsCached` 以外のキャッシュ関連のクエリヒントはすべて無視されます。

1. 最後の `iterate()` ステップは無視されます。

1. 残りのクエリは、バイトコード表現に従って順序付けられます。

結果の文字列は、既にキャッシュ内にあるクエリ結果のインデックスと照合され、クエリにキャッシュヒットがあるかどうかを判断します。

例えば、次のようなクエリがあるとします。

```
g.withSideEffect('Neptune#typePromotion', false).with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

このクエリは、次のバイトコードバージョンとして保存されます。

```
g.withSideEffect('Neptune#typePromotion', false)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes')
```

## 結果キャッシュに関連する例外
<a name="gremlin-results-cache-exceptions"></a>

キャッシュしようとしているクエリの結果が大きすぎてキャッシュメモリに収まらない場合は、以前にキャッシュされたものをすべて削除した後でも、Neptune は `QueryLimitExceededException` 障害を見つけます。結果は返されず、例外によって次のエラーメッセージが生成されます。

```
The result size is larger than the allocated cache,
      please refer to results cache best practices for options to rerun the query.
```

`noCacheExceptions` クエリヒントを使って、次のようにこのメッセージを抑制できます。

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#noCacheExceptions', true)
 .V().has('genre','drama').in('likes')
```

# Gremlin `mergeV()` および `mergeE()` ステップによる効率的なアップサートの実行
<a name="gremlin-efficient-upserts"></a>

アップサート (または条件付き挿入) は、頂点やエッジが既に存在する場合は再利用し、存在しない場合は作成します。効率的なアップサートは、Gremlin クエリのパフォーマンスに大きな違いをもたらすことができます。

アップサートを使用すると、冪等挿入操作、つまり、そのような操作を何回実行しても、全体的な結果は同じ操作を記述できます。これは、グラフの同じ部分に同時に変更を加えると、1 つ以上のトランザクションが `ConcurrentModificationException` で強制的にロールバックされ、再試行が必要になるような、同時書き込みの多いシナリオで役立ちます。

例えば、次のクエリは、指定された `Map` を使用して、`T.id` が `"v-1"` の頂点を最初に探すことによって、頂点をアップサートします。その頂点が見つかると、その頂点が返されます。見つからなかった場合は、その `id` とプロパティを持つ頂点が `onCreate` 句によって作成されます。

```
g.mergeV([(id):'v-1']).
  option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org'])
```

## アップサートをバッチ処理してスループットを向上させる
<a name="gremlin-upserts-batching"></a>

スループットの高い書き込みシナリオでは、`mergeV()` ステップと `mergeE()` ステップを連鎖して、頂点とエッジをバッチでアップサートできます。バッチ処理を行うと、多数の頂点やエッジをアップサートすることによるトランザクションのオーバーヘッドが軽減されます。その後、複数のクライアントを使用してバッチリクエストを並行して更新することで、スループットをさらに高めることができます。

経験則として、バッチリクエストごとに約 200 件のレコードをアップサートすることをお勧めします。レコードは 1 つの頂点、またはエッジラベル、またはプロパティです。例えば、1 つのラベルと 4 つのプロパティを持つ頂点では、5 つのレコードが作成されます。1 つのラベルと 1 つのプロパティを持つエッジでは、2 つのレコードが作成されます。それぞれ 1 つのラベルと 4 つのプロパティを持つ頂点のバッチをアップサートしたい場合、`200 / (1 + 4) = 40` のため、バッチサイズは 40 から始める必要があります。

バッチサイズを試してみることもできます。バッチあたり 200 レコードから始めるのが適切ですが、理想的なバッチサイズは作業負荷に応じて大きくなったり小さくなったりします。ただし、Neptune ではリクエストごとの Gremlin ステップの総数を制限する場合があることに注意してください。この制限は文書化されていませんが、念のため、リクエストに含まれるグレムリンステップ数は 1,500 を超えないようにしてください。Neptune は、1,500 ステップを超える大規模なバッチリクエストを拒否する場合があります。

スループットを高めるには、複数のクライアントを使用して、バッチを並行してアップサートできます (「[効率的なマルチスレッドの Gremlin 書き込みの作成](best-practices-gremlin-multithreaded-writes.md)」を参照)。クライアントの数は、Neptune ライターインスタンスのワーカースレッドの数と同じである必要があり、通常、これはサーバー上の vCPU の数の 2 倍です。例えば、`r5.8xlarge` インスタンスには 32 個の vCPU と 64 個のワーカースレッドがあります。`r5.8xlarge` を使用する高スループットの書き込みシナリオでは、64 台のクライアントが Neptune にバッチアップサートを並行して書き込みます。

各クライアントはバッチリクエストを送信し、リクエストが完了するのを待ってから、別のリクエストを送信する必要があります。複数のクライアントは並行して実行されますが、個々のクライアントはそれぞれ順番にリクエストを送信します。これにより、サーバー側のリクエストキューがフラッディングすることなく、すべてのワーカースレッドを占有するリクエストのストリームがサーバーに安定して供給されます (「[Neptune DB クラスターでの DB インスタンスのサイジング](feature-overview-db-clusters.md#feature-overview-sizing-instances)」を参照)。

## 複数のトラバーサーを生成するステップは避ける
<a name="gremlin-upserts-single-traverser"></a>

Gremlin ステップを実行すると、入力トラバーサーが 1 つ取得され、1 つ以上の出力トラバーサーが出力されます。1 つのステップで発生するトラバーサーの数によって、次のステップが実行される回数が決まります。

通常、バッチ操作を実行するときは、頂点 A のアップサートなどの各操作を 1 回実行する必要があります。これにより、一連の操作は、頂点 A をアップサート、頂点 B をアップサート、頂点 C をアップサートするというようになります。ステップが 1 つの要素のみを作成または変更する限り、そのステップはトラバーサーを 1 つだけ出力し、次の操作を表すステップは 1 回だけ実行されます。一方、1 つの操作で複数の要素を作成または変更すると、複数のトラバーサーが出力され、それ以降のステップは、発行されたトラバーサーごとに 1 回ずつ、というように複数回実行されます。その結果、データベースが不必要な追加作業を行うことになり、場合によっては不要な頂点、エッジ、またはプロパティ値が作成されることもあります。

問題が発生する例としては、`g.V().addV()` のようなクエリがあります。この単純なクエリは、グラフ内の頂点ごとに頂点を追加します。これは、`V()` がグラフ内の頂点ごとにトラバーサーを発行し、それらのトラバーサーのそれぞれが `addV()` への呼び出しをトリガーするためです。

複数のトラバーサーを発行する操作を処理する方法については、「[アップサートと挿入の混合](#gremlin-upserts-and-inserts)」を参照してください。

## 頂点のアップサート
<a name="gremlin-upserts-vertices"></a>

`mergeV()` ステップは、頂点をアップサートするために特別に設計されています。グラフ内の既存の頂点と一致する要素を表す `Map` を引数として取り、要素が見つからない場合は、その `Map` を使用して新しい頂点を作成します。このステップでは、作成時やマッチ時の動作を変更することも可能であり、`option()` モジュレータに `Merge.onCreate` および `Merge.onMatch` トークンを適用して、それぞれの動作を制御できます。このステップの使用方法の詳細については、TinkerPop の「[リファレンスドキュメント](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step)」を参照してください。

頂点 ID を使用して、特定の頂点が存在するかどうかを判断できます。Neptune では ID に関する同時実行の多いユースケースに合わせてアップサートを最適化するため、この方法が推奨されます。例として、次のクエリは、特定の頂点 ID を持つ頂点がまだ存在しない場合はその頂点を作成し、存在する場合はそれを再利用します。

```
g.mergeV([(T.id): 'v-1']).
    option(onCreate, [(T.label): 'PERSON', email: 'person-1@example.org', age: 21]).
    option(onMatch, [age: 22]).
  id()
```

このクエリは `id()` ステップで終わることに注意してください。頂点をアップサートする目的では必ずしも必要ではありませんが、アップサートクエリの最後に `id()` ステップを追加することで、サーバーはすべての頂点プロパティをクライアントにシリアル化し直さずに済むため、クエリのロックコストを削減できます。

あるいは、頂点プロパティを使用して頂点を識別することもできます。

```
g.mergeV([email: 'person-1@example.org']).
    option(onCreate, [(T.label): 'PERSON', age: 21]).
    option(onMatch, [age: 22]).
  id()
```

可能であれば、ユーザー指定の独自の ID を使用して頂点を作成し、これらの ID を使用してアップサート操作中に頂点が存在するかどうかを判断します。これにより、Neptune はアップサートを最適化できます。ID ベースのアップサートは、同時変更が頻繁に行われる場合、プロパティベースのアップサートよりもはるかに効率的です。

### 頂点アップサートの連鎖
<a name="gremlin-upserts-vertices-chaining"></a>

頂点アップサートを連鎖して、まとめて挿入することができます。

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .id()
```

または、次の `mergeV()` 構文を使用することもできます。

```
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']).
  mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']).
  mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org'])
```

ただし、この形式のクエリには、`id` による基本的な検索方法では不要な要素が検索条件に含まれているため、前のクエリほど効率的ではありません。

## エッジのアップサート
<a name="gremlin-upserts-edges"></a>

`mergeE()` ステップは、エッジをアップサートするために特別に設計されています。グラフ内の既存のエッジと一致する要素を表す `Map` を引数として取り、要素が見つからない場合は、その `Map` を使用して新しいエッジを作成します。このステップでは、作成時やマッチ時の動作を変更することも可能であり、`option()` モジュレータに `Merge.onCreate` および `Merge.onMatch` トークンを適用して、それぞれの動作を制御できます。このステップの使用方法の詳細については、TinkerPop の「[リファレンスドキュメント](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step)」を参照してください。

カスタム頂点 ID を使用して頂点をアップサートするのと同じ方法で、エッジ ID を使用してエッジをアップサートできます。繰り返しますが、Neptune がクエリを最適化できるようになるため、この方法が推奨されます。例えば、次のクエリは、エッジ ID がまだ存在しない場合はそのエッジ ID に基づいてエッジを作成し、存在する場合は再利用します。このクエリでは、新しいエッジを作成する必要がある場合には `Direction.from` および `Direction.to` 頂点の ID も使用します。

```
g.mergeE([(T.id): 'e-1']).
    option(onCreate, [(from): 'v-1', (to): 'v-2', weight: 1.0]).
    option(onMatch, [weight: 0.5]).
  id()
```

このクエリは `id()` ステップで終わることに注意してください。エッジをアップサートする目的では必ずしも必要ではありませんが、アップサートクエリの最後に `id()` ステップを追加することで、サーバーはすべてのエッジプロパティをクライアントにシリアル化し直さずに済むため、クエリのロックコストを削減できます。

多くのアプリケーションはカスタム頂点 ID を使用しますが、エッジ ID の生成は Neptune に任せています。エッジの ID はわからないが、`from` および `to` 頂点 ID はわかっている場合は、次のようなクエリを使用して、エッジをアップサートできます。

```
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  id()
```

ステップでエッジを作成するには、`mergeE()` によって参照されるすべての頂点が存在している必要があります。

### エッジのアップサートの連鎖
<a name="gremlin-upserts-edges-chaining"></a>

頂点アップサートの場合と同様、`mergeE()` ステップを連鎖して、バッチリクエストにするのは簡単です。

```
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']).
  mergeE([(from): 'v-3', (to): 'v-4', (T.label): 'KNOWS']).
  id()
```

## 頂点とエッジのアップサートの組み合わせ
<a name="gremlin-upserts-vertexes-and-edges"></a>

頂点とそれらを接続するエッジの両方をアップサートしたい場合があります。ここで紹介したバッチサンプルをミックスしてもかまいません。次の例では、3 つの頂点と 2 つのエッジをアップサートしています。

```
g.mergeV([(id):'v-1']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']).
  mergeV([(id):'v-2']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']).
  mergeV([(id):'v-3']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']).
  mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']).
 id()
```

## アップサートと挿入の混合
<a name="gremlin-upserts-and-inserts"></a>

頂点とそれらを接続するエッジの両方をアップサートしたい場合があります。ここで紹介したバッチサンプルをミックスしてもかまいません。次の例では、3 つの頂点と 2 つのエッジをアップサートしています。

アップサートは通常、一度に 1 つの要素を処理します。ここで説明したアップサートパターンに従うと、アップサート操作ごとにトラバーサーが 1 回発生し、それ以降の操作は 1 回だけ実行されます。

ただし、アップサートと挿入を混在させたい場合もあります。例えば、エッジを使用してアクションやイベントのインスタンスを表す場合などが該当します。リクエストでは、必要な頂点がすべて存在することを確認するためにアップサートを使用し、エッジを追加するためにインサートを使用する場合があります。この種のリクエストでは、各操作で発生する可能性のあるトラバーサーの数に注意してください。

アップサートとインサートを組み合わせて、イベントを表すエッジをグラフに追加する次の例を考えてみましょう。

```
// Fully optimized, but inserts too many edges
g.mergeV([(id):'v-1']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']).
  mergeV([(id):'v-2']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']).
  mergeV([(id):'v-3']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']).
  mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']).
  V('p-1', 'p-2').
  addE('FOLLOWED').to(V('p-1')).
  V('p-1', 'p-2', 'p-3').
  addE('VISITED').to(V('c-1')).
  id()
```

クエリでは 5 つのエッジを挿入する必要があります。2 つは FOLLOWED エッジであり、3 つは VISITED エッジです。ただし、記述されているクエリでは、8 つのエッジが挿入されます (2 つは FOLLOWED、6 つは VISITED)。これは、2 つの FOLLOWED エッジを挿入する操作で 2 つのトラバーサーが発生し、3 つのエッジを挿入する後続の挿入操作が 2 回実行されるためです。

この問題を解決するには、複数のトラバーサーが発生する可能性のある各操作の後に `fold()` ステップを追加します。

```
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']).
  mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']).
  mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org']).
  mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']).
  V('p-1', 'p-2').
  addE('FOLLOWED').
    to(V('p-1')).
  fold().
  V('p-1', 'p-2', 'p-3').
  addE('VISITED').
    to(V('c-1')).
  id()
```

ここでは、FOLLOWED エッジを挿入する操作の後に、`fold()` ステップを挿入しました。これにより、1 つのトラバーサーが発生し、それ以降の操作は 1 回だけ実行されます。

この方法の欠点は、`fold()` が最適化されていないため、クエリが完全には最適化されないことです。`fold()` の後に続く挿入操作も最適化されなくなってしまいます。

`fold()` を使用して、後続のステップの代わりにトラバーサーの数を減らす必要がある場合は、最もコストの低いものがクエリの最適化されていない部分を占めるように操作を順序付けてください。

## カーディナリティの設定
<a name="gremlin-upserts-setting-cardinality"></a>

 Neptune の頂点プロパティのデフォルトのカーディナリティが設定されています。つまり、mergeV() を使用する場合、マップで指定された値にはすべてそのカーディナリティが付与されます。単一のカーディナリティを使用するには、その使用法が明示的である必要があります。TinkerPop 3.7.0 以降では、次の例に示すように、カーディナリティをマップの一部として指定できる新しい構文があります。

```
g.mergeV([(T.id): '1234']).
  option(onMatch, ['age': single(20), 'name': single('alice'), 'city': set('miami')])
```

 または、次のようにカーディナリティを対象の `option` のデフォルトとして設定することもできます。

```
// age and name are set to single cardinality by default
g.mergeV([(T.id): '1234']).
  option(onMatch, ['age': 22, 'name': 'alice', 'city': set('boston')], single)
```

 バージョン 3.7.0 より前の `mergeV()` については、カーディナリティを設定するためのオプション数が少ない状態です。一般的なアプローチは、次のように `property()` ステップにフォールバックすることです。

```
g.mergeV([(T.id): '1234']). 
  option(onMatch, sideEffect(property(single,'age', 20).
  property(set,'city','miami')).constant([:]))
```

**注記**  
 このアプローチは、開始ステップで使用される場合にのみ `mergeV()` で機能します。したがって、この構文を使用する開始ステップの最初の `mergeV()` の後に、受信トラバーサーがグラフ要素である場合にエラーが発生するため、単一のトラバーサル内で `mergeV()` を連鎖することはできません。この場合、`mergeV()` 呼び出しを複数のリクエストに分割し、それぞれを開始ステップにすることができます。

# `fold()/coalesce()/unfold()` による効率的な Gremlin アップサートの実行
<a name="gremlin-efficient-upserts-pre-3.6"></a>

アップサート (または条件付き挿入) は、頂点やエッジが既に存在する場合は再利用し、存在しない場合は作成します。効率的なアップサートは、Gremlin クエリのパフォーマンスに大きな違いをもたらすことができます。

このページでは、`fold()/coalesce()/unfold()` Gremlin パターンを使用して効率的なアップサートを行う方法を説明します。ただし、Neptune エンジンバージョン [1.2.1.0](engine-releases-1.2.1.0.md) で導入された TinkerPop バージョン3.6.x のリリースでは、ほとんどの場合、新しい `mergeV()` および `mergeE()` ステップの方が適しています。ここで説明する `fold()/coalesce()/unfold()` パターンは、一部の複雑な状況ではまだ役に立つかもしれませんが、一般的な用途では、[Gremlin `mergeV()` および `mergeE()` ステップによる効率的なアップサートの実行](gremlin-efficient-upserts.md) で説明されているように、できれば `mergeV()` および `mergeE()` を使用してください。

アップサートを使用すると、冪等挿入操作、つまり、そのような操作を何回実行しても、全体的な結果は同じ操作を記述できます。これは、グラフの同じ部分に同時に変更を加えると、1 つ以上のトランザクションが強制的に `ConcurrentModificationException` でロールバックされ、再試行が必要になるような、同時書き込みの多いシナリオに役立ちます。

例えば、次のクエリは、最初にデータセット内の指定された頂点を探し、その結果をリストにまとめることで頂点を更新します。`coalesce()` ステップで最初に指定されたトラバーサルで、クエリはこのリストを展開します。展開されたリストが空でない場合、結果は `coalesce()` から出力されます。ただし、頂点が現在存在しないために `unfold()` が空のコレクションを返した場合、`coalesce()` は、その頂点が指定された 2 番目のトラバーサルの評価に移り、この 2 番目のトラバーサルで、クエリは欠落している頂点を作成します。

```
g.V('v-1').fold()
          .coalesce(
             unfold(),
             addV('Person').property(id, 'v-1')
                           .property('email', 'person-1@example.org')
           )
```

## アップサートには最適化された `coalesce()` の形式を使用する
<a name="gremlin-upserts-pre-3.6-coalesce"></a>

Neptune は `fold().coalesce(unfold(), ...)` イディオムを最適化して高スループットの更新を行うことができますが、この最適化は、`coalesce()` の両方の部分が頂点またはエッジのいずれかを返し、それ以外は何も返さない場合にのみ機能します。`coalesce()` のいずれかの部分からプロパティなど異なるものを返そうとした場合、Neptune の最適化は行われません。クエリは成功するかもしれませんが、特に大きなデータセットに対しては、最適化されたバージョンほどには機能しません。

最適化されていないアップサートクエリは実行時間を増加させ、スループットを低下させるため、Gremlin `explain` エンドポイントを使用して Upsert クエリが完全に最適化されているかどうかを判断する価値があります。`explain` プランを見直すときは、`+ not converted into Neptune steps` と `WARNING: >>` で始まる行を探してください。例えば、次のようになります。

```
+ not converted into Neptune steps: [FoldStep, CoalesceStep([[UnfoldStep], [AddEdgeSte...
WARNING: >> FoldStep << is not supported natively yet
```

これらの警告は、クエリが完全に最適化されない原因となっている部分を特定するのに役立ちます。

クエリを完全に最適化できない場合もあります。このような場合は、最適化できないステップをクエリの最後に配置して、エンジンができるだけ多くのステップを最適化できるようにする必要があります。この手法はバッチアップサートの例の一部で使用されています。バッチアップサートの例では、ある頂点またはエッジのセットに対して最適化されたアップサートをすべて実行してから、最適化されていない可能性のある追加の修正を同じ頂点またはエッジに適用します。

## アップサートをバッチ処理してスループットを向上させる
<a name="gremlin-upserts-pre-3.6-batching"></a>

高スループットの書き込みシナリオでは、アップサートのステップを連鎖させて頂点とエッジをバッチでアップサートできます。バッチ処理を行うと、多数の頂点やエッジをアップサートすることによるトランザクションのオーバーヘッドが軽減されます。その後、複数のクライアントを使用してバッチリクエストを並行して更新することで、スループットをさらに高めることができます。

経験則として、バッチリクエストごとに約 200 件のレコードをアップサートすることをお勧めします。レコードは 1 つの頂点、またはエッジラベル、またはプロパティです。例えば、1 つのラベルと 4 つのプロパティを持つ頂点では、5 つのレコードが作成されます。1 つのラベルと 1 つのプロパティを持つエッジでは、2 つのレコードが作成されます。それぞれ 1 つのラベルと 4 つのプロパティを持つ頂点のバッチをアップサートしたい場合、`200 / (1 + 4) = 40` のため、バッチサイズは 40 から始める必要があります。

バッチサイズを試してみることもできます。バッチあたり 200 レコードから始めるのが適切ですが、理想的なバッチサイズは作業負荷に応じて大きくなったり小さくなったりします。ただし、Neptune ではリクエストごとの Gremlin ステップの総数を制限する場合があることに注意してください。この制限は文書化されていませんが、念のため、リクエストに含まれるグレムリンステップ数は 1500 を超えないようにしてください。Neptune は、1,500 ステップを超える大規模なバッチリクエストを拒否する場合があります。

スループットを高めるには、複数のクライアントを使用して、バッチを並行してアップサートできます (「[効率的なマルチスレッドの Gremlin 書き込みの作成](best-practices-gremlin-multithreaded-writes.md)」を参照)。クライアントの数は、Neptune ライターインスタンスのワーカースレッドの数と同じである必要があり、通常、これはサーバー上の vCPU の数の 2 倍です。例えば、`r5.8xlarge` インスタンスには 32 個の vCPU と 64 個のワーカースレッドがあります。`r5.8xlarge` を使用する高スループットの書き込みシナリオでは、64 台のクライアントが Neptune にバッチアップサートを並行して書き込みます。

各クライアントはバッチリクエストを送信し、リクエストが完了するのを待ってから、別のリクエストを送信する必要があります。複数のクライアントは並行して実行されますが、個々のクライアントはそれぞれ順番にリクエストを送信します。これにより、サーバー側のリクエストキューがフラッディングすることなく、すべてのワーカースレッドを占有するリクエストのストリームがサーバーに安定して供給されます (「[Neptune DB クラスターでの DB インスタンスのサイジング](feature-overview-db-clusters.md#feature-overview-sizing-instances)」を参照)。

## 複数のトラバーサーを生成するステップは避ける
<a name="gremlin-upserts-pre-3.6-single-traverser"></a>

Gremlin ステップを実行すると、入力トラバーサーが 1 つ取得され、1 つ以上の出力トラバーサーが出力されます。1 つのステップで発生するトラバーサーの数によって、次のステップが実行される回数が決まります。

通常、バッチ操作を実行するときは、頂点 A のアップサートなどの各操作を 1 回実行する必要があります。これにより、一連の操作は、頂点 A をアップサート、頂点 B をアップサート、頂点 C をアップサートするというようになります。ステップが 1 つの要素のみを作成または変更する限り、そのステップはトラバーサーを 1 つだけ出力し、次の操作を表すステップは 1 回だけ実行されます。一方、1 つの操作で複数の要素を作成または変更すると、複数のトラバーサーが出力され、それ以降のステップは、発行されたトラバーサーごとに 1 回ずつ、というように複数回実行されます。その結果、データベースが不必要な追加作業を行うことになり、場合によっては不要な頂点、エッジ、またはプロパティ値が作成されることもあります。

問題が発生する例としては、`g.V().addV()` のようなクエリがあります。この単純なクエリは、グラフ内の頂点ごとに頂点を追加します。これは、`V()` がグラフ内の頂点ごとにトラバーサーを発行し、それらのトラバーサーのそれぞれが `addV()` への呼び出しをトリガーするためです。

複数のトラバーサーを発行する操作を処理する方法については、「[アップサートと挿入の混合](#gremlin-upserts-pre-3.6-and-inserts)」を参照してください。

## 頂点のアップサート
<a name="gremlin-upserts-pre-3.6-vertices"></a>

頂点 ID を使用して、対応する頂点が存在するかどうかを判断できます。Neptune では ID に関する同時実行の多いユースケースに合わせてアップサートを最適化するため、この方法が推奨されます。例として、次のクエリは、特定の頂点 ID を持つ頂点がまだ存在しない場合はその頂点を作成し、存在する場合はそれを再利用します。

```
g.V('v-1')
 .fold()
  .coalesce(unfold(),
            addV('Person').property(id, 'v-1')
                          .property('email', 'person-1@example.org'))
  .id()
```

このクエリは `id()` ステップで終わることに注意してください。頂点をアップサートする目的では必ずしも必要ではありませんが、アップサートクエリの最後に `id()` ステップを追加すると、サーバーはすべての頂点プロパティをクライアントにシリアル化し直さなくなるため、クエリのロックコストを削減できます。

あるいは、頂点プロパティを使用して頂点が存在するかどうかを調べることもできます。

```
g.V()
 .hasLabel('Person')
 .has('email', 'person-1@example.org')
 .fold()
 .coalesce(unfold(),
           addV('Person').property('email', 'person-1@example.org'))
 .id()
```

可能であれば、ユーザー指定の独自の ID を使用して頂点を作成し、これらの ID を使用してアップサート操作中に頂点が存在するかどうかを判断します。これにより、Neptune は ID 周辺のアップサートを最適化できます。ID ベースのアップサートは、同時変更が頻繁に行われる場合、プロパティベースのアップサートよりもはるかに効率的です。

### 頂点アップサートの連鎖
<a name="gremlin-upserts-pre-3.6-vertices-chaining"></a>

頂点アップサートを連鎖して、まとめて挿入することができます。

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .id()
```

## エッジのアップサート
<a name="gremlin-upserts-pre-3.6-edges"></a>

カスタム頂点 ID を使用して頂点をアップサートするのと同じ方法で、エッジ ID を使用してエッジをアップサートできます。繰り返しますが、Neptune がクエリを最適化できるようになるため、この方法が推奨されます。例えば、次のクエリは、エッジ ID がまだ存在しない場合はそのエッジ ID に基づいてエッジを作成し、存在する場合は再利用します。新しいエッジを作成する必要がある場合、クエリは `from` および `to` 頂点の ID も使用します。

```
g.E('e-1')
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2'))
                        .property(id, 'e-1'))
 .id()
```

多くのアプリケーションはカスタム頂点 ID を使用しますが、エッジ ID の生成は Neptune に任せています。エッジの ID はわからないが、`from` および `to` 頂点 ID はわかっている場合は、次のような式を使用して、エッジをアップサートできます。

```
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2')))
 .id()
```

`where()` 句の頂点ステップは `otherV()` ではなく `inV()` (または、`inE()` を使用してエッジを見つけた場合は `outV()`) でなければならないことに注意してください。ここでは `otherV()` を使用しないでください。使用すると、クエリが最適化されず、パフォーマンスが低下します。例えば、Neptune は次のクエリを最適化しません。

```
// Unoptimized upsert, because of otherV()
g.V('v-1')
 .outE('KNOWS')
 .where(otherV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2')))
 .id()
```

エッジまたは頂点 ID が事前にわからない場合は、頂点プロパティを使用してアップサートできます。

```
g.V()
 .hasLabel('Person')
 .has('name', 'person-1')
 .outE('LIVES_IN')
 .where(inV().hasLabel('City').has('name', 'city-1'))
 .fold()
 .coalesce(unfold(),
           addE('LIVES_IN').from(V().hasLabel('Person')
                                    .has('name', 'person-1'))
                           .to(V().hasLabel('City')
                                  .has('name', 'city-1')))
 .id()
```

頂点アップサートと同様に、Neptune がアップサートを完全に最適化できるように、プロパティベースのアップサートよりも、エッジ ID または `from` および `to` 頂点 ID を使用する ID ベースのエッジアップサートを使用する方が好ましいです。

### `from` および `to` 頂点の有無の確認
<a name="gremlin-upserts-pre-3.6-edges-checking"></a>

新しいエッジを作成するステップの構造 `addE().from().to()` に注意してください。この構造により、クエリは `from` と `to` の両方の頂点の存在を確実にチェックします。これらのいずれかが存在しない場合、クエリは次のようなエラーを返します。

```
{
  "detailedMessage": "Encountered a traverser that does not map to a value for child...
  "code": "IllegalArgumentException",
  "requestId": "..."
}
```

`from` または `to` のいずれかの頂点が存在しない可能性がある場合は、頂点間のエッジをアップセットする前に、頂点をアップサートしてみてください。「[頂点とエッジのアップサートの組み合わせ](#gremlin-upserts-pre-3.6-vertexes-and-edges)」を参照してください。

エッジを作成するには、使用すべきではない別の方法 `V().addE().to()` があります。`from` 頂点が存在する場合にのみ、エッジを追加します。`to` 頂点が存在しない場合、前述のようにクエリはエラーを生成しますが、`from` 頂点が存在しない場合、エラーを発生せずに、エッジの挿入に失敗します。例えば、次のアップサートは、`from` 頂点が存在しない場合、エッジをアップサートせずに完了します。

```
// Will not insert edge if from vertex does not exist
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2')))
 .id()
```

### エッジのアップサートの連鎖
<a name="gremlin-upserts-pre-3.6-edges-chaining"></a>

エッジアップサートを連結してバッチリクエストを作成する場合は、エッジ ID がわかっていても、各アップサートを頂点ルックアップから始める必要があります。

アップサートするエッジの ID と、`from` および `to` 頂点の ID がわかっている場合は、次の計算式を使用できます。

```
g.V('v-1')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2'))
                   .property(id, 'e-1'))
 .V('v-3')
 .outE('KNOWS')
 .hasId('e-2').fold()
 .coalesce(unfold(),
           V('v-3').addE('KNOWS')
                   .to(V('v-4'))
                   .property(id, 'e-2'))
 .V('v-5')
 .outE('KNOWS')
 .hasId('e-3')
 .fold()
 .coalesce(unfold(),
           V('v-5').addE('KNOWS')
                   .to(V('v-6'))
                   .property(id, 'e-3'))
 .id()
```

おそらく最も一般的なバッチエッジアップサートのシナリオは、`from` および `to` 頂点 ID はわかっているが、アップサートするエッジの ID はわからないというものです。その場合は、次の式を使用してください。

```
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2')))

 .V('v-3')
 .outE('KNOWS')
 .where(inV().hasId('v-4'))
 .fold()
 .coalesce(unfold(),
           V('v-3').addE('KNOWS')
                   .to(V('v-4')))
 .V('v-5')
 .outE('KNOWS')
 .where(inV().hasId('v-6'))
 .fold()
 .coalesce(unfold(),
           V('v-5').addE('KNOWS').to(V('v-6')))
 .id()
```

アップサートするエッジの ID はわかっているが、`from` および `to` 頂点の ID はわからない場合は、次の計算式を使用できます。

```
g.V()
 .hasLabel('Person')
 .has('email', 'person-1@example.org')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-1@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-2@example.org'))
                     .property(id, 'e-1'))
 .V()
 .hasLabel('Person')
 .has('email', 'person-3@example.org')
 .outE('KNOWS')
 .hasId('e-2')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-3@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-4@example.org'))
              .property(id, 'e-2'))
 .V()
 .hasLabel('Person')
 .has('email', 'person-5@example.org')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-5@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-6@example.org'))
                     .property(id, 'e-3'))
 .id()
```

## 頂点とエッジのアップサートの組み合わせ
<a name="gremlin-upserts-pre-3.6-vertexes-and-edges"></a>

頂点とそれらを接続するエッジの両方をアップサートしたい場合があります。ここで紹介したバッチサンプルをミックスしてもかまいません。次の例では、3 つの頂点と 2 つのエッジをアップサートしています。

```
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2')
                         .property('name', 'person-2@example.org'))
 .V('c-1')
 .fold()
 .coalesce(unfold(),
           addV('City').property(id, 'c-1')
                       .property('name', 'city-1'))
 .V('p-1')
 .outE('LIVES_IN')
 .where(inV().hasId('c-1'))
 .fold()
 .coalesce(unfold(),
           V('p-1').addE('LIVES_IN')
                   .to(V('c-1')))
 .V('p-2')
 .outE('LIVES_IN')
 .where(inV().hasId('c-1'))
 .fold()
 .coalesce(unfold(),
           V('p-2').addE('LIVES_IN')
                   .to(V('c-1')))
 .id()
```

## アップサートと挿入の混合
<a name="gremlin-upserts-pre-3.6-and-inserts"></a>

頂点とそれらを接続するエッジの両方をアップサートしたい場合があります。ここで紹介したバッチサンプルをミックスしてもかまいません。次の例では、3 つの頂点と 2 つのエッジをアップサートしています。

アップサートは通常、一度に 1 つの要素を処理します。ここで説明したアップサートパターンに従うと、アップサート操作ごとにトラバーサーが 1 回発生し、それ以降の操作は 1 回だけ実行されます。

ただし、アップサートと挿入を混在させたい場合もあります。例えば、エッジを使用してアクションやイベントのインスタンスを表す場合などが該当します。リクエストでは、必要な頂点がすべて存在することを確認するためにアップサートを使用し、エッジを追加するためにインサートを使用する場合があります。この種のリクエストでは、各操作で発生する可能性のあるトラバーサーの数に注意してください。

アップサートとインサートを組み合わせて、イベントを表すエッジをグラフに追加する次の例を考えてみましょう。

```
// Fully optimized, but inserts too many edges
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2')
                         .property('name', 'person-2@example.org'))
 .V('p-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-3')
                         .property('name', 'person-3@example.org'))
 .V('c-1')
 .fold()
 .coalesce(unfold(),
           addV('City').property(id, 'c-1')
                       .property('name', 'city-1'))
 .V('p-1', 'p-2')
 .addE('FOLLOWED')
 .to(V('p-1'))
 .V('p-1', 'p-2', 'p-3')
 .addE('VISITED')
 .to(V('c-1'))
 .id()
```

クエリでは 5 つのエッジを挿入する必要があります。2 つは FOLLOWED エッジであり、3 つは VISITED エッジです。ただし、記述されているクエリでは、8 つのエッジが挿入されます (2 つは FOLLOWED、6 つは VISITED)。これは、2 つの FOLLOWED エッジを挿入する操作で 2 つのトラバーサーが発生し、3 つのエッジを挿入する後続の挿入操作が 2 回実行されるためです。

この問題を解決するには、複数のトラバーサーが発生する可能性のある各操作の後に `fold()` ステップを追加します。

```
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2').
                         .property('name', 'person-2@example.org'))
 .V('p-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-3').
                         .property('name', 'person-3@example.org'))
 .V('c-1')
 .fold().
 .coalesce(unfold(),
            addV('City').property(id, 'c-1').
                        .property('name', 'city-1'))
 .V('p-1', 'p-2')
 .addE('FOLLOWED')
 .to(V('p-1'))
 .fold()
 .V('p-1', 'p-2', 'p-3')
 .addE('VISITED')
 .to(V('c-1')).
 .id()
```

ここでは、FOLLOWED エッジを挿入する操作の後に、`fold()` ステップを挿入しました。これにより、1 つのトラバーサーが発生し、それ以降の操作は 1 回だけ実行されます。

この方法の欠点は、`fold()` が最適化されていないため、クエリが完全には最適化されないことです。`fold()` の後に続く挿入操作は最適化されなくなります。

`fold()` を使用して、後続のステップの代わりにトラバーサーの数を減らす必要がある場合は、最もコストの低いものがクエリの最適化されていない部分を占めるように操作を順序付けてください。

## 既存の頂点とエッジを変更するアップサート
<a name="gremlin-upserts-pre-3.6-that-modify"></a>

頂点やエッジが存在しない場合は作成し、その頂点やエッジが新規か既存かに関わらず、プロパティを追加または更新したい場合があります。

プロパティを追加または変更するには、`property()` ステップを使用します。このステップは `coalesce()` ステップの外部で使用してください。`coalesce()` ステップ内で既存の頂点またはエッジのプロパティを変更しようとすると、クエリはクエリエンジンによって最適化されない場合があります。

次のクエリは、アップサートされた各頂点のカウンタープロパティを追加または更新します。各 `property()` ステップには単一のカーディナリティがあり、新しい値が既存の値のセットに追加されるのではなく、既存の値と置き換えられるようにします。

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .property(single, 'counter', 1)
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .property(single, 'counter', 2)
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .property(single, 'counter', 3)
 .id()
```

`lastUpdated` タイムスタンプ値など、アップサートされたすべての要素に適用されるプロパティ値がある場合は、クエリの最後にそのプロパティ値を追加または更新できます。

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2').
 .fold().
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .V('v-1', 'v-2', 'v-3')
 .property(single, 'lastUpdated', datetime('2020-02-08'))
 .id()
```

頂点やエッジをさらに変更するかどうかを決める条件が他にもある場合は、`has()` ステップを使用して、変更を適用する要素をフィルタリングできます。次の例では、`has()` ステップを使用して、アップサートされた頂点を `version` プロパティの値に基づいてフィルタリングしています。次に、クエリは `version` が 3 未満のすべての頂点の `version` を 3 倍に更新します。

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org')
                         .property('version', 3))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org')
                         .property('version', 3))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org')
                         .property('version', 3))
 .V('v-1', 'v-2', 'v-3')
 .has('version', lt(3))
 .property(single, 'version', 3)
 .id()
```

# Gremlin を使用して Neptune クエリ実行を分析する`explain`
<a name="gremlin-explain"></a>

Amazon Neptune に *explain* という名前の Gremlin 機能が追加されました。この機能は、Neptune エンジンが使用する実行アプローチを理解するためのセルフサービスツールです。この機能を呼び出すには、Gremlin クエリを送信する HTTP コールに `explain` パラメータを追加します。

`explain` 機能は、クエリ実行プランの論理構造に関する情報を提供します。この情報を使用して潜在的な評価と実行障害を明らかにし、[Gremlin クエリのチューニング](gremlin-traversal-tuning.md) で説明されているようにクエリを調整します。また、[クエリに関するヒント](gremlin-query-hints.md)を使用して、クエリ実行プランを改善できます。

**Topics**
+ [Neptune での Gremlin クエリの動作を理解する](gremlin-explain-background.md)
+ [Neptune での Gremlin `explain` APIの使用](gremlin-explain-api.md)
+ [Neptune の Gremlin `profile` API](gremlin-profile-api.md)
+ [`explain`および`profile`を使用した Gremlin クエリのチューニング](gremlin-traversal-tuning.md)
+ [Amazon Neptune でのネイティブ Gremlin ステップサポート](gremlin-step-support.md)

# Neptune での Gremlin クエリの動作を理解する
<a name="gremlin-explain-background"></a>

Amazon Neptune で Gremlin `explain` と `profile` レポートを最大限に活用するには、Gremlin クエリに関する背景情報を理解しておくと役立ちます。

**Topics**
+ [Neptune の Gremlin ステートメント](gremlin-explain-background-statements.md)
+ [Neptune がステートメントインデックスを使用して Gremlin クエリを処理する方法](gremlin-explain-background-indexing-examples.md)
+ [Neptune での Gremlin クエリの処理方法](gremlin-explain-background-querying.md)

# Neptune の Gremlin ステートメント
<a name="gremlin-explain-background-statements"></a>

Amazon Neptune のプロパティグラフデータは、4 つの位置 (四角形) のステートメントで構成されます。これらの各ステートメントは、プロパティグラフデータの個々のアトミック単位を表します。詳細については、「[Neptune のグラフデータモデル](feature-overview-data-model.md)」を参照してください。リソース記述フレームワーク (RDF) データモデルと同様に、これらの 4 つの位置は次のとおりです。
+ `subject (S)`
+ `predicate (P)`
+ `object (O)`
+ `graph (G)`

各ステートメントは、1 つ以上のリソースに関するアサーションです。たとえば、ステートメントでは、2 つのリソース間の関係の有無に対してアサーションを行ったり、いくつかのリソースにプロパティ (キーと値のペア) を付加したりすることができます。

述語は、関係の型またはプロパティの型を記述するステートメントの動詞と考えることができます。オブジェクトは、関係のターゲット、またはプロパティの値を表します。グラフの位置はオプションであり、さまざまな方法で使用できます。Neptune プロパティグラフ (PG) データの場合、未使用 (null グラフ) であるか、エッジ識別子を表すために使用されます。共有リソース識別子を持つ一連のステートメントはグラフを作成します。

Neptune プロパティグラフデータモデルには、次の 3 つのクラスのステートメントがあります。

**Topics**
+ [頂点ラベルステートメント](#gremlin-explain-background-vertex-labels)
+ [エッジステートメント](#gremlin-explain-background-edge-statements)
+ [プロパティステートメント](#gremlin-explain-background-property-statements)

## Gremlin 頂点ラベルステートメント
<a name="gremlin-explain-background-vertex-labels"></a>

Neptune の頂点ラベルステートメントは、次の 2 つの目的を果たします。
+ 頂点のラベルを追跡します。
+ これらのステートメントが少なくとも 1 つ存在することは、グラフに特定の頂点が存在することを意味します。

これらのステートメントのサブジェクトは頂点識別子、オブジェクトはラベルで、どちらもユーザーが指定します。これらのステートメントには、`<~label>` として表示される特別な固定述語と、`<~>` として表示されるデフォルトのグラフ識別子 (null グラフ) を使用します。

たとえば、次の `addV` トラバーサルを考えてみます。

```
g.addV("Person").property(id, "v1")
```

このトラバーサルにより、次のステートメントがグラフに追加されます。

```
StatementEvent[Added(<v1> <~label> <Person> <~>) .]
```

## Gremlin エッジステートメント
<a name="gremlin-explain-background-edge-statements"></a>

Gremlin エッジステートメントは、Neptune のグラフの 2 つの頂点間にエッジが存在することを意味します。エッジステートメントのサブジェクト (S) はソースの `from` 頂点です。述語 (P) はユーザー指定のエッジラベルです。オブジェクト (O) はターゲットの `to` 頂点です。グラフ (G) は、ユーザーが指定したエッジ識別子です。

たとえば、次の `addE` トラバーサルを考えてみます。

```
g.addE("knows").from(V("v1")).to(V("v2")).property(id, "e1")
```

トラバーサルにより、次のステートメントがグラフに追加されます。

```
StatementEvent[Added(<v1> <knows> <v2> <e1>) .]
```

## Gremlin プロパティステートメント
<a name="gremlin-explain-background-property-statements"></a>

Neptune の Gremlin プロパティステートメントは、頂点またはエッジの個々のプロパティ値をアサートします。サブジェクトは、ユーザーが指定した頂点またはエッジの識別子です。述語はプロパティ名 (キー) で、オブジェクトは個々のプロパティ値です。グラフ (G) はここでもデフォルトのグラフ識別子 (null グラフ) で、`<~>` と表示されます。

次の頂点プロパティの例を考えてみましょう。

```
g.V("v1").property("name", "John")
```

このステートメントの結果は次のようになります。

```
StatementEvent[Added(<v1> <name> "John" <~>) .]
```

オブジェクトがプリミティブ値 (`string`、`date`、`byte`、`short`、`int`、`long`、`float`、または `double`) のため、プロパティステートメントはお互いに異なります。そのオブジェクトは、別のアサーションのサブジェクトとして使用できるリソース識別子ではありません。

複数プロパティの場合、セット内の各プロパティ値は独自のステートメントを受け取ります。

```
g.V("v1").property(set, "phone", "956-424-2563").property(set, "phone", "956-354-3692 (tel:9563543692)")
```

この結果は以下のようになります。

```
StatementEvent[Added(<v1> <phone> "956-424-2563" <~>) .]
StatementEvent[Added(<v1> <phone> "956-354-3692" <~>) .]
```

エッジプロパティは頂点プロパティと同様に処理されますが、 (S) 位置にエッジ識別子を使用します。たとえば、エッジにプロパティを追加するとします。

```
g.E("e1").property("weight", 0.8)
```

これにより、次のステートメントがグラフに追加されます。

```
StatementEvent[Added(<e1> <weight> 0.8 <~>) .]
```

# Neptune がステートメントインデックスを使用して Gremlin クエリを処理する方法
<a name="gremlin-explain-background-indexing-examples"></a>

Amazon Neptune では、3 つのステートメントインデックスを使用してステートメントにアクセスします。詳細については、[Neptune でステートメントのインデックスを作成する方法](feature-overview-storage-indexing.md) に記載しています。Neptune は一部の位置が既知の Gremlin クエリからステートメント*パターン*を抽出し、残りはインデックス検索によって検出するように残されます。

Neptune は、プロパティグラフスキーマサイズが大きくないことを前提としています。つまり、個別のエッジラベルとプロパティ名の数がかなり少なく、個別の述語の総数が少ないことを意味します。Neptune は、個別のインデックスで個別の述語を追跡します。OSGP インデックスを使用するのではなく、この述語のキャッシュを使用して `{ all P x POGS }` のユニオンスキャンを実行します。リバーストラバーサル OSGP インデックスの必要性を回避することで、ストレージ領域とロードスループットの両方を節約できます。

Neptune Gremlin Explain/Profile API を使用すると、グラフの述語数を取得できます。その後、プロパティグラフスキーマが小さいという Neptune の前提をアプリケーションで無効にするかどうかを判断できます。

次の例は、Neptune がインデックスを使用して Gremlin クエリを処理する方法を示しています。

**質問: 頂点 `v1` のラベルは何か?**

```
  Gremlin code:      g.V('v1').label()
  Pattern:           (<v1>, <~label>, ?, ?)
  Known positions:   SP
  Lookup positions:  OG
  Index:             SPOG
  Key range:         <v1>:<~label>:*
```

**質問: 頂点 `v1` の「知っている」アウトエッジは何か?**

```
  Gremlin code:      g.V('v1').out('knows')
  Pattern:           (<v1>, <knows>, ?, ?)
  Known positions:   SP
  Lookup positions:  OG
  Index:             SPOG
  Key range:         <v1>:<knows>:*
```

**質問: どの頂点に `Person` 頂点ラベルがあるか?**

```
  Gremlin code:      g.V().hasLabel('Person')
  Pattern:           (?, <~label>, <Person>, <~>)
  Known positions:   POG
  Lookup positions:  S
  Index:             POGS
  Key range:         <~label>:<Person>:<~>:*
```

**質問 : 指定されたエッジ `e1` の始点と終点は何か?**

```
  Gremlin code:      g.E('e1').bothV()
  Pattern:           (?, ?, ?, <e1>)
  Known positions:   G
  Lookup positions:  SPO
  Index:             GPSO
  Key range:         <e1>:*
```

Neptune が持た**ない**ステートメントインデックスの 1 つは、リバーストラバーサル OSGP インデックスです。このインデックスは、次の例のように、すべてのエッジラベルにまたがるすべての受信エッジを収集するために使用できます。

**質問:入ってくる隣接頂点は何か`v1`?**

```
  Gremlin code:      g.V('v1').in()
  Pattern:           (?, ?, <v1>, ?)
  Known positions:   O
  Lookup positions:  SPG
  Index:             OSGP  // <-- Index does not exist
```

# Neptune での Gremlin クエリの処理方法
<a name="gremlin-explain-background-querying"></a>

Amazon Neptune では、より複雑なトラバーサルは、結合を作成するためにパターン間で共有できる名前付き変数の定義に基づいて関係を作成する一連のパターンで表すことができます。以下の例ではこれを示しています。

**質問: 頂点 `v1` の 2 ホップ近傍とは何か?**

```
  Gremlin code:      g.V(‘v1’).out('knows').out('knows').path()
  Pattern:           (?1=<v1>, <knows>, ?2, ?) X Pattern(?2, <knows>, ?3, ?)

  The pattern produces a three-column relation (?1, ?2, ?3) like this:
                     ?1     ?2     ?3
                     ================
                     v1     v2     v3
                     v1     v2     v4
                     v1     v5     v6
```

2 つのパターン (最初のパターンの O 位置と 2 番目のパターンの S 位置) 間で `?2` 変数を共有することで、最初のホップ近傍から 2 番目のホップ近傍への結合を作成します。各 Neptune ソリューションには、3 つの名前付き変数のバインドがあり、これを使用して [TinkerPop Traverser](http://tinkerpop.apache.org/docs/current/reference/#_the_traverser) (パス情報を含む) を再作成できます。

```
```

Gremlin クエリ処理の最初のステップは、クエリを TinkerPop [トラバーサル](http://tinkerpop.apache.org/docs/current/reference/#traversal)オブジェクトに解析することで、これは一連の TinkerPop [ステップ](http://tinkerpop.apache.org/docs/current/reference/#graph-traversal-steps)からなります。オープンソースの [Apache TinkerPop プロジェクト](http://tinkerpop.apache.org/)の一部であるこれらのステップは、リファレンス実装で Gremlin トラバーサルを構成する論理演算子と物理演算子の両方です。どちらも、クエリのモデルを表すために使用されます。これらは、それらが表す演算子のセマンティクスに従ってソリューションを生成できる実行可能な演算子です。たとえば、`.V()` は TinkerPop [GraphStep](http://tinkerpop.apache.org/docs/current/reference/#graph-step) によって表され、実行されます。

これらの既製の TinkerPop ステップは実行可能であるため、このような TinkerPop Traversal は任意の Gremlin クエリを実行して正解を生成できます。ただし、ラージグラフに対して実行すると、TinkerPop ステップは非常に非効率的で低速になることがあります。Neptune はそれらを使用する代わりに、前に説明したように、トラバーサルをパターンのグループで構成される宣言形式に変換しようとします。

Neptune は現在、ネイティブクエリエンジンですべての Gremlin 演算子 (ステップ) をサポートしていません。そのため、可能な限り多くのステップを、変換されたすべてのステップの宣言型論理クエリプランを含む単一の `NeptuneGraphQueryStep` にまとめようとします。理想的には、すべてのステップが変換されます。ただし、変換できないステップが発生した場合、Neptune はネイティブ実行を中断し、すべてのクエリ実行をその時点から TinkerPop ステップに延期します。ネイティブ実行の入出力は行われません。

ステップが論理クエリプランに変換されると、Neptune は一連のクエリオプティマイザを実行し、静的分析と推定基数に基づいてクエリプランを書き換えます。これらのオプティマイザは、範囲カウントに基づく演算子の順序変更、不要または冗長な演算子の除外、フィルタの再配置、異なるグループへの演算子のプッシュなどを行います。

最適化されたクエリプランが作成されると、Neptune はクエリの実行作業を行う物理演算子のパイプラインを作成します。これには、ステートメントインデックスからのデータの読み取り、さまざまなタイプの結合の実行、フィルタリング、順序付けなどが含まれます。パイプラインは、ソリューションストリームを生成し、その後 TinkerPop Traverser オブジェクトのストリームに変換し直します。

## クエリ結果のシリアル化
<a name="gremlin-explain-background-querying-serialization"></a>

Amazon Neptune は現在、TinkerPop レスポンスメッセージシリアライザーを使用して、クエリ結果 (TinkerPop Traversers) をシリアル化されたデータに変換し、ネットワーク経由でクライアントに送信します。これらのシリアル化形式は、かなり冗長になる傾向があります。

たとえば、`g.V().limit(1)` などの頂点クエリの結果をシリアル化するには、 Neptune クエリエンジンが 1 つの検索を実行してクエリ結果を生成する必要があります。ただし、`GraphSON` シリアライザーは、頂点をシリアル化形式にパッケージ化するために、多数の追加の検索を実行します。ラベルを取得するには 1 つの検索、プロパティキーを取得するには 1 つの検索、各キーのすべての値を取得するには、頂点のプロパティキーごとに 1 つの検索を実行する必要があります。

一部のシリアル化形式はより効率的ですが、すべて追加検索が必要です。さらに、TinkerPop シリアライザーは重複検索を回避しないため、多くの検索が不必要に繰り返されることがよくあります。

このため、必要な情報のみを具体的に尋ねるように、クエリを記述することが非常に重要になります。たとえば、`g.V().limit(1).id()` は頂点 ID のみを返し、追加のシリアライザー検索をすべて排除します。[Neptune の Gremlin `profile` API](gremlin-profile-api.md) で、クエリ実行中およびシリアル化中に行われた検索呼び出しの数を確認できます。

# Neptune での Gremlin `explain` APIの使用
<a name="gremlin-explain-api"></a>

Amazon Neptune Gremlin `explain` API は、指定されたクエリが実行された場合に実行されるクエリプランを返します。API はクエリを実際に実行しないため、プランはほぼ瞬時に返されます。

Neptune エンジンに固有の情報をレポートできるため、TinkerPop .explain() ステップとは異なります。

## Gremlin `explain` レポートに含まれる情報
<a name="gremlin-explain-api-results"></a>

`explain` レポートには、以下の情報が含まれています。
+ リクエストされたクエリ文字列。
+ **元のトラバーサル。**これは、クエリ文字列を TinkerPop ステップに解析して生成される TinkerPop Traversal オブジェクトです。これは元のクエリと同等で、TinkerPop TinkerGraph に対してクエリで `.explain()` を実行することによって生成されます。
+ **変換されたトラバーサル。**これは、TinkerPop Traversal を Neptune 論理クエリプラン表現に変換することによって生成される Neptune トラバーサルです。多くの場合、TinkerPop トラバーサル全体が 2 つの Neptune ステップに変換されます。1 つはクエリ全体を実行するステップ (`NeptuneGraphQueryStep`) で、もう 1 つは Neptune クエリエンジン出力を TinkerPop トラバーサーに変換し直しすステップ (`NeptuneTraverserConverterStep`) です。
+ **最適化されたトラバーサル。**これは、静的分析と推定基数に基づいてクエリを書き換える一連の静的作業削減オプティマイザを実行した後の Neptune クエリプランの最適化バージョンです。これらのオプティマイザは、範囲カウントに基づく演算子の順序変更、不要または冗長な演算子の除外、フィルタの再配置、異なるグループへの演算子のプッシュなどを行います。
+ **述語のカウント。**前述の Neptune インデックス作成戦略のため、多数の異なる述語があると、パフォーマンスの問題が発生する可能性があります。これは、エッジラベル (`.in` または `.both`) のないリバーストラバーサル演算子を使用するクエリに特に当てはまります。このような演算子が使用され、述語数が十分に高い場合、`explain` レポートには警告メッセージが表示されます。
+ **DFE 情報** DFE 代替エンジンが有効な場合、最適化トラバーサルに次のトラバーサルコンポーネントが表示されることがあります。
  + **`DFEStep`**   –   子 `DFENode` を含むトラバーサルの Neptune 最適化 DFE ステップ。`DFEStep` は、DFE エンジンで実行されるクエリプランの一部を表します。
  + **`DFENode`**   –   中間表現を 1 つ以上の子 `DFEJoinGroupNodes` として含みます。
  + **`DFEJoinGroupNode`**   –   1 つ以上の `DFENode` または `DFEJoinGroupNode` 要素の結合を表します。
  + **`NeptuneInterleavingStep`**   –  子 `DFEStep` を含むトラバーサルの Neptune 最適化 DFE ステップ。

    また、フロンティア要素、使用されるパス要素など、トラバーサルに関する情報を含む `stepInfo` 要素を含みます。この情報は、子 `DFEStep` の処理に使用されます。

  クエリが DFE によって評価されているかどうかを簡単に調べるには、`explain` 出力に `DFEStep` が含まれるかを確認します。`DFEStep` の一部ではない任意のトラバーサル部分は DFE によって実行されず、TinkerPop エンジンによって実行されます。

  サンプルレポートに関しては [DFE が有効な場合の例](#gremlin-explain-dfe) を参照してください。

## Gremlin `explain` 構文
<a name="gremlin-explain-api-syntax"></a>

`explain` API の構文は、次の例のように、`/gremlin/explain` を `/gremlin` の代わりにエンドポイントとして使用すること以外はクエリの HTTP API の構文と同じです。

```
curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().limit(1)"}'
```

前述のクエリでは、次の出力が生成されます。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().limit(1)

Original Traversal
==================
[GraphStep(vertex,[]), RangeGlobalStep(0,1)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
        }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY}
        }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 18
```

## 未変換の TinkerPop ステップ
<a name="gremlin-explain-unconverted-steps"></a>

理想的には、トラバーサルのすべての TinkerPop ステップにネイティブ Neptune 演算子カバレッジがあります。これに当てはまらない場合、Neptune は TinkerPop ステップの実行をフォールバックして、演算子カバレッジのギャップを確認します。Neptune がネイティブカバレッジを持っていないステップをトラバーサルで使用している場合、`explain` レポートにはギャップが発生した場所を示す警告が表示されます。

対応するネイティブ Neptune 演算子がないステップが検出されると、後続のステップにネイティブ Neptune 演算子がある場合でも、その時点からのトラバーサル全体が TinkerPop ステップを使用して実行されます。

ただし、Neptune フルテキスト検索が呼び出される場合は例外です。NeptuneSearchStep は、フルテキスト検索ステップとして同等のネイティブがないステップを実装します。

## クエリのすべてのステップに同等のネイティブがある `explain` 出力例
<a name="gremlin-explain-all-steps-converted"></a>

以下に、すべてのステップに同等のネイティブがあるクエリの `explain` レポートの例を示します。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().out()

Original Traversal
==================
[GraphStep(vertex,[]), VertexStep(OUT,vertex)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 18
```

## クエリ内の一部のステップに同等のネイティブがない例
<a name="gremlin-explain-not-all-steps-converted"></a>

Neptune は `GraphStep` と `VertexStep` の両方をネイティブに処理しますが、`FoldStep` と `UnfoldStep` を導入すると、結果 `explain` 出力は異なります。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().fold().unfold().out()

Original Traversal
==================
[GraphStep(vertex,[]), FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
        }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]
+ not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY}
        }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep,
    NeptuneMemoryTrackerStep
]
+ not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

WARNING: >> FoldStep << is not supported natively yet
```

この場合、`FoldStep` はネイティブ実行を中断します。ただし、`Fold/Unfold` ステップの下流に表示されるため、後続の `VertexStep` もネイティブに処理されなくなります。

パフォーマンスとコスト削減のためには、TinkerPop ステップ実装ではなく、可能な最大量の作業が Neptune クエリエンジン内でネイティブに行われるように、トラバーサルを策定することが重要です。

## Neptune フルテキスト検索を使用するクエリの例
<a name="gremlin-explain-full-text-search-steps"></a>

次のクエリでは、Neptune フルテキスト検索を使用します。

```
g.withSideEffect("Neptune#fts.endpoint", "some_endpoint")
  .V()
  .tail(100)
  .has("Neptune#fts mark*")
  -------
  .has("name", "Neptune#fts mark*")
  .has("Person", "name", "Neptune#fts mark*")
```

`.has("name", "Neptune#fts mark*")` パートは、検索の対象を `name` を持つ頂点に制限します。`.has("Person", "name", "Neptune#fts mark*")` は、検索の対象を `name` およびラベル `Person` を持つ頂点に制限します。これにより、`explain` レポートのトラバーサルは次のようになります。

```
Final Traversal
[NeptuneGraphQueryStep(Vertex) {
    JoinGroupNode {
        PatternNode[(?1, termid(1,URI), ?2, termid(0,URI)) . project distinct ?1 .], {estimatedCardinality=INFINITY}
    }, annotations={path=[Vertex(?1):GraphStep], maxVarId=4}
}, NeptuneTraverserConverterStep, NeptuneTailGlobalStep(10), NeptuneTinkerpopTraverserConverterStep, NeptuneSearchStep {
    JoinGroupNode {
        SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint}
    }
    JoinGroupNode {
        SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint}
    }
}]
```

## DFE が有効な場合の `explain` 使用例
<a name="gremlin-explain-dfe"></a>

DFE 代替クエリエンジンが有効な場合の `explain` レポート例を次に示します。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().as("a").out().has("name", "josh").out().in().where(eq("a"))


Original Traversal
==================
[GraphStep(vertex,[])@[a], VertexStep(OUT,vertex), HasStep([name.eq(josh)]), VertexStep(OUT,vertex), VertexStep(IN,vertex), WherePredicateStep(eq(a))]

Converted Traversal
===================
Neptune steps:
[
    DFEStep(Vertex) {
      DFENode {
        DFEJoinGroupNode[ children={
          DFEPatternNode[(?1, <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>, ?2, <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>) . project DISTINCT[?1] {rangeCountEstimate=unknown}],
          DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}]
        }, {rangeCountEstimate=unknown}
        ]
      } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep]
    } ,
    NeptuneTraverserConverterDFEStep
]
+ not converted into Neptune steps: HasStep([name.eq(josh)]),
Neptune steps:
[
    NeptuneInterleavingStep {
      StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms],
      DFEStep(Vertex) {
        DFENode {
          DFEJoinGroupNode[ children={
            DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}],
            DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}]
          }, {rangeCountEstimate=unknown}
          ]
        } [Vertex(?9):VertexStep, Vertex(?12):VertexStep]
      } 
    }
]
+ not converted into Neptune steps: WherePredicateStep(eq(a)),
Neptune steps:
[
    DFECleanupStep
]


Optimized Traversal
===================
Neptune steps:
[
    DFEStep(Vertex) {
      DFENode {
        DFEJoinGroupNode[ children={
          DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}]
        }, {rangeCountEstimate=unknown}
        ]
      } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep]
    } ,
    NeptuneTraverserConverterDFEStep
]
+ not converted into Neptune steps: NeptuneHasStep([name.eq(josh)]),
Neptune steps:
[
    NeptuneMemoryTrackerStep,
    NeptuneInterleavingStep {
      StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms],
      DFEStep(Vertex) {
        DFENode {
          DFEJoinGroupNode[ children={
            DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}],
            DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}]
          }, {rangeCountEstimate=unknown}
          ]
        } [Vertex(?9):VertexStep, Vertex(?12):VertexStep]
      } 
    }
]
+ not converted into Neptune steps: WherePredicateStep(eq(a)),
Neptune steps:
[
    DFECleanupStep
]


WARNING: >> [NeptuneHasStep([name.eq(josh)]), WherePredicateStep(eq(a))] << (or one of the children for each step) is not supported natively yet

Predicates
==========
# of predicates: 8
```

レポート内の DFE 固有のセクションの詳細については、[`explain` 内の情報](#gremlin-explain-api-results) を参照してください。

# Neptune の Gremlin `profile` API
<a name="gremlin-profile-api"></a>

Neptune Gremlin `profile` API は、指定された Gremlin トラバーサルを実行し、実行に関するさまざまなメトリクスを収集して、出力として Profile レポートを生成します。

Neptune エンジンに固有の情報をレポートできるため、TinkerPop .profile() ステップとは異なります。

Profile レポートには、クエリプランに関する次の情報が含まれます。
+ 物理演算子のパイプライン
+ クエリの実行とシリアル化のインデックスオペレーション
+ 結果のサイズ

`profile` API は、エンドポイントとして `/gremlin` の代わりに `/gremlin/profile` を使用して、クエリに HTTP API 構文の拡張バージョンを使用します。

## Neptune Gremlin に固有のパラメータ`profile`
<a name="gremlin-profile-api-parameters"></a>
+ **profile.results**–`boolean`、使用できる値:`TRUE` および `FALSE`、デフォルト値:`TRUE`。

  true の場合、クエリ結果が収集され、`profile` レポートの一部として表示されます。false の場合、結果カウントのみが表示されます。
+ **profile.chop**–`int`、デフォルト値:250。

  ゼロ以外の場合、結果の文字列はその文字数で切り捨てられます。これにより、すべての結果がキャプチャされなくなるわけではありません。Profile レポートの文字列のサイズを制限するだけです。ゼロに設定すると、文字列にはすべての結果が含まれます。
+ **profile.serializer** – `string`、デフォルト値: `<null>`。

  null 以外の場合、収集された結果は、このパラメータで指定された形式でシリアル化されたレスポンスメッセージで返されます。そのレスポンスメッセージを生成するために必要なインデックスオペレーションの数は、クライアントに送信されるバイト単位のサイズとともにレポートされます。

  使用できる値は、`<null>`、有効な MIME タイプまたは TinkerPop ドライバー「シリアライザー」列挙値です。

  ```
  "application/json" or "GRAPHSON"
  "application/vnd.gremlin-v1.0+json" or "GRAPHSON_V1"
  "application/vnd.gremlin-v1.0+json;types=false" or "GRAPHSON_V1_UNTYPED"
  "application/vnd.gremlin-v2.0+json" or "GRAPHSON_V2"
  "application/vnd.gremlin-v2.0+json;types=false" or "GRAPHSON_V2_UNTYPED"
  "application/vnd.gremlin-v3.0+json" or "GRAPHSON_V3"
  "application/vnd.gremlin-v3.0+json;types=false" or "GRAPHSON_V3_UNTYPED"
  "application/vnd.graphbinary-v1.0" or "GRAPHBINARY_V1"
  ```
+ **profile.indexOps**–`boolean`、使用できる値:`TRUE` および `FALSE`、デフォルト値:`FALSE`。

  true の場合、クエリの実行およびシリアル化中に行われたすべてのインデックスオペレーションの詳細レポートが表示されます。警告: このレポートは冗長な場合があります。



## Neptune Gremlin のサンプル出力`profile`
<a name="gremlin-profile-sample-output"></a>

サンプル `profile` クエリを以下に示します。

```
curl -k -X POST https://your-neptune-endpoint:port/gremlin/profile \
     -d '{"gremlin":"g.V().hasLabel(\"airport\").has(\"code\", \"AUS\").emit().repeat(in().simplePath()).times(2).limit(100)", "profile.serializer":"application/vnd.gremlin-v3.0+json"}'
```

このクエリは、ブログ記事 [Let Me Graph That For You – Part 1 – Air Routes](https://aws.amazon.com/blogs/database/let-me-graph-that-for-you-part-1-air-routes/) からエアルートサンプルグラフで実行された場合、次の `profile` レポートを生成します。

```
*******************************************************
                Neptune Gremlin Profile
*******************************************************

Query String
==================
g.V().hasLabel("airport").has("code", "AUS").emit().repeat(in().simplePath()).times(2).limit(100)

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([~label.eq(airport), code.eq(AUS)]), RepeatStep(emit(true),[VertexStep(IN,vertex), PathFilterStep(simple), RepeatEndStep],until(loops(2))), RangeGlobalStep(0,100)]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "AUS", ?) . project ?1 .], {estimatedCardinality=1, indexTime=84, hashJoin=true, joinTime=3, actualTotalOutput=1}
            PatternNode[(?1, <~label>, ?2=<airport>, <~>) . project ask .], {estimatedCardinality=3374, indexTime=29, hashJoin=true, joinTime=0, actualTotalOutput=61}
            RepeatNode {
                Repeat {
                    PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0, joinTime=3}
                }
                Emit {
                    Filter(true)
                }
                LoopsCondition {
                    LoopsFilter([?1, ?3],eq(2))
                }
            }, annotations={repeatMode=BFS, emitFirst=true, untilFirst=false, leftVar=?1, rightVar=?3}
        }, finishers=[limit(100)], annotations={path=[Vertex(?1):GraphStep, Repeat[Vertex(?3):VertexStep]], joinStats=true, optimizationTime=495, maxVarId=7, executionTime=323}
    },
    NeptuneTraverserConverterStep
]

Physical Pipeline
=================
NeptuneGraphQueryStep
    |-- StartOp
    |-- JoinGroupOp
        |-- SpoolerOp(100)
        |-- DynamicJoinOp(PatternNode[(?1, <code>, "AUS", ?) . project ?1 .], {estimatedCardinality=1, indexTime=84, hashJoin=true})
        |-- SpoolerOp(100)
        |-- DynamicJoinOp(PatternNode[(?1, <~label>, ?2=<airport>, <~>) . project ask .], {estimatedCardinality=3374, indexTime=29, hashJoin=true})
        |-- RepeatOp
            |-- <upstream input> (Iteration 0) [visited=1, output=1 (until=0, emit=1), next=1]
            |-- BindingSetQueue (Iteration 1) [visited=61, output=61 (until=0, emit=61), next=61]
                |-- SpoolerOp(100)
                |-- DynamicJoinOp(PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0})
            |-- BindingSetQueue (Iteration 2) [visited=38, output=38 (until=38, emit=0), next=0]
                |-- SpoolerOp(100)
                |-- DynamicJoinOp(PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0})
        |-- LimitOp(100)

Runtime (ms)
============
Query Execution:  392.686
Serialization:   2636.380

Traversal Metrics
=================
Step                                                               Count  Traversers       Time (ms)    % Dur
-------------------------------------------------------------------------------------------------------------
NeptuneGraphQueryStep(Vertex)                                        100         100         314.162    82.78
NeptuneTraverserConverterStep                                        100         100          65.333    17.22
                                            >TOTAL                     -           -         379.495        -

Repeat Metrics
==============
Iteration  Visited   Output    Until     Emit     Next
------------------------------------------------------
        0        1        1        0        1        1
        1       61       61        0       61       61
        2       38       38       38        0        0
------------------------------------------------------
               100      100       38       62       62

Predicates
==========
# of predicates: 16

WARNING: reverse traversal with no edge label(s) - .in() / .both() may impact query performance

Results
=======
Count: 100
Output: [v[3], v[3600], v[3614], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[47], v[49], v[136], v[13], v[15], v[16], v[17], v[18], v[389], v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[416], v[29], v[30], v[430], v[31], v[9...
Response serializer: GRYO_V3D0
Response size (bytes): 23566

Index Operations
================
Query execution:
    # of statement index ops: 3
    # of unique statement index ops: 3
    Duplication ratio: 1.0
    # of terms materialized: 0
Serialization:
    # of statement index ops: 200
    # of unique statement index ops: 140
    Duplication ratio: 1.43
    # of terms materialized: 393
```

Neptune `explain` の呼び出しによって返されるクエリプランに加えて、`profile` の結果にはクエリ実行に関するランタイム統計が含まれます。各 Join オペレーションには、その結合の実行にかかった時間と、それを通過した実際のソリューションの数でタグが付けられます。

`profile` 出力には、コアクエリ実行フェーズでの所要時間と、`profile.serializer` オプションが指定されている場合にはシリアル化フェーズも含まれます。

各フェーズで実行されたインデックスオペレーションの内訳は、`profile` 出力の下部にも含まれます。

同じクエリを連続して実行すると、キャッシュのため、実行時とインデックスオペレーションに関して異なる結果が表示される場合があります。

`repeat()` ステップを使用したクエリの場合、`repeat()` ステップが `NeptuneGraphQueryStep` の一部としてプッシュダウンされた場合、各反復処理のフロンティアの内訳が利用可能です。

## DFE が有効な時の `profile` レポートの違い
<a name="gremlin-profile-dfe-output"></a>

Neptune DFE 代替クエリエンジンが有効になっている場合、`profile`出力は多少異なります。

**最適トラバーサル:** このセクションは、`explain` 出力のセクションに似ていますが、追加情報が含まれています。これには、計画で考慮された DFE 演算子のタイプと、関連する最悪および最善のコスト見積もりが含まれます。

**物理パイプライン:** このセクションでは、クエリの実行に使用される演算子について説明します。`DFESubQuery` 要素は、DFE が担当するプランの一部を実行するために使用する物理プランを抽象化します。`DFESubQuery` 要素は次のセクションで展開され、DFE 統計情報が表示されます。

**DFeQueryエンジンの統計情報:** このセクションは、クエリの少なくとも一部が DFE によって実行された場合にのみ表示されます。DFE に固有の各種ランタイム統計を概説し、`DFESubQuery` による、クエリ実行のさまざまな部分に費やされた時間の詳細な内訳を以下に示します。

別の `DFESubQuery` 要素にネストされたサブクエリは、このセクションでフラット化され、一意の識別子に `subQuery=` で始まるヘッダーが付けられます。

**トラバーサルメトリクス:** このセクションには、ステップレベルのトラバーサルメトリックが表示され、DFE エンジンがクエリの全部または一部を実行すると、`DFEStep`および/または`NeptuneInterleavingStep`のメトリクスが表示されます。「[`explain`および`profile`を使用した Gremlin クエリのチューニング](gremlin-traversal-tuning.md)」を参照してください。

**注記**  
DFE はラボモードでリリースされる実験的な機能なので、`profile` 出力はまだ変更される可能性があります。

## Neptune データフローエンジン (DFE) が有効な場合のサンプル`profile` 出力
<a name="gremlin-profile-sample-dfe-output"></a>

DFE エンジンが Gremlin クエリの実行に使用されている場合、[Gremlin `profile` API](#gremlin-profile-api) の出力は、次の例に示すようにフォーマットされます。

クエリ:

```
curl https://your-neptune-endpoint:port/gremlin/profile \
  -d "{\"gremlin\": \"g.withSideEffect('Neptune#useDFE', true).V().has('code', 'ATL').out()\"}"
```

```
*******************************************************
                    Neptune Gremlin Profile
    *******************************************************

    Query String
    ==================
    g.withSideEffect('Neptune#useDFE', true).V().has('code', 'ATL').out()

    Original Traversal
    ==================
    [GraphStep(vertex,[]), HasStep([code.eq(ATL)]), VertexStep(OUT,vertex)]

    Optimized Traversal
    ===================
    Neptune steps:
    [
        DFEStep(Vertex) {
          DFENode {
            DFEJoinGroupNode[null](
              children=[
                DFEPatternNode((?1, vp://code[419430926], ?4, defaultGraph[526]) . project DISTINCT[?1] objectFilters=(in(ATL[452987149]) . ), {rangeCountEstimate=1},
                  opInfo=(type=PipelineJoin, cost=(exp=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=0.00),wc=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=0.00)),
                    disc=(type=PipelineScan, cost=(exp=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=34.00),wc=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=34.00))))),
                DFEPatternNode((?1, ?5, ?6, ?7) . project ALL[?1, ?6] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807})],
              opInfo=[
                OperatorInfoWithAlternative[
                  rec=(type=PipelineJoin, cost=(exp=(in=1.00,out=27.76,io=0.00,comp=0.00,mem=0.00),wc=(in=1.00,out=27.76,io=0.00,comp=0.00,mem=0.00)),
                    disc=(type=PipelineScan, cost=(exp=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00),wc=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00)))),
                  alt=(type=PipelineScan, cost=(exp=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00),wc=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00)))]])
          } [Vertex(?1):GraphStep, Vertex(?6):VertexStep]
        } ,
        NeptuneTraverserConverterDFEStep,
        DFECleanupStep
    ]


    Physical Pipeline
    =================
    DFEStep
        |-- DFESubQuery1

    DFEQueryEngine Statistics
    =================
    DFESubQuery1
    ╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤════════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio  │ Time (ms) ║
    ╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪════════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFESolutionInjection  │ solutions=[]                                                                                                 │ -    │ 0        │ 1         │ 0.00   │ 0.01      ║
    ║    │        │        │                       │ outSchema=[]                                                                                                 │      │          │           │        │           ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_1 │ -    │ 1        │ 1         │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 2  │ 3      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_2 │ -    │ 1        │ 242       │ 242.00 │ 0.02      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 3  │ 4      │ -      │ DFEMergeChunks        │ -                                                                                                            │ -    │ 242      │ 242       │ 1.00   │ 0.01      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 4  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 242      │ 0         │ 0.00   │ 0.01      ║
    ╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧════════╧═══════════╝


    subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_1
    ╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                   │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
    ╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFEPipelineScan      │ pattern=Node(?1) with property 'code' as ?4 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.22      ║
    ║    │        │        │                      │ inlineFilters=[(?4 IN ["ATL"])]                             │      │          │           │       │           ║
    ║    │        │        │                      │ patternEstimate=1                                           │      │          │           │       │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 1  │ 2      │ -      │ DFEMergeChunks       │ -                                                           │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 2  │ 4      │ -      │ DFERelationalJoin    │ joinVars=[]                                                 │ -    │ 2        │ 1         │ 0.50  │ 0.09      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 3  │ 2      │ -      │ DFESolutionInjection │ solutions=[]                                                │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
    ║    │        │        │                      │ outSchema=[]                                                │      │          │           │       │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 4  │ -      │ -      │ DFEDrain             │ -                                                           │ -    │ 1        │ 0         │ 0.00  │ 0.01      ║
    ╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


    subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_2
    ╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════╤══════╤══════════╤═══════════╤════════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                           │ Mode │ Units In │ Units Out │ Ratio  │ Time (ms) ║
    ╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════╪══════╪══════════╪═══════════╪════════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFESolutionInjection │ solutions=[]                        │ -    │ 0        │ 1         │ 0.00   │ 0.01      ║
    ║    │        │        │                      │ outSchema=[?1]                      │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 1  │ 2      │ 3      │ DFETee               │ -                                   │ -    │ 1        │ 2         │ 2.00   │ 0.01      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?1                           │ -    │ 1        │ 1         │ 1.00   │ 0.21      ║
    ║    │        │        │                      │ ordered=false                       │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?1]                           │ -    │ 1        │ 1         │ 1.00   │ 0.03      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Edge((?1)-[?7:?5]->(?6))    │ -    │ 1        │ 242       │ 242.00 │ 0.51      ║
    ║    │        │        │                      │ constraints=[]                      │      │          │           │        │           ║
    ║    │        │        │                      │ patternEstimate=9223372036854775807 │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 5  │ 6      │ 7      │ DFESync              │ -                                   │ -    │ 243      │ 243       │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                   │ -    │ 1        │ 1         │ 1.00   │ 0.01      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                   │ -    │ 242      │ 242       │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                   │ -    │ 243      │ 242       │ 1.00   │ 0.31      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 9  │ -      │ -      │ DFEDrain             │ -                                   │ -    │ 242      │ 0         │ 0.00   │ 0.01      ║
    ╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════╧══════╧══════════╧═══════════╧════════╧═══════════╝


    Runtime (ms)
    ============
    Query Execution: 11.744

    Traversal Metrics
    =================
    Step                                                               Count  Traversers       Time (ms)    % Dur
    -------------------------------------------------------------------------------------------------------------
    DFEStep(Vertex)                                                      242         242          10.849    95.48
    NeptuneTraverserConverterDFEStep                                     242         242           0.514     4.52
                                                >TOTAL                     -           -          11.363        -

    Predicates
    ==========
    # of predicates: 18

    Results
    =======
    Count: 242


    Index Operations
    ================
    Query execution:
        # of statement index ops: 0
        # of terms materialized: 0
```

**注記**  
DFE エンジンはラボモードでリリースされる実験的な機能なので、`profile` 出力は変更される可能性があります。

# `explain`および`profile`を使用した Gremlin クエリのチューニング
<a name="gremlin-traversal-tuning"></a>

Amazon Neptune で Gremlin クエリを調整して、Neptune [explain](gremlin-explain-api.md) および [profile](gremlin-profile-api.md) API から取得したレポートで入手できる情報を使用して、パフォーマンスを向上させることができます。そうすることで、Neptune が Gremlin トラバーサルをどのように処理するのかを理解するのに役立ちます。

**重要**  
TinkerPop バージョン 3.4.11 に変更が加えられ、クエリの処理方法の正確性が向上しましたが、現時点ではクエリのパフォーマンスに重大な影響を与える場合があります。  
たとえば、この種類のクエリの実行速度が大幅に遅くなる可能性があります。  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  out()
```
TinkerPop 3.4.11 の変更により、制限ステップの後の頂点は、最適ではない方法でフェッチされるようになりました。これを回避するには、barrier() ステップを `order().by()` の次の任意のポイントに追加して、クエリを変更できます。例:   

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  barrier().
  out()
```
TinkerPop 3.4.11 が Neptune [エンジンバージョン 1.0.5.0](engine-releases-1.0.5.0.md)で有効になりました。

## Neptune の Gremlin トラバーサル処理について理解する
<a name="gremlin-traversal-processing"></a>

Gremlin トラバーサルが Neptune に送信されると、トラバーサルをエンジンが実行するための基礎となる実行計画に変換する 主要なプロセスが 3 つあります。パーシング、変換、最適化です。

![\[3 つのプロセスが Gremlin クエリを実行プランに変換します。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/Gremlin_traversal_processing.png)


### トラバーサル解析プロセス
<a name="gremlin-traversal-processing-parsing"></a>

トラバーサルを処理する最初のステップは、それを共通言語に解析することです。Neptune では、その共通言語は TinkerPop の一連のステップであり、[TinkerPop API](http://tinkerpop.apache.org/javadocs/3.4.8/full/org/apache/tinkerpop/gremlin/process/traversal/Step.html)の一部です。これらの各ステップは、トラバーサル内の計算単位を表します。

Gremlin トラバーサルを文字列またはバイトコードとしてNeptune に送信できます。REST エンドポイントと Java クライアントドライバ `submit()` メソッドは次の例のように、トラバーサルを文字列として送信します。

```
client.submit("g.V()")
```

[Gremlin 言語変種 (GLV)](https://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/)を使用するアプリケーションおよび言語ドライバはバイトコードでトラバーサルを送信します。

### トラバーサル変換プロセス
<a name="gremlin-traversal-processing-conversion"></a>

トラバーサルの処理の 2 番目のステップは、その TinkerPop ステップを、変換済みおよび未変換の Neptune ステップセットに変換することです。Apache TinkerPop Gremlin クエリ言語のほとんどのステップは、基盤となる Neptune エンジン上で実行するように最適化された Neptune 固有のステップに変換されます。Neptune に相当する値を含まない TinkerPop ステップがトラバーサルで検出されると、そのステップとその後のすべてのステップは TinkerPop クエリエンジンによって処理されます。

どのような状況でどのようなステップが変換できるかの詳細については、[Gremlin ステップサポート](gremlin-step-support.md)を参照してください。

### トラバーサル最適化プロセス
<a name="gremlin-traversal-processing-optimization"></a>

トラバーサル処理の最後のステップは、オプティマイザを介して変換されたステップと未変換の一連のステップを実行し、最適な実行プランを決定することです。この最適化の出力は、Neptune エンジンが処理する実行計画です。

## Neptune Gremlin `explain` API を使用してクエリを調整する
<a name="gremlin-traversal-tuning-explain"></a>

Neptune explain APIは、Gremlin`explain()` ステップとは同じではありません。これは、クエリの実行時に Neptune エンジンが処理する最終実行プランを返します。処理を実行しないため、使用されるパラメータに関係なく同じプランが返され、実際の実行に関する統計が出力に含まれません。

アンカレッジのすべての空港の頂点を見つける次の単純なトラバーサルを考えます。

```
g.V().has('code','ANC')
```

このトラバーサルを Neptune `explain` APIで実行するには、2 つの方法があります。最初の方法は、EXPLAIN エンドポイントに対して、次のように REST 呼び出しを行うことです。

```
curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().has('code','ANC')"}'
```

2 番目は、`explain` パラメータで Neptune ワークベンチの [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) セルマジックを使う方法です。これにより、セル本文に含まれるトラバーサルが Neptune `explain`API に渡され、セルを実行すると、結果の出力が表示されます。

```
%%gremlin explain

g.V().has('code','ANC')
```

結果としての `explain` API 出力は、Neptune のトラバーサルの実行プランを記述します。次の図に示すように、計画には、処理パイプラインに次の 3 つの各ステップが含まれています。

![\[単純な Gremlin トラバーサルの API 出力を説明する。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/Gremlin_explain_output_1.png)


### 変換されないステップを見てトラバーサルを調整する。
<a name="gremlin-traversal-tuning-explain-non-converted-steps"></a>

Neptune `explain` API 出力で最初に探すものの 1 つは、Neptune ネイティブステップに変換されない Gremlin ステップ用です。クエリプランで、Neptune ネイティブステップに変換できないステップが検出されると、そのステップと計画内の後続のすべてのステップが Gremlin サーバーによって処理されます。

上記の例では、トラバーサル内のすべてのステップが変換されました。このトラバーサルの `explain` API 出力を調べてみましょう。

```
g.V().has('code','ANC').out().choose(hasLabel('airport'), values('code'), constant('Not an airport'))
```

下の画像でわかるように、Neptune は `choose()` ステップを変換できませんでした。

![\[すべてのステップを変換できるわけではない API 出力を説明する。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/Gremlin_explain_output_2.png)


トラバーサルのパフォーマンスを調整するには、いくつかの方法があります。最初の方法では、変換できなかったステップを排除するような方法で書き直します。もう 1 つの方法では、ステップをトラバーサルの最後に移動して、他のすべてのステップをネイティブステップに変換できるようにします。

変換されないステップを含むクエリプランは、常に調整する必要はありません。変換できないステップがトラバーサルの終わりにあり、グラフのトラバース方法ではなく出力のフォーマットに関連している場合、パフォーマンスにはほとんど影響しません。

### 
<a name="gremlin-traversal-tuning-explain-unindexed-lookups"></a>

Neptune `explain` APIからの出力を調べる他の方法で使うのは、インデックスを使用しないステップです。次のトラバーサルは、アンカレッジに着陸するフライトがあるすべての空港を検索します。

```
g.V().has('code','ANC').in().values('code')
```

このトラバーサルの explain API からの出力は次のとおりです。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().has('code','ANC').in().values('code')

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,vertex), PropertiesStep([code],value)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, <code>, "ANC", ?) . project ask .]
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
            PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1}
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY}
            PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 26

WARNING: reverse traversal with no edge label(s) - .in() / .both() may impact query performance
```

出力の下部にある `WARNING` メッセージが発生するのは、トラバーサルの `in()` ステップは、Neptune が維持する 3 つのインデックスのいずれかを使用して処理することができないからです ([Neptune でステートメントのインデックスを作成する方法](feature-overview-storage-indexing.md) および [Neptune の Gremlin ステートメント](gremlin-explain-background-statements.md) を参照)。`in()` ステップにはエッジフィルターが含まれていないため、`SPOG`、`POGS`または`GPSO` インデックスを使って解決できないのです。代わりに、Neptune は要求された頂点を見つけるためにユニオンスキャンを実行しなければならず、これは非常に非効率です。

この状況において、トラバーサルを調整するには、2 つの方法があります。1 つ目は、インデックス付きルックアップを使用してクエリを解決できるように、1 つ以上のフィルタ条件を `in()` ステップに追加します。上記の例で、次のようになります。

```
g.V().has('code','ANC').in('route').values('code')
```

修正済みトラバーサルに対する Neptune `explain` API からの出力には、もう `WARNING` メッセージは含まれていません。

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().has('code','ANC').in('route').values('code')

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,[route],vertex), PropertiesStep([code],value)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, <code>, "ANC", ?) . project ask .]
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . ContainsFilter(?5 in (<route>)) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
            PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1}
            PatternNode[(?3, ?5=<route>, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=32042}
            PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 26
```

この種のトラバーサルを多数実行している場合に取る方法は、有効なオプショナル `OSGP` インデックスを持つ Neptune DB クラスターでそれらを実行することです ([OSGP インデックスの有効化](feature-overview-storage-indexing.md#feature-overview-storage-indexing-osgp) を参照)。`OSGP` インデックスの有効化には欠点があります。
+ データをロードする前に、DB クラスターで有効にする必要があります。
+ 頂点とエッジの挿入速度が最大 23% 遅くなる場合があります。
+ ストレージ使用量は約 20% 増加します。
+ すべてのインデックスにリクエストを分散する読み取りクエリでは、レイテンシーが増加する可能性があります。

`OSGP` インデックスがあることは、制限された一連のクエリパターンに対して非常に意味がありますが、それらを頻繁に実行しない限り、3 つのプライマリインデックスを使用して記述するトラバーサルを確実に解決できるようにすることをお勧めします。

### 多数の述語を使用する
<a name="gremlin-traversal-tuning-explain-many-predicates"></a>

Neptune は、グラフ内の各エッジラベルと各個別の頂点またはエッジプロパティ名を述語として扱い、デフォルトで異なる述語の数が比較的少なくなるように設計されています。グラフデータに数千を超える述語が含まれていると、パフォーマンスが低下する可能性があります。

次のような場合は、Neptune `explain` 出力によって警告が表示されます。

```
Predicates
==========
# of predicates: 9549
WARNING: high predicate count (# of distinct property names and edge labels)
```

ラベルとプロパティの数、これにしたがった述語数を減らすためにデータモデルを再加工するのが容易でない場合、トラバーサルを調整する最良の方法は、上で説明したように、有効化した `OSGP` インデックスを持つ DB クラスタ内でこれらを実行することです。

## Neptune Gremlin `profile` API を使用してトラバーサルを調整する
<a name="gremlin-traversal-tuning-profile"></a>

Neptune `profile` API は Gremlin `profile()` ステップとはかなり異なります。`explain` API のように、その出力には、Neptune エンジンがトラバーサルの実行時に使用するクエリプランが含まれます。また、`profile` 出力には、パラメーターの設定方法に基づいて、トラバーサルの実際の実行統計が含まれます。

アンカレッジのすべての空港の頂点を見つける次の単純なトラバーサルを考えます。

```
g.V().has('code','ANC')
```

`explain` API の場合は、`profile` REST 呼び出しを使用する API を呼び出せます。

```
curl -X POST https://your-neptune-endpoint:port/gremlin/profile -d '{"gremlin":"g.V().has('code','ANC')"}'
```

2番目は、`profile` パラメータで Neptune ワークベンチの [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) セルマジックを使う方法です。これにより、セル本文に含まれるトラバーサルが Neptune `profile`API に渡され、セルを実行すると、結果の出力が表示されます。

```
%%gremlin profile

g.V().has('code','ANC')
```

結果としての `profile` API 出力には、次の図に示すように、Neptune のトラバーサル実行プランとプランの実行に関する統計の両方が含まれます。

![\[Neptune profile API 出力の一例。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/Gremlin_profile_output_1.png)


`profile` 出力の場合、実行計画セクションにはトラバーサルの最終実行計画のみが含まれ、中間ステップは含まれません。パイプラインセクションには、実行された物理パイプライン操作と、トラバーサル実行にかかった実際の時間 (ミリ秒単位) が含まれます。ランタイムメトリクスは、2 つの異なるバージョンのトラバーサルの最適化にかかる時間を比較する際に非常に役立ちます。

**注記**  
トラバーサルの初期ランタイムは、通常、後続のランタイムよりも長くなります。これは、最初のランタイムによって関連するデータがキャッシュされるためです。

`profile` 出力の第 3 セクションには、実行統計とトラバーサルの結果が含まれます。この情報がトラバーサルのチューニングにどのように役立つかを確認するには、次のトラバーサルを検討してください。このトラバーサルでは、名前が「Anchora」で始まるすべての空港と、それらの空港から 2 回のホップで到達可能なすべての空港、戻り空港コード、飛行ルート、および距離が検索されます。

```
%%gremlin profile

g.withSideEffect("Neptune#fts.endpoint", "{your-OpenSearch-endpoint-URL").
    V().has("city", "Neptune#fts Anchora~").
    repeat(outE('route').inV().simplePath()).times(2).
    project('Destination', 'Route').
        by('code').
        by(path().by('code').by('dist'))
```

### Neptune `profile` API 出力のトラバーサルメトリクス
<a name="gremlin-traversal-tuning-profile-traversal-metrics"></a>

すべての `profile` 出力で使用できる最初のメトリクスセットは、トラバーサルメトリクスです。これらは Gremlin `profile()` ステップメトリクスに似ていますが、いくつかの違いがあります。

```
Traversal Metrics
=================
Step                                                               Count  Traversers       Time (ms)    % Dur
-------------------------------------------------------------------------------------------------------------
NeptuneGraphQueryStep(Vertex)                                       3856        3856          91.701     9.09
NeptuneTraverserConverterStep                                       3856        3856          38.787     3.84
ProjectStep([Destination, Route],[value(code), ...                  3856        3856         878.786    87.07
  PathStep([value(code), value(dist)])                              3856        3856         601.359
                                            >TOTAL                     -           -        1009.274        -
```

トラバーサルメトリクステーブルの最初の列には、トラバーサルによって実行されるステップがリストされます。最初の 2 つのステップは、一般に Neptune 固有のステップ `NeptuneGraphQueryStep` および `NeptuneTraverserConverterStep` です。

`NeptuneGraphQueryStep` は、Neptune エンジンによってネイティブに変換および実行できるトラバーサルの全体の実行時間を表します。

`NeptuneTraverserConverterStep` は、変換されたステップの出力を TinkerPop トラバーサーに変換するプロセスを表します。TinkerPop トラバーサーを使用すると、ステップを変換できなかったステップを処理したり、結果を TinkerPOP 互換形式で返すことができます。

上記の例では、変換されていないステップがいくつかあるので、これらの各 TinkerPop ステップ (`ProjectStep`、`PathStep`) がテーブルに行として表示されます。

テーブルの 2 列目、`Count`は、ステップを通過した*表現された*トラバーサーの数を報告し、一方で 3 列目、`Traversers`は、[TinkerPop プロファイルステップのドキュメント](https://tinkerpop.apache.org/docs/current/reference/#profile-step)で説明されているように、そのステップを通過したトラバーサーの数を報告します。。

この例では、3,856 個の頂点と 3,856 個のトラバーサーが `NeptuneGraphQueryStep` で返され、これらの数字は残りの処理を通して同じままです。これは `ProjectStep` および `PathStep` 結果をフィルタリングするのではなく、フォーマットしているからです。

**注記**  
TinkerPop と違って、Neptune エンジンは`NeptuneGraphQueryStep` および `NeptuneTraverserConverterStep` ステップの中で*一括処理*によりパフォーマンスを最適化することはありません。一括処理は、同じ頂点上のトラバーサーを組み合わせて演算オーバーヘッドを削減する TinkerPop オペレーションであり、それが原因で `Count` および `Traversers` の数は異なります。一括処理は、Neptune が TinkerPop に委譲するステップでのみ発生し、Neptune がネイティブに処理するステップでは発生しないため、`Count` および `Traverser` 列はめったに異なりません。

時間]列には、ステップが要したミリ秒数が報告され、`% Dur` 列には、ステップが要した合計処理時間の割合が報告されます。これらは、最も時間がかかったステップを示すことで、チューニング作業を集中させる場所を示すメトリクスです。

### Neptune `profile` API 出力でのインデックスオペレーションメトリクス
<a name="gremlin-traversal-tuning-profile-index-operations"></a>

Neptune プロファイル API の出力にあるもう 1 つのメトリクスセットは、インデックスオペレーションです。

```
Index Operations
================
Query execution:
    # of statement index ops: 23191
    # of unique statement index ops: 5960
    Duplication ratio: 3.89
    # of terms materialized: 0
```

次のレポート:
+ インデックスルックアップの合計数。
+ 実行された一意のインデックスルックアップの数。
+ 一意のインデックスルックアップに対する総インデックスルックアップの比率。比が低いほど、冗長性が低くなります。
+ 用語辞書からマテリアライズされた用語の数。

### Neptune `profile` API 出力のリピートメトリクス
<a name="gremlin-traversal-tuning-profile-repeat-metrics"></a>

トラバーサルが上記の例のように `repeat()` ステップを実行すると、リピートメトリックを含むセクションが`profile`出力に表示されます。

```
Repeat Metrics
==============
Iteration  Visited   Output    Until     Emit     Next
------------------------------------------------------
        0        2        0        0        0        2
        1       53        0        0        0       53
        2     3856     3856     3856        0        0
------------------------------------------------------
              3911     3856     3856        0       55
```

次のレポート:
+ 行のループカウント (`Iteration`列)。
+ ループが訪問した要素の数 (`Visited`列)。
+ ループが出力した要素の数 (`Output`列)。
+ ループが出力した最後の要素 (`Until`列)。
+ ループが発した要素の数 (`Emit`列)。
+ ループから後続のループに渡される要素の数 (`Next`列)。

これらのリピートメトリクスは、トラバーサルの分岐係数を理解し、データベースによって処理されている作業量を把握するのに非常に役立ちます。これらの数値を使用して、パフォーマンスの問題を診断できます。特に、同じトラバーサルが異なるパラメータで劇的に異なる場合です。

### Neptune `profile` API 出力のフルテキスト検索メトリクス
<a name="gremlin-traversal-tuning-profile-fts-metrics"></a>

トラバーサルが[フルテキスト検索](full-text-search.md)ルックアップを実行すると、上記の例のように、フルテキスト検索 (FTS) メトリクスを含むセクションが `profile` 出力に表示されます。

```
FTS Metrics
==============
SearchNode[(idVar=?1, query=Anchora~, field=city) . project ?1 .],
    {endpoint=your-OpenSearch-endpoint-URL, incomingSolutionsThreshold=1000, estimatedCardinality=INFINITY,
    remoteCallTimeSummary=[total=65, avg=32.500000, max=37, min=28],
    remoteCallTime=65, remoteCalls=2, joinTime=0, indexTime=0, remoteResults=2}

    2 result(s) produced from SearchNode above
```

これは、ElasticSearch (ES) クラスターに送信されたクエリを示し、フルテキスト検索に関連するパフォーマンスの問題を特定するのに役立つ ElasticSearch との相互作用に関するいくつかのメトリクスを報告します。
+ ElasticSearch インデックスへの呼び出しに関する概要情報:
  + すべての remoteCalls がクエリを満たすのに必要な合計ミリ秒数 (`total`)。
  + remoteCall で費やされた平均ミリ秒数 (`avg`)。
  + remoteCall で費やされた最低ミリ秒数 (`min`)。
  + remoteCall で費やされた最大ミリ秒数 (`max`)。
+ ElasticSearch へのリモートコールによって消費された合計時間 (`remoteCallTime`)。
+ ElasticSearch に対して行われたリモートコール数 (`remoteCalls`)。
+ ElasticSearch 結果の結合に費やされたミリ秒数 (`joinTime`)。
+ インデックスルックアップに費やされたミリ秒数 (`indexTime`)。
+ ElasticSearch によって返された結果の総数 (`remoteResults`)。

# Amazon Neptune でのネイティブ Gremlin ステップサポート
<a name="gremlin-step-support"></a>

Amazon Neptune エンジンでは、[Gremlin クエリのチューニング](gremlin-traversal-tuning.md) で説明されているように、すべての Gremlin ステップに対する完全なネイティブサポートはありません。。現在のサポートは 4 つのカテゴリに分類されます。
+ [常にネイティブ Neptune エンジンオペレーションに変換できる Gremlin ステップ](#gremlin-steps-always)
+ [場合によってはネイティブ Neptune エンジンオペレーションに変換できる Gremlin ステップ](#gremlin-steps-sometimes) 
+ [ネイティブ Neptune エンジンオペレーションに変換されない Gremlin ステップ](#gremlin-steps-never) 
+ [Neptune ではまったくサポートされていない Gremlin ステップ](#neptune-gremlin-steps-unsupported) 

## 常にネイティブ Neptune エンジンオペレーションに変換できる Gremlin ステップ
<a name="gremlin-steps-always"></a>

多くの Gremlin ステップは、次の条件を満たす限り、ネイティブ Neptune エンジンオペレーションに変換できます。
+ クエリでは、変換できないステップの前には表示されません。
+ 親ステップがあれば、その親ステップは変換できます。
+ もしあれば、すべての子トラバーサルは変換できます。

以下の Gremlin ステップは、次の条件を満たす限り、ネイティブ Neptune エンジンオペレーションに変換できます。
+ [and( )](http://tinkerpop.apache.org/docs/current/reference/#and-step)
+ [as( )](http://tinkerpop.apache.org/docs/current/reference/#as-step)
+ [count( )](http://tinkerpop.apache.org/docs/current/reference/#count-step)
+ [E( )](http://tinkerpop.apache.org/docs/current/reference/#graph-step)
+ [emit( )](http://tinkerpop.apache.org/docs/current/reference/#emit-step)
+ [explain( )](http://tinkerpop.apache.org/docs/current/reference/#explain-step)
+ [group( )](http://tinkerpop.apache.org/docs/current/reference/#group-step)
+ [groupCount( )](http://tinkerpop.apache.org/docs/current/reference/#groupcount-step)
+ [identity( )](http://tinkerpop.apache.org/docs/current/reference/#identity-step)
+ [is( )](http://tinkerpop.apache.org/docs/current/reference/#is-step)
+ [key( )](http://tinkerpop.apache.org/docs/current/reference/#key-step)
+ [label( )](http://tinkerpop.apache.org/docs/current/reference/#label-step)
+ [limit( )](http://tinkerpop.apache.org/docs/current/reference/#limit-step)
+ [local( )](http://tinkerpop.apache.org/docs/current/reference/#local-step)
+ [loops( )](http://tinkerpop.apache.org/docs/current/reference/#loops-step)
+ [not( )](http://tinkerpop.apache.org/docs/current/reference/#not-step)
+ [or( )](http://tinkerpop.apache.org/docs/current/reference/#or-step)
+ [profile( )](http://tinkerpop.apache.org/docs/current/reference/#profile-step)
+ [properties( )](http://tinkerpop.apache.org/docs/current/reference/#properties-step)
+ [subgraph( )](http://tinkerpop.apache.org/docs/current/reference/#subgraph-step)
+ [until( )](http://tinkerpop.apache.org/docs/current/reference/#until-step)
+ [V( )](http://tinkerpop.apache.org/docs/current/reference/#graph-step)
+ [value( )](http://tinkerpop.apache.org/docs/current/reference/#value-step)
+ [valueMap( )](http://tinkerpop.apache.org/docs/current/reference/#valuemap-step)
+ [values( )](http://tinkerpop.apache.org/docs/current/reference/#values-step)

## 場合によってはネイティブ Neptune エンジンオペレーションに変換できる Gremlin ステップ
<a name="gremlin-steps-sometimes"></a>

一部の Gremlin ステップは、状況によってはネイティブ Neptune エンジンオペレーションに変換できますが、他の状況では変換できません。
+ [addE( )](http://tinkerpop.apache.org/docs/current/reference/#addedge-step)   –   トラバーサルをキーとして含む `property()` ステップが直後に続く場合を除き、`addE()` ステップは、通常ネイティブ Neptune エンジンオペレーションに変換できます。
+ [addV( )](http://tinkerpop.apache.org/docs/current/reference/#addvertex-step)   –   トラバーサルをキーとして含む `property()` ステップが直後に続く場合を除き、または複数のラベルが割り当てられる場合を除き、`addV()` ステップは、通常ネイティブ Neptune エンジンオペレーションに変換できます。
+ [aggregate( )](http://tinkerpop.apache.org/docs/current/reference/#store-step)   –   子トラバーサルまたはサブトラバーサルで使用されている場合を除き、または格納される値が頂点、エッジ、ID、ラベル、またはプロパティ値以外のものでない限り、通常 `aggregate()` ステップは、ネイティブ Neptune エンジンオペレーションに変換できます。

  次の例では、子トラバーサルで使用されているため、`aggregate()` は変換されません。

  ```
  g.V().has('code','ANC').as('a')
       .project('flights').by(select('a')
       .outE().aggregate('x'))
  ```

  この例では、格納される値が `min()` であるため、aggregate () は変換されません。

  ```
  g.V().has('code','ANC').outE().aggregate('x').by(values('dist').min())
  ```
+ [barrier( )](http://tinkerpop.apache.org/docs/current/reference/#barrier-step)   –   `barrier()`ステップは、その後のステップが変換されない限り、通常ネイティブ Neptune エンジンオペレーションに変換できます。
+ [cap( )](http://tinkerpop.apache.org/docs/current/reference/#cap-step)   –   `cap()` ステップが変換される唯一のケースは、`unfold()` ステップと組み合わせて頂点、エッジ、ID、またはプロパティ値の集約の展開バージョンを返す場合です。この例では、次に `.unfold()` が後続するので、`cap()` は変換されます。

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```

  ただし、`.unfold()` を削除すると、`cap()` は変換されません。

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport')
  ```
+ [coalesce( )](http://tinkerpop.apache.org/docs/current/reference/#coalesce-step)   –   `coalesce()` ステップが変換される唯一のケースは、[TinkerPop レシピページ](http://tinkerpop.apache.org/docs/current/recipes/)で推奨される[アップサートパターン](http://tinkerpop.apache.org/docs/current/recipes/#element-existence)に続く場合です。その他の coalesce() パターンは使用できません。変換は、すべての子トラバーサルが変換できる場合に限られ、それらはすべて出力と同じタイプ (頂点、エッジ、ID、値、キー、またはラベル) を生成し、新しい要素にトラバースし、`repeat()` ステップは含みません。
+ [constant( )](http://tinkerpop.apache.org/docs/current/reference/#constant-step)   –   constant () ステップは現在、次のように、定数値を割り当てるためのトラバーサルの `sack().by()` 一部内で使われる場合にのみ変換されます。

  ```
  g.V().has('code','ANC').sack(assign).by(constant(10)).out().limit(2)
  ```
+ [cyclicPath( )](http://tinkerpop.apache.org/docs/current/reference/#cyclicpath-step)   –   `cyclicPath()` ステップは、それが `by()`、`from()`、`to()` モジュレータのいずれかと使われている場合を除き、通常ネイティブ Neptune エンジンオペレーションに変換できます。次のクエリでは、たとえば、`cyclicPath()` は変換されません。

  ```
  g.V().has('code','ANC').as('a').out().out().cyclicPath().by('code')
  g.V().has('code','ANC').as('a').out().out().cyclicPath().from('a')
  g.V().has('code','ANC').as('a').out().out().cyclicPath().to('a')
  ```
+ [drop( )](http://tinkerpop.apache.org/docs/current/reference/#drop-step)   –   `drop()` ステップは、それが `sideEffect(` または `optional()` ステップのいずれかで使われている場合を除き、通常、ネイティブ Neptune エンジンオペレーションに変換できます。
+ [fold( )](http://tinkerpop.apache.org/docs/current/reference/#fold-step)   –   fold () ステップを変換できる状況は2つしかありません。つまり、[TinkerPop レシピページ](http://tinkerpop.apache.org/docs/current/recipes/)で推奨されている[アップサートパターン](http://tinkerpop.apache.org/docs/current/recipes/#element-existence)で使われる場合と、次のような `group().by()` コンテキストでそれが使われる場合です。

  ```
  g.V().has('code','ANC').out().group().by().by(values('code', 'city').fold())
  ```
+  [has( )](http://tinkerpop.apache.org/docs/current/reference/#has-step) – 「has()」ステップは、通常、「T」が述語「P.eq」、「P.neq」、または「P.contains」を使用したクエリで指定されるネイティブ Neptune エンジンオペレーションに変換できます。「has()」のバリエーションを想定します。「hasId('id1234')」は「has(eq, T.id, 'id1234')」と同等であり、「P」のインスタンスはネイティブに変換されます。
+ [id( )](http://tinkerpop.apache.org/docs/current/reference/#id-step)   –   `id()` ステップは、プロパティで使用されない限り、次のように変換されます。

  ```
  g.V().has('code','ANC').properties('code').id()
  ```
+  [mergeE()](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step) – パラメータ (マージ条件、`onCreate` および `onMatch`) が定数 (`null`、定数 `Map` または `Map` の`select()` のいずれか) である場合は、`mergeE()` ステップをネイティブ Neptune エンジンオペレーションに変換できます。[エッジのアップサート](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-efficient-upserts.html#gremlin-upserts-edges)のすべての例を変換できます。
+  [mergeV()](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step) – パラメータ (マージ条件、`onCreate` および `onMatch`) が定数 (`null`、定数 `Map`、または `Map` の `select()`のいずれか) である場合は、mergeV() ステップをネイティブ Neptune エンジンオペレーションに変換できます。[頂点のアップサート](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-efficient-upserts.html#gremlin-upserts-vertices)のすべての例を変換できます。
+ [order( )](http://tinkerpop.apache.org/docs/current/reference/#order-step)   –   `order()` ステップは、その後のステップが変換されない限り、通常 ネイティブ Neptune エンジンオペレーションに変換できます。
  + `order()` ステップは、次のようにネストされた子トラバーサル内にあります。

    ```
    g.V().has('code','ANC').where(V().out().order().by(id))
    ```
  + たとえば、`order(local)` で、ローカル順序付けが使用されています。
  + カスタムコンパレータは、`by()` モジュレーションで順序付けするために使われます。一例として、この使用法`sack()`があります。

    ```
    g.withSack(0).
      V().has('code','ANC').
          repeat(outE().sack(sum).by('dist').inV()).times(2).limit(10).
          order().by(sack())
    ```
  + 同じ要素に複数の順序があります。
+ [project( )](http://tinkerpop.apache.org/docs/current/reference/#project-step)   –   `project()`に従う`by()`ステートメントの数が、次のように、指定されたラベルの数と一致しないのでなければ、`project()`ステップは、通常ネイティブ Neptune エンジンオペレーションに変換できます。

  ```
  g.V().has('code','ANC').project('x', 'y').by(id)
  ```
+ [range( )](http://tinkerpop.apache.org/docs/current/reference/#range-step)   –   `range()`ステップは、対象範囲の下端がゼロの場合にのみ変換されます (たとえば、`range(0,3)`)。
+ [repeat( )](http://tinkerpop.apache.org/docs/current/reference/#repeat-step)   –   次のように別の`repeat()`ステップノード内にネストされている場合を除き、`repeat()`ステップは、通常ネイティブ Neptune エンジンオペレーションに変換できます。

  ```
  g.V().has('code','ANC').repeat(out().repeat(out()).times(2)).times(2)
  ```
+ [sack( )](http://tinkerpop.apache.org/docs/current/reference/#sack-step)   –   `sack()`ステップは、次の場合を除き、通常ネイティブ Neptune エンジンオペレーションに変換できます。
  + 数値以外のサック演算子が使用されている場合。
  + `+`、`-`、`mult`、`div`、`min` および `max` 以外の数値サック演算子が使用されている場合。
  + 次のように、サック値に基づいてフィルタリングするために `where()` ステップの中で `sack()` が使われる場合。

    ```
    g.V().has('code','ANC').sack(assign).by(values('code')).where(sack().is('ANC'))
    ```
+ [sum( )](http://tinkerpop.apache.org/docs/current/reference/#sum-step)   –   `sum()` ステップは、通常、ネイティブ Neptune エンジンオペレーションに変換できますが、次のようにグローバル総和の計算に使用される場合は変換できません。

  ```
  g.V().has('code','ANC').outE('routes').values('dist').sum()
  ```
+ [union()](http://tinkerpop.apache.org/docs/current/reference/#union-step) — `union()` ステップは、ターミナルステップ以外のクエリの最後のステップである限り、ネイティブ Neptune エンジン操作に変換できます。
+ [unfold( )](http://tinkerpop.apache.org/docs/current/reference/#unfold-step)   –   `unfold()` ステップは、[TinkerPop レシピページ](http://tinkerpop.apache.org/docs/current/recipes/)で推奨される[アップサートパターン](http://tinkerpop.apache.org/docs/current/recipes/#element-existence)で使われる場合と、次のように `cap()` と併用される場合にのみ、ネイティブ Neptune エンジンオペレーションに変換できます。

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```
+ [where( )](http://tinkerpop.apache.org/docs/current/reference/#where-step)   –   `where()` ステップは、次の場合を除き、通常 ネイティブ Neptune エンジンオペレーションに変換できます。
  + 次のように、by () モジュレーションを使用する場合。

    ```
    g.V().hasLabel('airport').as('a')
         .where(gt('a')).by('runways')
    ```
  + `eq`、`neq`、`within`、および `without` 以外の比較演算子が用いられる場合。
  + ユーザー指定の集計が使用される場合。

## ネイティブ Neptune エンジンオペレーションに変換されない Gremlin ステップ
<a name="gremlin-steps-never"></a>

次の Gremlin ステップは Neptune でサポートされていますが、ネイティブ Neptune エンジンオペレーションに変換されることはありません。代わりに、Gremlin サーバーによって実行されます。
+ [choose( )](http://tinkerpop.apache.org/docs/current/reference/#choose-step)
+ [coin( )](http://tinkerpop.apache.org/docs/current/reference/#coin-step)
+ [inject( )](http://tinkerpop.apache.org/docs/current/reference/#inject-step)
+ [match( )](http://tinkerpop.apache.org/docs/current/reference/#match-step)
+ [math( )](http://tinkerpop.apache.org/docs/current/reference/#math-step)
+ [max( )](http://tinkerpop.apache.org/docs/current/reference/#max-step)
+ [mean( )](http://tinkerpop.apache.org/docs/current/reference/#mean-step)
+ [min( )](http://tinkerpop.apache.org/docs/current/reference/#min-step)
+ [option( )](http://tinkerpop.apache.org/docs/current/reference/#option-step)
+ [optional( )](http://tinkerpop.apache.org/docs/current/reference/#optional-step)
+ [path( )](http://tinkerpop.apache.org/docs/current/reference/#path-step)
+ [propertyMap( )](http://tinkerpop.apache.org/docs/current/reference/#propertymap-step)
+ [sample( )](http://tinkerpop.apache.org/docs/current/reference/#sample-step)
+ [skip( )](http://tinkerpop.apache.org/docs/current/reference/#skip-step)
+ [tail( )](http://tinkerpop.apache.org/docs/current/reference/#tail-step)
+ [timeLimit( )](http://tinkerpop.apache.org/docs/current/reference/#timelimit-step)
+ [tree( )](http://tinkerpop.apache.org/docs/current/reference/#tree-step)

## Neptune ではまったくサポートされていない Gremlin ステップ
<a name="neptune-gremlin-steps-unsupported"></a>

次の Gremlin ステップは、Neptune ではまったくサポートされていません。ほとんどの場合、これは `GraphComputer` が必要なためで、これは Neptune が現在サポートしていません。
+ [connectedComponent( )](http://tinkerpop.apache.org/docs/current/reference/#connectedcomponent-step)
+ [io( )](http://tinkerpop.apache.org/docs/current/reference/#io-step)
+ [shortestPath( )](http://tinkerpop.apache.org/docs/current/reference/#shortestpath-step)
+ [withComputer( )](http://tinkerpop.apache.org/docs/current/reference/#with-step)
+ [pageRank( )](http://tinkerpop.apache.org/docs/current/reference/#pagerank-step)
+ [peerPressure( )](http://tinkerpop.apache.org/docs/current/reference/#peerpressure-step)
+ [program( )](http://tinkerpop.apache.org/docs/current/reference/#program-step)

`io()` ステップは実際には部分的にサポートされていて、URL からの `read()` には使用できますが、`write()` には使用できません。

# Gremlin と Neptune DFE クエリエンジンを使用する
<a name="gremlin-with-dfe"></a>

[ラボモード](features-lab-mode.md)で Neptune [代替クエリエンジン](neptune-dfe-engine.md) (DFE) を有効にしたら (`neptune_lab_mode` DB クラスターのパラメータを `DFEQueryEngine=enabled` に設定することによる)、Neptune は読み取り専用の Gremlin クエリ/トラバーサルを中間論理表現に変換し、可能な限り DFE エンジンで実行します。

ただし、DFE はまだ Gremlin のすべてのステップをサポートしていません。DFE でステップをネイティブに実行できない場合、Neptune は TinkerPop にフォールバックしてステップを実行します。これが発生すると、`explain` および `profile` レポートに警告が含まれます。

# DFE での Gremlin ステップカバレッジ
<a name="gremlin-step-coverage-in-DFE"></a>

 Gremlin DFE はラボモード機能であり、クラスターパラメータを有効にするか、`Neptune#useDFE` クエリヒントを使用することによって使用できます。詳細については、「[Neptune DFE クエリエンジンでの Gremlin の使用](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-with-dfe.html)」を参照してください。

 次の手順は Gremlin DFE で使用できます。

## パスとトラバーサルステップ:
<a name="DFE-path-and-traversal"></a>

 [asDate()](https://tinkerpop.apache.org/docs/current/reference/#asDate-step), [barrier()](https://tinkerpop.apache.org/docs/current/reference/#barrier-step), [call()](https://tinkerpop.apache.org/docs/current/reference/#call-step), [cap()](https://tinkerpop.apache.org/docs/current/reference/#cap-step), [dateAdd()](https://tinkerpop.apache.org/docs/current/reference/#dateadd-step), [dateDiff()](https://tinkerpop.apache.org/docs/current/reference/#datediff-step), [disjunct()](https://tinkerpop.apache.org/docs/current/reference/#disjunct-step), [drop()](https://tinkerpop.apache.org/docs/current/reference/#drop-step), [fail()](https://tinkerpop.apache.org/docs/current/reference/#fail-step), [filter()](https://tinkerpop.apache.org/docs/current/reference/#filter-step), [flatMap()](https://tinkerpop.apache.org/docs/current/reference/#flatmap-step), [id()](https://tinkerpop.apache.org/docs/current/reference/#id-step), [identity()](https://tinkerpop.apache.org/docs/current/reference/#identity-step), [index()](https://tinkerpop.apache.org/docs/current/reference/#index-step), [intersect()](https://tinkerpop.apache.org/docs/current/reference/#intersect-step), [inject()](https://tinkerpop.apache.org/docs/current/reference/#inject-step), [label()](https://tinkerpop.apache.org/docs/current/reference/#label-step), [length()](https://tinkerpop.apache.org/docs/current/reference/#length-step), [loops()](https://tinkerpop.apache.org/docs/current/reference/#loops-step), [map()](https://tinkerpop.apache.org/docs/current/reference/#map-step), [order()](https://tinkerpop.apache.org/docs/current/reference/#order-step), [order(local)](https://tinkerpop.apache.org/docs/current/reference/#order-step), [path()](https://tinkerpop.apache.org/docs/current/reference/#path-step), [project()](https://tinkerpop.apache.org/docs/current/reference/#project-step), [range()](https://tinkerpop.apache.org/docs/current/reference/#range-step), [repeat()](https://tinkerpop.apache.org/docs/current/reference/#repeat-step), [reverse()](https://tinkerpop.apache.org/docs/current/reference/#reverse-step), [sack()](https://tinkerpop.apache.org/docs/current/reference/#sack-step), [sample()](https://tinkerpop.apache.org/docs/current/reference/#sample-step), [select()](https://tinkerpop.apache.org/docs/current/reference/#select-step), [sideEffect()](https://tinkerpop.apache.org/docs/current/reference/#sideeffect-step), [split()](https://tinkerpop.apache.org/docs/current/reference/#split-step), [unfold()](https://tinkerpop.apache.org/docs/current/reference/#unfold-step), [union()](https://tinkerpop.apache.org/docs/current/reference/#union-step) 

## 集約と収集のステップ:
<a name="DFE-aggregate-and-collection"></a>

 [aggregate(global)](https://tinkerpop.apache.org/docs/current/reference/#aggregate-step)、 [combine()](https://tinkerpop.apache.org/docs/current/reference/#combine-step)、[count()](https://tinkerpop.apache.org/docs/current/reference/#count-step)、[dedup()](https://tinkerpop.apache.org/docs/current/reference/#dedup-step)、[dedup(local)](https://tinkerpop.apache.org/docs/current/reference/#dedup-step)、[fold()](https://tinkerpop.apache.org/docs/current/reference/#fold-step)、[group()](https://tinkerpop.apache.org/docs/current/reference/#group-step)、[groupCount()](https://tinkerpop.apache.org/docs/current/reference/#groupcount-step)、

## 数学的なステップ:
<a name="DFE-mathematical"></a>

 [max()](https://tinkerpop.apache.org/docs/current/reference/#max-step)、[mean()](https://tinkerpop.apache.org/docs/current/reference/#mean-step)、[min()](https://tinkerpop.apache.org/docs/current/reference/#min-step)、[sum()](https://tinkerpop.apache.org/docs/current/reference/#sum-step) 

## 要素ステップ:
<a name="DFE-element"></a>

 [otherV()](https://tinkerpop.apache.org/docs/current/reference/#otherv-step)、[elementMap()](https://tinkerpop.apache.org/docs/current/reference/#elementmap-step)、[element()](https://tinkerpop.apache.org/docs/current/reference/#element-step)、[v()](https://tinkerpop.apache.org/docs/current/reference/#graph-step)、[ out()、in()、both()、outE()、inE()、bothE()、outV()、inV()、bothV()、otherV()](https://tinkerpop.apache.org/docs/current/reference/#vertex-step) 

## プロパティステップ:
<a name="DFE-property"></a>

 [properties()](https://tinkerpop.apache.org/docs/current/reference/#properties-step)、[key()](https://tinkerpop.apache.org/docs/current/reference/#key-step)、[valueMap()](https://tinkerpop.apache.org/docs/current/reference/#propertymap-step)、[value()](https://tinkerpop.apache.org/docs/current/reference/#value-step) 

## フィルターステップ:
<a name="DFE-filter"></a>

 [and()](https://tinkerpop.apache.org/docs/current/reference/#and-step)、[coalesce()](https://tinkerpop.apache.org/docs/current/reference/#coalesce-step)、[coin()](https://tinkerpop.apache.org/docs/current/reference/#coin-step)、[has()](https://tinkerpop.apache.org/docs/current/reference/#has-step)、[is()](https://tinkerpop.apache.org/docs/current/reference/#is-step)、[local()](https://tinkerpop.apache.org/docs/current/reference/#local-step)、[none()](https://tinkerpop.apache.org/docs/current/reference/#none-step)、[not()](https://tinkerpop.apache.org/docs/current/reference/#not-step)、[or()](https://tinkerpop.apache.org/docs/current/reference/#or-step)、[where()](https://tinkerpop.apache.org/docs/current/reference/#where-step) 

## 文字列操作ステップ:
<a name="DFE-string-manipulation"></a>

 [concat()](https://tinkerpop.apache.org/docs/current/reference/#concat-step)、[lTrim()](https://tinkerpop.apache.org/docs/current/reference/#lTrim-step)、[rTrim()](https://tinkerpop.apache.org/docs/current/reference/#rtrim-step)、[substring()](https://tinkerpop.apache.org/docs/current/reference/#substring-step)、[toLower()](https://tinkerpop.apache.org/docs/current/reference/#toLower-step)、[toUpper()](https://tinkerpop.apache.org/docs/current/reference/#toUpper-step)、[trim()](https://tinkerpop.apache.org/docs/current/reference/#trim-step) 

## 述語:
<a name="DFE-predicates"></a>
+  [比較: eq、neq、lt、lte、gt、gte](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [包含: within、without](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [TextP: endingWith、containing、notStartingWith、notEndingWith、notContaining](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [P: and、or、between、outside、inside](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 

## 制限事項
<a name="gremlin-with-dfe-limitations"></a>

 制限付きで繰り返し、繰り返しトラバーサルと重複排除内のラベルは DFE ではまだサポートされていません。

```
// With Limit inside the repeat traversal
  g.V().has('code','AGR').repeat(out().limit(5)).until(has('code','FRA'))
  
  // With Labels inside the repeat traversal
  g.V().has('code','AGR').repeat(out().as('a')).until(has('code','FRA'))
  
  // With Dedup inside the repeat traversal
  g.V().has('code','AGR').repeat(out().dedup()).until(has('code','FRA'))
```

 ネストされた繰り返しを含むパス、または分岐ステップはまだサポートされていません。

```
// Path with branching steps
  g.V().has('code','AGR').union(identity, outE().inV()).path().by('code')
  
  
  // With nested repeat
  g.V().has('code','AGR').repeat(out().union(identity(), out())).path().by('code')
```

## クエリ計画インターリーブ
<a name="gremlin-with-dfe-interleaving"></a>

変換プロセスで、対応するネイティブ DFE 演算子を持たない Gremlin ステップが検出されると、Tinkerpop の使用にフォールバックする前に、DFE エンジンでネイティブに実行できる他の中間クエリ部分を見つけようとします。これは、最上位レベルのトラバーサルにインターリーブロジックを適用することによって行われます。その結果、サポートされているステップは可能な限り使用されます。

このような中間的な非プレフィックスクエリ変換は、`NeptuneInterleavingStep` および`explain` 出力にある `profile` を使って表されます。

パフォーマンスの比較のために、DFE エンジンを使用してプレフィックス部分を実行しながら、クエリでのインターリーブをオフにしたい場合があります。または、非プレフィックスクエリの実行に TinkerPop エンジンだけを使用することもできます。これを行うには、`disableInterleaving` クエリヒントを使用します。

[useDFE](gremlin-query-hints-useDFE.md) 値の `false` クエリヒントにより DFE でクエリがまったく実行されなくなるように、`disableInterleaving` 値の `true` クエリヒントはクエリの変換の DFE インターリーブをオフにします。例: 

```
g.with('Neptune#disableInterleaving', true)
 .V().has('genre','drama').in('likes')
```

## Gremlin `explain` および `profile` 出力の更新
<a name="gremlin-with-dfe-explain-update"></a>

Gremlin [explain](gremlin-explain.md) は、Neptune がクエリの実行に使用する最適化されたトラバーサルの詳細を示します。DFE エンジンが無効化されているときの `explain` 出力はどのようなものかの例について、[サンプル DFE `explain` 出力](gremlin-explain-api.md#gremlin-explain-dfe)をご覧ください。

[Gremlin `profile` API](gremlin-profile-api.md) は指定された Gremlin トラバーサルを実行し、実行に関するさまざまなメトリクスを収集して、最適化されたクエリプランの詳細と、さまざまな演算子の実行時統計情報を含むプロファイルレポートを生成します。`profile` DFE エンジンが無効化されているときの出力はどのようなものかの例について、[サンプル DFE `profile` 出力](gremlin-profile-api.md#gremlin-profile-sample-dfe-output)をご覧ください。

**注記**  
DFE はラボモードでリリースされる実験的な機能なので、`explain` および `profile` 出力の正確な形式は変更される可能性があります。

# openCypher でNeptune グラフにアクセスする
<a name="access-graph-opencypher"></a>

Neptune は、openCypher を使用したグラフアプリケーションの構築をサポートしています。これは、現在、グラフデータベースを操作する開発者にとって最も人気のあるクエリ言語の 1 つです。開発者、ビジネスアナリスト、データサイエンティストは、openCypher の SQL の影響が大きい構文を好みます。これは、グラフアプリケーションのクエリを作成するためによく知られた構造を提供するからです。

**openCypher** は、プロパティグラフの宣言型クエリ言語です。当初は Neo4j が 開発し、その後 2015 年にオープンソース化され、Apache 2 オープンソースライセンスの下で [openCypher](http://www.opencypher.org/) プロジェクトで活用されました。構文は [Cypher クエリ言語リファレンス、バージョン 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf) で説明されています。

openCypher 仕様の Neptune サポートの制限と相違点については、「[Amazon Neptune における openCypher の仕様準拠](feature-opencypher-compliance.md)」を参照してください。

**注記**  
Cypher クエリ言語の現在の Neo4j 実装は、openCypher 仕様とはいくつかの点で異なっています。現在の Neo4j Cypher コードを Neptune に移行する場合、詳細については, 「[Neptune の Neo4j との互換性](migration-compatibility.md)」と「[Neptune 上の openCypherで実行するように Cypher クエリを書き直す](migration-opencypher-rewrites.md)」を参照してください。

エンジンリリース 1.1.1.0 以降、openCypher は Neptune での本番使用が可能になりました。

## Gremlin 対 openCypher：類似点と相違点
<a name="access-graph-opencypher-overview-with-gremlin"></a>

Gremlin と openCypher はどちらもプロパティグラフクエリ言語であり、多くの点で補完的です。

Gremlin は、プログラマーに魅力的で、コードにシームレスに収まるように設計されました。その結果、Gremlin は設計上命令的ですが、OpenenCypher の宣言構文は SQL や SPARQL の経験を持つ人々はより身近に感じるかもしれません。Gremlin は Jupyter ノートブックで Python を使用するデータサイエンティストにとってより自然に見えるかもしれませんが、openCypher は SQL の背景を持つビジネスユーザーにはより直感的だと思えるかもしれません。

うれしいことに Neptune でGremlin と openCypher いずれかを**選ぶ必要はありません**。どちらの言語でも、データの入力に使用された 2 つの言語に関係なく、同じグラフでクエリを実行できます。何をするかによって、いくつかのことには Gremlinを、他のことには openCypher を、と使い分ける方が便利になるかもしれません。

Gremlin は、一連のステップでグラフ内を移動する方法を制御できる命令構文を使用します。各ステップは、データのストリームを取り込み、そのデータに対して何らかのアクション (フィルター、マップなどを使用して) を実行し、結果を次のステップに出力します。Gremlin クエリは、通常、`g.V()`　形式をとります。そして追加のステップが続きます。

openCypher では、SQL の影響が大きい宣言構文を使用します。この構文は、(`()-[]->()` のような) モチーフ構文を使用してグラフ内で検索するノードと関係のパターンを指定します。openCypher クエリは、多くの場合、`MATCH` 句、それに `WHERE`、`WITH`、および `RETURN` のような他の句が続きます。

# openCypher の使用を開始する方法
<a name="access-graph-opencypher-overview-getting-started"></a>

Neptune のプロパティグラフデータは、ロードされた方法に関係なく openCypher を使用してクエリできますが、RDF としてロードされたデータのクエリに openCypher を使用することはできません。

[Neptune バルクローダー](bulk-load.md)は、プロパティグラフデータを[Gremlin の CSV 形式](bulk-load-tutorial-format-gremlin.md)と、[openCypher の CSV 形式](bulk-load-tutorial-format-opencypher.md)で受領します。また、もちろん、Gremlin や openCypher クエリを使用して、プロパティデータをグラフに追加することもできます。

Cypher クエリ言語を学習するためのオンラインチュートリアルが数多く用意されています。ここでは、openCypher クエリの簡単な例をいくつか挙げていますので、言語を理解するのに役立つかもしれませんが、openCypher を使用して Neptune グラフをクエリする最も簡単で簡単な方法は、openCypher ノートブックを[Neptune ワークベンチ](graph-notebooks.md)で使うことです。ワークベンチはオープンソースであり、次のサイトで GitHub でホストされています。[https://github.com/aws-samples/amazon-neptune-samples](https://github.com/aws-samples/amazon-neptune-samples/)。

openCypher ノートブックは GitHub [Neptune グラフノートブックリポジトリ](https://github.com/aws/graph-notebook/tree/main/src/graph_notebook/notebooks)にあります。特に、openCypher の[エアルートの可視化](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/Air-Routes-openCypher.ipynb)、および[イングリッシュ・プレミア・チーム](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/EPL-openCypher.ipynb)のノートブックをご確認ください。。

openCypher によって処理されるデータは、順序付けられていない一連のキー/値マップの形式をとります。これらのマップを調整、操作、および拡張する主な方法は、キーと値のペアに対してパターンマッチング、挿入、更新、削除などのタスクを実行する句を使用することです。

openCypher には、グラフ内のデータパターンを見つけるためのいくつかの句があり、そのうちの `MATCH` が最も一般的です。`MATCH` グラフ内で検索するノード、リレーションシップ、およびフィルタのパターンを指定できます。例: 
+ **すべてのノードを取得する**

  ```
  MATCH (n) RETURN n
  ```
+ **接続されたノードを検索する**

  ```
  MATCH (n)-[r]->(d) RETURN n, r, d
  ```
+ **パスを見つける**

  ```
  MATCH p=(n)-[r]->(d) RETURN p
  ```
+ **ラベル付きのすべてのノードを取得する**

  ```
  MATCH (n:airport) RETURN n
  ```

上記の最初のクエリはグラフ内のすべてのノードを返し、次の 2 つはリレーションシップを持つすべてのノードを返すことに注意してください。これは一般的にはお勧めしません！ほとんどの場合、返されるデータを絞り込む必要があります。これは、4 番目の例のように、ノードまたはリレーションシップのラベルとプロパティを指定することで実行できます。

openCypher 構文の便利なチートシートは Neptune [github サンプルリポジトリ](https://github.com/aws-samples/amazon-neptune-samples/tree/master/opencypher/Cheatsheet.md)にあります。

# Neptune openCypher ステータスサーブレットとステータスエンドポイント
<a name="access-graph-opencypher-status"></a>

openCypher ステータスエンドポイントは、サーバー上で現在実行されている、または実行を待っているクエリに関する情報へのアクセスを提供します。また、これらのクエリをキャンセルすることもできます。エンドポイントは、次の通りです。

```
https://(the server):(the port number)/openCypher/status
```

サーバーから現在のステータスを取得する、またはクエリをキャンセルするHTTP `GET` および `POST` メソッドを使用できます。また、実行中のクエリまたは待機中のクエリをキャンセルする `DELETE` メソッドを使用することもできます。

## ステータスリクエストのパラメータ
<a name="access-graph-opencypher-status-parameters"></a>

**ステータスクエリパラメータ**
+ **`includeWaiting`** (`true` または `false`) — `true` に設定し、かつその他のパラメータが存在しない場合は、待機中のクエリと実行中のクエリのステータス情報が返されます。
+ **`cancelQuery`** — `GET` および `POST` メソッドを使用してのみ使用し、これがキャンセル要求であることを示します。`DELETE` メソッドはこのパラメータを必要としません。

  `cancelQuery` パラメータの値は使用されませんが、`cancelQuery` が存在する場合、キャンセルするクエリを識別するには、`queryId` パラメータが必要です。
+ **`queryId`** — 特定のクエリの ID が含まれます。

  `GET` または `POST` メソッドと併用およびし、なおかつ `cancelQuery` パラメータが存在しない場合 `queryId` は、識別する特定のクエリのステータス情報を返します。`cancelQuery` パラメータが存在する場合、`queryId` が特定するクエリはキャンセルされます。

  `DELETE` メソッドと併用する場合、`queryId` は常に特定のクエリがキャンセルされることを示します。
+ **`silent`** — クエリをキャンセルするときにのみ使用されます。`true` に設定されている場合、キャンセルは予告なしに行われます。

## ステータスリクエストのレスポンスフィールド
<a name="access-graph-opencypher-status-response-fields"></a>

**特定のクエリの ID が指定されていない場合、ステータスレスポンスフィールドは表示されない**
+ **acceptedQueryCount**   –   受け入れられながらもまだ完了していないクエリの数 (キュー内のクエリを含む)。
+ **runningQueryCount**   –   現在実行されている openCypher クエリの数。
+ **queries**   –   現在の openCypher クエリのリスト。

**特定のクエリのステータスレスポンスフィールド**
+ **queryId**   –   クエリの GUID ID。Neptune は、この ID 値を各クエリに自動的に割り当てます。または、独自の ID を割り当てることもできます ([Neptune Gremlin または SPARQL クエリにカスタム ID を挿入する](features-query-id.md)を参照)。
+ **queryString**   –   送信されたクエリ。それより長い場合、これは 1024 文字に切り捨てられます。
+ **queryEvalStats** — このクエリの統計情報。
  + **waited** - クエリが待機していた時間をミリ秒単位で示します。
  + **elapsed**   –   これまでクエリが実行されていた時間 (マイクロ秒)。
  + **cancelled** — `True` はクエリがキャンセルされたことを示し、`False` はキャンセルされていないことを示します。

## ステータスリクエストとレスポンスの例
<a name="access-graph-opencypher-status-samples"></a>
+ **待機中のクエリを含む、すべてのクエリのステータスを要求します。**

  ```
  curl https://server:port/openCypher/status \
    --data-urlencode "includeWaiting=true"
  ```

  *レスポンス*:

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **待機中のクエリを**含まない**、すべてのクエリのステータスを要求します。**

  ```
  curl https://server:port/openCypher/status
  ```

  *レスポンス*:

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **1 つのクエリのステータスをリクエストします。**

  ```
  curl https://server:port/openCypher/status \
   --data-urlencode "queryId=eadc6eea-698b-4a2f-8554-5270ab17ebee"
  ```

  *レスポンス*:

  ```
  {
    "queryId" : "eadc6eea-698b-4a2f-8554-5270ab17ebee",
    "queryString" : "MATCH (n1)-[:knows]->(n2), (n2)-[:knows]->(n3), (n3)-[:knows]->(n4), (n4)-[:knows]->(n5), (n5)-[:knows]->(n6), (n6)-[:knows]->(n7), (n7)-[:knows]->(n8), (n8)-[:knows]->(n9), (n9)-[:knows]->(n10) RETURN COUNT(n1);",
    "queryEvalStats" : {
      "waited" : 0,
      "elapsed" : 23463,
      "cancelled" : false
    }
  }
  ```
+ **クエリのキャンセルをリクエストします**

  1. `POST` を使用する:

  ```
  curl -X POST https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=f43ce17b-db01-4d37-a074-c76d1c26d7a9"
  ```

  *レスポンス*:

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  2. `GET` を使用する:

  ```
  curl -X GET https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=588af350-cfde-4222-bee6-b9cedc87180d"
  ```

  *レスポンス*:

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  3. `DELETE` を使用する:

  ```
  curl -X DELETE \
    -s "https://server:port/openCypher/status?queryId=b9a516d1-d25c-4301-bb80-10b2743ecf0e"
  ```

  *レスポンス*:

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

# Amazon Neptune OpenCypher HTTPS エンドポイント
<a name="access-graph-opencypher-queries"></a>

**Topics**
+ [OpenCypher が HTTPS エンドポイントでクエリを読み書きする](#access-graph-opencypher-queries-read-write)
+ [デフォルトの OpenCypher JSON 結果フォーマット](#access-graph-opencypher-queries-results-simple-JSON)
+ [マルチパートの OpenCypher レスポンスのオプションの HTTP 末尾ヘッダー](#optional-http-trailing-headers)

**注記**  
Neptune は現在、REST API リクエストの HTTP/2 をサポートしていません。クライアントは、エンドポイントに接続するときに HTTP/1.1 を使用する必要があります。

## OpenCypher が HTTPS エンドポイントでクエリを読み書きする
<a name="access-graph-opencypher-queries-read-write"></a>

OpenCypher HTTPS エンドポイントは、`GET` と `POST` のメソッドの両方を使用してクエリを読み取って更新します。`DELETE` と `PUT` メソッドはサポートされていません。

次の手順では、`curl` コマンドおよび HTTPS を使用して OpenCypher エンドポイントに接続する方法について説明します。Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

構文は次のとおりです。

```
HTTPS://(the server):(the port number)/openCypher
```

以下に、読み取りクエリーのサンプルを示します。片方は `POST` を、もう一方は `GET` を使います。

1. `POST` を使用する:

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n1) RETURN n1;"
```

2. `GET` を使用する (クエリ文字列は URL に符号化されています)。

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n1)%20RETURN%20n1"
```

以下に、書き込み/更新クエリのサンプルを示します。片方は`POST` を、もう一方は `GET` を使います。

1. `POST` を使用する:

```
curl HTTPS://server:port/openCypher \
  -d "query=CREATE (n:Person { age: 25 })"
```

2. `GET` を使用する (クエリ文字列は URL に符号化されています)。

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=CREATE%20(n%3APerson%20%7B%20age%3A%2025%20%7D)"
```

## デフォルトの OpenCypher JSON 結果フォーマット
<a name="access-graph-opencypher-queries-results-simple-JSON"></a>

次の JSON 形式がデフォルトで返されます。または、リクエストヘッダーを明示的に `Accept: application/json` に設定することで返されます。このフォーマットは、ほとんどのライブラリのネイティブ言語機能を使用してオブジェクトに簡単に解析できるように設計されています。

返される JSON ドキュメントには、1 つのフィールドが含まれています。`results` には、クエリの戻り値が含まれています。以下の例は、一般的な値の JSON フォーマットを示しています。

**値のレスポンスの例:**

```
{
  "results": [
    {
      "count(a)": 121
    }
  ]
}
```

**ノードレスポンスの例:**

```
{
  "results": [
    {
      "a": {
        "~id": "22",
        "~entityType": "node",
        "~labels": [
          "airport"
        ],
        "~properties": {
          "desc": "Seattle-Tacoma",
          "lon": -122.30899810791,
          "runways": 3,
          "type": "airport",
          "country": "US",
          "region": "US-WA",
          "lat": 47.4490013122559,
          "elev": 432,
          "city": "Seattle",
          "icao": "KSEA",
          "code": "SEA",
          "longest": 11901
        }
      }
    }
  ]
}
```

**リレーションシップレスポンスの例:**

```
{
  "results": [
    {
      "r": {
        "~id": "7389",
        "~entityType": "relationship",
        "~start": "22",
        "~end": "151",
        "~type": "route",
        "~properties": {
          "dist": 956
        }
      }
    }
  ]
}
```

**パスレスポンスの例:**

```
{
  "results": [
    {
      "p": [
        {
          "~id": "22",
          "~entityType": "node",
          "~labels": [
            "airport"
          ],
          "~properties": {
            "desc": "Seattle-Tacoma",
            "lon": -122.30899810791,
            "runways": 3,
            "type": "airport",
            "country": "US",
            "region": "US-WA",
            "lat": 47.4490013122559,
            "elev": 432,
            "city": "Seattle",
            "icao": "KSEA",
            "code": "SEA",
            "longest": 11901
          }
        },
        {
          "~id": "7389",
          "~entityType": "relationship",
          "~start": "22",
          "~end": "151",
          "~type": "route",
          "~properties": {
            "dist": 956
          }
        },
        {
          "~id": "151",
          "~entityType": "node",
          "~labels": [
            "airport"
          ],
          "~properties": {
            "desc": "Ontario International Airport",
            "lon": -117.600997924805,
            "runways": 2,
            "type": "airport",
            "country": "US",
            "region": "US-CA",
            "lat": 34.0559997558594,
            "elev": 944,
            "city": "Ontario",
            "icao": "KONT",
            "code": "ONT",
            "longest": 12198
          }
        }
      ]
    }
  ]
}
```

## マルチパートの OpenCypher レスポンスのオプションの HTTP 末尾ヘッダー
<a name="optional-http-trailing-headers"></a>

 この機能は、Neptune エンジンリリース [1.4.5.0](https://docs.aws.amazon.com/releases/release-1.4.5.0.xml) 以降で利用できます。

 OpenCypher クエリと更新に対する HTTP レスポンスは通常、複数のチャンクで返されます。初期レスポンスチャンクの送信後に障害が発生した場合 (HTTP ステータスコードが 200)、問題を診断するのは難しい可能性があります。デフォルトでは、「Neptune」はエラーメッセージをメッセージ本文に追加してこのような障害を報告します。エラーメッセージは、レスポンスのストリーミングの性質が原因で破損する可能性があります。

**末尾のヘッダーの使用**  
 エラーの検出と診断を向上させるには、転送エンコード (TE) トレーラーヘッダー (te: トレーラー) をリクエストに配置することで、末尾のヘッダーを有効にします。これを行うと、Neptune はレスポンスチャンクの末尾ヘッダー内に 2 つの新しいヘッダーフィールドを含めます。
+  `X-Neptune-Status` — 応答コードの後ろに短い名前が続きます。たとえば、成功した場合、末尾ヘッダーは次のようになります。`X-Neptune-Status: 200 OK`。失敗の場合、応答コードは、`X-Neptune-Status: 500 TimeLimitExceededException` といった Neptune エンジンのエラーコードとなる可能性があります。
+  `X-Neptune-Detail` — 成功したリクエストでは空です。エラーの場合は、JSON エラーメッセージが含まれます。HTTP ヘッダー値には ASCII 文字しか使用できないため、JSON 文字列は URL 符号化されます。エラーメッセージは、レスポンスメッセージ本文にも追加されます。

 詳細については、「[TE リクエストヘッダーに関する MDN ページ](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)」を参照してください。

**OpenCypher 末尾ヘッダーの使用例**  
 この例では、末尾のヘッダーが時間制限を超えるクエリの診断にどのように役立つかを示します。

```
curl --raw 'https://your-neptune-endpoint:port/openCypher' \
-H 'TE: trailers' \
-d 'query=MATCH(n) RETURN n.firstName'
 
 
Output:
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< trailer: X-Neptune-Status, X-Neptune-Detail
< content-type: application/json;charset=UTF-8
< 
< 
{
  "results": [{
      "n.firstName": "Hossein"
    }, {
      "n.firstName": "Jan"
    }, {
      "n.firstName": "Miguel"
    }, {
      "n.firstName": "Eric"
    }, 
{"detailedMessage":"Operation terminated (deadline exceeded)",
"code":"TimeLimitExceededException",
"requestId":"a7e9d2aa-fbb7-486e-8447-2ef2a8544080",
"message":"Operation terminated (deadline exceeded)"}
0
X-Neptune-Status: 500 TimeLimitExceededException
X-Neptune-Detail: %7B%22detailedMessage%22%3A%22Operation+terminated+%28deadline+exceeded%29%22%2C%22code%22%3A%22TimeLimitExceededException%22%2C%22requestId%22%3A%22a7e9d2aa-fbb7-486e-8447-2ef2a8544080%22%2C%22message%22%3A%22Operation+terminated+%28deadline+exceeded%29%22%7D
```

**レスポンスの内訳:**  
 前述の例は、末尾のヘッダーが設定されている OpenCypher レスポンスがクエリ障害の診断にどのように役立つかを示しています。ここでは、(1) ストリーミングの開始を示す 200 OK ステータスの初期ヘッダー、(2) 失敗前に正常にストリーミングされた部分的な (破損している) JSON 結果、(3) タイムアウトを示す追加エラーメッセージ、(4) 最終ステータス (500 TimeLimitExceededException) と詳細なエラー情報を含む末尾ヘッダーの 4 つの連続した部分を示します。

# AWS SDK を使用して openCypher クエリを実行する
<a name="access-graph-opencypher-sdk"></a>

 AWS SDK を使用すると、任意のプログラミング言語を使用して、Neptune グラフに対して openCypher クエリを実行できます。Neptune データ API SDK (サービス名 `neptunedata`) は、openCypher クエリを送信するための [ExecuteOpenCypherQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteOpenCypherQuery.html) openCypher アクションを提供します。

これらの例は、Neptune DB クラスターと同じ Virtual Private Cloud (VPC) の Amazon EC2 インスタンス、またはクラスターエンドポイントへのネットワーク接続がある場所から実行する必要があります。

各 SDK 言語の`neptunedata`サービスの API リファレンスドキュメントへの直接リンクは、以下にあります。


| プログラミング言語 | Neptunedata API リファレンス | 
| --- | --- | 
| C\$1\$1 | [https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html](https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html) | 
| Go | [https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/](https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/) | 
| Java | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html) | 
| JavaScript | [https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/) | 
| Kotlin | [https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html](https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html) | 
| .NET | [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html) | 
| PHP | [https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html](https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html) | 
| Python | [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html) | 
| Ruby | [https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html) | 
| Rust | [https://crates.io/crates/aws-sdk-neptunedata](https://crates.io/crates/aws-sdk-neptunedata) | 
| CLI | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

## openCypher AWS SDK の例
<a name="access-graph-opencypher-sdk-examples"></a>

次の例は、`neptunedata`クライアントをセットアップし、openCypher クエリを実行し、結果を出力する方法を示しています。*YOUR\$1NEPTUNE\$1HOST* と *YOUR\$1NEPTUNE\$1PORT* を Neptune DB クラスターのエンドポイントとポートに置き換えます。

**クライアント側のタイムアウトと再試行の設定**  
SDK クライアントのタイムアウトは、*クライアント*がレスポンスを待機する時間を制御します。クエリがサーバー上で実行される時間は制御されません。サーバーが終了する前にクライアントがタイムアウトした場合、クライアントが結果を取得する方法がない間、クエリは Neptune で実行し続ける可能性があります。  
クライアント側の読み取りタイムアウトを `0` (タイムアウトなし) に設定するか、Neptune DB クラスターのサーバー側の [neptune\$1query\$1timeout](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) 設定よりも少なくとも数秒長い値に設定することをお勧めします。これにより、Neptune はクエリのタイムアウトを制御できます。  
また、最大再試行回数を設定することをお勧めします `1` (再試行なし）。SDK がサーバーでまだ実行されているクエリを再試行すると、オペレーションが重複する可能性があります。これは、再試行によって意図しない重複書き込みが発生する可能性があるミューテーションクエリでは特に重要です。

------
#### [ Python ]

1. Boto3 をインストールするには、[インストール手順に従い](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)ます。

1. という名前のファイルを作成し`openCypherExample.py`、次のコードを貼り付けます。

   ```
   import boto3
   import json
   from botocore.config import Config
   
   # Disable the client-side read timeout and retries so that
   # Neptune's server-side neptune_query_timeout controls query duration.
   client = boto3.client(
       'neptunedata',
       endpoint_url=f'https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT',
       config=Config(read_timeout=None, retries={'total_max_attempts': 1})
   )
   
   response = client.execute_open_cypher_query(
       openCypherQuery='MATCH (n) RETURN n LIMIT 1'
   )
   
   print(json.dumps(response['results'], indent=2))
   ```

1. 例を実行します。 `python openCypherExample.py`

------
#### [ Java ]

1. [インストール手順に従って](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) AWS SDK for Java をセットアップします。

1. 次のコードを使用して をセットアップし`NeptunedataClient`、openCypher クエリを実行して結果を出力します。

   ```
   import java.net.URI;
   import java.time.Duration;
   import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
   import software.amazon.awssdk.core.retry.RetryPolicy;
   import software.amazon.awssdk.services.neptunedata.NeptunedataClient;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteOpenCypherQueryRequest;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteOpenCypherQueryResponse;
   
   // Disable the client-side timeout and retries so that
   // Neptune's server-side neptune_query_timeout controls query duration.
   NeptunedataClient client = NeptunedataClient.builder()
       .endpointOverride(URI.create("https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT"))
       .overrideConfiguration(ClientOverrideConfiguration.builder()
           .apiCallTimeout(Duration.ZERO)
           .retryPolicy(RetryPolicy.none())
           .build())
       .build();
   
   ExecuteOpenCypherQueryRequest request = ExecuteOpenCypherQueryRequest.builder()
       .openCypherQuery("MATCH (n) RETURN n LIMIT 1")
       .build();
   
   ExecuteOpenCypherQueryResponse response = client.executeOpenCypherQuery(request);
   
   System.out.println(response.results().toString());
   ```

------
#### [ JavaScript ]

1. [インストール手順に従って](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) AWS SDK for JavaScript をセットアップします。neptunedata クライアントパッケージをインストールします: `npm install @aws-sdk/client-neptunedata`。

1. という名前のファイルを作成し`openCypherExample.js`、次のコードを貼り付けます。

   ```
   import { NeptunedataClient, ExecuteOpenCypherQueryCommand } from "@aws-sdk/client-neptunedata";
   import { NodeHttpHandler } from "@smithy/node-http-handler";
   
   const config = {
       endpoint: "https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT",
       // Disable the client-side request timeout so that
       // Neptune's server-side neptune_query_timeout controls query duration.
       requestHandler: new NodeHttpHandler({
           requestTimeout: 0
       }),
       maxAttempts: 1
   };
   
   const client = new NeptunedataClient(config);
   
   const input = {
       openCypherQuery: "MATCH (n) RETURN n LIMIT 1"
   };
   
   const command = new ExecuteOpenCypherQueryCommand(input);
   const response = await client.send(command);
   
   console.log(JSON.stringify(response, null, 2));
   ```

1. 例を実行します。 `node openCypherExample.js`

------

# Bolt プロトコルを使用して openCypher クエリを Neptune に作成する
<a name="access-graph-opencypher-bolt"></a>

[Bolt](https://boltprotocol.org/) は、当初は Neo4j に開発された、Creative Commons 3.0 [Attribution-ShareAlike](https://creativecommons.org/licenses/by-sa/3.0/) ライセンスの下で使用権利を得たステートメント指向のクライアント/サーバープロトコルです。これは、クライアント駆動型です。つまり、クライアントは常にメッセージ交換を開始します。

Neo4j の Bolt ドライバを使用して Neptune に接続するには、URL とポート番号を `bolt` URI スキームを使ってクラスターエンドポイントに置き換えるだけです。1 つの Neptune インスタンスが実行されている場合は、read\$1write エンドポイントを使用します。複数のインスタンスが実行されている場合は、ライター用とすべてのリードレプリカ用に 2 つのドライバを推奨します。デフォルトの 2 つのエンドポイントしかない場合は、read\$1write と read\$1only ドライバで十分ですが、カスタムエンドポイントがある場合は、それぞれにドライバインスタンスを作成することを検討してください。

**注記**  
Bolt の仕様では、Bolt は TCP または WebSockets を使用して接続できると記載されていますが、Neptune は Bolt について TCP 接続のみをサポートしています。

Neptune は、t3.medium と t4g.medium を除くすべてのインスタンスサイズで最大 1,000 件の同時 Bolt 接続を許可します。t3.medium および t4g.medium インスタンスでは、512 接続のみが許可されます。

Bolt ドライバを使用するさまざまな言語の openCypher クエリの例については、Neo4j [ドライバ & 言語ガイド](https://neo4j.com/developer/language-guides/)ドキュメントを参照してください。

**重要**  
Python、.NET、JavaScript、および Golang 用の Neo4j Bolt ドライバーは、当初 Signature v4 AWS 認証トークンの自動更新をサポートしていませんでした。つまり、署名の有効期限が切れると (多くの場合 5 分後)、ドライバーは認証に失敗し、それ以降のリクエストも失敗しました。以下の Python、.NET、JavaScript、および Go のサンプルはすべて、この問題の影響を受けました。  
詳細については、「[Neo4j Python ドライバーの問題 \$1834](https://github.com/neo4j/neo4j-python-driver/issues/834)」、「[Neo4j .NET の問題 \$1664](https://github.com/neo4j/neo4j-dotnet-driver/issues/664)」、「[Neo4j JavaScript ドライバーの問題 \$1993](https://github.com/neo4j/neo4j-javascript-driver/issues/993)」、および「[Neo4j goLang ドライバーの問題 \$1429](https://github.com/neo4j/neo4j-go-driver/issues/429)」を参照してください。  
ドライバーバージョン 5.8.0 以降、Go ドライバー用の新しいプレビュー再認証 API がリリースされました (「[v5.8.0 - 再認証に関するフィードバック募集](https://github.com/neo4j/neo4j-go-driver/discussions/482)」を参照)。

## Bolt と Java を使用して Neptune に接続するには
<a name="access-graph-opencypher-bolt-java"></a>

Maven から使用する任意のバージョンのドライバをダウンロードできます。[MVN リポジトリ](https://mvnrepository.com/artifact/org.neo4j.driver/neo4j-java-driver)または、この依存関係をプロジェクトに追加できます。

```
<dependency>
  <groupId>org.neo4j.driver</groupId>
  <artifactId>neo4j-java-driver</artifactId>
  <version>4.3.3</version>
</dependency>
```

次に、これらの Bolt ドライバの 1 つを使用して Java で Neptune に接続するには、次のようなコードを使用して、クラスター内のプライマリ/ライターインスタンスのドライバインスタンスを作成します。

```
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;

final Driver driver =
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
    AuthTokens.none(),
    Config.builder().withEncryption()
                    .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                    .build());
```

1 つ以上のリーダーレプリカがある場合は、同様に、次のようなコードを使用して、それらのドライバインスタンスを作成できます。

```
final Driver read_only_driver =              // (without connection timeout)
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
      Config.builder().withEncryption()
                      .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                      .build());
```

または、タイムアウトを設定して:

```
final Driver read_only_timeout_driver =      // (with connection timeout)
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
    Config.builder().withConnectionTimeout(30, TimeUnit.SECONDS)
                    .withEncryption()
                    .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                    .build());
```

カスタムエンドポイントがある場合は、各エンドポイントにドライバインスタンスを作成することをお勧めします。

## Bolt を使用した Python openCypher クエリの例
<a name="access-graph-opencypher-bolt-python"></a>

以下は、Bolt を使用して Python で Python openCypher クエリを作成する方法です。

```
python -m pip install neo4j
```

```
from neo4j import GraphDatabase
uri = "bolt://(your cluster endpoint URL):(your cluster port)"
driver = GraphDatabase.driver(uri, auth=("username", "password"), encrypted=True)
```

`auth` パラメータは無視される点に注意してください。

## Bolt を使用した .NET openCypher クエリの例
<a name="access-graph-opencypher-bolt-dotnet"></a>

Bolt を使用して .NET で openCypher クエリを実行するには、まず NuHet を使用して Neo4j ドライバーをインストールします。同期呼び出しを行うには、次のように `.Simple` バージョンを使用します。

```
Install-Package Neo4j.Driver.Simple-4.3.0
```

```
using Neo4j.Driver;

namespace hello
{
  // This example creates a node and reads a node in a Neptune
  // Cluster where IAM Authentication is not enabled.
  public class HelloWorldExample : IDisposable
  {
    private bool _disposed = false;
    private readonly IDriver _driver;
    private static string url = "bolt://(your cluster endpoint URL):(your cluster port)";
    private static string createNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'";
    private static string readNodeQuery = "MATCH(n:Greeting) RETURN n.message";

    ~HelloWorldExample() => Dispose(false);

    public HelloWorldExample(string uri)
    {
      _driver = GraphDatabase.Driver(uri, AuthTokens.None, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted));
    }

    public void createNode()
    {
      // Open a session
      using (var session = _driver.Session())
      {
         // Run the query in a write transaction
        var greeting = session.WriteTransaction(tx =>
        {
          var result = tx.Run(createNodeQuery);
          // Consume the result
          return result.Consume();
        });

        // The output will look like this:
        //   ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample".....
        Console.WriteLine(greeting);
      }
    }

    public void retrieveNode()
    {
      // Open a session
      using (var session = _driver.Session())
      {
        // Run the query in a read transaction
        var greeting = session.ReadTransaction(tx =>
        {
          var result = tx.Run(readNodeQuery);
          // Consume the result. Read the single node
          // created in a previous step.
          return result.Single()[0].As<string>();
        });
        // The output will look like this:
        //   HelloWorldExample
        Console.WriteLine(greeting);
      }
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (_disposed)
        return;
      if (disposing)
      {
        _driver?.Dispose();
      }
      _disposed = true;
    }

    public static void Main()
    {
      using (var apiCaller = new HelloWorldExample(url))
      {
        apiCaller.createNode();
        apiCaller.retrieveNode();
      }
    }
  }
}
```

## Bolt と IAM 認証を使用した Java openCypher クエリの例
<a name="access-graph-opencypher-bolt-java-iam-auth"></a>

以下の Java コードは、IAM 認証で Bolt を使用して Java で openCypher クエリを作成する方法を示しています。JavaDoc コメントには、その使用方法が説明されています。ドライバーインスタンスが使用可能になると、そのインスタンスを使用して複数の認証リクエストを行うことができます。

```
package software.amazon.neptune.bolt;

import com.amazonaws.DefaultRequest;
import com.amazonaws.Request;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.http.HttpMethodName;
import com.google.gson.Gson;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import org.neo4j.driver.Value;
import org.neo4j.driver.Values;
import org.neo4j.driver.internal.security.InternalAuthToken;
import org.neo4j.driver.internal.value.StringValue;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static com.amazonaws.auth.internal.SignerConstants.AUTHORIZATION;
import static com.amazonaws.auth.internal.SignerConstants.HOST;
import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_DATE;
import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_SECURITY_TOKEN;

/**
 * Use this class instead of `AuthTokens.basic` when working with an IAM
 * auth-enabled server. It works the same as `AuthTokens.basic` when using
 * static credentials, and avoids making requests with an expired signature
 * when using temporary credentials. Internally, it generates a new signature
 * on every invocation (this may change in a future implementation).
 *
 * Note that authentication happens only the first time for a pooled connection.
 *
 * Typical usage:
 *
 * NeptuneAuthToken authToken = NeptuneAuthToken.builder()
 *     .credentialsProvider(credentialsProvider)
 *     .region("aws region")
 *     .url("cluster endpoint url")
 *     .build();
 *
 * Driver driver = GraphDatabase.driver(
 *     authToken.getUrl(),
 *     authToken,
 *     config
 * );
 */

public class NeptuneAuthToken extends InternalAuthToken {
  private static final String SCHEME = "basic";
  private static final String REALM = "realm";
  private static final String SERVICE_NAME = "neptune-db";
  private static final String HTTP_METHOD_HDR = "HttpMethod";
  private static final String DUMMY_USERNAME = "username";
  @NonNull
  private final String region;
  @NonNull
  @Getter
  private final String url;
  @NonNull
  private final AWSCredentialsProvider credentialsProvider;
  private final Gson gson = new Gson();

  @Builder
  private NeptuneAuthToken(
      @NonNull final String region,
      @NonNull final String url,
      @NonNull final AWSCredentialsProvider credentialsProvider
  ) {
      // The superclass caches the result of toMap(), which we don't want
      super(Collections.emptyMap());
      this.region = region;
      this.url = url;
      this.credentialsProvider = credentialsProvider;
  }

  @Override
  public Map<String, Value> toMap() {
    final Map<String, Value> map = new HashMap<>();
    map.put(SCHEME_KEY, Values.value(SCHEME));
    map.put(PRINCIPAL_KEY, Values.value(DUMMY_USERNAME));
    map.put(CREDENTIALS_KEY, new StringValue(getSignedHeader()));
    map.put(REALM_KEY, Values.value(REALM));

    return map;
  }

  private String getSignedHeader() {
    final Request<Void> request = new DefaultRequest<>(SERVICE_NAME);
    request.setHttpMethod(HttpMethodName.GET);
    request.setEndpoint(URI.create(url));
    // Comment out the following line if you're using an engine version older than 1.2.0.0
    request.setResourcePath("/opencypher");

    final AWS4Signer signer = new AWS4Signer();
    signer.setRegionName(region);
    signer.setServiceName(request.getServiceName());
    signer.sign(request, credentialsProvider.getCredentials());

    return getAuthInfoJson(request);
  }

  private String getAuthInfoJson(final Request<Void> request) {
    final Map<String, Object> obj = new HashMap<>();
    obj.put(AUTHORIZATION, request.getHeaders().get(AUTHORIZATION));
    obj.put(HTTP_METHOD_HDR, request.getHttpMethod());
    obj.put(X_AMZ_DATE, request.getHeaders().get(X_AMZ_DATE));
    obj.put(HOST, request.getHeaders().get(HOST));
    obj.put(X_AMZ_SECURITY_TOKEN, request.getHeaders().get(X_AMZ_SECURITY_TOKEN));

    return gson.toJson(obj);
  }
}
```

## Bolt と IAM 認証を使用した Python openCypher クエリの例
<a name="access-graph-opencypher-bolt-python-iam-auth"></a>

以下の Python クラスを使用すると、IAM 認証付きの Bolt を使用して Python で openCypher クエリを作成できます。

```
import json

from neo4j import Auth
from botocore.awsrequest import AWSRequest
from botocore.credentials import Credentials
from botocore.auth import (
  SigV4Auth,
  _host_from_url,
)

SCHEME = "basic"
REALM = "realm"
SERVICE_NAME = "neptune-db"
DUMMY_USERNAME = "username"
HTTP_METHOD_HDR = "HttpMethod"
HTTP_METHOD = "GET"
AUTHORIZATION = "Authorization"
X_AMZ_DATE = "X-Amz-Date"
X_AMZ_SECURITY_TOKEN = "X-Amz-Security-Token"
HOST = "Host"


class NeptuneAuthToken(Auth):
  def __init__(
    self,
    credentials: Credentials,
    region: str,
    url: str,
    **parameters
  ):
    # Do NOT add "/opencypher" in the line below if you're using an engine version older than 1.2.0.0
    request = AWSRequest(method=HTTP_METHOD, url=url + "/opencypher")
    request.headers.add_header("Host", _host_from_url(request.url))
    sigv4 = SigV4Auth(credentials, SERVICE_NAME, region)
    sigv4.add_auth(request)

    auth_obj = {
      hdr: request.headers[hdr]
      for hdr in [AUTHORIZATION, X_AMZ_DATE, X_AMZ_SECURITY_TOKEN, HOST]
    }
    auth_obj[HTTP_METHOD_HDR] = request.method
    creds: str = json.dumps(auth_obj)
    super().__init__(SCHEME, DUMMY_USERNAME, creds, REALM, **parameters)
```

このクラスを使用してドライバーを次のように作成します。

```
  authToken = NeptuneAuthToken(creds, REGION, URL)
  driver = GraphDatabase.driver(URL, auth=authToken, encrypted=True)
```

## IAM 認証と Bolt を使用した Node.js の例
<a name="access-graph-opencypher-bolt-nodejs-iam-auth"></a>

以下の Node.js コードは、 AWS SDK for JavaScript バージョン 3 および ES6 構文を使用して、リクエストを認証するドライバーを作成します。

```
import neo4j from "neo4j-driver";
import { HttpRequest }  from "@smithy/protocol-http";
import { defaultProvider } from "@aws-sdk/credential-provider-node";
import { SignatureV4 } from "@smithy/signature-v4";
import crypto from "@aws-crypto/sha256-js";
const { Sha256 } = crypto;
import assert from "node:assert";

const region = "us-west-2";
const serviceName = "neptune-db";
const host = "(your cluster endpoint URL)";
const port = 8182;
const protocol = "bolt";
const hostPort = host + ":" + port;
const url = protocol + "://" + hostPort;
const createQuery = "CREATE (n:Greeting {message: 'Hello'}) RETURN ID(n)";
const readQuery = "MATCH(n:Greeting) WHERE ID(n) = $id RETURN n.message";

async function signedHeader() {
  const req = new HttpRequest({
    method: "GET",
    protocol: protocol,
    hostname: host,
    port: port,
    // Comment out the following line if you're using an engine version older than 1.2.0.0
    path: "/opencypher",
    headers: {
      host: hostPort
    }
  });

  const signer = new SignatureV4({
    credentials: defaultProvider(),
    region: region,
    service: serviceName,
    sha256: Sha256
  });

  return signer.sign(req, { unsignableHeaders: new Set(["x-amz-content-sha256"]) })
    .then((signedRequest) => {
      const authInfo = {
        "Authorization": signedRequest.headers["authorization"],
        "HttpMethod": signedRequest.method,
        "X-Amz-Date": signedRequest.headers["x-amz-date"],
        "Host": signedRequest.headers["host"],
        "X-Amz-Security-Token": signedRequest.headers["x-amz-security-token"]
      };
      return JSON.stringify(authInfo);
    });
}

async function createDriver() {
  let authToken = { scheme: "basic", realm: "realm", principal: "username", credentials: await signedHeader() };

  return neo4j.driver(url, authToken, {
      encrypted: "ENCRYPTION_ON",
      trust: "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES",
      maxConnectionPoolSize: 1,
      // logging: neo4j.logging.console("debug")
    }
  );
}

async function unmanagedTxn(driver) {
  const session = driver.session();
  const tx = session.beginTransaction();
  try {
    const created = await tx.run(createQuery);
    const matched = await tx.run(readQuery, { id: created.records[0].get(0) });
    const msg = matched.records[0].get("n.message");
    assert.equal(msg, "Hello");
    await tx.commit();
  } catch (err) {
    // The transaction will be rolled back, now handle the error.
    console.log(err);
  } finally {
    await session.close();
  }
}

const driver = await createDriver();
try {
  await unmanagedTxn(driver);
} catch (err) {
  console.log(err);
} finally {
  await driver.close();
}
```

## Bolt と IAM 認証を使用した .NET openCypher クエリの例
<a name="access-graph-opencypher-bolt-dotnet-iam-auth"></a>

.NET で IAM 認証を有効にするには、接続を確立するときにリクエストに署名する必要があります。以下の例は、認証トークンを生成する `NeptuneAuthToken` ヘルパーを作成する方法を示しています。

```
using Amazon.Runtime;
using Amazon.Util;
using Neo4j.Driver;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Web;

namespace Hello
{
  /*
   * Use this class instead of `AuthTokens.None` when working with an IAM-auth-enabled server.
   *
   * Note that authentication happens only the first time for a pooled connection.
   *
   * Typical usage:
   *
   * var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host);
   * _driver = GraphDatabase.Driver(Url, authToken, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted));
   */

  public class NeptuneAuthToken
  {
    private const string ServiceName = "neptune-db";
    private const string Scheme = "basic";
    private const string Realm = "realm";
    private const string DummyUserName = "username";
    private const string Algorithm = "AWS4-HMAC-SHA256";
    private const string AWSRequest = "aws4_request";

    private readonly string _accessKey;
    private readonly string _secretKey;
    private readonly string _region;

    private readonly string _emptyPayloadHash;

    private readonly SHA256 _sha256;


    public NeptuneAuthToken(string awsKey = null, string secretKey = null, string region = null)
    {
      var awsCredentials = awsKey == null || secretKey == null
        ? FallbackCredentialsFactory.GetCredentials().GetCredentials()
        : null;

      _accessKey = awsKey ?? awsCredentials.AccessKey;
      _secretKey = secretKey ?? awsCredentials.SecretKey;
      _region = region ?? FallbackRegionFactory.GetRegionEndpoint().SystemName; //ex: us-east-1

      _sha256 = SHA256.Create();
      _emptyPayloadHash = Hash(Array.Empty<byte>());
    }

    public IAuthToken GetAuthToken(string url)
    {
      return AuthTokens.Custom(DummyUserName, GetCredentials(url), Realm, Scheme);
    }

    /******************** AWS SIGNING FUNCTIONS *********************/
    private string Hash(byte[] bytesToHash)
    {
      return ToHexString(_sha256.ComputeHash(bytesToHash));
    }

    private static byte[] HmacSHA256(byte[] key, string data)
    {
      return new HMACSHA256(key).ComputeHash(Encoding.UTF8.GetBytes(data));
    }

    private byte[] GetSignatureKey(string dateStamp)
    {
      var kSecret = Encoding.UTF8.GetBytes($"AWS4{_secretKey}");
      var kDate = HmacSHA256(kSecret, dateStamp);
      var kRegion = HmacSHA256(kDate, _region);
      var kService = HmacSHA256(kRegion, ServiceName);
      return HmacSHA256(kService, AWSRequest);
    }

    private static string ToHexString(byte[] array)
    {
      return Convert.ToHexString(array).ToLowerInvariant();
    }

    private string GetCredentials(string url)
    {
      var request = new HttpRequestMessage
      {
        Method = HttpMethod.Get,
        RequestUri = new Uri($"https://{url}/opencypher")
      };

      var signedrequest = Sign(request);

      var headers = new Dictionary<string, object>
      {
        [HeaderKeys.AuthorizationHeader] = signedrequest.Headers.GetValues(HeaderKeys.AuthorizationHeader).FirstOrDefault(),
        ["HttpMethod"] = HttpMethod.Get.ToString(),
        [HeaderKeys.XAmzDateHeader] = signedrequest.Headers.GetValues(HeaderKeys.XAmzDateHeader).FirstOrDefault(),
        // Host should be capitalized, not like in Amazon.Util.HeaderKeys.HostHeader
        ["Host"] = signedrequest.Headers.GetValues(HeaderKeys.HostHeader).FirstOrDefault(),
      };

      return JsonSerializer.Serialize(headers);
    }

    private HttpRequestMessage Sign(HttpRequestMessage request)
    {
      var now = DateTimeOffset.UtcNow;
      var amzdate = now.ToString("yyyyMMddTHHmmssZ");
      var datestamp = now.ToString("yyyyMMdd");

      if (request.Headers.Host == null)
      {
        request.Headers.Host = $"{request.RequestUri.Host}:{request.RequestUri.Port}";
      }

      request.Headers.Add(HeaderKeys.XAmzDateHeader, amzdate);

      var canonicalQueryParams = GetCanonicalQueryParams(request);

      var canonicalRequest = new StringBuilder();
      canonicalRequest.Append(request.Method + "\n");
      canonicalRequest.Append(request.RequestUri.AbsolutePath + "\n");
      canonicalRequest.Append(canonicalQueryParams + "\n");

      var signedHeadersList = new List<string>();
      foreach (var header in request.Headers.OrderBy(a => a.Key.ToLowerInvariant()))
      {
        canonicalRequest.Append(header.Key.ToLowerInvariant());
        canonicalRequest.Append(':');
        canonicalRequest.Append(string.Join(",", header.Value.Select(s => s.Trim())));
        canonicalRequest.Append('\n');
        signedHeadersList.Add(header.Key.ToLowerInvariant());
      }
      canonicalRequest.Append('\n');

      var signedHeaders = string.Join(";", signedHeadersList);
      canonicalRequest.Append(signedHeaders + "\n");
      canonicalRequest.Append(_emptyPayloadHash);

      var credentialScope = $"{datestamp}/{_region}/{ServiceName}/{AWSRequest}";
      var stringToSign = $"{Algorithm}\n{amzdate}\n{credentialScope}\n"
        + Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString()));

      var signing_key = GetSignatureKey(datestamp);
      var signature = ToHexString(HmacSHA256(signing_key, stringToSign));

      request.Headers.TryAddWithoutValidation(HeaderKeys.AuthorizationHeader,
        $"{Algorithm} Credential={_accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}");

      return request;
    }

    private static string GetCanonicalQueryParams(HttpRequestMessage request)
    {
      var querystring = HttpUtility.ParseQueryString(request.RequestUri.Query);

      // Query params must be escaped in upper case (i.e. "%2C", not "%2c").
      var queryParams = querystring.AllKeys.OrderBy(a => a)
        .Select(key => $"{key}={Uri.EscapeDataString(querystring[key])}");
      return string.Join("&", queryParams);
    }
  }
}
```

以下は、.NET で Bolt と IAM 認証を使用して openCypher クエリを作成する方法です。次の例では、`NeptuneAuthToken` ヘルパーを使用しています。

```
using Neo4j.Driver;

namespace Hello
{
  public class HelloWorldExample
  {
    private const string Host = "(your hostname):8182";
    private const string Url = $"bolt://{Host}";
    private const string CreateNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'";
    private const string ReadNodeQuery = "MATCH(n:Greeting) RETURN n.message";

    private const string AccessKey = "(your access key)";
    private const string SecretKey = "(your secret key)";
    private const string Region = "(your AWS region)"; // e.g. "us-west-2"

    private readonly IDriver _driver;

    public HelloWorldExample()
    {
      var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host);

      // Note that when the connection is reinitialized after max connection lifetime
      // has been reached, the signature token could have already been expired (usually 5 min)
      // You can face exceptions like:
      //   `Unexpected server exception 'Signature expired: XXXX is now earlier than YYYY (ZZZZ - 5 min.)`
      _driver = GraphDatabase.Driver(Url, authToken, o =>
                o.WithMaxConnectionLifetime(TimeSpan.FromMinutes(60)).WithEncryptionLevel(EncryptionLevel.Encrypted));
    }

    public async Task CreateNode()
    {
      // Open a session
      using (var session = _driver.AsyncSession())
      {
        // Run the query in a write transaction
        var greeting = await session.WriteTransactionAsync(async tx =>
        {
          var result = await tx.RunAsync(CreateNodeQuery);
          // Consume the result
          return await result.ConsumeAsync();
        });

        // The output will look like this:
        //   ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample".....
        Console.WriteLine(greeting.Query);
      }
    }

    public async Task RetrieveNode()
    {
      // Open a session
      using (var session = _driver.AsyncSession())
      {
        // Run the query in a read transaction
        var greeting = await session.ReadTransactionAsync(async tx =>
        {
          var result = await tx.RunAsync(ReadNodeQuery);
          var records = await result.ToListAsync();

          // Consume the result. Read the single node
          // created in a previous step.
          return records[0].Values.First().Value;
        });
        // The output will look like this:
        //   HelloWorldExample
        Console.WriteLine(greeting);
      }
    }
  }
}
```

この例は、以下のコードを以下のパッケージで `.NET 6` または `.NET 7` に対して実行することで起動できます。
+ **`Neo4j`**`.Driver=4.3.0`
+ **`AWSSDK`**`.Core=3.7.102.1`

```
namespace Hello
{
  class Program
  {
    static async Task Main()
    {
      var apiCaller = new HelloWorldExample();

      await apiCaller.CreateNode();
      await apiCaller.RetrieveNode();
    }
  }
}
```

## Bolt と IAM 認証を使用した Golang openCypher クエリの例
<a name="access-graph-opencypher-bolt-golang-iam-auth"></a>

以下の Golang パッケージは、Bolt と IAM 認証を使用して Go 言語で openCypher クエリを作成する方法を示しています。

```
package main

import (
  "context"
  "encoding/json"
  "fmt"
  "github.com/aws/aws-sdk-go/aws/credentials"
  "github.com/aws/aws-sdk-go/aws/signer/v4"
  "github.com/neo4j/neo4j-go-driver/v5/neo4j"
  "log"
  "net/http"
  "os"
  "time"
)

const (
  ServiceName   = "neptune-db"
  DummyUsername = "username"
)

// Find node by id using Go driver
func findNode(ctx context.Context, region string, hostAndPort string, nodeId string) (string, error) {
  req, err := http.NewRequest(http.MethodGet, "https://"+hostAndPort+"/opencypher", nil)

  if err != nil {
    return "", fmt.Errorf("error creating request, %v", err)
  }

  // credentials must have been exported as environment variables
  signer := v4.NewSigner(credentials.NewEnvCredentials())
  _, err = signer.Sign(req, nil, ServiceName, region, time.Now())

  if err != nil {
    return "", fmt.Errorf("error signing request: %v", err)
  }

  hdrs := []string{"Authorization", "X-Amz-Date", "X-Amz-Security-Token"}
  hdrMap := make(map[string]string)
  for _, h := range hdrs {
    hdrMap[h] = req.Header.Get(h)
  }

  hdrMap["Host"] = req.Host
  hdrMap["HttpMethod"] = req.Method

  password, err := json.Marshal(hdrMap)
  if err != nil {
    return "", fmt.Errorf("error creating JSON, %v", err)
  }
  authToken := neo4j.BasicAuth(DummyUsername, string(password), "")
  // +s enables encryption with a full certificate check
  // Use +ssc to disable client side TLS verification
  driver, err := neo4j.NewDriverWithContext("bolt+s://"+hostAndPort+"/opencypher", authToken)
  if err != nil {
    return "", fmt.Errorf("error creating driver, %v", err)
  }

  defer driver.Close(ctx)

  if err := driver.VerifyConnectivity(ctx); err != nil {
    log.Fatalf("failed to verify connection, %v", err)
  }

  config := neo4j.SessionConfig{}

  session := driver.NewSession(ctx, config)
  defer session.Close(ctx)

  result, err := session.Run(
    ctx,
    fmt.Sprintf("MATCH (n) WHERE ID(n) = '%s' RETURN n", nodeId),
    map[string]any{},
  )
  if err != nil {
    return "", fmt.Errorf("error running query, %v", err)
  }

  if !result.Next(ctx) {
    return "", fmt.Errorf("node not found")
  }

  n, found := result.Record().Get("n")
  if !found {
    return "", fmt.Errorf("node not found")
  }

  return fmt.Sprintf("+%v\n", n), nil
}

func main() {
  if len(os.Args) < 3 {
    log.Fatal("Usage: go main.go (region) (host and port)")
  }
  region := os.Args[1]
  hostAndPort := os.Args[2]
  ctx := context.Background()

  res, err := findNode(ctx, region, hostAndPort, "72c2e8c1-7d5f-5f30-10ca-9d2bb8c4afbc")
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(res)
}
```

## Neptune での Bolt 接続動作
<a name="access-graph-opencypher-bolt-connections"></a>

Neptune Bolt 接続に関する注意事項をいくつか次に示します。
+ Bolt 接続は TCP レイヤーで作成されるため、HTTP エンドポイントでできるように、それらの前では[Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html)は使えません。
+ Neptune が Bolt 接続に使用するポートは、DB クラスターのポートです。
+ 渡された Bolt プリアンブルに基づいて、Neptune サーバーは最適な Bolt バージョン (1、2、3、または 4.0) を選択します。
+ クライアントが任意の時点でオープンできる Neptune サーバーへの最大接続数は 1,000 です。
+ クエリの後にクライアントが接続を閉じない場合、その結合を使用して次のクエリを実行できます。
+ ただし、接続が 20 分間アイドル状態になると、サーバーは自動的に閉じます。
+ IAM 認証が有効になっていない場合は、ダミーのユーザー名とパスワードを入力する代わりに `AuthTokens.none()` を使用できます。例えば、Java では次のようになります。

  ```
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(),
      Config.builder().withEncryption().withTrustStrategy(TrustStrategy.trustSystemCertificates()).build());
  ```
+ IAM 認証が有効になっている場合、Bolt 接続は確立されてから 10 日経過すると、他の理由で Bolt 接続がまだ閉じられていない場合、常に数分で切断されます。
+ クライアントが前のクエリの結果を消費せずに、接続を介して実行用のクエリを送信すると、新しいクエリは破棄されます。代わりに以前の結果を破棄するには、クライアントは接続を介してリセットメッセージを送信する必要があります。
+ 特定の接続では、一度に作成できるトランザクションは 1 つだけです。
+ トランザクション中に例外が発生すると、Neptune サーバーはトランザクションをロールバックし、接続を閉じます。この場合、ドライバーは次のクエリ用に新しい接続を作成します。
+ セッションはスレッドセーフではないことに注意してください。複数の並列操作では、複数の別々のセッションを使用する必要があります。

# openCypher のパラメーター化されたクエリの例
<a name="opencypher-parameterized-queries"></a>

Neptune はパラメーター化された openCypher クエリをサポートしています。これにより、同じクエリ構造を異なる引数で複数回使用できます。クエリ構造は変更されないため、Neptune は抽象構文ツリー (AST) を何度も解析しなくてもキャッシュできます。

## HTTPS エンドポイントを使用する openCypher パラメーター化されたクエリの例
<a name="opencypher-http-parameterized-queries"></a>

以下は、Neptune openCypher HTTPS エンドポイントでパラメーター化されたクエリを使用する例です。クエリ は、次のとおりです。

```
MATCH (n {name: $name, age: $age})
RETURN n
```

パラメータの定義は次のとおりです。

```
parameters={"name": "john", "age": 20}
```

`GET` を使用すると、次のようなパラメータ化されたクエリを送信できます。

```
curl -k \
  "https://localhost:8182/openCypher?query=MATCH%20%28n%20%7Bname:\$name,age:\$age%7D%29%20RETURN%20n&parameters=%7B%22name%22:%22john%22,%22age%22:20%7D"
```

または、`POST` を使用することもできます。

```
curl -k \
  https://localhost:8182/openCypher \
  -d "query=MATCH (n {name: \$name, age: \$age}) RETURN n" \
  -d "parameters={\"name\": \"john\", \"age\": 20}"
```

または、`DIRECT POST` を使用します。

```
curl -k \
   -H "Content-Type: application/opencypher" \
  "https://localhost:8182/openCypher?parameters=%7B%22name%22:%22john%22,%22age%22:20%7D" \
  -d "MATCH (n {name: \$name, age: \$age}) RETURN n"
```

## Bolt を使った openCypher のパラメーター化されたクエリの例
<a name="opencypher-bolt-parameterized-queries"></a>

以下は、Bolt プロトコルを使用した openCypher パラメーター化されたクエリの Python の例です。

```
from neo4j import GraphDatabase
uri = "bolt://[neptune-endpoint-url]:8182"
driver = GraphDatabase.driver(uri, auth=("", ""))

def match_name_and_age(tx, name, age):
  # Parameterized Query
  tx.run("MATCH (n {name: $name, age: $age}) RETURN n", name=name, age=age)

with driver.session() as session:
  # Parameters
  session.read_transaction(match_name_and_age, "john", 20)

driver.close()
```

以下は、Bolt プロトコルを使用する openCypher パラメーター化されたクエリの Java の例です。

```
Driver driver = GraphDatabase.driver("bolt+s://(your cluster endpoint URL):8182");
HashMap<String, Object> parameters = new HashMap<>();
parameters.put("name", "john");
parameters.put("age", 20);
String queryString = "MATCH (n {name: $name, age: $age}) RETURN n";
Result result = driver.session().run(queryString, parameters);
```

# openCypher データモデル
<a name="access-graph-opencypher-data-model"></a>

Neptune openCypher エンジンは Gremlin と同じプロパティグラフモデルに基づいて構築されます。特に、次のことに注意してください。
+ すべてのノードには 1 つ以上のラベルがあります。ラベルなしでノードを挿入すると、`vertex` という名前のデフォルトラベルが付きます。ノードのラベルをすべて削除しようとすると、エラーがスローされます。
+ リレーションシップとは、1 つのリレーションシップタイプを持ち、2 つのノード間に単方向接続を形成するエンティティです (つまり、ノードの 1 つ*から*もう 1 つ*に*)。
+ ノードとリレーションシップは両方ともプロパティを持つことができますが、そうする必要はありません。Neptune は、ゼロのプロパティを持つノードとリレーションシップをサポートしています。
+ Neptune はメタプロパティをサポートしていません。メタプロパティも openCypher 仕様に含まれていません。
+ Grumlin を使用して作成された場合は、グラフ内のプロパティを複数値にすることができます。つまり、ノードまたはリレーションシッププロパティには、1 つの値だけでなく、さまざまな値のセットを設定できます。Neptune は openCypher セマンティクスを拡張して、複数値のプロパティを正常に処理します。

サポートされているデータ型については、[openCypher データ形式](bulk-load-tutorial-format-opencypher.md) を参照してください。ただし、現在、`Array` プロパティ値を openCypher グラフに挿入することはお勧めしていません。同様に、バルクローダーを使用して配列プロパティ値を挿入できます。現在の Neptune openCypher リリースでは、単一のリスト値ではなく、複数の値を持つプロパティのセットとして扱われます。

このリリースでサポートされるデータ型のリストを次に示します。
+ `Bool`
+ `Byte`
+ `Short`
+ `Int` 
+ `Long`
+ `Float` (プラスマイナスインフィニティと NaN を含みますが、INF は含まれません)
+ `Double` (プラスマイナスインフィニティと NaN を含みますが、INF は含まれません)
+ `DateTime` 
+ `String`

# openCypher `explain` 機能
<a name="access-graph-opencypher-explain"></a>

openCypher の `explain` 機能は、Neptune エンジンが取る実行アプローチの理解に役立つ Amazon Neptune のセルフサービスツールです。explain を呼び出すには、openCypher [HTTPS](access-graph-opencypher-queries.md) リクエストに `explain=mode` でパラメータを渡します。`mode` の値は次のいずれかになります。

****
+ **`static`** - `static` モードでは、`explain` はクエリプランの静的構造のみを表示します。実際にはクエリを実行しません。
+ **`dynamic`** — `dynamic` モードでは、`explain` はクエリも実行し、クエリプランの動的な要素も含まれます。これらには、演算子を介して通過する中間バインドの数、送信バインドに対する着信バインドの割合、各演算子の所要合計時間が含まれる場合があります。
+ **`details`** - `details` モードでは、`explain` は動的モードで表示される情報に加えて、実際の openCypher クエリ文字列や、結合演算子が基づくパターンの推定範囲数などの詳細を出力します。

  

例えば、`POST` を使用します。

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n) RETURN n LIMIT 1;" \
  -d "explain=dynamic"
```

または、`GET` を使用します。

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n)%20RETURN%20n%20LIMIT%201&explain=dynamic"
```

## Neptune における openCypher `explain` の制限事項
<a name="access-graph-opencypher-explain-limitations"></a>

openCypher explain の現在のリリースには、次のような制約事項があります。
+ explain プランは、現在、読み取り専用操作を実行するクエリでのみ使用できます。`CREATE`、`DELETE`、`MERGE`、`SET` など、何らかのニューテーションを行うクエリはサポートされていません。
+ 特定のプランの演算子と出力は、将来のリリースで変更される可能性があります。

## openCypher `explain` 出力に含まれる DFE 演算子
<a name="access-graph-opencypher-dfe-operators"></a>

openCypher `explain` 機能が提供する情報を使用するには、[DFE クエリエンジン](neptune-dfe-engine.md)の仕組みについて、いくつかの詳細を理解する必要があります (DFE は Neptune が openCypher クエリの処理に使用するエンジン)。

DFE エンジンは、すべてのクエリを演算子のパイプラインに変換します。最初の演算子から始まり、中間ソリューションは、1 つの演算子から次の演算子へと、この演算子パイプラインを流れます。explain テーブルの各行は、評価ポイントまでの結果を表します。

DFE クエリプランで使用できる演算子は次のとおりです。

**DFEApply** — 指定した変数に保存されている値に対して、引数セクションで指定した関数を実行します。

**DFEBindRelation** — 指定された名前の変数を結合します。

**DFEChunkLocalSubQuery** — これは実行中のサブクエリのラッパーとして機能するノンブロッキング操作です。

**DFEDistinctColumn** — 指定された変数に基づいて、入力値の個別のサブセットを返します。

**DFEDistinctRelation** — 指定された変数に基づいて、入力ソリューションの個別のサブセットを返します。

**DFEDrain** — サブクエリの最後に表示され、そのサブクエリの終了ステップとして機能します。ソリューションの数は `Units In` として記録されます。`Units Out` は常に 0 です。

**DFEForwardValue** — すべての入力チャンクを出力チャンクとして直接コピーし、ダウンストリームの演算子に渡します。

**DFEGroupByHashIndex** — 以前に計算したハッシュインデックス (`DFEHashIndexBuild` 操作を使用) に基づいて、入力ソリューションに対してグループ化操作を実行します。出力として、指定された入力は、すべての入力ソリューションのグループキーを含む列によって拡張されます。

**DFEHashIndexBuild** — 副作用として一連の変数に対してハッシュインデックスを構築します。通常、このハッシュインデックスは後の操作で再利用されます。このハッシュインデックスの使用場所については、`DFEHashIndexJoin` または `DFEGroupByHashIndex` を参照してください。

**DFEHashIndexJoin** — 以前に構築したハッシュインデックスに対して受信ソリューションで結合を実行します。このハッシュインデックスの構築場所については、`DFEHashIndexBuild` を参照してください。

**DFEJoinExists** — 左側と右側の入力リレーションを取得し、指定された結合変数で定義されている右側のリレーションの値に対応する左側のリレーションの値を保持します。

**** — これはサブクエリのラッパーとして機能するノンブロッキング操作であり、繰り返し実行してループで使用できます。

**DFEMergeChunks** — これは、アップストリームの演算子からのチャンクを 1 つのソリューションのチャンクにまとめて、ダウンストリームの演算子に渡すブロッキング操作です (`DFESplitChunks` の逆)。

**DFEMinus** — 左側と右側の入力リレーションを取得し、指定された結合変数で定義されている右側のリレーションの値に対応しない左側のリレーションの値を保持します。両方のリレーションで変数に重複がない場合、この演算子は単に左側の入力リレーションを返します。

**DFENotExists** — 左側と右側の入力リレーションを取得し、指定された結合変数で定義されている右側のリレーションの値に対応しない左側のリレーションの値を保持します。両方のリレーションで変数に重複がない場合、この演算子は空のリレーションを返します。

**DFEOptionalJoin** — 左外部結合 (OPTIONAL 結合とも呼ばれます) を実行します。右側に少なくとも 1 つの結合パートナーがある左側のソリューションは結合され、右側に結合パートナーがない左側のソリューションはそのまま転送されます。これはブロッキング操作です。

**DFEPipelineJoin** — `pattern` 引数によって定義されたタプルパターンに対して入力を結合します。

**DFEPipelineRangeCount** — 特定のパターンに一致するソリューションの数をカウントし、そのカウント値を含む 1 つの単項ソリューションを返します。

**DFEPipelineScan** — 列に特定のフィルターを適用して、または適用せずに、データベースをスキャンして、指定された `pattern` 引数を探します。

**DFEProject** — 複数の入力列を受け取り、必要な列のみを投影します。

**DFEReduce** — 指定された変数に対して指定された集計関数を実行します。

**DFERelationalJoin** — マージ結合を使用して、指定されたパターンキーに基づいて前の演算子の入力を結合します。これはブロッキング操作です。

**DFERouteChunks** — 入力チャンクを単一の入力エッジから受け取り、これらのチャンクを複数の出力エッジに沿ってルーティングします。

**DFESelectRows** — この演算子は、左側の入力リレーションソリューションから選択的に行を取得し、ダウンストリームの演算子に転送します。行は、演算子の右側の入力リレーションで指定された行識別子に基づいて選択されます。

**DFESerialize** — クエリの最終結果を JSON 文字列としてシリアル化し、各入力ソリューションを適切な変数名にマッピングします。ノードとエッジの結果の場合、これらの結果はエンティティプロパティとメタデータのマップにシリアル化されます。

**DFESort** — 入力リレーションを受け取り、指定されたソートキーに基づいてソートされたリレーションを生成します。

**DFESplitByGroup** — 1 つの入力エッジからの各単一入力チャンクを、別の入力エッジの対応する入力チャンクの行 ID で識別される行グループに対応する小さな出力チャンクに分割します。

**DFESplitChunks** — 各単一入力チャンクをより小さい出力チャンクに分割します (`DFEMergeChunks` の逆)。

**DFEStreamingHashIndexBuild** — `DFEHashIndexBuild` のストリーミングバージョン。

**DFEStreamingGroupByHashIndex** — `DFEGroupByHashIndex` のストリーミングバージョン。

**DFESubquery** — この演算子はすべてのプランの最初に表示され、openCypher のプラン全体である [DFE エンジン](neptune-dfe-engine.md)上で実行されるプランの部分をカプセル化します。

**DFESymmetricHashJoin** — ハッシュ結合を使用して、指定されたパターンキーに基づいて前の演算子の入力を結合します。これは非ブロッキング操作です。

**DFESync** — この演算子は、ノンブロッキングプランをサポートする同期演算子です。2 つの受信エッジからソリューションを受け取り、これらのソリューションを適切なダウンストリームエッジに転送します。同期の目的で、これらのエッジの 1 つに沿った入力は内部でバッファリングされる場合があります。

**DFETee** — これは、同じソリューションセットを複数の演算子に送信する分岐演算子です。

**DFETermResolution** — 入力に対してローカライズ操作またはグローバル化操作を実行し、それぞれローカライズされた識別子またはグローバル化された識別子の列を生成します。

**** — 入力列の値のリストを個別の要素として出力列に展開します。

**DFEunion** — 2 つ以上の入力リレーションを受け取り、目的の出力スキーマを使用して、これらのリレーションの和集合を生成します。

**SolutionInjection** — explain 出力で他のすべての前に表示されます。Units Out 列の値は 1 になります。ただし、これはノーオペレーションとして機能し、実際には DFE エンジンにソリューションは挿入されません。

**TermResolution** — プランの最後に表示され、Neptune エンジンのオブジェクトを openCypher オブジェクトに変換します。

## openCypher `explain` 出力の列
<a name="access-graph-opencypher-explain-columns"></a>

Neptune が openCypher explain 出力として生成するクエリプラン情報には、1 行に 1 つの演算子を含むテーブルが含まれています。このテーブルには、次の列があります。

**ID** — プラン内のこの演算子の数値 ID。

**Out \$11** (および **Out \$12**) — この演算子の下流にいる演算子の ID。ダウンストリーム演算子は最大で 2 つまで存在できます。

**名前** — この演算子の名前。

**引数** — 演算子に関連する詳細。これには、入力スキーマ、出力スキーマ、パターン (`PipelineScan` と`PipelineJoin`) などが含まれます。

**モード** — 基本的な演算子の動作を説明するラベル。この列はほとんど空白 (`-`) です。唯一の例外は `TermResolution` であり、この場合、モードは `id2value_opencypher` になり、ID から openCypher 値への解決を示します。

**Units In** — この演算子への入力として渡されるソリューションの数。`DFEPipelineScan`、`SolutionInjections`、`DFESubquery` など、静的な値が注入されていない上流演算子のない演算子は、ゼロの値を持ちます。

**Units Out** — この演算子の出力として生成されるソリューションの数。`DFEDrain` は特殊なケースであり、排出されるソリューションの数が `Units In` に記録され、`Units Out` は常にゼロになります。

**比率** — `Units In` に対する `Units Out` の比率。

**時間 (ms)** — この演算子が消費した CPU 時間 (ミリ秒単位)。

## openCypher explain 出力の基本的な例
<a name="access-graph-opencypher-explain-basic-example"></a>

openCypher `explain` 出力の基本的な例を次に示します。このクエリは、デフォルトの ASCII 出力形式の `details` モードを使用して `explain` を起動する空港コード `ATL` を含むノードを航路データセット内で単一ノードで検索します。

```
curl -d "query=MATCH (n {code: 'ATL'}) RETURN n" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                      ~
Query:
MATCH (n {code: 'ATL'}) RETURN n

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?n]          │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 2.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?n) with property 'code' as ?n_code2 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.21      ║
║    │        │        │                       │ inlineFilters=[(?n_code2 IN ["ATL"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEProject            │ columns=[?n]                                                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?n, ?n_code2]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?n                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.20      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?n]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?n) with property 'ALL' and label '?n_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.35      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

最上位では、他の何よりも先に `SolutionInjection` が表示され, ユニットアウトは 1 です。実際にはソリューションを注入しないことに注意してください。次の演算子 `DFESubquery` のユニットインは 0 であることがわかります。

最上位の `SolutionInjection` の後は、`DFESubquery` および `TermResolution` 演算子です。`DFESubquery` は、[DFE エンジン](neptune-dfe-engine.md)にプッシュされるクエリ実行プランの一部をカプセル化します (openCypher クエリの場合、クエリプラン全体が DFE によって実行されます)。クエリプラン内のすべての演算子は、`DFESubquery` によって参照される `subQuery1` の内部にネストされています。唯一の例外は `TermResolution` であり、内部 ID を完全にシリアル化された openCypher オブジェクトにマテリアライズします。

DFE エンジンにプッシュされるすべての演算子の名前は `DFE` プレフィックスで始まります。前述のように、openCypher クエリプラン全体が DFE によって実行されるため、結果として、最後の `TermResolution` 演算子を除くすべての演算子は `DFE` で始まります。

`subQuery1` の内部には、メモリ制限のあるメカニズムで実行されるプッシュ実行プランの一部をカプセル化する `DFEChunkLocalSubQuery` または `DFELoopSubQuery` 演算子が 0 個以上存在する可能性があります。`DFEChunkLocalSubQuery` は、ここでは、サブクエリへの入力として使用される 1 つの `SolutionInjection` を含みます。出力でそのサブクエリのテーブルを見つけるには、`DFEChunkLocalSubQuery` または `DFELoopSubQuery` 演算子の `Arguments` 列で指定された `subQuery=graph URI` を検索します。

`subQuery1` では、`ID` が 0 の`DFEPipelineScan` は、データベースをスキャンして、指定された `pattern` を探します。このパターンは、プロパティ `code` が変数 `?n_code2` として保存されているエンティティをすべてのラベルにわたってスキャンします (`airport` を `n:airport` に付加することによって、特定のラベルに絞り込むことができます)。`inlineFilters` 引数は、`code` プロパティが `ATL` に等しい場合のフィルタリングを示します。

次に、`DFEChunkLocalSubQuery` 演算子は `DFEPipelineJoin` を含むサブクエリの中間結果を結合します。これによって、前の `DFEPipelineScan` は `code` プロパティを持つすべてのエンティティをスキャンするため、`?n` が実際にノードであることが保証されます。

# 制限付きのリレーションシップルックアップの `explain` 出力例
<a name="access-graph-opencypher-explain-example-2"></a>

このクエリは、タイプ `route` の 2 つの匿名ノード間のリレーションシップを検索し、最大 10 を返します。やはり、`explain` モードは `details` であり、出力形式はデフォルトの ASCII 形式です。`explain` 出力は次のとおりです。

ここでは、`DFEPipelineScan` は、匿名ノード `?anon_node7` で始まり、別の匿名ノード `?anon_node21` で終わり、`?p_type1` として保存されたリレーションシップタイプを持つエッジをスキャンします。`?p_type1` が `el://route` であるフィルターがあり (`el` はエッジラベルを表します)、クエリ文字列の `[p:route]` に対応します。

`DFEDrain` は、`Arguments` 列に示されているように、出力ソリューションを 10 個に制限して収集します。`DFEDrain` は、制限に達するか、すべてのソリューションが生成されるか、いずれか早い方で終了します。

```
curl -d "query=MATCH ()-[p:route]->() RETURN p LIMIT 10" -k https://localhost:8182/openCypher -d "explain=details"                                                                                              ~
Query:
MATCH ()-[p:route]->() RETURN p LIMIT 10

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 10        │ 0.00  │ 5.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?p]          │ id2value_opencypher │ 10       │ 10        │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═════════════════╤═══════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name            │ Arguments                                                 │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═════════════════╪═══════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan │ pattern=Edge((?anon_node7)-[?p:?p_type1]->(?anon_node21)) │ -    │ 0        │ 1000      │ 0.00  │ 0.66      ║
║    │        │        │                 │ inlineFilters=[(?p_type1 IN [<el://route>])]              │      │          │           │       │           ║
║    │        │        │                 │ patternEstimate=26219                                     │      │          │           │       │           ║
╟────┼────────┼────────┼─────────────────┼───────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEProject      │ columns=[?p]                                              │ -    │ 1000     │ 1000      │ 1.00  │ 0.14      ║
╟────┼────────┼────────┼─────────────────┼───────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ DFEDrain        │ limit=10                                                  │ -    │ 1000     │ 0         │ 0.00  │ 0.11      ║
╚════╧════════╧════════╧═════════════════╧═══════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# 値式関数の `explain` 出力例
<a name="access-graph-opencypher-explain-example-3"></a>

関数:

```
MATCH (a) RETURN DISTINCT labels(a)
```

以下の `explain` 出力では、`DFEPipelineScan` (ID 0) はすべてのノードラベルをスキャンします。これは `MATCH (a` に対応します。

`DFEChunkLocalSubquery` (ID 1) は、それぞれの `?a` のラベルを集約します。これは `labels(a)` に対応します。`DFEApply` と `DFEReduce` を通してそれが分かります。

`BindRelation` (ID 2) は、列の汎用名 `?__gen_labelsOfa2` を `?labels(a)` に変更するために使用されます。

`DFEDistinctRelation` (ID 4) は、異なるラベルのみを取得します (複数の :airport ノードがあると、重複したラベル ["airport"] になります)。これは `DISTINCT labels(a)` に対応します。

```
curl -d "query=MATCH (a) RETURN DISTINCT labels(a)" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                    ~
Query:
MATCH (a) RETURN DISTINCT labels(a)

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 5         │ 0.00  │ 81.00     ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?labels(a)]  │ id2value_opencypher │ 5        │ 5         │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?a) with property 'ALL' and label '?a_label1'                                                   │ -    │ 0        │ 3750      │ 0.00  │ 26.77     ║
║    │        │        │                       │ patternEstimate=3506                                                                                         │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#8b314f55-2cc7-456a-a48a-c76a0465cfab/graph_1 │ -    │ 3750     │ 3750      │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEBindRelation       │ inputVars=[?a, ?__gen_labelsOfa2, ?__gen_labelsOfa2]                                                         │ -    │ 3750     │ 3750      │ 1.00  │ 0.08      ║
║    │        │        │                       │ outputVars=[?a, ?__gen_labelsOfa2, ?labels(a)]                                                               │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEProject            │ columns=[?labels(a)]                                                                                         │ -    │ 3750     │ 3750      │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEDistinctRelation   │ -                                                                                                            │ -    │ 3750     │ 5         │ 0.00  │ 2.78      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 5        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#8b314f55-2cc7-456a-a48a-c76a0465cfab/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?a]                                             │ -        │ 0        │ 3750      │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -        │ 3750     │ 7500      │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEProject           │ columns=[?a]                                               │ -        │ 3750     │ 3750      │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 17     │ -      │ DFEOptionalJoin      │ -                                                          │ -        │ 7500     │ 3750      │ 0.50  │ 0.44      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEDistinctRelation  │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 2.23      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ DFEDistinctColumn    │ column=?a                                                  │ -        │ 3750     │ 3750      │ 1.00  │ 1.50      ║
║    │        │        │                      │ ordered=false                                              │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 7      │ -      │ DFEPipelineJoin      │ pattern=Node(?a) with property 'ALL' and label '?a_label3' │ -        │ 3750     │ 3750      │ 1.00  │ 10.58     ║
║    │        │        │                      │ patternEstimate=3506                                       │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ 9      │ DFETee               │ -                                                          │ -        │ 3750     │ 7500      │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 10     │ -      │ DFEBindRelation      │ inputVars=[?a_label3]                                      │ -        │ 3750     │ 3750      │ 1.00  │ 0.04      ║
║    │        │        │                      │ outputVars=[?100]                                          │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ 11     │ -      │ DFEBindRelation      │ inputVars=[?a, ?a_label3, ?100]                            │ -        │ 7500     │ 3750      │ 0.50  │ 0.07      ║
║    │        │        │                      │ outputVars=[?a, ?a_label3, ?100]                           │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 10 │ 9      │ -      │ DFETermResolution    │ column=?100                                                │ id2value │ 3750     │ 3750      │ 1.00  │ 7.60      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 11 │ 12     │ -      │ DFEBindRelation      │ inputVars=[?a, ?a_label3, ?100]                            │ -        │ 3750     │ 3750      │ 1.00  │ 0.06      ║
║    │        │        │                      │ outputVars=[?a, ?100, ?a_label3]                           │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 12 │ 13     │ -      │ DFEApply             │ functor=nodeLabel(?a_label3)                               │ -        │ 3750     │ 3750      │ 1.00  │ 0.55      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 13 │ 14     │ -      │ DFEProject           │ columns=[?a, ?a_label3_alias4]                             │ -        │ 3750     │ 3750      │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 14 │ 15     │ -      │ DFEMergeChunks       │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 15 │ 16     │ -      │ DFEReduce            │ functor=collect(?a_label3_alias4)                          │ -        │ 3750     │ 3750      │ 1.00  │ 6.37      ║
║    │        │        │                      │ segmentationKey=[?a]                                       │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 16 │ 3      │ -      │ DFEMergeChunks       │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 17 │ -      │ -      │ DFEDrain             │ -                                                          │ -        │ 3750     │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# 数学値式関数の `explain` 出力例
<a name="access-graph-opencypher-explain-example-4"></a>

この例では、`RETURN abs(-10)` は定数 `-10` の絶対値を取り、単純な評価を行います。

`DFEChunkLocalSubQuery` (ID 1) は、変数 `?100` に格納されている静的な値 `-10` に対してソリューション注入を実行します。

`DFEApply` (ID 2) は、`?100` 変数に格納されている静的な値に対して絶対値関数 `abs()` を実行する演算子です。

クエリと結果の `explain` 出力は次のとおりです。

```
curl -d "query=RETURN abs(-10)" -k https://localhost:8182/openCypher  -d "explain=details"                                                                                                                       ~
Query:
RETURN abs(-10)

╔════╤════════╤════════╤═══════════════════╤═══════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments             │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]        │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1    │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼───────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?_internalVar1] │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection  │ outSchema=[]                                                                                                 │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#c4cc6148-cce3-4561-93c0-deb91f257356/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEApply              │ functor=abs(?100)                                                                                            │ -    │ 1        │ 1         │ 1.00  │ 0.26      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEBindRelation       │ inputVars=[?_internalVar2, ?_internalVar2]                                                                   │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
║    │        │        │                       │ outputVars=[?_internalVar2, ?_internalVar1]                                                                  │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEProject            │ columns=[?_internalVar1]                                                                                     │ -    │ 1        │ 1         │ 1.00  │ 0.06      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.05      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝

subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#c4cc6148-cce3-4561-93c0-deb91f257356/graph_1
╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                           │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ solutions=[?100 -> [-10^^<LONG>]]   │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
║    │        │        │                      │ outSchema=[?100]                    │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 3      │ -      │ DFERelationalJoin    │ joinVars=[]                         │ -    │ 2        │ 1         │ 0.50  │ 0.18      ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 1      │ -      │ DFESolutionInjection │ outSchema=[]                        │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain             │ -                                   │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# 可変長パス (VLP) クエリの `explain` 出力例
<a name="access-graph-opencypher-explain-example-5"></a>

これは、可変長パスクエリを処理するための、より複雑なクエリプランの例です。この例では、わかりやすくするために、`explain` 出力の一部のみを示しています。

`subQuery1` では、`...graph_1` サブクエリを挿入する `DFEPipelineScan` (ID 0) と `DFEChunkLocalSubQuery` (ID 1) が、`YPO` コードを含むノードをスキャンします。

`subQuery1` では、`...graph_2` サブクエリを挿入する `DFEChunkLocalSubQuery` (ID 0) が、`LAX` コードを含むノードをスキャンします。

`subQuery1` では、`DFEChunkLocalSubQuery` (ID 3) が `...graph3` サブクエリを挿入し、これが `DFELoopSubQuery` (ID 17) を含み、これが `...graph5` サブクエリを挿入します。この操作は、2 つのノード間のクエリ文字列の `-[*2]->` 可変長パターンを解決する役割を果たします。

```
curl -d "query=MATCH p=(a {code: 'YPO'})-[*2]->(b{code: 'LAX'}) return p" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                                                                                                ~
Query:
MATCH p=(a {code: 'YPO'})-[*2]->(b{code: 'LAX'}) return p

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 0         │ 0.00  │ 84.00     ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?p]          │ id2value_opencypher │ 0        │ 0         │ 0.00  │ 0         ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?a) with property 'code' as ?a_code7 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.68      ║
║    │        │        │                       │ inlineFilters=[(?a_code7 IN ["YPO"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_2 │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_3 │ -    │ 1        │ 0         │ 0.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEBindRelation       │ inputVars=[?__gen_path6, ?anon_rel26, ?b_code8, ?b, ?a_code7, ?a, ?__gen_path6]                              │ -    │ 0        │ 0         │ 0.00  │ 0.10      ║
║    │        │        │                       │ outputVars=[?__gen_path6, ?anon_rel26, ?b_code8, ?b, ?a_code7, ?a, ?p]                                       │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ DFEProject            │ columns=[?p]                                                                                                 │ -    │ 0        │ 0         │ 0.00  │ 0.05      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 0        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?a, ?a_code7]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?a                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?a]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?a) with property 'ALL' and label '?a_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.47      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.26      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_2
╔════╤════════╤════════╤══════════════════════╤═══════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                         │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪═══════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan      │ pattern=Node(?b) with property 'code' as ?b_code8 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.38      ║
║    │        │        │                      │ inlineFilters=[(?b_code8 IN ["LAX"^^xsd:string])]                 │      │          │           │       │           ║
║    │        │        │                      │ patternEstimate=1                                                 │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEMergeChunks       │ -                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFERelationalJoin    │ joinVars=[]                                                       │ -    │ 2        │ 1         │ 0.50  │ 0.19      ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 2      │ -      │ DFESolutionInjection │ outSchema=[?a, ?a_code7]                                          │ -    │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ DFEDrain             │ -                                                                 │ -    │ 1        │ 0         │ 0.00  │ 0.01      ║
╚════╧════════╧════════╧══════════════════════╧═══════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_3
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
...
║ 17 │ 18     │ -      │ DFELoopSubQuery       │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_5 │ -        │ 1        │ 2         │ 2.00  │ 0.31      ║
...
```

# Neptune openCypher でのトランザクション
<a name="access-graph-opencypher-transactions"></a>

Amazon Neptune の openCypher 実装は、[Neptune によって定義されたトランザクションセマンティクスを使用します](transactions-neptune.md)。ただし、Bolt ドライバーによって提供される分離レベルは、以下のセクションで説明するように、Bolt トランザクションセマンティクスに特定の影響を及ぼします。

## 読み取り専用の Bolt トランザクションクエリ
<a name="access-graph-opencypher-transactions-ro"></a>

読み取り専用クエリの処理には、次のようなさまざまなトランザクションモデルと分離レベルがあります。

### 暗黙的な読み取り専用トランザクションクエリ
<a name="access-graph-opencypher-transactions-ro-implicit"></a>

読み取り専用の暗黙的トランザクションの例を次に示します。

```
public void executeReadImplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
          Config.builder().withEncryption()
                          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig.builder()
                                             .withFetchSize(1000)
                                             .withDefaultAccessMode(AccessMode.READ)
                                             .build();

  // run the query as access mode read
  driver.session(sessionConfig).readTransaction(new TransactionWork<String>()
    {
      final StringBuilder resultCollector = new StringBuilder();

      @Override
      public String execute(final Transaction tx)
      {
        // execute the query
        Result queryResult = tx.run(READ_QUERY);

        // Read the result
        for (Record record : queryResult.list())
        {
          for (String key : record.keys())
          {
            resultCollector.append(key)
                           .append(":")
                           .append(record.get(key).asNode().toString());
          }
        }
        return resultCollector.toString();
      }

    }
  );

  // close the driver.
  driver.close();
}
```

リードレプリカは読み取り専用クエリしか受け付けないため、リードレプリカに対するすべてのクエリは、セッション構成に設定されているアクセスモードに関係なく、読み取り暗黙のトランザクションとして実行されます。Neptune は、`SNAPSHOT` 分離セマンティクスでは、読み取り暗黙のトランザクションを[読み取り専用クエリ](transactions-neptune.md#transactions-neptune-read-only)として評価します。

障害が発生すると、読み取り暗黙のトランザクションはデフォルトで再試行されます。

### 読み取り専用トランザクションクエリをオートコミットする
<a name="access-graph-opencypher-transactions-ro-autocommit"></a>

読み取り専用のオートコミットトランザクションの例を次に示します。

```
public void executeAutoCommitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // Create the session config.
  final SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.READ)
    .build();

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // result collector
  final StringBuilder resultCollector = new StringBuilder();

  // create a session
  final Session session = driver.session(sessionConfig);

  // run the query
  final Result queryResult = session.run(READ_QUERY);
  for (final Record record : queryResult.list())
  {
    for (String key : record.keys())
    {
      resultCollector.append(key)
                     .append(":")
                     .append(record.get(key).asNode().toString());
    }
  }

  // close the session
  session.close();

  // close the driver
  driver.close();
}
```

セッション設定でアクセスモードが `READ` に設定されている場合、Neptune は、`SNAPSHOT` 分離セマンティクスではオートコミットトランザクションクエリを[読み取り専用クエリ](transactions-neptune.md#transactions-neptune-read-only)として評価します。リードレプリカは読み取り専用クエリしか受け付けないことに注意してください。

セッション設定を渡さない場合、オートコミットクエリはデフォルトでミューテーションクエリを分離して処理されるため、アクセスモードを明示的に `READ` に設定したセッション設定を渡すことが重要です。

失敗した場合、読み取り専用のオートコミットクエリは再試行されません。

### 暗黙的な読み取り専用トランザクションクエリ
<a name="access-graph-opencypher-transactions-ro-explicit"></a>

以下は明示的な読み取り専用トランザクションの例です。

```
public void executeReadExplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // Create the session config.
  final SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.READ)
    .build();

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // result collector
  final StringBuilder resultCollector = new StringBuilder();

  // create a session
  final Session session = driver.session(sessionConfig);

  // begin transaction
  final Transaction tx = session.beginTransaction();

  // run the query on transaction
  final List<Record> list = tx.run(READ_QUERY).list();

  // read the result
  for (final Record record : list)
  {
    for (String key : record.keys())
    {
      resultCollector
        .append(key)
        .append(":")
        .append(record.get(key).asNode().toString());
    }
  }

  // commit the transaction and for rollback we can use beginTransaction.rollback();
  tx.commit();

  // close the driver
  driver.close();
}
```

セッション設定でアクセスモードが `READ` に設定されている場合、Neptune は、`SNAPSHOT` 分離セマンティクスでは明示的な読み取り専用トランザクションを[読み取り専用クエリ](transactions-neptune.md#transactions-neptune-read-only)として評価します。リードレプリカは読み取り専用クエリしか受け付けないことに注意してください。

セッション設定を渡さない場合、明示的読み取り専用トランザクションは、デフォルトではミューテーションクエリ分離で処理されるため、アクセスモードを明示的に `READ` に設定したセッション設定を渡すことが重要です。

失敗した場合、読み取り専用の明示的なクエリはデフォルトで再試行されます。

## ミューテーション Bolt トランザクションクエリ
<a name="access-graph-opencypher-transactions-wr"></a>

読み取り専用クエリと同様、ミューテーションクエリの処理にはさまざまな方法があり、次のようなさまざまなトランザクションモデルと分離レベルがあります。

### 暗黙的なミューテーショントランザクションクエリ
<a name="access-graph-opencypher-transactions-wr-implicit"></a>

暗黙的なミューテーショントランザクションの例を示します。

```
public void executeWriteImplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // create node with label as label and properties.
  final String WRITE_QUERY = "CREATE (n:label {name : 'foo'})";

  // Read the vertex created with label as label.
  final String READ_QUERY = "MATCH (n:label) RETURN n";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.WRITE)
    .build();

  final StringBuilder resultCollector = new StringBuilder();

  // run the query as access mode write
  driver.session(sessionConfig).writeTransaction(new TransactionWork<String>()
  {
    @Override
    public String execute(final Transaction tx)
    {
      // execute the write query and consume the result.
      tx.run(WRITE_QUERY).consume();

      // read the vertex written in the same transaction
      final List<Record> list = tx.run(READ_QUERY).list();

      // read the result
      for (final Record record : list)
      {
        for (String key : record.keys())
        {
          resultCollector
            .append(key)
            .append(":")
            .append(record.get(key).asNode().toString());
        }
      }
      return resultCollector.toString();
    }
  }); // at the end, the transaction is automatically committed.

  // close the driver.
  driver.close();
}
```

ミューテーションクエリの一部として行われる読み取りは、[Neptune ミューテーショントランザクション](transactions-neptune.md#transactions-neptune-mutation)では通常の保証に従って `READ COMMITTED` 分離で実行されます。

セッション設定を具体的に渡すかどうかにかかわらず、そのトランザクションは常に書き込みトランザクションとして扱われます。

コンフリクトについては、「[ロック待機タイムアウトを使用した競合の解決](transactions-neptune.md#transactions-neptune-conflicts)」を参照してください。

### オートコミットミューテーショントランザクションクエリ
<a name="access-graph-opencypher-transactions-wr-autocommit"></a>

ミューテーションオートコミットクエリは、ミューテーション暗黙的トランザクションと同じ動作を継承します。

セッション設定を渡さなかった場合、トランザクションはデフォルトでは書き込みトランザクションとして扱われます。

失敗した場合、ミューテーションオートコミットクエリは、自動的に再試行されません。

### 明示的なミューテーショントランザクションクエリ
<a name="access-graph-opencypher-transactions-wr-explicit"></a>

明示的なミューテーショントランザクションの例を示します。

```
public void executeWriteExplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // create node with label as label and properties.
  final String WRITE_QUERY = "CREATE (n:label {name : 'foo'})";

  // Read the vertex created with label as label.
  final String READ_QUERY = "MATCH (n:label) RETURN n";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.WRITE)
    .build();

  final StringBuilder resultCollector = new StringBuilder();

  final Session session = driver.session(sessionConfig);

  // run the query as access mode write
  final Transaction tx = driver.session(sessionConfig).beginTransaction();

  // execute the write query and consume the result.
  tx.run(WRITE_QUERY).consume();

  // read the result from the previous write query in a same transaction.
  final List<Record> list = tx.run(READ_QUERY).list();

  // read the result
  for (final Record record : list)
  {
    for (String key : record.keys())
    {
      resultCollector
        .append(key)
        .append(":")
        .append(record.get(key).asNode().toString());
    }
  }

  // commit the transaction and for rollback we can use tx.rollback();
  tx.commit();

  // close the session
  session.close();

  // close the driver.
  driver.close();
}
```

明示的なミューテーションクエリは、暗黙的なミューテーショントランザクションと同じ動作を継承します。

セッション設定を渡さなかった場合、トランザクションはデフォルトでは書き込みトランザクションとして扱われます。

コンフリクトについては、「[ロック待機タイムアウトを使用した競合の解決](transactions-neptune.md#transactions-neptune-conflicts)」を参照してください。

# openCypher クエリヒント
<a name="opencypher-query-hints"></a>

**重要**  
 openCypher クエリヒントは、エンジンリリース [1.3.2.0](https://docs.aws.amazon.com//neptune/latest/userguide/engine-releases-1.3.2.0.html) 以降でのみ利用できます。

 Amazon Neptune では、`USING` 句を使用して openCypher クエリのクエリヒントを指定できます。これらのヒントにより、最適化と評価に関する戦略を制御できます。

 クエリヒントの構文は次のとおりです。

```
USING {scope}:{hint} {value}
```

1.  `{scope}` は、ヒントが適用されるスコープ `Query`または `Clause` を定義します。

    スコープ値 `Query` は、クエリヒントがクエリ全体 (クエリレベル) に適用されることを表します。

    スコープ値 `Clause` は、クエリヒントがヒントの前にある句 (句レベル) に適用されることを表します。

1.  `{hint}` は、適用されているクエリヒントの名前です。

1.  `{value}` は `{hint}` の引数です。

 値について大文字と小文字は区別されません。

 例えば、クエリのクエリプランキャッシュを有効にするには: 

```
Using QUERY:PLANCACHE "enabled" 
MATCH (a:Person {firstName: "Erin", lastName: $lastName})
 RETURN a
```

**注記**  
 現在、**クエリ**スコープクエリヒント **PLANCACHE**、**TIMEOUTMILLISECONDS**、および **assumeConsistentDataTypes** がサポートされています。サポートされているクエリヒントを以下に示します。

**Topics**
+ [openCypher クエリプランのキャッシュヒント](opencypher-query-hints-qpc-hint.md)
+ [AssumeConsistentDataTypes ヒント](opencypher-query-hints-AssumeConsistentDataTypes.md)
+ [openCypher クエリタイムアウトヒント](opencypher-query-hints-timeout-hint.md)

# openCypher クエリプランのキャッシュヒント
<a name="opencypher-query-hints-qpc-hint"></a>

 クエリプランのキャッシュ動作は、クエリレベルのクエリヒント `QUERY:PLANCACHE` によってクエリごとに (パラメータ化されているかどうかにかかわらず) 上書きできます。`USING` 句と併用する必要があります。クエリヒントは、値として `enabled` または `disabled` を受け入れます。クエリプランのキャッシュの詳細については、「[Amazon Neptune のクエリプランキャッシュ](access-graph-qpc.md)」を参照してください。

```
# Forcing plan to be cached or reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
  
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  -d "parameters={\"arg\": 123}"
  
# Forcing plan to be neither cached nor reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

# AssumeConsistentDataTypes ヒント
<a name="opencypher-query-hints-AssumeConsistentDataTypes"></a>

 openCypher は、数値データ型 (int、byte、short、long など) の一致が型の昇格セマンティクスで実行されるパラダイムに従います。例えば、入力値 10 のプロパティをタイプが短いすべてのプロパティで検索する場合、タイプ昇格セマンティクスでは、10 のプロパティも長い値として一致します。場合によっては、型キャストによってオーバーヘッドが発生し、型キャストが実行されなかった場合よりも効率の低いクエリプランが発生する可能性があります。特に、データ型がデータで一貫して使用されている場合 (例: すべての人の年齢が長い値として保存されている場合) は、タイププロモーションを実行すると、クエリ結果に影響を与えずにオーバーヘッドが発生します。

 データベースに保存されている数値プロパティデータ値が一貫した型であることがわかっている場合に最適化を可能にするために、`assumeConsistentDataTypes` というクエリヒント (値が `true/false`、デフォルトは `false`) を使用できます。このクエリヒントに `true` の値を指定すると、エンジンはプロパティ値のみが常に長いか二重であると想定し、タイプ昇格セマンティクスをスキップします。クエリで指定された数値は、長い値 (浮動小数点値以外) と二重値 (浮動小数点値) のいずれかであるとみなされます。

 データが 1 つのデータ型を一貫して使用している場合 (例: すべての経過時間が `long` として保存されている場合) は、`assumeConsistentDataTypes` ヒントを使用すると、異なる数値型に対して不要な等価チェックをスキップしてクエリを最適化できます。ただし、同じプロパティのデータ型に一貫性がない場合は、ヒントを使用すると、クエリがヒントが想定する単一のデータ型にのみ一致するため、結果の一部が失われる可能性があります。

```
# Database loaded with following openCypher CSV's

# File 1
:ID,age:Int
n1,20
n2,25

# File 2
:ID,age:Long
n3,25


# Example (no hint)
MATCH (n:Person) 
WHERE n.age >= 25
RETURN n

# Result
n2
n3

Returns all person whose age is >= 25 and the values >= 25 can be with any of these datatypes
i.e. byte, short, int, long, double or float

-----------------------------------------------------------------------------------

# Example (with hint present)
USING QUERY:assumeConsistentDataTypes "true"
MATCH (n:Person)
WHERE n.age >= 25
RETURN n

# Result
n3

Returns only "n3" and not "n2". The reason is that even though the numerical value
matches (25), the datatype is "int" and is considered a non-match.
```

 この違いは、説明を通じて検証することもできます。

 説明なし: 

```
# Query
MATCH (n)
WHERE n.age = 20
RETURN n

# Explain Snippet
╔═════╤══════════╤══════════╤══════════════════════════════╤═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤════════╤════════════╤══════════════╤═════════╤══════════════╗
║ ID │ Out #1 │ Out #2 │ Name                   │ Arguments                                                                                                                            │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠═════╪══════════╪══════════╪══════════════════════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪════════╪════════════╪══════════════╪═════════╪══════════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan (DFX)  │ pattern=Node(?n) with property 'age' as ?n_age2 and label 'ALL'                                                                      │ -    │ 0        │ 1         │ 0.00  │ 0.10      ║
║    │        │        │                        │ inlineFilters=[(?n_age2 IN ["20"^^xsd:byte, "20"^^xsd:int, "20"^^xsd:long, "20"^^xsd:short, "20.0"^^xsd:double, "20.0"^^xsd:float])] │      │          │           │       │           ║
║    │        │        │                        │ patternEstimate=1                                                                                                                    │      │          │           │       │           ║
╟─────┼──────────┼──────────┼──────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────┼──────────────┼─────────┼──────────────╢

# The inFilters field contains all numeric types
```

 ヒントを使用して: 

```
# Query
MATCH (n)
WHERE n.age = 20
RETURN n

# Explain Snippet
╔═════╤══════════╤══════════╤══════════════════════════════╤═════════════════════════════════════════════════════════════════════════════════╤════════╤════════════╤══════════════╤═════════╤══════════════╗
║ ID │ Out #1 │ Out #2 │ Name                   │ Arguments                                                       │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠═════╪══════════╪══════════╪══════════════════════════════╪═════════════════════════════════════════════════════════════════════════════════╪════════╪════════════╪══════════════╪═════════╪══════════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan (DFX)  │ pattern=Node(?n) with property 'age' as ?n_age2 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.07      ║
║    │        │        │                        │ inlineFilters=[(?n_age2 IN ["20"^^xsd:long])]                   │      │          │           │       │           ║
║    │        │        │                        │ patternEstimate=1                                               │      │          │           │       │           ║
╟─────┼──────────┼──────────┼──────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┼────────┼────────────┼──────────────┼─────────┼──────────────╢

# The inFilters field only contains long datatype
```

# openCypher クエリタイムアウトヒント
<a name="opencypher-query-hints-timeout-hint"></a>

 クエリタイムアウト動作は、クエリレベルのクエリヒント によってクエリごとに設定できます`QUERY:TIMEOUTMILLISECONDS`。`USING` 句とともに使用する必要があります。クエリヒントは、負以外の を値として受け入れます。

```
# Using query-level timeout hint 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 100 MATCH(n) RETURN n LIMIT 1"
```

 クエリタイムアウト動作では、クラスターレベルのタイムアウトとクエリレベルのタイムアウトの最小値が考慮されます。クエリタイムアウトの動作については、以下の例を参照してください。クラスターレベルのクエリタイムアウトの詳細については、[「neptune\$1query\$1timeout](https://docs.aws.amazon.com/neptune/latest/userguide/parameters.html#parameters-db-cluster-parameters-neptune_query_timeout)」を参照してください。

```
# Suppose `neptune_query_timeout` is 10000 ms and query-level timeout is set to 100 ms
# It will consider 100 ms as the final timeout 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 100 MATCH(n) RETURN n LIMIT 1"

# Suppose `neptune_query_timeout` is 100 ms and query-level timeout is set to 10000 ms
# It will still consider 100 ms as the final timeout 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 10000 MATCH(n) RETURN n LIMIT 1"
```

# Neptune openCypher の制限事項
<a name="access-graph-opencypher-limitations"></a>

Amazon Neptune リリースの openCypher では、[openCypher の仕様準拠](feature-opencypher-compliance.md) で説明されているように、「[Cypher クエリ言語リファレンス、バージョン 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf)」で指定されているすべての内容がまだサポートされているわけではありません。将来のリリースでは、これらの制限の多くに対処する予定です。

# Neptune openCypher の例外
<a name="access-graph-opencypher-exceptions"></a>

Amazon Neptune で openCypher を操作する場合、さまざまな例外が発生する可能性があります。HTTPS エンドポイントまたは Bolt ドライバーから発生する可能性がある一般的な例外を以下に示します (Bolt ドライバーからの例外はすべてサーバー状態例外として報告されます)。


| HTTP コード | エラーメッセージ | 再取得可能? | 回避策 | 
| --- | --- | --- | --- | 
| 400 | *(openCypher パーサーから直接伝達される構文エラー)* | いいえ | クエリ構文を修正して再試行してください。 | 
| 500 | `Operation terminated (out of memory)` | はい | クエリを作り直してフィルタ条件を追加し、必要なメモリを削減してください。 | 
| 500 | 操作は終了しました (期限超過) | はい | DB クラスターパラメータグループのクエリタイムアウトを増やすか、[リクエストを再試行してください](https://docs.aws.amazon.com/general/latest/gr/api-retries.html)。 | 
| 500 | 操作は終了しました (ユーザーによってキャンセルされました) | はい | リクエストを再試行します。 | 
| 500 | データベースのリセットが進行中です。クラスターが使用可能になったら、クエリを再試行してください。 | はい | リセットが完了したら再試行してください。 | 
| 500 | 同時操作が競合しているため操作が失敗しました (再試行してください)。トランザクションは現在ロールバック中です。 | はい | [指数バックオフとリトライ戦略](best-practices-opencypher-retry-logic.md)を使用して再試行してください。 | 
| 400 | *(操作名)* 操作/機能がサポートされていない例外 | いいえ | 指定されたオペレーションは、サポートされていません。 | 
| 400 | 読み取り専用レプリカに対して openCypher の更新が試みられました | いいえ | ターゲットエンドポイントをライターエンドポイントに変更します。 | 
| 400 | MalFormedQueryException (Neptune は内部パーサーの状態を表示しません) | いいえ | クエリ構文を修正して再試行してください。 | 
| 400 | ノードにはまだリレーションシップがあるため削除できません。このノードを削除するには、まずリレーションシップを削除する必要があります。 | いいえ | `MATCH (n) DELETE n` を使用する代わりに `MATCH(n) DETACH DELETE(n)` を使用してください。 | 
| 400 | 無効な操作: ノードの最後のラベルを削除しようとしています。ノードには少なくとも 1 つのラベルが必要です。 | いいえ | Neptune では、すべてのノードに少なくとも 1 つのラベルが必要であり、明示的なラベルなしでノードを作成すると、デフォルトのラベル `vertex` が割り当てられます。最後のラベルが削除されないように、クエリやアプリケーションのロジックを変更してください。ノードのシングルトンラベルは、新しいラベルを設定してから古いラベルを削除することで更新できます。 | 
| 500 | リクエストの最大数を超えました。ConfiguredQueueCapacity=\$1\$1 for connId = \$1\$1 | はい | 現在、スタックやプロトコルに関係なく、処理できる同時リクエストは 8,192 件のみです。 | 
| 500 | 最大接続制限を超えました。 | はい | 1 つのインスタンスで許可される Bolt の同時接続数は 1000 件までです (HTTP には制限はありません)。 | 
| 400 | [ノード、リレーションシップ、パスのいずれか] が必要で、リテラルを取得しました | いいえ | 正しい引数、正しいクエリ構文を渡していることを確認して、再試行してください。 | 
| 400 | プロパティ値は単純なリテラルでなければなりません。または:Set プロパティのマップが必要でしたが、見つかりませんでした。 | いいえ | SET 句は単純なリテラルのみを受け入れ、複合型は受け付けません。 | 
| 400 | 見つかったエンティティは削除対象として渡されましたが、見つかりません。 | いいえ | 削除しようとしているエンティティがデータベースに存在することを確認してください。 | 
| 400 | ユーザーにはデータベースへのアクセス権がない場合の確認 | いいえ | 使用中の IAM ロールのポリシーを確認してください。 | 
| 400 | リクエストの一部としてトークンは渡されていません。 | いいえ | IAM 対応クラスターでは、適切に署名されたトークンをクエリリクエストの一部として渡す必要があります。 | 
| 400 | エラーメッセージは伝播されます。 | いいえ | リクエスト ID を使用して AWS サポートにお問い合わせください。 | 
| 500 | 操作は終了しました (内部エラー) | はい | リクエスト ID を使用して AWS サポートにお問い合わせください。 | 

# Amazon Neptune の openCypher 拡張機能
<a name="access-graph-opencypher-extensions"></a>

 Amazon Neptune は openCypher 仕様リファレンスバージョン 9 をサポートしています。詳細については、Amazon Neptune の「[Amazon Neptune における openCypher の仕様準拠](feature-opencypher-compliance.md)」を参照してください。さらに、Amazon Neptune はここに記載されている機能をサポートしています。特定のバージョンが記載されていない限り、機能は Neptune データベースと Neptune Analytics で使用できます。

## クエリ時間 S3 データアクセス
<a name="opencypher-compliance-neptune-read"></a>

Neptune Database 1.4.7.0 以降で使用できます。

Neptune は、openCypher クエリ内で直接 Amazon S3 から CSV または Parquet データを読み取る `neptune.read()`関数をサポートしています。クエリを実行する前にデータをインポートするバルクローダーとは異なり、 はクエリ実行時に Amazon S3 データ`neptune.read()`にアクセスします。

詳細なドキュメントについては、「」を参照してください[neptune.read()](access-graph-opencypher-21-extensions-s3-read.md)。

## Neptune 固有の `join()` 関数
<a name="opencypher-compliance-join-function"></a>

Neptune データベースと Neptune Analytics で使用できます。

Neptune は openCypher 仕様にはない `join()` 関数を実装しています。文字列リテラルと文字列区切り文字のリストから文字列リテラルを作成します。2 つの引数を取ります。
+ 1 番目の引数は文字列リテラルのリストです。
+ 2 番目の引数は区切り文字列であり、0、1、または複数の文字で構成できます。

例:

```
join(["abc", "def", "ghi"], ", ")    // Returns "abc, def, ghi"
```

## Neptune 固有の `removeKeyFromMap()` 関数
<a name="opencypher-compliance-removeKeyFromMap-function"></a>

Neptune データベースと Neptune Analytics で使用できます。

Neptune は openCypher 仕様にはない `removeKeyFromMap()` 関数を実装しています。指定されたキーをマップから削除し、生成された新しいマップを返します。

関数は 2 つの引数を取ります。
+ 最初の引数は、キーを削除するマップです。
+ 2 番目の引数は、マップから削除するキーです。

`removeKeyFromMap()` 関数は、マップのリストを巻き戻して、ノードやリレーションシップの値を設定したい場合に特に便利です。例えば、次のようになります。

```
UNWIND [{`~id`: 'id1', name: 'john'}, {`~id`: 'id2', name: 'jim'}] as val
CREATE (n {`~id`: val.`~id`})
SET n = removeKeyFromMap(val, '~id')
```

## ノードとリレーションシッププロパティのカスタム ID 値
<a name="opencypher-compliance-custom-ids"></a>

Neptune データベース 1.2.0.2 以降、および Neptune Analytics で使用できます。

[エンジンリリース 1.2.0.2](engine-releases-1.2.0.2.md) 以降、Neptune は openCypher 仕様を拡張し、`CREATE`, `MERGE`, および `MATCH` 句でノードとリレーションシップの `id` 値を指定できるようになりました。これにより、システムによって生成された UUID の代わりに、ユーザーフレンドリーな文字列を割り当てて、ノードやリレーションシップを識別できるようになりました。

Neptune Analytics では、カスタム ID 値をエッジに使用することはできません。

**警告**  
`~id` は、現在、予約済みのプロパティ名と見なされているため、openCypher 仕様に対するこの拡張は下位互換性がありません。`~id` をデータやクエリで既にプロパティとして使用している場合、既存のプロパティを新しいプロパティキーに移行して、古いものを削除する必要があります。「[現在、`~id` をプロパティとして使用している場合の対処方法](#opencypher-compliance-custom-ids-migrating)」を参照してください。

カスタム ID を持つノードとリレーションシップを作成する方法の例を次に示します。

```
CREATE (n {`~id`: 'fromNode', name: 'john'})
  -[:knows {`~id`: 'john-knows->jim', since: 2020}]
  ->(m {`~id`: 'toNode', name: 'jim'})
```

既に使用されているカスタム ID を作成しようとすると、Neptune は `DuplicateDataException` エラーをスローします。

`MATCH` 句でカスタム ID を使用する例を次に示します。

```
MATCH (n {`~id`: 'id1'})
RETURN n
```

`MERGE` 句でカスタム ID を使用する例を次に示します。

```
MATCH (n {name: 'john'}), (m {name: 'jim'})
MERGE (n)-[r {`~id`: 'john->jim'}]->(m)
RETURN r
```

### 現在、`~id` をプロパティとして使用している場合の対処方法
<a name="opencypher-compliance-custom-ids-migrating"></a>

[エンジンリリース 1.2.0.2](engine-releases-1.2.0.2.md) では、openCypher 句の `~id` キーは、プロパティではなく `id` として扱われるようになりました。つまり、`~id` という名前のプロパティがある場合、アクセスできなくなるということです。

`~id` プロパティを使用している場合、エンジンリリース `1.2.0.2` 以降にアップグレードする前にしなければならないことは、まず、既存の `~id` プロパティを新しいプロパティキーに移行し、`~id` プロパティを削除することです。例えば、次のクエリは、
+ すべてのノードに「newId」という名前の新しいプロパティを作成します。
+ 「\$1id」プロパティの値を「newId」プロパティにコピーし、
+ データから「\$1id」プロパティを削除します。

```
MATCH (n)
WHERE exists(n.`~id`)
SET n.newId = n.`~id`
REMOVE n.`~id`
```

データ内の、`~id` プロパティのあるリレーションシップについても同じことを行う必要があります。

また、`~id` プロパティを参照するクエリを使用している場合は、すべて変更する必要があります。例えば、次のクエリは、

```
MATCH (n)
WHERE n.`~id` = 'some-value'
RETURN n
```

次のように変わります。

```
MATCH (n)
WHERE n.newId = 'some-value'
RETURN n
```

## Neptune での CALL サブクエリのサポート
<a name="call-subquery-support"></a>

 Neptune データベース 1.4.1.0 以降、および Neptune Analytics で使用できます。

 Amazon Neptune は `CALL` サブクエリをサポートしています。`CALL` サブクエリは、`CALL` サブクエリへの入力ごとに分離されたスコープで実行されるメインクエリの一部です。

 例えば、グラフに人物、それらの人物の友人、住んでいた都市に関するデータが含まれているとします。`CALL` サブクエリを使用して、誰かの各友人が住んでいた 2 つの最大の都市を取得できます。

```
MATCH (person:Person)-[:knows]->(friend) 
CALL { 
  WITH friend 
  MATCH (friend)-[:lived_in]->(city) 
  RETURN city 
  ORDER BY city.population DESC
  LIMIT 2 
} 
RETURN person, friend, city
```

 この例では、`CALL { ... }` 内のクエリ部分は、前述の MATCH 句に一致する各 `friend` に対して実行されます。内部クエリが実行されると、`ORDER` 句と `LIMIT` 句は特定の友人が住んでいた都市に対してローカルであるため、友人ごとに (最大で) 2 つの都市を取得します。

 すべてのクエリ句は `CALL` サブクエリ内で使用できます。これには、ネストされた `CALL` サブクエリも含まれます。最初の `WITH` 句と出力される変数にはいくつかの制限があり、以下で説明します。

### CALL サブクエリ内の変数の範囲
<a name="variable-scope-inside-call-subquery"></a>

 内部で使用される `CALL` サブクエリの前にある句の変数は、最初の `WITH` 句によってインポートする必要があります。通常の `WITH` 句とは異なり、変数のリストのみを配置することができますが、エイリアスは許可されず、`DISTINCT`、`ORDER BY`、`WHERE`、`SKIP`、または `LIMIT` と併用することはできません。

### CALL サブクエリから返される変数
<a name="variables-returned-call-subquery"></a>

 `CALL` サブクエリから出力される変数は、最後の `RETURN` 句で指定します。出力された変数は、`CALL` サブクエリの前にある変数と重複できないことに注意してください。

### 制限事項
<a name="call-subquery-limitations"></a>

 現時点では、`CALL` サブクエリ内の更新はサポートされていません。

## Neptune openCypher 関数
<a name="opencypher-compliance-new-functions"></a>

 Neptune データベース 1.4.1.0 以降、および Neptune Analytics で使用できます。

**textIndexOf**

 `textIndexOf(text :: STRING, lookup :: STRING, from = 0 :: INTEGER?, to = -1 :: INTEGER?) :: (INTEGER?)` 

 オフセット `from` (包含) からオフセット `to` (除外) までの `text` の範囲で `lookup` の最初の出現のインデックスを返します。`to` が -1 の場合、範囲は `text` の最後まで続きます。インデックス作成はゼロベースであり、Unicode スカラー値 (非代理コードポイント) で表されます。

```
RETURN textIndexOf('Amazon Neptune', 'e')
{
  "results": [{
      "textIndexOf('Amazon Neptune', 'e')": 8
    }]
}
```

**collToSet**

 `collToSet(values :: LIST OF ANY?) :: (LIST? OF ANY?)` 

 元のリストの一意の要素のみを含む新しいリストを返します。元のリストの順序は**維持**されます (例: `[1, 6, 5, 1, 5]` は `[1, 6, 5]` を返します)。

```
RETURN collToSet([1, 6, 5, 1, 1, 5])
{
  "results": [{
      "collToSet([1, 6, 5, 1, 1, 5])": [1, 6, 5]
    }]
}
```

**collSubtract**

 `collSubtract(first :: LIST OF ANY?, second :: LIST OF ANY?) :: (LIST? OF ANY?)` 

 `second` の要素を除く `first` のすべての一意の要素が含まれる新しいリストを返します。

```
RETURN collSubtract([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collSubtract([2, 5, 1, 0], [1, 5])": [0, 2]
    }]
}
```

**collIntersection**

 `collIntersection(first :: LIST? OF ANY?, second :: LIST? OF ANY?) :: (LIST? OF ANY?)` 

 `first` と `second` の交差のすべての一意の要素を含む新しいリストを返します。

```
RETURN collIntersection([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collIntersection([2, 5, 1, 0], [1, 5])": [1, 5]
    }]
}
```

## ソート関数
<a name="sorting-functions"></a>

 以下の各セクションでは、コレクションをソートする関数を定義します。これらの関数は (場合によってはオプションで) `config` マップ引数、またはソートキーやソート方向を定義する複数のマップのリストを取得します。

```
{ key: STRING, order: STRING }
```

 `key` は値がソートに使用されるマッププロパティまたはノードプロパティのいずれかです。`order` は「`asc`」または「`desc`」 (大文字と小文字は区別されません) であり、それぞれ昇順または降順のソートを指定します。デフォルトでは、ソートは昇順で実行されます。

**collSort**

 `collSort(coll :: LIST OF ANY, config :: MAP?) :: (LIST? OF ANY?)` 

 `coll` 入力リストから要素を含む新しいソート済みリストを返します。

```
RETURN collSort([5, 3, 1], {order: 'asc'})
{
  "results": [{
      "collSort([5, 3, 1])": [1, 3, 5]
    }]
}
```

**collSortMaps**

 `collSortMaps(coll :: LIST OF MAP, config :: MAP) :: (LIST? OF ANY?)` 

 指定された `key` プロパティの値でソートされたマップのリストを返します。

```
RETURN collSortMaps([{name: 'Alice', age: 25}, {name: 'Bob', age: 35}, {name: 'Charlie', age: 18}], {key: 'age', order: 'desc'})
{
  "results": [{
      "x": [{
          "age": 35,
          "name": "Bob"
        }, {
          "age": 25,
          "name": "Alice"
        }, {
          "age": 18,
          "name": "Charlie"
        }]
    }]
}
```

**collSortMulti**

```
collSortMulti(coll :: LIST OF MAP?, 
configs = [] :: LIST OF MAP, 
limit = -1 :: INTEGER?, 
skip = 0 :: INTEGER?) :: (LIST? OF ANY?)
```

 指定された `key` プロパティの値でソートされたマップのリストを返します。オプションで制限とスキップを適用します。

```
RETURN collSortMulti([{name: 'Alice', age: 25}, {name: 'Bob', age: 35}, {name: 'Charlie', age: 18}], [{key: 'age', order: 'desc'}, {key:'name'}]) as x
{
  "results": [{
      "x": [{
          "age": 35,
          "name": "Bob"
        }, {
          "age": 25,
          "name": "Alice"
        }, {
          "age": 18,
          "name": "Charlie"
        }]
    }]
}
```

**collSortNodes**

 `collSortNodes(coll :: LIST OF NODE, config :: MAP) :: (LIST? OF NODE?)` 

 `coll` 入力リストのソートされたバージョンを返し、ノード要素をそれぞれの `key` プロパティの値でソートします。

```
create (n:person {name: 'Alice', age: 23}), (m:person {name: 'Eve', age: 21}), (o:person {name:'Bob', age:25})
{"results":[]}

match (n:person) with collect(n) as people return collSortNodes(people, {key: 'name', order: 'desc'})
{
  "results": [{
      "collSortNodes(people, 'name')": [{
          "~id": "e599240a-8c23-4337-8aa8-f603c8fb5488",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 21,
            "name": "Eve"
          }
        }, {
          "~id": "8a6ef785-59e3-4a0b-a0ff-389655a9c4e6",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 25,
            "name": "Bob"
          }
        }, {
          "~id": "466bc826-f47f-452c-8a27-6b7bdf7ae9b4",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 23,
            "name": "Alice"
          }
        }]
    }]
}

match (n:person) with collect(n) as people return collSortNodes(people, {key: 'age'})
{
  "results": [{
      "collSortNodes(people, '^age')": [{
          "~id": "e599240a-8c23-4337-8aa8-f603c8fb5488",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 21,
            "name": "Eve"
          }
        }, {
          "~id": "466bc826-f47f-452c-8a27-6b7bdf7ae9b4",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 23,
            "name": "Alice"
          }
        }, {
          "~id": "8a6ef785-59e3-4a0b-a0ff-389655a9c4e6",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 25,
            "name": "Bob"
          }
        }]
    }]
}
```

## 時間関数
<a name="temporal-functions"></a>

 一時関数は Neptune バージョン [1.4.5.0](https://docs.aws.amazon.com/releases/release-1.4.5.0.xml) 以降で使用できます。

### day
<a name="temporal-functions-day"></a>

 `day(temporal :: (datetime | date)) :: (LONG)` 

 `datetime` または `date` の値から月の `day` を返します。`datetime` の場合: 値は、日を抽出する前に入力に基づいて UTC に正規化されます。`date` の場合: 日はタイムゾーンに基づいて抽出されます。

 `datetime` 入力は Neptune データベースと Neptune Analytics の両方で使用できます。

```
RETURN day(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "day(datetime('2021-06-03T01:48:14Z'))": 3
    }]
}
```

 ここで、`datetime` は UTC に正規化されるため、\$108:00 は 6 月 2 日に戻ります。

```
RETURN day(datetime('2021-06-03T00:00:00+08:00'))
{
  "results": [{
      "day(datetime('2021-06-03T00:00:00+08:00'))": 2
    }]
}
```

 `date` 入力は Neptune Analytics でのみ使用できます。

```
RETURN day(date('2021-06-03Z'))
{
  "results": [{
      "day(date('2021-06-03Z'))": 3
    }]
}
```

 `date` はタイムゾーンを保持し、6 月 3 日を維持します。

```
RETURN day(date('2021-06-03+08:00'))
{
  "results": [{
      "day(date('2021-06-03+08:00'))": 3
    }]
}
```

### month
<a name="temporal-functions-month"></a>

 `month(temporal :: (datetime | date)) :: (LONG)` 

 `datetime` または `date` の値 (1～12) から月を返します。`datetime` の場合: 値は月を抽出する前に入力に基づいて UTC に正規化されます。`date` の場合: 月はタイムゾーンに基づいて抽出されます。

 `datetime` 入力は Neptune データベースと Neptune Analytics の両方で使用できます。

```
RETURN month(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "month(datetime('2021-06-03T01:48:14Z'))": 6
    }]
}
```

 ここで、`datetime` は UTC に正規化されるため、\$108:00 は 5 月 31 日に戻ります。

```
RETURN month(datetime('2021-06-01T00:00:00+08:00'))
{
  "results": [{
      "month(datetime('2021-06-01T00:00:00+08:00'))": 5
    }]
}
```

 `date` 入力は Neptune Analytics でのみ使用できます。

```
RETURN month(date('2021-06-03Z'))
{
  "results": [{
      "month(date('2021-06-03Z'))": 6
    }]
}
```

 `date` はタイムゾーンを保持し、6 月 1 日を維持します。

```
RETURN month(date('2021-06-01+08:00'))
{
  "results": [{
      "month(date('2021-06-01+08:00'))": 6
    }]
}
```

### year
<a name="temporal-functions-year"></a>

 `year(temporal :: (datetime | date)) :: (LONG)` 

 `datetime` または `date` の値から年を返します。`datetime` の場合: 値は年を抽出する前に入力に基づいて UTC に正規化されます。`date` の場合: 年はタイムゾーンに基づいて抽出されます。

 `datetime` 入力は Neptune データベースと Neptune Analytics の両方で使用できます。

```
RETURN year(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "year(datetime('2021-06-03T01:48:14Z'))": 2021
    }]
}
```

 ここで、`datetime` は UTC に正規化されるため、\$108:00 は 2020 年 12 月 31 日に戻ります。

```
RETURN year(datetime('2021-01-01T00:00:00+08:00'))
{
  "results": [{
      "year(datetime('2021-01-01T00:00:00+08:00'))": 2020
    }]
}
```

 `date` 入力は Neptune Analytics でのみ使用できます。

```
RETURN year(date('2021-06-03Z'))
{
  "results": [{
      "year(date('2021-06-03Z'))": 2021
    }]
}
```

 `date` はタイムゾーンを保持し、2021 年 6 月を維持します。

```
RETURN year(date('2021-01-01+08:00'))
{
  "results": [{
      "year(date('2021-01-01+08:00'))": 2021
    }]
}
```

### Neptune openCypher 関数
<a name="openCypher-functions"></a>

 Neptune データベース 1.4.6.0 以降、および Neptune Analytics で使用できます。

#### reduce()
<a name="openCypher-functions-reduce"></a>

 削減は、実行中の合計または「アキュムレータ」と組み合わせることで、各リスト要素を順次処理します。初期値から始めて、各オペレーションの後にアキュムレータを更新し、その更新された値を次のイテレーションで使用します。

 `for i in (0, ..., n) acc = acc X list[I], where X denotes any binary operator` 

 すべての要素が処理されると、最終的な累積結果が返されます。

 一般的な reduce() 構造 – `reduce(accumulator = initial , variable IN list | expression)` 

**タイプ仕様:**  
 `- initial: starting value for the accumulator :: (Long | FLOAT | STRING | LIST? OF (STRING, LONG, FLOAT)) - list: the input list :: LIST OF T where T matches initial type - variable :: represents each element in the input list - expression :: Only supports '+' and '*' operator - return :: Same type as initial ` 

**制限:**  
 現在、`reduce()` 式は次の対象のみをサポートしています。
+  数値乗算 
+  数値の追加 
+  文字列の連結 
+  リストの連結 

 これらは `+` または `*` の演算子で表されます。式は、以下に示すようにバイナリ式であることが必要 – `expression pattern: accumulator + any variable or accumulator * any variable` 

**オーバーフロー処理:**  
 Neptune は `reduce()` の評価中に数値オーバーフローを検出し、データ型に基づいて異なる応答を行います。

```
LONG (signed 64‑bit)
--------------------
• Valid range: –9 223 372 036 854 775 808 … 9 223 372 036 854 775 807  
• If any intermediate or final value falls outside this range,
  Neptune aborts the query with long overflow error message.
  
FLOAT (IEEE‑754 double)
-----------------------
• Largest finite value ≈ 1.79 × 10^308  
• Larger results overflow to INF
  Once `INF` is produced, it propagates through the remainder
  of the reduction.
```

**例:**  
reduce() 関数については、次の例を参照してください。

```
1. Long Addition:
RETURN reduce(sum = 0, n IN [1, 2, 3] | sum + n)
{
  "results": [{
      "reduce(sum = 0, n IN [1, 2, 3] | sum + n)": 6
    }]
}

2. String Concatenation:
RETURN reduce(str = "", x IN ["A", "B", "C"] | str + x) 
{
  "results": [{
      "reduce(str = "", x IN ["A", "B", "C"] | str + x)": "ABC"
    }]
}

3. List Combination:
RETURN reduce(lst = [], x IN [1, 2, 3] | lst + x)
{
  "results": [{
      "reduce(lst = [], x IN [1, 2, 3] | lst + x)": [1, 2, 3]
    }]
}

4. Float Addition:
RETURN reduce(total = 0.0, x IN [1.5, 2.5, 3.5] | total + x) 
{
  "results": [{
      "reduce(total = 0.0, x IN [1.5, 2.5, 3.5] | total + x)": 7.5
    }]
}

5. Long Multiplication:
RETURN reduce(product = 1, n IN [1, 2, 3] | product * n)
{
  "results": [{
      "reduce(product = 0, n IN [1, 2, 3] | product * n)": 6
    }]
}

6. Float Multiplication:
RETURN reduce(product = 1.0, n IN [1.5, 2.5, 3.5] | product * n)
{
  "results": [{
      "reduce(product = 1.0, n IN [1.5, 2.5, 3.5] | product * n)": 13.125
    }]
}

7. Long Overflow (Exception):
RETURN reduce(s = 9223372036854775807, x IN [2, 3] | s * x) AS result
{
"results": [{
    "reduce(s = 9223372036854775807, x IN [2, 3] | s * x) AS result": long overflow
    }]
}

8. Float Overflow:
RETURN reduce(s = 9.0e307, x IN [8.0e307, 1.0e307] | s + x) AS result
{
"results": [{
    "reduce(s = 9.0e307, x IN [8.0e307, 1.0e307] | s + x) AS result": INF
    }]
}
```

# neptune.read()
<a name="access-graph-opencypher-21-extensions-s3-read"></a>

 Neptune は、Amazon S3 からデータ`neptune.read`を読み取ってから、データを使用して openCypher クエリ (読み取り、挿入、更新) を実行する`CALL`手順をサポートしています。プロシージャは、ファイル内の各行を宣言された結果変数行として生成します。呼び出し元の IAM 認証情報を使用して Amazon S3 のデータにアクセスします。アクセス許可を設定するには[neptune.read() のアクセス許可の管理](access-graph-opencypher-21-extensions-s3-read-permissions.md)、「」を参照してください。Amazon S3 バケットの AWS リージョンは、インスタンスが配置されているのと同じリージョンにある必要があります。現在、クロスリージョン読み取りはサポートされていません。

 **[Syntax]** (構文) 

```
CALL neptune.read(
  {
    source: "string",
    format: "parquet/csv",
    concurrency: 10
  }
)
YIELD row
...
```

**入力**
+  **source** (必須) - 1 **つの**オブジェクトへの Amazon S3 URI。複数のオブジェクトに対する Amazon S3 プレフィックスはサポートされていません。
+  **format** (必須) - `parquet`および `csv`がサポートされています。
  +  サポートされている Parquet 形式の詳細については、「」を参照してください[サポートされている Parquet 列タイプ](access-graph-opencypher-21-extensions-s3-read-parquet.md#access-graph-opencypher-21-extensions-s3-read-parquet-column-types)。
  +  サポートされている csv 形式の詳細については、「」を参照してください[openCypher データのロード形式](bulk-load-tutorial-format-opencypher.md)。
+  **concurrency** (オプション) - タイプ: 0 以上の整数。デフォルト: 0。ファイルの読み取りに使用するスレッドの数を指定します。値が 0 の場合、リソースで許可されるスレッドの最大数が使用されます。Parquet では、多数の行グループに設定することをお勧めします。

**アウトプット**

 neptune.read は以下を返します。
+  **行** - type:Map 
  +  ファイル内の各行。キーは列、値は各列にあるデータです。
  +  プロパティアクセス () のように、各列のデータにアクセスできます`row.col`。

## neptune.read() のベストプラクティス
<a name="access-graph-opencypher-21-extensions-s3-read-best-practices"></a>

Neptune S3 の読み取りオペレーションはメモリを大量に消費する可能性があります。[Amazon Neptune のインスタンスタイプの選択」で説明されているように、本稼働ワークロードに適したインスタンスタイプ](instance-types.md)を使用してください。

`neptune.read()` リクエストのメモリ使用量とパフォーマンスは、ファイルサイズ、列数、行数、ファイル形式など、さまざまな要因の影響を受けます。構造によっては、小さいファイル (100MB 以下の CSV ファイル、20MB 以下の Parquet ファイルなど) は、ほとんどの本番稼働用インスタンスタイプで確実に動作しますが、大きいファイルでは、小さいインスタンスタイプでは提供できない大量のメモリが必要になる場合があります。

この機能のテストでは、小さいファイルから始めて徐々にスケールし、読み取りワークロードがインスタンスサイズに対応できるようにすることをお勧めします。out-of-memory例外やインスタンスの再起動につながる`neptune.read()`リクエストに気付いた場合は、ファイルを小さなチャンクに分割し、ファイルの複雑さを軽減し、より大きなインスタンスタイプにアップグレードすることを検討してください。

# Parquet を使用したクエリの例
<a name="access-graph-opencypher-21-extensions-s3-read-parquet"></a>

次のクエリ例では、特定の Parquet ファイル内の行数を返します。

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
RETURN count(row)
```

 AWS CLI 次のコードを実行して、 の `execute-open-cypher-query`オペレーションを使用してクエリ例を実行できます。

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'parquet'}) YIELD row RETURN count(row)" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

クエリは、Parquet ファイルから読み取られた行に対して柔軟に処理できます。たとえば、次のクエリでは、Parquet ファイルにあるデータにフィールドが設定されているノードを作成します。

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**警告**  
`MATCH(n)` 句の前のような大きな結果生成`CALL`句を使用することはお勧めしません。これにより、以前の句からの受信ソリューションと neptune.read によって読み取られた行との積が交差するため、クエリの実行時間が長くなります。neptune.read `CALL` でクエリを開始することをお勧めします。

## サポートされている Parquet 列タイプ
<a name="access-graph-opencypher-21-extensions-s3-read-parquet-column-types"></a>

**Parquet データ型:**
+ NULL
+ BOOLEAN
+ FLOAT
+ DOUBLE
+ STRING
+ 符号付き整数: UINT8, UINT16, UINT32, UINT64
+ MAP: は 1 つのレベルのみをサポートします。ネストされた はサポートされていません。
+ LIST: は 1 つのレベルのみをサポートします。ネストされた はサポートされていません。

**Neptune 固有のデータ型:**

CSV 形式のプロパティ列ヘッダーとは異なり、Parquet 形式のプロパティ列ヘッダーにはプロパティ名のみが必要なため、型名や基数は必要ありません。

ただし、Parquet 形式では、Any type、Date type、dateTime type、Geometry type など、メタデータに注釈を必要とする特殊な列タイプがいくつかあります。次のオブジェクトは、これらの特殊なタイプの列を含むファイルに必要なメタデータ注釈の例です。

```
"metadata": {
    "anyTypeColumns": ["UserCol1"],
    "dateTypeColumns": ["UserCol2"],
    "dateTimeTypeColumns": ["UserCol3"],
    "geometryTypeColumns": ["UserCol4"]
}
```

以下は、これらのタイプに関連する予想されるペイロードの詳細です。
+ 列タイプ 任意の はユーザー列でサポートされています。Any 型は、サポートされている他のすべてのタイプの「構文シュガー」型です。ユーザー列に複数のタイプがある場合に非常に便利です。Any type 値のペイロードは、json 文字列のリストです: `{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`。各 json 文字列に値フィールドと type フィールドがあります。Any 列の基数値が設定されます。つまり、列は複数の値を受け入れることができます。
  + Neptune は、任意のタイプで次のタイプをサポートしています: Bool (またはブール値）、Byte、Short、Int、Long、UnsignedByte、UnsignedShort、UnsignedInt、UnsignedLong、Float、Double、Date、dateTime、String、Geometry。
  + ベクトルタイプは、どのタイプでもサポートされていません。
  + ネスト すべてのタイプはサポートされていません。例えば、`{"value": {"value": "10", "type": "Int"}, "type": "Any"}`。
+ Date および Datetime タイプの列は、ユーザー列でサポートされています。これらの列のペイロードは、XSD 形式または以下のいずれかの形式に従って文字列として指定する必要があります。
  + yyyy-MM-dd
  + yyyy-MM-ddTHH:mm
  + yyyy-MM-ddTHH:mm:ss
  + yyyy-MM-ddTHH:mm:ssZ
  + yyyy-MM-ddTHH:mm:ss.SSSZ
  + yyyy-MM-ddTHH:mm:ss[\$1\$1-]hhmm
  + yyyy-MM-ddTHH:mm:ss.SSS[\$1\$1-]hhmm
+ ジオメトリ列タイプは、ユーザー列でサポートされています。これらの列のペイロードには、Well-known text (WKT) 形式の文字列として提供される Point 型のジオメトリプリミティブのみを含める必要があります。たとえば、POINT (30 10) は有効なジオメトリ値になります。

## サンプル parquet 出力
<a name="sample-parquet-output"></a>

次のような Parquet ファイルがあるとします。

```
<s3 path>

Parquet Type:
    int8     int16       int32             int64              float      double    string
+--------+---------+-------------+----------------------+------------+------------+----------+
|   Byte |   Short |       Int   |                Long  |     Float  |    Double  | String   |
|--------+---------+-------------+----------------------+------------+------------+----------|
|   -128 |  -32768 | -2147483648 | -9223372036854775808 |    1.23456 |    1.23457 | first    |
|    127 |   32767 |  2147483647 |  9223372036854775807 |  nan       |  nan       | second   |
|      0 |       0 |           0 |                    0 | -inf       | -inf       | third    |
|      0 |       0 |           0 |                    0 |  inf       |  inf       | fourth   |
+--------+---------+-------------+----------------------+------------+------------+----------+
```

次のクエリを使用して neptune.read から返される出力の例を次に示します。

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'parquet'}) YIELD row RETURN row" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

```
{
 "results": [{
 "row": {
 "Float": 1.23456,
 "Byte": -128,
 "Int": -2147483648,
 "Long": -9223372036854775808,
 "String": "first",
 "Short": -32768,
 "Double": 1.2345678899999999
 }
 }, {
 "row": {
 "Float": "NaN",
 "Byte": 127,
 "Int": 2147483647,
 "Long": 9223372036854775807,
 "String": "second",
 "Short": 32767,
 "Double": "NaN"
 }
 }, {
 "row": {
 "Float": "-INF",
 "Byte": 0,
 "Int": 0,
 "Long": 0,
 "String": "third",
 "Short": 0,
 "Double": "-INF"
 }
 }, {
 "row": {
 "Float": "INF",
 "Byte": 0,
 "Int": 0,
 "Long": 0,
 "String": "fourth",
 "Short": 0,
 "Double": "INF"
 }
 }]
}
```

現在、Parquet ファイルからのデータフィールドにノードまたはエッジラベルを設定する方法はありません。クエリは、ラベル/タイプごとに 1 つずつ、複数のクエリに分割することをお勧めします。

```
CALL neptune.read({source: '<s3 path>', format: 'parquet'})
 YIELD row 
WHERE row.`~label` = 'airport'
CREATE (n:airport)

CALL neptune.read({source: '<s3 path>', format: 'parquet'})
YIELD row 
WHERE row.`~label` = 'country'
CREATE (n:country)
```

# CSV を使用したクエリの例
<a name="access-graph-opencypher-21-extensions-s3-read-csv"></a>

この例では、クエリは特定の CSV ファイル内の行数を返します。

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
RETURN count(row)
```

クエリの例は、次のコード AWS CLI を実行して、 の execute-open-cypher-query オペレーションを使用して実行できます。

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'csv'}) YIELD row RETURN count(row)" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

クエリは、CSV ファイルから読み取られた行に対して柔軟に処理できます。たとえば、次のクエリは、CSV ファイルからデータに設定されたフィールドを持つノードを作成します。

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**警告**  
CALL 句の前に MATCH(n) のような大きな結果生成句を使用することはお勧めしません。これにより、以前の句からの受信ソリューションと neptune.read によって読み取られた行との積が交差するため、クエリの実行時間が長くなります。CALL neptune.read を使用してクエリを開始することをお勧めします。

## プロパティ列ヘッダー
<a name="property-column-headers"></a>

次の構文を使用して、プロパティ列 (`:`) を指定できます。タイプ名では大文字と小文字が区別されません。プロパティ名内にコロンが表示される場合は、コロンの前にバックスラッシュ を付けてエスケープする必要があります`\:`。

```
propertyname:type
```

**注記**  
列ヘッダーでは、スペース、カンマ、キャリッジリターン、改行文字は使用できません。そのため、プロパティ名にこれらの文字を使用することはできません。
タイプに `[]` を追加することで、配列型の列を指定できます。  

  ```
                          propertyname:type[]
  ```
エッジのプロパティに指定できるのは 1 つの値のみです。配列型が指定された場合や 2 つ目の値が指定された場合はエラーが発生します。次の例は、Int 型の age という名前のプロパティの列ヘッダーを示しています。  

  ```
  age:Int
  ```

ファイルのすべての行は、その位置に整数があるか、空のままにする必要があります。文字列の配列は許可されますが、バックスラッシュ (`;`) を使用してエスケープしない限り、配列内の文字列にセミコロン () 文字を含めることはできません`\;`。

## サポートされている CSV 列タイプ
<a name="supported-csv-column-types"></a>
+ **BOOL (または BOOLEAN)** - 使用できる値: true、false。ブールフィールドであることを示しています。true 以外の値は false として扱われます。
+ **FLOAT** - 範囲: Infinity、INF、-Infinity、-INF、NaN (not-a-number) を含む 32 ビット IEEE 754 浮動小数点。
+ **DOUBLE** - 範囲: Infinity、INF、-Infinity、-INF、NaN (not-a-number) を含む 64 ビット IEEE 754 浮動小数点。
+ **STRING** - 
  + 引用符はオプションです。カンマ、改行、キャリッジリターン文字は、二重引用符 (") で囲まれた文字列に含まれている場合、自動的にエスケープされます。例: "Hello, World"。
  + 引用符を引用文字列に含めるには、例：「Hello "World"」の 2 つの文字列を使用して引用符をエスケープします。
  + 文字列の配列は許可されますが、バックスラッシュ (\$1;) を使用してエスケープしない限り、配列内の文字列にセミコロン (;) 文字を含めることはできません。
  + 配列内の文字列を引用符で囲む場合は、配列全体を 1 組の引用符で囲む必要があります。例：「文字列 1、文字列 2、文字列 3」。
+ **DATE、DATETIME** - 日時値は、XSD 形式、または次のいずれかの形式で指定できます。
  + yyyy-MM-dd
  + yyyy-MM-ddTHH:mm
  + yyyy-MM-ddTHH:mm:ss
  + yyyy-MM-ddTHH:mm:ssZ
  + yyyy-MM-ddTHH:mm:ss.SSSZ
  + yyyy-MM-ddTHH:mm:ss[\$1\$1-]hhmm
  + yyyy-MM-ddTHH:mm:ss.SSS[\$1\$1-]hhmm
+ **署名された整数** - 
  + バイト: -128～127
  + ショート: -32768～32767
  + Int: -2^31 から 2^31-1
  + ロング: -2^63 から 2^63-1

**Neptune 固有の列タイプ:**
+ 列タイプ 任意の はユーザー列でサポートされています。Any 型は、サポートされている他のすべてのタイプの「構文シュガー」型です。ユーザー列に複数のタイプがある場合に非常に便利です。Any type 値のペイロードは、json 文字列のリストです: `{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`。各 json 文字列に値フィールドと type フィールドがあります。Any タイプの列ヘッダーは propertyname:Any です。Any 列の基数値が設定されます。つまり、列は複数の値を受け入れることができます。
  + Neptune は、任意のタイプで次のタイプをサポートしています: Bool (またはブール値）、Byte、Short、Int、Long、UnsignedByte、UnsignedShort、UnsignedInt、UnsignedLong、Float、Double、Date、dateTime、String、Geometry。
  + ベクトルタイプは、どのタイプでもサポートされていません。
  + ネスト すべてのタイプはサポートされていません。例えば、`{"value": {"value": "10", "type": "Int"}, "type": "Any"}`。
+ ジオメトリ列タイプは、ユーザー列でサポートされています。これらの列のペイロードには、Well-known text (WKT) 形式の文字列として提供される Point 型のジオメトリプリミティブのみを含める必要があります。たとえば、POINT (30 10) は有効なジオメトリ値になります。

## サンプル CSV 出力
<a name="sample-csv-output"></a>

次の CSV ファイルがあるとします。

```
<s3 path>
colA:byte,colB:short,colC:int,colD:long,colE:float,colF:double,colG:string
-128,-32768,-2147483648,-9223372036854775808,1.23456,1.23457,first
127,32767,2147483647,9223372036854775807,nan,nan,second
0,0,0,0,-inf,-inf,third
0,0,0,0,inf,inf,fourth
```

この例では、次のクエリを使用して neptune.read から返される出力を示しています。

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'csv'}) YIELD row RETURN row" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

```
{
  "results": [{
      "row": {
        "colD": -9223372036854775808,
        "colC": -2147483648,
        "colE": 1.23456,
        "colB": -32768,
        "colF": 1.2345699999999999,
        "colG": "first",
        "colA": -128
      }
    }, {
      "row": {
        "colD": 9223372036854775807,
        "colC": 2147483647,
        "colE": "NaN",
        "colB": 32767,
        "colF": "NaN",
        "colG": "second",
        "colA": 127
      }
    }, {
      "row": {
        "colD": 0,
        "colC": 0,
        "colE": "-INF",
        "colB": 0,
        "colF": "-INF",
        "colG": "third",
        "colA": 0
      }
    }, {
      "row": {
        "colD": 0,
        "colC": 0,
        "colE": "INF",
        "colB": 0,
        "colF": "INF",
        "colG": "fourth",
        "colA": 0
      }
    }]
}
```

現在、CSV ファイルからのデータフィールドにノードまたはエッジラベルを設定する方法はありません。クエリは、ラベル/タイプごとに 1 つずつ、複数のクエリに分割することをお勧めします。

```
CALL neptune.read({source: '<s3 path>', format: 'csv'})
 YIELD row 
WHERE row.`~label` = 'airport'
CREATE (n:airport)

CALL neptune.read({source: '<s3 path>', format: 'csv'})
YIELD row 
WHERE row.`~label` = 'country'
CREATE (n:country)
```

# neptune.read() のアクセス許可の管理
<a name="access-graph-opencypher-21-extensions-s3-read-permissions"></a>

## 必要な IAM ポリシー
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-iam"></a>

を使用する openCypher クエリを実行するには`neptune.read()`、Neptune データベースのデータにアクセスするための適切なアクセス許可が必要です。読み取り専用クエリには `ReadDataViaQuery`アクションが必要です。データを変更するクエリでは、`WriteDataViaQuery`挿入または削除が必要です`DeleteDataViaQuery`。次の の例では、指定されたクラスターに対する 3 つのアクションすべてを許可します。

さらに、データファイルを含む S3 バケットにアクセスするためのアクセス許可が必要です。NeptuneS3Access ポリシーステートメントは、必要な S3 アクセス許可を付与します。
+ **`s3:ListBucket`**: バケットの存在を検証し、コンテンツを一覧表示するために必要です。
+ **`s3:GetObject`**: コンテンツを openCypher クエリに統合するために読み取ることができるように、指定されたオブジェクトにアクセスするために必要です。

S3 バケットが でサーバー側の暗号化を使用している場合は AWS KMS、KMS アクセス許可も付与する必要があります。NeptuneS3KMSAccess ポリシーステートメントにより、Neptune は暗号化された S3 オブジェクトにアクセスするときにデータを復号し、データキーを生成できます。この条件は、リージョン内の S3 および RDS サービスから送信されるリクエストに KMS オペレーションを制限します。
+ **`kms:Decrypt`**: Neptune がデータを読み取ることができるように、暗号化されたオブジェクトの復号を実行するために必要です。
+ **`kms:GenerateDataKey`**: 読み取り対象のオブジェクトを取得するために使用される S3 API でも必要です。

```
{
  "Sid": "NeptuneQueryAccess",
  "Effect": "Allow",
  "Action": [
      "neptune-db:ReadDataViaQuery",
      "neptune-db:WriteDataViaQuery",
      "neptune-db:DeleteDataViaQuery"
  ],
  "Resource": "arn:aws:neptune-db:<REGION>:<AWS_ACCOUNT_ID>:<CLUSTER_RESOURCE_ID>/*"
},
{
  "Sid": "NeptuneS3Access",
  "Effect": "Allow",
  "Action": [
      "s3:ListBucket",
      "s3:GetObject"
  ],
  "Resource": [
      "arn:aws:s3:::neptune-read-bucket",
      "arn:aws:s3:::neptune-read-bucket/*"
  ]
},
{
  "Sid": "NeptuneS3KMSAccess",
  "Effect": "Allow",
  "Action": [
      "kms:Decrypt",
      "kms:GenerateDataKey"
  ],
  "Resource": "arn:aws:kms:<REGION>:<AWS_ACCOUNT_ID>:key/<KEY_ID>",
  "Condition": {
      "StringEquals": {
        "kms:ViaService": [
            "s3.<REGION>.amazonaws.com",
            "rds.<REGION>.amazonaws.com"
        ]
      }
  }
}
```

## インポートの前提条件
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-prerequisites"></a>

これらのアクセス許可と前提条件により、適切なアクセスコントロールとデータ保護対策を維持しながら、S3 データを openCypher クエリに安全かつ確実に統合できます。
+ **IAM 認証**: この機能は、IAM 認証が有効になっている Neptune クラスターでのみサポートされています。IAM 認証対応クラスターを作成して接続する方法の詳細については、[Amazon Neptune データベースの保護](security.md)」を参照してください。
+ **VPC エンドポイント**:
  + Neptune が Amazon S3 と通信できるようにするには、Amazon S3 のゲートウェイタイプの VPC エンドポイントが必要です。
  + クエリでカスタム AWS KMS 暗号化を使用するには、Neptune が と通信できるようにするには、 のインターフェイスタイプの VPC エンドポイント AWS KMS が必要です AWS KMS。
  + このエンドポイントの設定方法の詳細については、[Amazon S3 VPC エンドポイントの作成](bulk-load-tutorial-IAM.md)」を参照してください。

# 空間データ
<a name="access-graph-opencypher-22-spatial-data"></a>

Amazon Neptune は空間クエリをサポートするようになり、グラフにジオメトリデータを保存および分析できるようになりました。地理的位置 (マップ上の座標など) に一般的に使用されますが、空間特徴は位置と近接性が重要な任意の 2 次元データで機能します。この機能を使用して、「この顧客から 5 マイル以内の店舗はどれですか？」、「このサービスエリアと交差するすべての配送ルートを見つける」、「この間取り図のどのコンポーネントが HVAC ゾーンと重複していますか？」などの質問に回答します。Neptune は、ポイント、ポリゴン、その他のジオメトリシェイプで動作する業界標準の空間型関数を使用して空間サポートを実装します。空間データをノードとエッジのプロパティとして保存し、空間関数を使用して距離を計算したり、ポイントが境界内にあるかどうかを確認したり、重複する領域を検索したりできます。これらはすべて openCypher クエリ内にあります。

**一般的なユースケース:**
+ **地理的アプリケーション**: ロケーションベースのレコメンデーション、ジオフェンシング、ルートプランニング、テリトリー分析
+ **施設とスペースの管理**: 間取り図のレイアウト、機器の配置、ゾーンカバレッジ
+ **ネットワークトポロジ**: 物理インフラストラクチャマッピング、カバレッジエリア、サービス境界
+ **設計と CAD**: 2D 設計におけるコンポーネントの配置、衝突検出、空間関係
+ **ゲーム開発**: キャラクターの配置、衝突検出、area-of-effectの計算

Amazon Neptune の空間型実装は、他のデータベースと同様に ISO/IEC 13249-3:2016 ディレクティブに従います。[空間関数](access-graph-opencypher-22-spatial-functions.md) は openCypher クエリ言語で使用できます。

## 座標系
<a name="access-graph-opencypher-22-spatial-data-coordinate-system"></a>

Neptune には、データベース全体に 1 つの空間参照識別子 (SRID) があります。座標系の同種性により、クエリ中のユーザーエラーが減少し、データベースのパフォーマンスが向上します。最初のリリース (1.4.7.0) では、SRID 0 とも呼ばれるデカルト座標系がサポートされています。

SRID 0 の Neptune 実装は、経度と緯度の値と互換性があります。を使用して `ST_DistanceSpheroid` WGS84/SRID 4326 に基づいて距離を計算します。

現在の実装では、3 次元座標の保存がサポートされています。Spatial Functions は現在、x 軸および y 軸 (2 次元) 座標の使用のみをサポートしています。z 軸座標は現在、使用可能な空間関数ではサポートされていません。

## 位置データの保存
<a name="storing-spatial-data"></a>

Geometry プロパティタイプを使用して、ノードとエッジに位置データを保存します。Well-Known Text (WKT) 形式からジオメトリ値を作成します。これは、地理的なシェイプをテキストとして表す標準的な方法です。たとえば、ポイントの場所を保存するには:

```
CREATE (n:airport {code: 'ATL', location: ST_GeomFromText('POINT (-84.4281 33.6367)')})
```

地理的座標を使用する場合、最初の引数 (x) は経度を表し、2 番目の引数 (y) は緯度を表します。これは、空間データベースで使用される標準の座標順序と ISO 19125 標準に従います。

**注記**  
 Neptune は、「ジオメトリ」と呼ばれる新しいデータ型をサポートするようになりました。ノードまたはエッジの Geometry プロパティは、 `ST_GeomFromText`関数を使用して WKT 文字列から作成できます。  
Neptune は、特殊な空間インデックスにポイントデータを自動的に保存して、空間型関数のパフォーマンスを向上させます。例えば、ポリゴン内のポイントを見つける`ST_Contains`ために使用される は、特殊な空間インデックスによって加速されます。  
[ ジオメトリの Well-Known Text 表現の Wikipedia ページ ](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry)

## 空間データを一括でロードする
<a name="loading-spatial-data-bulk"></a>

データを一括ロードする場合は、CSV ヘッダーでジオメトリタイプを指定します。Neptune は WKT 文字列を解析し、適切なジオメトリプロパティを作成します。

```
:ID,:LABEL,code:String,city:String,location:Geometry
21,airport,ATL,Atlanta,POINT (-84.42810059 33.63669968)
32,airport,ANC,Anchorage,POINT (-149.9960022 61.17440033)
43,airport,AUS,Austin,POINT (-97.66989899 30.19449997)
```

CSV 形式の詳細については、[openCypher bulk load format](bulk-load-tutorial-format-opencypher.md)」を参照してください。

## 空間データのクエリの実行
<a name="querying-spatial-data"></a>

次のクエリ例では、[エアルートデータセットを使用して](https://github.com/krlawrence/graph/tree/main/sample-data)、Neptune で空間関数を使用する方法を示します。

データに Geometry プロパティではなく個別の緯度プロパティと経度プロパティがある場合は、クエリ時にポイントに変換できます。特定のロケーションに最も近い 10 の空港を見つけます。

```
MATCH (a:airport)
WITH a, ST_GeomFromText('POINT (' + a.lon + ' ' + a.lat + ')') AS airportLocation
WITH a, airportLocation, ST_Distance(ST_GeomFromText('POINT (-84.4281 33.6367)'), airportLocation) AS distance
WHERE distance IS NOT NULL
RETURN a.code, a.city, distance
ORDER BY distance ASC
LIMIT 10
```

として保存されているロケーションがすでにある場合は`ST_Point`、それらのロケーション値を直接使用できます。

1.  プロパティの設定

   ```
   MATCH (a:airport)
   SET a.location = ST_GeomFromText('POINT (' + a.lon + ' ' + a.lat + ')')
   ```

1. ST\$1Distance を使用したクエリ:

   ```
   MATCH (a:airport)
   WHERE a.location IS NOT NULL
   WITH a, ST_Distance(ST_GeomFromText('POINT (-84.4281 33.6367)'), a.location) AS distance
   RETURN a.code, a.city, distance
   ORDER BY distance ASC
   LIMIT 10
   ```

### Bolt ドライバーの使用
<a name="querying-spatial-data-bolt"></a>

ほとんどのクエリメソッドは、ジオメトリ値を人間が読み取り可能な WKT 文字列として返します。Bolt ドライバーを使用している場合、ジオメトリ値は WKB (Well-Known Binary) 形式で返されます。WKB をアプリケーションの Geometry オブジェクトに変換します。

```
try (Session session = driver.session()) {
    Result result = session.run("MATCH (n:airport {code: 'ATL'}) RETURN n.location as geom");
    
    Record record = result.single();
    byte[] wkbBytes = record.get("geom").asByteArray();
    
    // Convert WKB to Geometry object using JTS library
    WKBReader wkbReader = new WKBReader();
    Geometry geom = wkbReader.read(wkbBytes);
}
```

# 空間関数
<a name="access-graph-opencypher-22-spatial-functions"></a>

Neptune openCypher では、ジオメトリデータ型を操作するために次の空間関数を使用できます。
+ [ST\$1Point](access-graph-opencypher-22-spatial-functions-st-point.md)
+ [ST\$1GeomFromText](access-graph-opencypher-22-spatial-functions-st-geomfromtext.md)
+ [ST\$1AsText](access-graph-opencypher-22-spatial-functions-st-astext.md)
+ [ST\$1GeometryType](access-graph-opencypher-22-spatial-functions-st-geometrytype.md)
+ [ST\$1Equals](access-graph-opencypher-22-spatial-functions-st-equals.md)
+ [ST\$1Contains](access-graph-opencypher-22-spatial-functions-st-contains.md)
+ [ST\$1Intersects](access-graph-opencypher-22-spatial-functions-st-intersect.md)
+ [ST\$1Distance](access-graph-opencypher-22-spatial-functions-st-distance.md)
+ [ST\$1DistanceSpheroid](access-graph-opencypher-22-spatial-functions-st-distancespheroid.md)
+ [ST\$1Envelope](access-graph-opencypher-22-spatial-functions-st-envelope.md)
+ [ST\$1Buffer](access-graph-opencypher-22-spatial-functions-st-buffer.md)

# ST\$1Point
<a name="access-graph-opencypher-22-spatial-functions-st-point"></a>

ST\$1Point は、入力座標値からポイントを返します。

**[Syntax]** (構文)

```
ST_Point(x, y, z)
```

**引数**
+ `x` - 最初の座標を表すデータ型 DOUBLE PRECISION の値。
+ `y` - 2 番目の座標を表すデータ型 DOUBLE PRECISION の値。
+ `z` - (オプション)

**座標順序**

地理的座標を使用する場合、最初の引数 (`x`) は**経度**を表し、2 番目の引数 (`y`) は**緯度**を表します。これは、空間データベースで使用される標準の座標順序と ISO 19125 標準に従います。

```
// Correct: longitude first, latitude second
ST_Point(-84.4281, 33.6367)  // Atlanta airport

// Incorrect: latitude first, longitude second
ST_Point(33.6367, -84.4281)  // This will return NaN in distance calculations
```

**有効な座標範囲**

地理的データの場合、座標が有効な範囲内にあることを確認します。
+ 経度 (`x`): -180～180
+ 緯度 (`y`): -90～90

これらの範囲外の座標は、 などの距離計算関数で使用すると `NaN` (数値ではない) を返します`ST_DistanceSpheroid`。

**戻り型**

サブタイプ POINT の GEOMETRY

*x* または *y* が null の場合、null が返されます。

**例**

次の は、入力座標からポイントジオメトリを構築します。

```
RETURN ST_Point(5.0, 7.0); 
POINT(5 7)
```

# ST\$1GeomFromText
<a name="access-graph-opencypher-22-spatial-functions-st-geomfromtext"></a>

ST\$1GeomFromText は、入力ジオメトリの WKT (Well-Known Text) 表現からジオメトリオブジェクトを作成します。

**[Syntax]** (構文)

```
ST_GeomFromText(wkt_string)
```

**引数**
+ `wkt_string` - ジオメトリの WKT 表現であるデータ型 STRING の値。

**戻り型**

GEOMETRY

wkt\$1string が null の場合、null が返されます。

wkt\$1string が有効でない場合、BadRequestException が返されます。

**例**

```
RETURN ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')             
POLYGON((0 0,0 1,1 1,1 0,0 0))
```

# ST\$1AsText
<a name="access-graph-opencypher-22-spatial-functions-st-astext"></a>

ST\$1AsText は、入力ジオメトリの WKT (Well-Known Text) 表現を返します。

**[Syntax]** (構文)

```
ST_AsText(geo)
```

**引数**
+ `geo` - データ型 GEOMETRY の値、または GEOMETRY に評価される式。

**戻り型**

STRING

geo が null の場合、null が返されます。

入力パラメータがジオメトリでない場合、BadRequestException が返されます。

結果が 64-KB STRING より大きい場合、エラーが返されます。

**例**

```
RETURN ST_AsText(ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))'))             
POLYGON((0 0,0 1,1 1,1 0,0 0))
```

# ST\$1GeometryType
<a name="access-graph-opencypher-22-spatial-functions-st-geometrytype"></a>

ST\$1GeometryType は、ジオメトリのタイプを文字列として返します。

**[Syntax]** (構文)

```
ST_GeometryType(geom)
```

**引数**
+ `geom` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。

**戻り型**

STRING

geom が null の場合、null が返されます。

入力パラメータがジオメトリでない場合、BadRequestException が返されます。

**例**

```
RETURN ST_GeometryType(ST_GeomFromText('LINESTRING(77.29 29.07,77.42 29.26,77.27 29.31,77.29 29.07)'));
ST_LineString
```

# ST\$1Equals
<a name="access-graph-opencypher-22-spatial-functions-st-equals"></a>

ST\$1Equals は、入力ジオメトリの 2D 射影がトポロジ的に等しい場合に true を返します。ジオメトリに等しいポイントセットがある場合、ジオメトリはトポロジ的に等しいと見なされます。トポロジ的に等しいジオメトリでは、この等価性を維持しながら頂点の順序が異なる場合があります。

**[Syntax]** (構文)

```
ST_Equals(geom1, geom2)
```

**引数**
+ `geom1` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。
+ `geom2` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。この値を *geom1* と比較して、*geom1* と等しいかどうかを判断します。

**戻り型**

BOOLEAN

*geom1* または *geom2* が null の場合、null が返されます。

geom1 または geom2 が Geometries でない場合、BadRequestException が返されます。

**例**

```
RETURN ST_Equals(
    ST_GeomFromText('POLYGON ((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 3,2 1,0 -3,-1 3))'));
false
```

次の は、2 つのライン文字列が幾何学的に等しいかどうかを確認します。

```
RETURN ST_Equals(
    ST_GeomFromText('LINESTRING (1 0, 10 0)'), 
    ST_GeomFromText('LINESTRING(1 0,5 0,10 0)'));
true
```

# ST\$1Contains
<a name="access-graph-opencypher-22-spatial-functions-st-contains"></a>

ST\$1Contains は、最初の入力ジオメトリの 2D 投影に、2 番目の入力ジオメトリの 2D 投影が含まれている場合に true を返します。ジオメトリ A は、B のすべてのポイントが A のポイントであり、内部に空の交差がない場合にジオメトリ B を含みます。ST\$1Contains(A, B) は ST\$1Within(B, A) と同等です。

**[Syntax]** (構文)

```
ST_Contains(geom1, geom2)
```

**引数**
+ `geom1` - GEOMETRY 型の値、または GEOMETRY 型に評価される式。
+ `geom2` - GEOMETRY 型の値、または GEOMETRY 型に評価される式。この値を *geom1* と比較して、*geom1* に含まれているかどうかを判断します。

**戻り型**

BOOLEAN

*geom1* または *geom2* が null の場合、null が返されます。

入力パラメータがジオメトリでない場合、BadRequestException が返されます。

**例**

```
RETURN ST_Contains(
    ST_GeomFromText('POLYGON((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 3,2 1,0 -3,-1 3))'));
false
```

# ST\$1Intersects
<a name="access-graph-opencypher-22-spatial-functions-st-intersect"></a>

ST\$1Intersects は、2 つの入力ジオメトリの 2D 射影が少なくとも 1 つの共通したポイントを持つ場合、true を返します。

**[Syntax]** (構文)

```
ST_Intersects(geom1, geom2)
```

**引数**
+ `geom1` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。
+ `geom2` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。

**戻り型**

BOOLEAN

*geom1* または *geom2* が null の場合、null が返されます。

入力パラメータがジオメトリでない場合、BadRequestException が返されます。

**例**

```
RETURN ST_Intersects(
    ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(2 2,2 5,5 5,5 2,2 2))'), 
    ST_GeomFromText('MULTIPOINT((4 4),(6 6))'));
true
```

# ST\$1Distance
<a name="access-graph-opencypher-22-spatial-functions-st-distance"></a>

入力がジオメトリの場合、ST\$1Distance は 2 つのジオメトリの 2D 射影による値の間で、最短のユークリッド距離を返します。

**[Syntax]** (構文)

```
ST_Distance(geo1, geo2)
```

**引数**
+ `geo1` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。
+ `geo2` - データ型 GEOMETRY の値、または GEOMETRY に評価される式。

**戻り型**

入力ジオメトリと同じ単位の DOUBLE PRECISION。

geo1 または geo2 が null の場合、null が返されます。

入力パラメータがジオメトリでない場合、BadRequestException が返されます。

**例**

```
RETURN ST_Distance(
    ST_GeomFromText('POLYGON((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 -3,-2 -1,0 -3,-1 -3))'));
1.4142135623731
```

# ST\$1DistanceSpheroid
<a name="access-graph-opencypher-22-spatial-functions-st-distancespheroid"></a>

2 つの lon/lat ジオメトリ間の最小距離をメートル単位で返します。スフェロイドは WGS84/SRID 4326 です。

**[Syntax]** (構文)

```
ST_DistanceSpheroid(geom1, geom2);
```

**引数**
+ `geom1` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。
+ `geom2` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。

**戻り型**

FLOAT

geom が null の場合、null が返されます。

**例**

```
RETURN ST_DistanceSpheroid(
    ST_GeomFromText('POINT(-110 42)'),
    ST_GeomFromText('POINT(-118 38)'))
814278.77
```

# ST\$1Envelope
<a name="access-graph-opencypher-22-spatial-functions-st-envelope"></a>

ST\$1Envelope は、次のように、入力ジオメトリの最小の境界ボックスを返します。
+ 入力ジオメトリが空の場合、返されるジオメトリは POINT EMPTY になります。
+ 入力ジオメトリの最小の境界ボックスに含まれるのが 1 つのポイントのみの場合、返されるジオメトリは 1 つのポイントです。
+ 上記のいずれも当てはまらない場合、関数は、頂点が最小境界ボックスの角であるcounter-clockwise-orientedゴンを返します。

空でないすべての入力に対して、この関数は入力ジオメトリの 2D 射影を処理します。

**[Syntax]** (構文)

```
ST_Envelope(geom)
```

**引数**
+ `geom` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。

**戻り型**

GEOMETRY

geom が null の場合、null が返されます。

**例**

```
RETURN ST_Envelope(ST_GeomFromText("POLYGON ((2 1, 4 3, 6 1, 5 5, 3 4, 2 1))"))
POLYGON ((2 1, 6 1, 6 5, 2 5, 2 1))
```

# ST\$1Buffer
<a name="access-graph-opencypher-22-spatial-functions-st-buffer"></a>

ST\$1Buffer は、xy-デカルト平面に投影された入力ジオメトリからの距離が入力距離以下であるすべてのポイントを表す 2D ジオメトリを返します。

**[Syntax]** (構文)

```
ST_Buffer(geom, distance, number_of_segments_per_quarter_circle)
```

**引数**
+ `geom` - データ型 GEOMETRY の値、または GEOMETRY 型に評価される式。
+ `distance` - バッファの距離 (または半径) を表すデータ型 DOUBLE PRECISION の値。
+ `number_of_segments_per_quarter_circle` - データ型 INTEGER の値 (0 以上である必要があります）。この値は、入力ジオメトリの各頂点の周りの四分円を近似するためのポイントの数を決定します。負の値はデフォルトでゼロになります。デフォルトは 8 です。

**戻り型**

GEOMETRY

ST\$1Buffer 関数は、xy-デカルト平面内の 2 次元 (2D) ジオメトリを返します。

**例**

```
RETURN ST_Buffer(ST_GeomFromText('LINESTRING (1 2,5 2,5 8)'), 2, 4);
POLYGON ((3 4, 3 8, 3.1522409349774265 8.76536686473018,
         3.585786437626905 9.414213562373096, 4.234633135269821 9.847759065022574,
         5 10, 5.765366864730179 9.847759065022574,
         6.414213562373095 9.414213562373096, 6.847759065022574 8.76536686473018,
         7 8, 7 2, 6.847759065022574 1.2346331352698203,
         6.414213562373095 0.5857864376269051, 5.765366864730179 0.1522409349774265,
         5 0, 1 0, 0.2346331352698193 0.152240934977427,
         -0.4142135623730954 0.5857864376269051,
         -0.8477590650225737 1.2346331352698208, -1 2.0000000000000004,
         -0.8477590650225735 2.7653668647301797,
         -0.4142135623730949 3.414213562373095,
         0.2346331352698206 3.8477590650225735, 1 4, 3 4))
```

次は、円に近似する入力ポイントジオメトリのバッファを返します。このコマンドは四分円あたりのセグメント数として 3 を指定するため、関数は 3 つのセグメントを使用して四分円を近似します。

```
RETURN ST_Buffer(ST_GeomFromText('POINT (1 1)'), 1.0, 8));
POLYGON ((2 1, 1.9807852804032304 0.8049096779838718,
     1.9238795325112867 0.6173165676349102, 1.8314696123025453 0.4444297669803978,
     1.7071067811865475 0.2928932188134525, 1.5555702330196022 0.1685303876974548,
     1.3826834323650898 0.0761204674887133, 1.1950903220161284 0.0192147195967696,
     1 0, 0.8049096779838718 0.0192147195967696, 0.6173165676349103 0.0761204674887133,
    0.444429766980398 0.1685303876974545, 0.2928932188134525 0.2928932188134524,
     0.1685303876974546 0.4444297669803978, 0.0761204674887133 0.6173165676349102,
     0.0192147195967696 0.8049096779838714, 0 0.9999999999999999,
     0.0192147195967696 1.1950903220161284, 0.0761204674887132 1.3826834323650896,
     0.1685303876974545 1.555570233019602, 0.2928932188134523 1.7071067811865475,
     0.4444297669803978 1.8314696123025453, 0.6173165676349097 1.9238795325112865,
     0.8049096779838714 1.9807852804032304, 0.9999999999999998 2,
     1.1950903220161284 1.9807852804032304, 1.38268343236509 1.9238795325112865,
     1.5555702330196017 1.8314696123025453, 1.7071067811865475 1.7071067811865477,
     1.8314696123025453 1.5555702330196022, 1.9238795325112865 1.3826834323650905,
     1.9807852804032304 1.1950903220161286, 2 1))
```

# SPARQL を使用した Neptune グラフへのアクセス
<a name="access-graph-sparql"></a>

SPARQL は、ウェブ用に設計されたグラフデータ形式であるリソース記述フレームワーク (RDF) のためのクエリ言語です。Amazon Neptune は、SPARQL 1.1 と互換性があります。つまり、Neptune DB インスタンス に接続して、[SPARQL 1.1 クエリ言語](https://www.w3.org/TR/sparql11-query/)仕様で記述されたクエリ言語を使用してグラフにクエリを実行できるということです。

 SPARQL のクエリは、返す変数を指定する `SELECT` 句と、グラフで一致するデータを指定する `WHERE` 句で構成されます。SPARQL クエリに慣れていない場合は、[SPARQL 1.1 クエリ言語](https://www.w3.org/TR/sparql11-query/#WritingSimpleQueries)にある「[シンプルなクエリの書き込み](https://www.w3.org/TR/sparql11-query/)」を参照してください。

**重要**  
データをロードするには、`SPARQL UPDATE INSERT` は小さなデータセットに対してはうまく機能しますが、ファイルから大量のデータをロードする必要がある場合は、「[Amazon Neptune 一括ローダーを使用したデータの取り込み](bulk-load.md)」を参照してください。

Neptune の SPARQL 実装の仕様の詳細については、[SPARQL 標準準拠](feature-sparql-compliance.md)を参照してください。

始めるには以下のものが必要です。
+ Neptune DB インスタンス。Neptune DB インスタンスの作成については、[Amazon Neptune クラスターの作成](get-started-create-cluster.md) を参照してください。
+ Neptune DB インスタンスと同じ Virtual Private Cloud (VPC) にある Amazon EC2; インスタンス。

**Topics**
+ [RDF4J コンソールを使用して Neptune DB インスタンスに接続する](access-graph-sparql-rdf4j-console.md)
+ [RDF4J Workbench を使用して Neptune DB インスタンスに接続する](access-graph-sparql-rdf4j-workbench.md)
+ [Java を使用して Neptune DB インスタンスに接続する](access-graph-sparql-java.md)
+ [SPARQL HTTP API](sparql-api-reference.md)
+ [SPARQL クエリヒント](sparql-query-hints.md)
+ [SPARQL DESCRIBE のデフォルトグラフに対する動作](sparql-default-describe.md)
+ [SPARQL クエリステータス API](sparql-api-status.md)
+ [SPARQL クエリのキャンセル](sparql-api-status-cancel.md)
+ [Amazon Neptune での SPARQL 1.1 グラフストア HTTP プロトコル (GSP) の使用](sparql-graph-store-protocol.md)
+ [SPARQL `explain` を使用して Neptune クエリ実行を分析する](sparql-explain.md)
+ [`SERVICE` 拡張を使用した Neptune での SPARQL フェデレーティッドクエリ](sparql-service.md)

# RDF4J コンソールを使用して Neptune DB インスタンスに接続する
<a name="access-graph-sparql-rdf4j-console"></a>



RDF4J コンソールにより、REPL (read-eval-print loop) 環境で Resource Description Framework (RDF) グラフおよびクエリを試してみることができます。

リポジトリとしてリモートグラフデータベースを追加して、RDF4J コンソールからクエリを実行できます。このセクションでは、Neptune DB インスタンス にリモートで接続するための RDF4J コンソールの設定について説明します。

**RDF4J コンソールを使用して Neptune に接続するには**

1. RDF4J ウェブサイトの[ダウンロードページ](http://rdf4j.org/download/)から、RDF4J SDK をダウンロードしてください。

1. RDF4J SDK zip ファイルを解凍します。

1. ターミナルで RDF4J SDK ディレクトリに移動し、次のコマンドを入力して RDF4J コンソールを実行します。

   ```
   bin/console.sh
   ```

   次のような出力が表示されます:

   ```
   14:11:51.126 [main] DEBUG o.e.r.c.platform.PlatformFactory - os.name = linux
   14:11:51.130 [main] DEBUG o.e.r.c.platform.PlatformFactory - Detected Posix platform
   Connected to default data directory
   RDF4J Console 3.6.1
   
   3.6.1
   Type 'help' for help.
   >
   ```

   `>` プロンプトが表示されます。これは、RDF4J コンソールの一般プロンプトです。このプロンプトを使用して、リポジトリやその他の操作を設定します。リポジトリでは、クエリを実行するための独自のプロンプトが表示されます。

1. `>` プロンプトで、次のように入力して Neptune DB インスタンスに SPARQL リポジトリを作成します。

    

   ```
   create sparql
   ```

1. RDF4J コンソールで、SPARQL エンドポイントへの接続に必要な変数の値を求められます。

   ```
   Please specify values for the following variables:
   ```

   次の値を指定します。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/access-graph-sparql-rdf4j-console.html)

   Neptune DB インスタンスのアドレスを見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   このオペレーションが成功した場合は、次のメッセージが表示されます。

    

   ```
   Repository created
   ```

1. `>` プロンプトで、次のように入力して Neptune DB インスタンスに接続します。

   ```
   open neptune
   ```

   このオペレーションが成功した場合は、次のメッセージが表示されます。

    

   ```
   Opened repository 'neptune'
   ```

   `neptune>` プロンプトが表示されます。このプロンプトで、Neptune グラフに対するクエリを実行することができます。

    
**注記**  
リポジトリが追加されました。次に `bin/console.sh` を実行する場合は、直接 `open neptune` コマンドを実行して Neptune DB インスタンスに接続することができます。

1. `neptune>` プロンプトで、次のように入力して SPARQL クエリを実行します。このクエリは、10 の制限がある `?s ?p ?o` クエリを使用して、グラフのトリプル (主語 - 述語 - 目的語) のうち最大 10 個を返します。その他の対象にクエリを実行するには、`sparql` コマンドの後のテキストを別の SPARQL クエリで置き換えます。

   ```
   sparql select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

# RDF4J Workbench を使用して Neptune DB インスタンスに接続する
<a name="access-graph-sparql-rdf4j-workbench"></a>

このセクションでは、RDF4J Workbench および RDF4J Server を使用してAmazon Neptune DB インスタンスに接続する方法について説明します。RDF4J Server は、Neptune SPARQL HTTP REST エンドポイントと RDF4J Workbench 間のプロキシとして必要です。

RDF4J Workbench では、ローカルファイルのロードを含め、グラフの実験を行う簡単なインターフェイスを提供します。詳しくは、RDF4J ドキュメントにある「[セクションを追加する](https://rdf4j.org/documentation/tools/server-workbench/#add)」を参照してください。

**前提条件**  
開始する前に、以下を実行します。
+ Java 1.8 以降をインストールします。
+ RDF4J Server および RDF4J Workbench をインストールします。詳細については、「[RDF4J Server および RDF4J Workbench のインストール](https://rdf4j.org/documentation/tools/server-workbench/#installing-rdf4j-server-and-rdf4j-workbench)」を参照してください。

**RDF4J Workbench を使用して Neptune に接続するには**

1. ウェブブラウザで、RDF4J Workbench ウェブアプリケーションがデプロイされている URL に移動します。たとえば、Apache Tomcat を使用している場合の URL は次のようになります。[https://*ec2\$1hostname*:8080/rdf4j-workbench/](http://localhost:8080/rdf4j-workbench/)。

1. [**Connect to RDF4J Server (RDF4J Server に接続)**] と求められたら、**RDF4J Server** がインストールされて実行中であり、サーバーの URL が正しいことを確認します。そして、次のステップに進みます。

1. 左のペインの [**New repository**] (新しいレポジトリ) を選択します。

   [**New repository(新しいレポジトリ)**]
   + [**Type (タイプ)**] ドロップダウンリストで、[**SPARQL endpoint proxy (SPARQL エンドポイントのプロキシ)**] を選択します。
   + [**ID**] に [**neptune**] を入力します。
   + **役職**の場合、タイプ **Neptune DB インスタンス**。

   [**次へ**] を選択します。

1. [**New repository(新しいレポジトリ)**]
   + [**SPARQL query endpoint URL (SPARQL クエリのエンドポイント URL)**] については、「`https://your-neptune-endpoint:port/sparql`」と入力します。
   + [**SPARQL update endpoint URL (SPARQL 更新のエンドポイント URL)**] については、「`https://your-neptune-endpoint:port/sparql`」と入力します。

   Neptune DB インスタンスのアドレスを見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   **[作成]** を選択します。

1. [**neptune**] リポジトリが、リポジトリのリストに表示されます。新しいリポジトリが使用できるようになるまで数分かかることがあります。

1. テーブルの [**ID**] 列で、[**neptune**] リンクをクリックします。

1. 左のペインの [**Query**] (クエリ) を選択します。

    
**注記**  
[**Explore (詳しく見る)**] の下にあるメニュー項目が無効になっている場合は、RDF4J Server に再接続してもう一度 [**neptune**] リポジトリを選択する必要があるかもしれません。  
これを行うには、右上隅にある **[change]** (変更) リンクを使用します。

1. クエリフィールドで次の SPARQL クエリを入力し、[**Execute**] (実行) を選択します。

    

   ```
   select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

    

前述の例では、10 の制限がある `?s ?p ?o` クエリを使用して、グラフのトリプル (主語 - 述語 - 目的語) のうち最大 10 個を返します。

# Java を使用して Neptune DB インスタンスに接続する
<a name="access-graph-sparql-java"></a>

このセクションでは、Amazon Neptune DB インスタンスに接続し、SPARQL クエリを実行する完全な Java サンプルを実行する方法について説明します。

Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

**Java を使用して Neptune に接続するには**

1. Apache Maven を EC2 インスタンスにインストールします。Amazon Linux 2023 (推奨) を使用している場合は、以下の対象を使用します。

   ```
   sudo dnf update -y
   sudo dnf install maven -y
   ```

   Amazon Linux 2 を使用している場合は、[https://maven.apache.org/download.cgi:](https://maven.apache.org/download.cgi:) から最新のバイナリをダウンロードします。

   ```
   sudo yum remove maven -y
   wget https://dlcdn.apache.org/maven/maven-3/ <version>/binaries/apache-maven-<version>-bin.tar.gz
   sudo tar -xzf apache-maven-<version>-bin.tar.gz -C /opt/
   sudo ln -sf /opt/apache-maven-<version> /opt/maven
   echo 'export MAVEN_HOME=/opt/maven' >> ~/.bashrc
   echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> ~/.bashrc
   source ~/.bashrc
   ```

1. この例は Java 8 のみでテストされています。EC2 インスタンスで Java 8 をインストールするには、次のように入力します。

   ```
   sudo yum install java-1.8.0-devel
   ```

1. EC2 インスタンスで Java 8 をデフォルトランタイムとして設定するには、次のように入力します。

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   プロンプトが表示されたら、Java 8 の数を入力します。

1. EC2 インスタンスで Java 8 をデフォルトコンパイラとして設定するには、次のように入力します。

   ```
   sudo /usr/sbin/alternatives --config javac
   ```

   プロンプトが表示されたら、Java 8 の数を入力します。

1. 新しいディレクトリで `pom.xml` ファイルを作成してから、テキストエディタで開きます。

1. 以下を `pom.xml` ファイルにコピーし保存します (通常、バージョン番号を最新の安定バージョンに調整できます)。

   ```
   <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.amazonaws</groupId>
     <artifactId>RDFExample</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>RDFExample</name>
     <url>https://maven.apache.org</url>
     <dependencies>
       <dependency>
         <groupId>org.eclipse.rdf4j</groupId>
         <artifactId>rdf4j-runtime</artifactId>
         <version>3.6</version>
       </dependency>
     </dependencies>
     <build>
       <plugins>
         <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>exec-maven-plugin</artifactId>
             <version>1.2.1</version>
             <configuration>
               <mainClass>com.amazonaws.App</mainClass>
             </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
             <source>1.8</source>
             <target>1.8</target>
           </configuration>
         </plugin>
       </plugins>
     </build>
   </project>
   ```
**注記**  
既存の Maven プロジェクトを変更する場合、必要な依存関係が前述のコードにおいて強調表示されます。

1. ソースコード例 (`src/main/java/com/amazonaws/`) のサブディレクトリを作成するには、コマンドラインで次のように入力してください。

   ```
   mkdir -p src/main/java/com/amazonaws/
   ```

1. `src/main/java/com/amazonaws/` ディレクトリで `App.java` という名前のファイルを作成してから、テキストエディタで開きます。

1. `App.java` ファイルに次の内容をコピーします。*your-neptune-endpoint* を Neptune DB インスタンスのアドレスで置き換えます。
**注記**  
Neptune DB インスタンスのホスト名を見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

   ```
   package com.amazonaws;
   
   import org.eclipse.rdf4j.repository.Repository;
   import org.eclipse.rdf4j.repository.http.HTTPRepository;
   import org.eclipse.rdf4j.repository.sparql.SPARQLRepository;
   
   import java.util.List;
   import org.eclipse.rdf4j.RDF4JException;
   import org.eclipse.rdf4j.repository.RepositoryConnection;
   import org.eclipse.rdf4j.query.TupleQuery;
   import org.eclipse.rdf4j.query.TupleQueryResult;
   import org.eclipse.rdf4j.query.BindingSet;
   import org.eclipse.rdf4j.query.QueryLanguage;
   import org.eclipse.rdf4j.model.Value;
   
   public class App
   {
       public static void main( String[] args )
       {
           String sparqlEndpoint = "https://your-neptune-endpoint:port/sparql";
           Repository repo = new SPARQLRepository(sparqlEndpoint);
           repo.initialize();
   
           try (RepositoryConnection conn = repo.getConnection()) {
              String queryString = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } limit 10";
   
              TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
   
              try (TupleQueryResult result = tupleQuery.evaluate()) {
                 while (result.hasNext()) {  // iterate over the result
                      BindingSet bindingSet = result.next();
   
                      Value s = bindingSet.getValue("s");
                      Value p = bindingSet.getValue("p");
                      Value o = bindingSet.getValue("o");
   
                      System.out.print(s);
                      System.out.print("\t");
                      System.out.print(p);
                      System.out.print("\t");
                      System.out.println(o);
                 }
              }
           }
       }
   }
   ```

1. 次の Maven コマンドを使用してサンプルをコンパイルおよび実行します。

   ```
   mvn compile exec:java
   ```

前述の例では、10 の制限がある `?s ?p ?o` クエリを使用して、グラフのトリプル (主語 - 述語 - 目的語) のうち最大 10 個を返します。その他の対象にクエリを実行するには、クエリを別の SPARQL クエリで置き換えます。

この例では、結果の反復は返された各変数の値を出力します。`Value` オブジェクトは `String` に変換され、その後出力されます。クエリの `SELECT` 部分を変更した場合は、コードを変更する必要があります。

# SPARQL HTTP API
<a name="sparql-api-reference"></a>

SPARQL HTTP リクエストは、次のエンドポイントで受け付けられます。`https://your-neptune-endpoint:port/sparql`

SPARQL を使用した Amazon Neptune への接続の詳細については、[SPARQL を使用した Neptune グラフへのアクセス](access-graph-sparql.md)を参照してください。

SPARQL プロトコルとクエリ言語の詳細については、「[SPARQL 1.1 プロトコル](https://www.w3.org/TR/sparql11-protocol/#protocol)」および「[SPARQL 1.1 クエリ言語](https://www.w3.org/TR/sparql11-query/)」仕様を参照してください。

以下のトピックでは、SPARQL RDF シリアル化形式、および Neptune で SPARQL HTTP API を使用する方法について説明します。

**Contents**
+ [HTTP REST エンドポイントを使用して Neptune DB インスタンスに接続する](access-graph-sparql-http-rest.md)
+ [マルチパートの SPARQL レスポンスのオプションの HTTP 末尾ヘッダー](access-graph-sparql-http-trailing-headers.md)
+ [Neptune の SPARQL で使用される RDF メディアタイプ。](sparql-media-type-support.md)
  + [Neptune SPARQL で使用される RDF シリアル化形式](sparql-media-type-support.md#sparql-serialization-formats)
  + [Neptune SPARQL で使用される SPARQL 結果のシリアル化形式](sparql-media-type-support.md#sparql-serialization-formats-neptune-output)
  + [Neptune が RDF データのインポートに使用できるメディアタイプ](sparql-media-type-support.md#sparql-serialization-formats-input)
  + [Neptune がクエリ結果のエクスポートに使用できるメディアタイプ](sparql-media-type-support.md#sparql-serialization-formats-output)
+ [SPARQL UPDATE LOAD を使用して Neptune にデータをインポートする](sparql-api-reference-update-load.md)
+ [SPARQL UPDATE UNLOAD を使用して Neptune からデータを削除する](sparql-api-reference-unload.md)

# HTTP REST エンドポイントを使用して Neptune DB インスタンスに接続する
<a name="access-graph-sparql-http-rest"></a>

**注記**  
Neptune は現在、REST API リクエストの HTTP/2 をサポートしていません。クライアントは、エンドポイントに接続するときに HTTP/1.1 を使用する必要があります。

次の手順は、**curl** コマンドを使用し、HTTPS を介した接続で HTTP 構文を使用して SPARQL エンドポイントに接続する方法について説明します。Neptune DB インスタンスと同じ仮想プライベートクラウド (VPC) の Amazon EC2 インスタンスからこれらの手順を実行してください。

Neptune DB インスタンスへの SPARQL クエリ用の HTTP エンドポイントは `https://your-neptune-endpoint:port/sparql` です。

**注記**  
Neptune DB インスタンスのホスト名を見つける方法については、[Amazon Neptune エンドポイントに接続する](feature-overview-endpoints.md) セクションを参照してください。

Amazon Neptune では、SPARQL クエリ用の HTTP エンドポイントが用意されています。REST インターフェイスは、SPARQL バージョン 1.1 と互換性があります。

**HTTP POST を使用したクエリ**  
次の例では、**curl** を使用して、HTTP **POST** を通じて SPARQL **`QUERY`** を送信します。

```
curl -X POST --data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' https://your-neptune-endpoint:port/sparql
```

前述の例では、10 の制限がある `?s ?p ?o` クエリを使用して、グラフのトリプル (主語 - 述語 - 目的語) のうち最大 10 個を返します。その他の対象にクエリを実行するには、別の SPARQL クエリで置き換えます。

**注記**  
`SELECT` および `ASK` クエリの場合、レスポンスのデフォルトの MIME メディアタイプは `application/sparql-results+json` です。  
`CONSTRUCT` および `DESCRIBE` クエリの場合、レスポンスのデフォルトの MIME タイプは `application/n-quads` です。  
Neptune によってシリアル化に使用されるメディアタイプのリストについては、[Neptune SPARQL で使用される RDF シリアル化形式](sparql-media-type-support.md#sparql-serialization-formats)を参照してください。

**HTTP POST を使用した更新**  
次の例では、**curl** を使用して、HTTP **POST** を通じて SPARQL **`UPDATE`** を送信します。

```
curl -X POST --data-binary 'update=INSERT DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }' https://your-neptune-endpoint:port/sparql
```

前述の例では、次のトリプルを SPARQL デフォルトのグラフに挿入します。`<https://test.com/s> <https://test.com/p> <https://test.com/o>`

# マルチパートの SPARQL レスポンスのオプションの HTTP 末尾ヘッダー
<a name="access-graph-sparql-http-trailing-headers"></a>

SPARQL クエリと更新に対する HTTP 応答は、多くの場合、複数のパートまたはチャンクで返されます。クエリまたは更新がこれらのチャンクの送信を開始した後に発生する障害を診断するのは難しい場合があります。特に、最初のチャンクは HTTP ステータスコードが `200` であるからです。

末尾のヘッダーを明示的にリクエストしない限り、Neptune は、エラーメッセージをメッセージ本文に追加することによってのみ、そのような障害を報告しますが、通常これは破損しています。

この種の問題の検出と診断を容易にするために、転送エンコーディング (TE) トレーラーヘッダー (`te: trailers`) をリクエストに入れることができます (例として[TE リクエストヘッダーに関する MDN ページ](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)を参照)。これを行うと、Neptune はレスポンスチャンクの末尾ヘッダー内に 2 つの新しいヘッダーフィールドを含めます。
+ `X-Neptune-Status`— 応答コードの後ろに短い名前が続きます。たとえば、成功した場合、末尾ヘッダーは次のようになります。`X-Neptune-Status: 200 OK`。失敗の場合、応答コードは、`X-Neptune-Status: 500 TimeLimitExceededException` といった[ Neptune エンジンのエラーコード](errors-engine-codes.md)となる可能性があります。
+ `X-Neptune-Detail`— 成功したリクエストでは空です。エラーの場合は、JSON エラーメッセージが含まれます。HTTP ヘッダー値には ASCII 文字しか使用できないため、JSON 文字列は URL 符号化されます。エラーメッセージは、レスポンスメッセージ本文にも追加されます。

# Neptune の SPARQL で使用される RDF メディアタイプ。
<a name="sparql-media-type-support"></a>

Resource Description Framework (RDF) データはさまざまな方法でシリアル化することができ、そのほとんどは SPARQL が消費または出力することができます。

## Neptune SPARQL で使用される RDF シリアル化形式
<a name="sparql-serialization-formats"></a>
+ **RDF/XML**  –   RDF の XML シリアル化。[RDF 1.1 XML 構文](https://www.w3.org/TR/rdf-syntax-grammar/)で定義されています。メディアタイプ: `application/rdf+xml`。一般的なファイル拡張子: `.rdf`。
+ **N-Triples**  –   RDF グラフをエンコードするための行ベースのプレーンテキスト形式。[RDF 1.1 N-Triples](https://www.w3.org/TR/n-triples/) で定義されています。メディアタイプ: `application/n-triples`、`text/turtle`、または `text/plain`。。一般的なファイル拡張子: `.nt`。
+ **N-Quads**  –   グラフをエンコードするための行ベースのプレーンテキスト形式。[RDF 1.1 N-Quads](https://www.w3.org/TR/n-quads/) で定義されています。これは N-Triples の拡張子です。メディアタイプ: `application/n-quads`、または 7 ビットの US-ASCII でエンコードされている場合は `text/x-nquads`。一般的なファイル拡張子: `.nq`。
+ **Turtle**  –   [ RDF 1.1 Turtle](https://www.w3.org/TR/turtle/) で定義されている RDF のテキスト構文で、RDF グラフをコンパクトで自然なテキスト形式で、一般的な使用パターンとデータ型の省略形で完全に記述できるようにします。Turtle は、N-Triples 形式および SPARQL の 3 つのパターン構文との互換性を提供します。メディアタイプ: `text/turtle`一般的なファイル形式: `.ttl`。
+ **TriG**  –   [ RDF 1.1 TriG](https://www.w3.org/TR/trig/) で定義されている RDF のテキスト構文で、RDF グラフをコンパクトで自然なテキスト形式で、一般的な使用パターンとデータ型の省略形で完全に記述できるようにします。TriG は Turtle 形式の拡張子です。メディアタイプ: `application/trig`。一般的なファイル拡張子: `.trig`。
+ **N3 (Notation3)** - [Notation3 (N3): 読み取り可能な RDF 構文](https://www.w3.org/TeamSubmission/n3/) で定義されているアサーションとロジック構文。N3 は、式 (グラフ自体であるリテラル)、変数、論理的意味、および機能的述部を追加することによって RDF データモデルを拡張し、RDF/XML に代わるテキスト形式の構文を提供します。メディアタイプ: `text/n3`。一般的なファイル拡張子: `.n3`。
+ **JSON-LD**  –   [JSON-LD 1.0](https://www.w3.org/TR/json-ld/)で定義されているデータシリアル化およびメッセージング形式。メディアタイプ: `application/ld+json`。一般的なファイル拡張子: `.jsonld`。
+ **TriXX** - [TriX: XML での RDF トリプル で定義されている](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html)、XML での RDF のシリアル化。メディアタイプ: `application/trix`。一般的なファイル拡張子: `.trix`。
+ **SPARQL JSON 結果**  –   [SPARQL 1.1 クエリ結果 JSON 形式](https://www.w3.org/TR/sparql11-results-json)を使用した、RDF のシリアル化。メディアタイプ: `application/sparql-results+json`。一般的なファイル拡張子: `.srj`。
+ **RDF4J バイナリ形式** - [RDF4J バイナリ RDF 形式](https://rdf4j.org/documentation/reference/rdf4j-binary) で説明されている、RDF データをエンコードするためのバイナリ形式。メディアタイプ: `application/x-binary-rdf`。

## Neptune SPARQL で使用される SPARQL 結果のシリアル化形式
<a name="sparql-serialization-formats-neptune-output"></a>
+ **SPARQL XML 結果**  –   [SPARQL クエリ結果 XML 形式 (Second Edition)](https://www.w3.org/TR/rdf-sparql-XMLres/) で定義されている、SPARQL クエリ言語によって提供される変数バインディングおよびブール結果形式の XML 形式。メディアタイプ: `application/sparql-results+xml`。一般的なファイル拡張子: `.srx`。
+ **SPARQL CSVとTSVの結果** — カンマ区切り値とタブ区切り値を使用して、[SPARQL 1.1 クエリ結果 CSV および TSV 形式](https://www.w3.org/TR/sparql11-results-csv-tsv/)で定義される `SELECT` クエリから SPARQL クエリの結果を表現します。メディアタイプ: カンマ区切り値の `text/csv`、およびタブ区切り値の `text/tab-separated-values`。一般的なファイル拡張子: カンマ区切り値の `.csv`、およびタブ区切り値の `.tsv`。
+ **バイナリ結果テーブル**  –   SPARQL クエリの出力をエンコードするためのバイナリ形式。メディアタイプ: `application/x-binary-rdf-results-table`。
+ **SPARQL JSON 結果**  –   [SPARQL 1.1 クエリ結果 JSON 形式](https://www.w3.org/TR/sparql11-results-json/)を使用した、RDF のシリアル化。メディアタイプ: `application/sparql-results+json`。

## Neptune が RDF データのインポートに使用できるメディアタイプ
<a name="sparql-serialization-formats-input"></a>

**[Neptune bulk-loader](bulk-load.md) によってサポートされるメディアタイプ**
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [N-Quads](https://www.w3.org/TR/n-quads/)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [Turtle](https://www.w3.org/TR/turtle/)

**SPARQL UPDATE LOAD がインポートできるメディアタイプ**
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [N-Quads](https://www.w3.org/TR/n-quads/)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [TriG](https://www.w3.org/TR/trig/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)

## Neptune がクエリ結果のエクスポートに使用できるメディアタイプ
<a name="sparql-serialization-formats-output"></a>

SPARQL クエリ応答の出力形式を指定するには、クエリリクエストともに `"Accept: media-type"` ヘッダーを送信します。例: 

```
curl -H "Accept: application/nquads" ...
```

**SPARQL SELECT が Neptune から出力できる RDF メディアタイプ**
+ [SPARQL JSON 結果](https://www.w3.org/TR/sparql11-results-json) (これはデフォルトです)
+ [SPARQL XML 結果](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **バイナリ結果テーブル** (メディアタイプ: `application/x-binary-rdf-results-table`)
+ [カンマ区切り値 (CSV)](https://www.w3.org/TR/sparql11-results-csv-tsv/)
+ [タブ区切り値 (TSV)](https://www.w3.org/TR/sparql11-results-csv-tsv/)

**SPARQL ASK が Neptune から出力できる RDF メディアタイプ**
+ [SPARQL JSON 結果](https://www.w3.org/TR/sparql11-results-json) (これはデフォルトです)
+ [SPARQL XML 結果](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **Boolean** (メディアタイプ: `text/boolean`、「true」または「false」を意味します)

**SPARQL CONSTRUCT が Neptune から出力できる RDF メディアタイプ**
+ [N-Quads](https://www.w3.org/TR/n-quads/) (これはデフォルトです)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [TriX](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html)
+ [TriG](https://www.w3.org/TR/trig/)
+ [SPARQL JSON 結果](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4J バイナリ RDF形式](https://rdf4j.org/documentation/reference/rdf4j-binary)

**SPARQL DESCRIBE が Neptune から出力できる RDF メディアタイプ**
+ [N-Quads](https://www.w3.org/TR/n-quads/) (これはデフォルトです)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [TriX](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html)
+ [TriG](https://www.w3.org/TR/trig/)
+ [SPARQL JSON 結果](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4J バイナリ RDF形式](https://rdf4j.org/documentation/reference/rdf4j-binary)

# SPARQL UPDATE LOAD を使用して Neptune にデータをインポートする
<a name="sparql-api-reference-update-load"></a>

SPARQL UPDATE LOAD コマンドの構文は、[SPARQL 1.1 アップデートの推奨事項](https://www.w3.org/TR/sparql11-update/#load)に記載されています。

```
LOAD SILENT (URL of data to be loaded) INTO GRAPH (named graph into which to load the data)
```
+ **`SILENT`** — (*オプション*) 処理中にエラーが発生した場合でも、オペレーションは成功を返します。

  これは、単一のトランザクションに `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"` のような複数のステートメントが含まれている場合に便利です。また、リモートデータの一部が処理できない場合でも、トランザクションを完了させる必要があります。
+ *ロードするデータの URL* — (*必須*) グラフにロードするデータを含むリモートデータファイルを指定します。

  リモートファイルには、次のいずれかの拡張子を指定する必要があります。
  + NTriples 用 `.nt`。
  + NQuads 用 `.nq`。
  + Trig 用 `.trig`。
  + RDF/XML 用 `.rdf`。
  + Turtle 用 `.ttl`。
  + N3 用 `.n3`。
  + JSON-LD 用 `.jsonld`。
+ **`INTO GRAPH`***(データをロードする名前付きグラフ)* — (*オプション*) データをロードするグラフを指定します。

  Neptune はすべてのトリプルを名前が付いたグラフに関連付けます。フォールバック名前付きグラフ URI、 `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`などを使用して、デフォルトの名前付きグラフを指定できます。次のようになります。

  ```
  INTO GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

**注記**  
大量のデータをロードする必要がある場合は、UPDATE LOAD ではなく Neptune バルクローダーを使用することをお勧めします。バルクローダーについては、[Amazon Neptune 一括ローダーを使用したデータの取り込み](bulk-load.md)を参照してください。

`SPARQL UPDATE LOAD` を使用して、 Amazon S3 から直接データをロードすることも、セルフホストウェブサーバーから取得したファイルからデータをロードすることもできます。ロードするリソースは Neptune サーバーと同じリージョンに存在し、リソースのエンドポイントは VPC でホワイトリストに登録されている必要があります。Amazon S3 エンドポイントを作成する方法については、[Amazon S3 VPC エンドポイントの作成](bulk-load-data.md#bulk-load-prereqs-s3) を参照してください。

すべての`SPARQL UPDATE LOAD` URI は `https://` で始まる必要があります。これには Amazon S3 URL が含まれます。

バルクローダーとは対照的に、`SPARQL UPDATE LOAD` への呼び出しは完全にトランザクション型です。

**SPARQL UPDATE LOAD を使用して Amazon S3 から Neptune にファイルを直接ロードする**

Neptune では、SPARQL UPDATE LOAD を使用するときに Amazon S3 に IAM ロールを渡すことはできないため、問題の Amazon S3 バケットはパブリックであるか、LOAD クエリで[署名付き Amazon S3 URL](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html)を使用する必要があります。

Amazon S3 ファイルの署名付き URL を生成するには、次のような AWS CLI コマンドを使用できます。

```
aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to load)
```

次に、結果の署名付き URL を `LOAD` コマンドで使えます。

```
curl https://(a Neptune endpoint URL):8182/sparql \
  --data-urlencode 'update=load (pre-signed URL of the remote Amazon S3 file of data to be loaded) \
                           into graph (named graph)'
```

詳細については、「[リクエストの認証: クエリパラメータの使用](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html)」を参照してください。[Boto3 のドキュメント](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html)に、Python スクリプトを使用して署名付き URL を生成する方法が記載されています。

また、ロードするファイルのコンテンツタイプも正しく設定する必要があります。

1. 次のように `-metadata` パラメータを使用してファイルを Amazon S3 にアップロードするときにファイルのコンテンツタイプを設定します。

   ```
   aws s3 cp test.nt s3://bucket-name/my-plain-text-input/test.nt --metadata Content-Type=text/plain
   aws s3 cp test.rdf s3://bucket-name/my-rdf-input/test.rdf --metadata Content-Type=application/rdf+xml
   ```

1. メディアタイプの情報が実際に存在することを確認してください。以下を実行します:

   ```
   curl -v bucket-name/folder-name
   ```

   このコマンドの出力には、ファイルをアップロードするときに設定したメディアタイプ情報が表示されます。

1. その後、`SPARQL UPDATE LOAD` コマンドを使用してこれらのファイルを Neptune にインポートできます。

   ```
   curl https://your-neptune-endpoint:port/sparql \
     -d "update=LOAD <https://s3.amazonaws.com/bucket-name/my-rdf-input/test.rdf>"
   ```

上記の手順は、パブリック バケット、または LOAD クエリで [署名付き Amazon S3 URL ](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html)を使用してアクセスするバケットに対してのみ機能します。

 以下に示すように、プライベート Amazon S3 バケットからロードするようにウェブプロキシサーバーを設定することもできます。

**ウェブサーバーを使用して SPARQL UPDATE LOAD でファイルを Neptune にロードする**

1. Neptune とロードするファイルをホストしている VPC 内で実行されているマシンにウェブサーバーをインストールします。たとえば、Amazon Linux を使用している場合は、次のように Apache をインストールします。

   ```
   sudo yum install httpd mod_ssl
   sudo /usr/sbin/apachectl start
   ```

1. ロードしようとしている RDF ファイルコンテンツの MIME タイプを定義します。SPARQL はウェブサーバーから送信された `Content-type` ヘッダーを使用してコンテンツの入力形式を決定するため、ウェブサーバーに関連する MIME タイプを定義する必要があります。

   たとえば、ファイル形式を識別するために次のファイル拡張子を使用するとします。
   + NTriples 用 `.nt`。
   + NQuads 用 `.nq`。
   + Trig 用 `.trig`。
   + RDF/XML 用 `.rdf`。
   + Turtle 用 `.ttl`。
   + N3 用 `.n3`。
   + JSON-LD 用 `.jsonld`。

   ウェブサーバーとして Apache 2 を使用している場合は、ファイル `/etc/mime.types` を編集して次のタイプを追加します。

   ```
    text/plain nt
    application/n-quads nq
    application/trig trig
    application/rdf+xml rdf
    application/x-turtle ttl
    text/rdf+n3 n3
    application/ld+json jsonld
   ```

1. MIME タイプマッピングが機能することを確認します。ウェブサーバーを起動して実行し、選択した形式で RDFファイルをホストしたら、ローカルホストからウェブサーバーにリクエストを送信して設定をテストできます。

   たとえば、次のようなリクエストを送信します。

   ```
   curl -v http://localhost:80/test.rdf
   ```

   `curl` からの詳細な出力には、このような行が表示されるはずです。

   ```
   Content-Type: application/rdf+xml
   ```

   これは、コンテンツタイプマッピングが正常に定義されたことを示しています。

1. これで、SPARQL UPDATE コマンドを使用してデータをロードする準備が整いました。

   ```
   curl https://your-neptune-endpoint:port/sparql \
       -d "update=LOAD <http://web_server_private_ip:80/test.rdf>"
   ```

**注記**  
`SPARQL UPDATE LOAD` を使用すると、ロードされるソースファイルが大きい場合にウェブサーバーでタイムアウトが発生する可能性があります。Neptune は、ストリーミング時と、サーバーで設定したタイムアウトよりも時間がかかる大きなファイルでは、ファイルデータを処理します。これにより、サーバーが接続を閉じることがあります。その場合、Neptune がストリームで予期しない EOF を検出すると、次のエラーメッセージが表示されることがあります。  

```
{
  "detailedMessage":"Invalid syntax in the specified file",
  "code":"InvalidParameterException"
}
```
このメッセージが表示され、ソースファイルに無効な構文が含まれていると思われる場合は、ウェブサーバーのタイムアウト設定を大きくしてみてください。さらに、サーバーでデバッグログを有効にし、タイムアウトを探すことで、問題を診断することもできます。

# SPARQL UPDATE UNLOAD を使用して Neptune からデータを削除する
<a name="sparql-api-reference-unload"></a>

Neptune はカスタム SPARQL オペレーション、`UNLOAD`、も提供し、リモートソースで指定されたデータを削除する場合に使用します。`UNLOAD` は `LOAD` オペレーションの対応物と見なすことができます。構文は次のとおりです。

```
UNLOAD SILENT (URL of the remote data to be unloaded) FROM GRAPH (named graph from which to remove the data)
```
+ **`SILENT`** — (*オプション*) データ処理中にエラーが発生した場合でも、オペレーションは成功を返します。

  これは、単一のトランザクションに `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"` のような複数のステートメントが含まれている場合に便利です。また、リモートデータの一部が処理できない場合でも、トランザクションを完了させる必要があります。
+ *アンロードするリモートデータの URL* — (*必須*) グラフにロードするデータを含むリモートデータファイルを指定します。

  リモートファイルには、次のいずれかの拡張子が必要です (UPDATE-LOAD がサポートする形式と同じです)。
  + NTriples 用 `.nt`。
  + NQuads 用 `.nq`。
  + Trig 用 `.trig`。
  + RDF/XML 用 `.rdf`。
  + Turtle 用 `.ttl`。
  + N3 用 `.n3`。
  + JSON-LD 用 `.jsonld`。

  このファイルに含まれるすべてのデータは、`UNLOAD` オペレーションによって DB クラスターから削除されます。

  データをアンロードするには、Amazon S3 認証はいずれも URL に含める必要があります。Amazon S3 ファイルに事前署名し、結果の URL を使用して安全にアクセスできます。例: 

  ```
  aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to unload)
  ```

  次に:

  ```
  curl https://(a Neptune endpoint URL):8182/sparql \
    --data-urlencode 'update=unload (pre-signed URL of the remote Amazon S3 data to be unloaded) \
                             from graph (named graph)'
  ```

  詳細については、「[リクエストの認証: クエリパラメータの使用](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html)」を参照してください。
+ **`FROM GRAPH `***(データを削除する名前付きグラフ)* — (*オプション*) リモートデータのアンロード元となる名前付きグラフを指定します。

  Neptune はすべてのトリプルを名前が付いたグラフに関連付けます。フォールバック名前付きグラフ URI、`http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph` などを使用して、デフォルトの名前付きグラフを指定できます。次のようになります。

  ```
  FROM GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

それと同じ方法で `LOAD` は `INSERT DATA { (inline data) }` に、`UNLOAD` は `DELETE DATA { (inline data) }` に対応しています。`DELETE DATA` 同様に、`UNLOAD` は空白ノードを含むデータでは機能しません。

たとえば、ローカル Web サーバーが、`data.nt` という名前のファイルを提供しているとします。これには、次の 2 つのトリプルが含まれています。

```
<http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#b> .
<http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#c> .
```

以下の `UNLOAD` コマンドは名前の付いたグラフ `<http://example.org/graph1>` から、これら 2 つのトリプルを削除します。

```
UNLOAD <http://localhost:80/data.nt> FROM GRAPH <http://example.org/graph1>
```

これは、以下の `DELETE DATA` コマンドを使用する場合と同じ結果になります。

```
DELETE DATA {
  GRAPH <http://example.org/graph1> {
    <http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#b> .
    <http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#c> .
  }
}
```

**`UNLOAD` コマンドによってスローされる例外**
+ **`InvalidParameterException`** — データに空のノードがありました。*HTTP status*: 400 Bad Request。

  *メッセージ*` Blank nodes are not allowed for UNLOAD`

   
+ **`InvalidParameterException`** — データ内に壊れた構文がありました。*HTTP status*: 400 Bad Request。

  *メッセージ*`Invalid syntax in the specified file.`

   
+ **`UnloadUrlAccessDeniedException `**   –   アクセスが拒否されました。*HTTP status*: 400 Bad Request。

  *メッセージ*`Update failure: Endpoint (Neptune endpoint) reported access denied error. Please verify access.`

   
+ **`BadRequestException `** — リモートデータを取得できません。*HTTP status*: 400 Bad Request。

  *メッセージ*:*(HTTP レスポンスによって決まります)。*

# SPARQL クエリヒント
<a name="sparql-query-hints"></a>

クエリヒントを使用して Amazon Neptune の特定の SPARQL クエリの最適化と評価戦略を指定することができます。

クエリヒントは、以下の部分で SPARQL クエリに組み込まれている追加の 3 つのパターンで表されます。

```
scope hint value
```
+ *scope* - クエリ内の特定のグループまたは完全なクエリなど、クエリヒントが適用されるクエリの部分を決定します。
+ *hint* – 適用するヒントのタイプを特定します。
+ *value* – 検討中のシステムアスペクトの動作を決めます。

クエリのヒントとスコープは、Amazon Neptune 名前空間 `http://aws.amazon.com/neptune/vocab/v01/QueryHints#` の事前定義された条件として表示されます。このセクションの例には、クエリで定義され、クエリに含まれている `hint` プレフィックスとして名前空間が含まれています。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```

たとえば、以下は `SELECT` クエリに `joinOrder` ヒントを含める方法を示します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ... {
 hint:Query hint:joinOrder "Ordered" .
 ...
}
```

前述のクエリは、Neptune エンジンに、クエリ内の結合を評価するように指示します。*指定された*順序付けを行い、自動並べ替えを無効にします。

クエリヒントを使用するときは、以下について検討します。
+ 単一のクエリでさまざまなクエリヒントを組み合わせることができます。たとえば、ボトムアップ評価のためにサブクエリに注釈を追加するには `bottomUp` クエリヒントを使用できます。また、サブクエリ内の結合の順序を修正するには `joinOrder` クエリヒントを使用できます。
+ 別の重複していないスコープで同じクエリを複数回使用できます。
+ クエリヒントはヒントです。クエリエンジンは通常、特定のクエリヒントを考慮することを目的としていますが、それらを無視することもあります。
+ クエリヒントはセマンティクスを維持します。クエリヒントを追加しても、クエリの出力は変更されません (順序保証が指定されていない場合、つまり、ORDER BY を使用して結果の順序が明示的に適用されない場合を除く)。

以下のセクションでは、Neptune で使用可能なクエリヒントとその使用方法に関する詳しい情報が記載されています。

**Topics**
+ [Neptune における SPARQL クエリヒントの範囲。](#sparql-query-hints-scope)
+ [`joinOrder` SPARQL クエリヒント](sparql-query-hints-joinOrder.md)
+ [`evaluationStrategy`SPARQL クエリヒント](sparql-query-hints-evaluationStrategy.md)
+ [`queryTimeout` SPARQL クエリヒント](sparql-query-hints-queryTimeout.md)
+ [`rangeSafe` SPARQL クエリヒント](sparql-query-hints-rangeSafe.md)
+ [`queryId`SPARQL クエリヒント](sparql-query-hints-queryId.md)
+ [`useDFE` SPARQL クエリヒント](sparql-query-hints-useDFE.md)
+ [DESCRIBE で使用される SPARQL クエリヒント](sparql-query-hints-for-describe.md)

## Neptune における SPARQL クエリヒントの範囲。
<a name="sparql-query-hints-scope"></a>

次の表は、Amazon Neptune で使用可能なスコープ、関連付けられたヒント、SPARQL クエリヒントの説明を示します。これらのエントリの `hint` プレフィックスは、ヒントの Neptune 名前空間を表します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```


| スコープ | サポートされるヒント | 説明 | 
| --- | --- | --- | 
| hint:Query | [joinOrder](sparql-query-hints-joinOrder.md) | クエリヒントはクエリ全体に適用されます。 | 
| hint:Query | [queryTimeout](sparql-query-hints-queryTimeout.md) | タイムアウト値はクエリ全体に適用されます。 | 
| hint:Query | [RangeSafe](sparql-query-hints-rangeSafe.md) | タイプ昇格は、クエリ全体に対して無効になっています。 | 
| hint:Query | [queryId](sparql-query-hints-queryId.md) | クエリ ID 値はクエリ全体に適用されます。 | 
| hint:Query | [useDFE](sparql-query-hints-useDFE.md) | DFE の使用は、クエリ全体に対して無効になっています。 | 
| hint:Group | [joinOrder](sparql-query-hints-joinOrder.md) | クエリヒントは指定されたグループの最上位の要素に適用されますが、ネストされた要素 (サブクエリなど) や親要素には適用されません。 | 
| hint:SubQuery | [evaluationStrategy](sparql-query-hints-evaluationStrategy.md) | ヒントは指定されて、ネストされた SELECT サブクエリに適用されます。サブクエリの前に計算されたソリューションを考慮せずに、サブクエリは個別に評価されます。 | 

# `joinOrder` SPARQL クエリヒント
<a name="sparql-query-hints-joinOrder"></a>

SPARQL クエリを送信すると、Amazon Neptune クエリエンジンはクエリの構造を調査します。クエリの各パートの順序を変更し、評価に必要な作業の量とクエリレスポンス時間を最小限にしようとします。

たとえば、一連の接続された 3 つのパターンは通常、指定された順序では評価されません。ヒューリスティックと統計 (個々のパターンの選択性と共有変数で接続される方法など) を使用して順序が変更されます。さらに、サブクエリ、FILTER、複雑な OPTIONAL や MINUS ブロックなど、より複雑なパターンがクエリに含まれている場合、Neptune クエリエンジンは評価の順序を効率的にするために、可能な限りそれらの順序を変更します。

より複雑なクエリでは、Neptune で選択されるクエリの評価順序は常に最適であるとは限りません。たとえば、Neptune では、クエリ評価中に発生するインスタンスデータ固有の特性 (グラフでの power ノードの発生など) を見逃す可能性があります。

データの正確な特性がわかっていて、クエリ実行の順序を手動で指定する場合は、Neptune `joinOrder` クエリヒントを使用して特定の順序でクエリが評価されるように指定します。

## `joinOrder` SPARQL ヒント構文
<a name="sparql-query-hints-joinOrder-syntax"></a>

`joinOrder` クエリヒントは、SPARQL クエリに含まれる 3 つのパターンとして指定されます。

わかりやすくするために、次の構文では、クエリに定義されて含まれる `hint` プレフィックスを使用して Neptune クエリヒント名前空間を指定します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
scope hint:joinOrder "Ordered" .
```

**利用可能なスコープ**
+ `hint:Query`
+ `hint:Group`

クエリヒントスコープの詳細については、「[Neptune における SPARQL クエリヒントの範囲。](sparql-query-hints.md#sparql-query-hints-scope)」を参照してください。

## `joinOrder`SPARQL ヒントの例
<a name="sparql-query-hints-joinOrder-example"></a>

このセクションでは、`joinOrder` クエリヒントを使用した場合と使用していない場合に記述されたクエリ、および関連する最適化を示します。

この例では、データセットに次のものが含まれていることを前提としています。
+ `Jane` を含む 1,000 人に `:likes` エッジを持つ (「いいね！」した) `John` という名前の 1 人の人物。
+ `John` を含む 10 人に `:likes` エッジを持つ (「いいね！」した) `Jane` という名前の 1 人の人物。

**クエリヒントなし**  
次の SPARQL クエリは、一連のソーシャルネットワーキングデータから相互に「いいね！」した `John` と `Jane` という名前のすべての人物のペアを抽出します。

```
PREFIX : <https://example.com/>
SELECT ?john ?jane {
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

Neptune クエリエンジンは、記述とは異なる順序でステートメントを評価する可能性があります。たとえば、次の順序で評価するように選択される場合があります。

1. `John` という名前の人物をすべて検索します。

1. `:likes` エッジによって `John` に接続されているすべての人物を検索します。

1. `Jane` という名前の人物でこのセットをフィルタリングします。

1. `:likes` エッジによって `John` に接続されている人物でこのセットをフィルタリングします。

データセットによると、この順序で評価すると 2 番目のステップで 1,000 のエンティティが抽出されます。これは 3 番目のステップで 1 つのノード `Jane` に絞り込まれます。そして最後のステップで、`Jane` も `John` ノードに対して `:likes` エッジを持っていると判断されます。

**クエリヒント**  
`Jane` ノードには発信 `:likes` エッジが 10 個しかないため、このノードから開始する方が有利です。これにより、2 番目のステップで 1,000 のエンティティを抽出することを回避し、クエリの評価中の作業量を低減できます。

次の例では **joinOrder** クエリヒントを使用し、クエリの自動結合の順序変更をすべて無効にすることで、`Jane` ノードとその発信エッジが最初に処理されるようにします。

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

応用できる現実社会のシナリオとしては、ネットワーク内の人物を「コネクションが多いインフルエンサー」や「コネクションが少ない通常のユーザー」に分類する、ソーシャルネットワークへの応用などが挙げられます。このようなシナリオでは、前述の例のようなクエリで、インフルエンサー (`John`) の前に通常のユーザー (`Jane`) が処理されるようになっていることを確認します。

**クエリヒントと順序変更**  
この例をさらに一歩進めることができます。`:name` 属性が単一のノードに固有であることがわかっている場合は、`joinOrder` クエリヒントの順序を変更して使用することで、クエリの時間を短縮することができます。このステップでは、最初に一意のノードが抽出されるようにします。

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person2 :name "John" .
  ?person1 :likes ?person2 .
  ?person2 :likes ?person1 .
}
```

この場合、各ステップで以下の単一のアクションへのクエリを減らすことができます。

1. `:name` `Jane` を持つ 1 人の人物のノードを検索します。

1. `:name` `John` を持つ 1 人の人物のノードを検索します。

1. 最初のノードが 2 番目のノードに `:likes` エッジで接続されていることを確認します。

1. 2 番目のノードが最初のノードに `:likes` エッジで接続されていることを確認します。



**重要**  
間違った順序を選択した場合、`joinOrder` クエリヒントのパフォーマンスが大幅に低下する可能性があります。たとえば、前述の例は `:name` 属性が一意でない場合、非効率的です。100 ノードすべての名前が `Jane` で 1,000 ノードすべての名前が `John` の場合、クエリで 1,000 \$1 100 (100,000) ペアの `:likes` エッジを確認することになります。

# `evaluationStrategy`SPARQL クエリヒント
<a name="sparql-query-hints-evaluationStrategy"></a>

`evaluationStrategy` クエリヒントは、注釈が付けられたクエリのフラグメントを独立したユニットとして下部から評価するように Amazon Neptune クエリエンジンに指示します。つまり、前回の評価ステップからのソリューションは、クエリフラグメントの計算に使用されません。クエリフラグメントはスタンドアロンユニットとして評価され、生成されたソリューションは計算された後にクエリの残りの部分と結合されます。

`evaluationStrategy` クエリヒントを使用することは、(パイプライン化されていない) クエリプランをブロックすることを意味します。つまり、クエリヒントによって注釈が付けられたフラグメントのソリューションは、メインメモリでマテリアライズおよびバッファされます。特に注釈が付けられたクエリフラグメントが大量の結果を計算する場合、このクエリヒントを使用することによって、クエリの評価に必要なメインメモリの量が大幅に増加する可能性があります。

## `evaluationStrategy` SPARQL ヒント構文
<a name="sparql-query-hints-evaluationStrategy-syntax"></a>

`evaluationStrategy` クエリヒントは、SPARQL クエリに含まれる 3 つのパターンとして指定されます。

わかりやすくするために、次の構文では、クエリに定義されて含まれる `hint` プレフィックスを使用して Neptune クエリヒント名前空間を指定します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
hint:SubQuery hint:evaluationStrategy "BottomUp" .
```

**利用可能なスコープ**
+ `hint:SubQuery`

**注記**  
このクエリヒントは、ネストされたサブクエリでのみサポートされています。

クエリヒントスコープの詳細については、「[Neptune における SPARQL クエリヒントの範囲。](sparql-query-hints.md#sparql-query-hints-scope)」を参照してください。

## `evaluationStrategy`SPARQL ヒントの例
<a name="sparql-query-hints-evaluationStrategy-example"></a>



このセクションでは、`evaluationStrategy` クエリヒントを使用した場合と使用していない場合に記述されたクエリ、および関連する最適化を示します。

この例では、データセットに次の特性があることを前提としています。
+ 1,000 のエッジラベル `:connectedTo` が含まれています。
+ 各 `component` ノードは、平均 100 の他の `component` ノードに接続されています。
+ ノード間の 4 つのホップの周期的な接続の標準的な数は、約 100 です。

一般的な例として、`evaluationStrategy` ヒントはサイクルを含むクエリパターンを最適化するのに役立ちます。

**クエリヒントなし**  
次の SPARQL クエリは、4 つのホップを通じて周期的に相互に接続される `component` ノードをすべて抽出します。

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
  ?component1 :connectedTo ?component2 .
  ?component2 :connectedTo ?component3 .
  ?component3 :connectedTo ?component4 .
  ?component4 :connectedTo ?component1 .
}
```

Neptune クエリエンジンのアプローチは、次のステップを使用してこのクエリを評価することです。
+ グラフ内の 1,000 の `connectedTo` エッジをすべて抽出します。
+ 100 倍で展開します (100 は component2 からの発信 `connectedTo` エッジの数)。

  中間結果: 100,000 ノード。
+ 100 倍で展開します (100 は component3 からの発信 `connectedTo` エッジの数)。

  中間結果: 10,000,000 ノード。
+ サイクルを閉じるために 10,000,000 ノードをスキャンします。

この結果、一定量のメインメモリを持つクエリプランがストリーミングされます。

**クエリヒントとサブクエリ**  
メインメモリスペースと高速コンピューティングのトレードオフを実現できます。`evaluationStrategy` クエリヒントを使用してクエリを書き換えることで、2 つの小さなマテリアライズされたサブセット間の結合をエンジンに計算させることができます。

```
PREFIX : <https://example.com/>
          PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
  {
    SELECT * WHERE {
      hint:SubQuery hint:evaluationStrategy "BottomUp" .
      ?component1 :connectedTo ?component2 .
      ?component2 :connectedTo ?component3 .
    }
  }
  {
    SELECT * WHERE {
      hint:SubQuery hint:evaluationStrategy "BottomUp" .
      ?component3 :connectedTo ?component4 .
      ?component4 :connectedTo ?component1 .
    }
  }
}
```

今後のパターンの入力として、前の 3 つのパターンの結果を反復的に使用しながら 3 つのパターンを順番に評価する代わりに、`evaluationStrategy` ヒントを使用すると、2 つのサブクエリを個別に評価することができます。この 2 つのサブクエリは、中間結果で 100,000 のノードを生成します。これは、最終出力を生成するために結合されます。

特に、より大規模なインスタンスタイプで Neptune を実行するとき、メインメモリにこれら 2 つの 100,000 サブセットを一時的に保管することにより、評価の時間を大幅に短縮するのと引き換えにメモリ使用量が増加します。

# `queryTimeout` SPARQL クエリヒント
<a name="sparql-query-hints-queryTimeout"></a>

`queryTimeout` クエリヒントは、DB パラメータグループに設定されている `neptune_query_timeout` 値より短いタイムアウトを指定します。

このヒントの結果としてクエリが終了すると、 `Operation terminated (deadline exceeded)` メッセージとともに `TimeLimitExceededException` がスローされます。

## `queryTimeout` SPARQL ヒント構文
<a name="sparql-query-hints-queryTimeout-syntax"></a>

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ... WHERE {
    hint:Query hint:queryTimeout 10 .
    # OR
    hint:Query hint:queryTimeout "10" .
    # OR
    hint:Query hint:queryTimeout "10"^^xsd:integer .
 ...
}
```

タイムアウト値はミリ秒単位で表されます。

タイムアウト値は、DB `neptune_query_timeout` パラメーターグループで設定された値より小さくする必要があります。それ以外の場合は、 `Malformed query: Query hint 'queryTimeout' must be less than neptune_query_timeout DB Parameter Group` メッセージとともに `MalformedQueryException` 例外がスローされます。

`queryTimeout` クエリヒントは、メインクエリの `WHERE` 句、または次の例に示すようにいずれかのサブクエリの `WHERE` 句に指定する必要があります。

すべてのクエリ / サブクエリおよび SPARQL 更新セクション（INSERT、DELETE など）で 1 回のみ設定する必要があります。それ以外の場合は、 `Malformed query: Query hint 'queryTimeout' must be set only once` メッセージとともに `MalformedQueryException` 例外がスローされます。

**利用可能なスコープ**

`queryTimeout` ヒントは、SPARQL クエリと更新の両方に適用できます。
+ SPARQL クエリでは、メインクエリまたはサブクエリの WHERE 句に表示されます。
+ SPARQL 更新では、INSERT、DELETE、または WHERE 句で設定できます。複数の更新句がある場合は、そのうちの 1 つにのみ設定できます。

クエリヒントスコープの詳細については、「[Neptune における SPARQL クエリヒントの範囲。](sparql-query-hints.md#sparql-query-hints-scope)」を参照してください。

## `queryTimeout`SPARQL ヒントの例
<a name="sparql-query-hints-queryTimeout-example"></a>

`UPDATE` クエリのメイン `WHERE` 句で `hint:queryTimeout` を使用する例を示します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
INSERT {
    ?s ?p ?o
} WHERE {
    hint:Query hint:queryTimeout 100 .
    ?s ?p ?o .
}
```

ここで、`hint:queryTimeout` はサブクエリの `WHERE` 句にあります。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
   ?s ?p ?o .
   {
      SELECT ?s WHERE {
         hint:Query hint:queryTimeout 100 .
         ?s ?p1 ?o1 .
      }
   }
}
```

# `rangeSafe` SPARQL クエリヒント
<a name="sparql-query-hints-rangeSafe"></a>

SPARQL クエリのタイププロモーションをオフにするには、このクエリヒントを使用します。

数値または範囲を越える `FILTER` を含む SPARQL クエリを送信する場合、Neptune クエリエンジンは通常、クエリの実行時に型の上位変換を使用する必要があります。つまり、フィルタリングする値を保持できるすべてのタイプの値を調べる必要があります。

たとえば、55 に等しい値をフィルタリングする場合、エンジンは 55 に等しい整数、55L に等しい長整数、55.0 に等しい浮動小数点数などを探す必要があります。各型の上位変換では、ストレージに対する追加のルックアップが必要なため、単純なクエリの完了に予期せず長い時間がかかることがあります。

多くの場合、特定のタイプの値を見つけるだけで済むことが事前にわかっているため、型の上位変換は不要です。この場合、クエリを劇的に高速化するには、型の上位変換をオフにする `rangeSafe` クエリヒントを使います。

## `rangeSafe` SPARQL ヒント構文
<a name="sparql-query-hints-rangeSafe-syntax"></a>

`rangeSafe` クエリヒントは、タイププロモーションをオフにする `true` の値を取ります。また、`false` (デフォルト) の値も受け入れます。

**例。**次の例は、1 より大きい `o` の整数値のフィルタリング時にタイプ昇格をオフにする方法を示しています。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
   ?s ?p ?o .
   hint:Prior hint:rangeSafe 'true' .
   FILTER (?o > '1'^^<http://www.w3.org/2001/XMLSchema#int>)
```

# `queryId`SPARQL クエリヒント
<a name="sparql-query-hints-queryId"></a>

このクエリヒントを使用して、独自の queryId 値を SPARQL クエリに割り当てます。

例:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * WHERE {
  hint:Query hint:queryId "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
  {?s ?p ?o}}
```

割り当てる値は、Neptune DB 内のすべてのクエリで一意である必要があります。

# `useDFE` SPARQL クエリヒント
<a name="sparql-query-hints-useDFE"></a>

このクエリヒントを使用して、クエリを実行するための DFE の使用を有効にします。[neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) インスタンスパラメータはデフォルトでは `viaQueryHint` に設定されるため、デフォルトでは、このクエリヒントが `true` に設定されていないと、Neptune は DFE を使用しません。このインスタンスパラメータを `enabled` に設定した場合、`useDFE` クエリヒントが `false` に設定されているクエリを除き、すべてのクエリに DFE エンジンが使用されます。

DFE の使用をクエリに使用できるようにする例

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>

SELECT ?john ?jane
{
  hint:Query hint:useDFE true .
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

# DESCRIBE で使用される SPARQL クエリヒント
<a name="sparql-query-hints-for-describe"></a>

SPARQL `DESCRIBE` クエリは、リソースの説明をリクエストするための柔軟なメカニズムを提供します。ただし、SPARQL 仕様では、`DESCRIBE` の正確なセマンティクスは定義されていません。

[エンジンリリース 1.2.0.2](engine-releases-1.2.0.2.md) 以降、Neptune はさまざまな状況に適したいくつかの異なる `DESCRIBE` モードとアルゴリズムをサポートしています。

このサンプルデータセットは、さまざまなモードを説明するのに役立ちます。

```
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix : <https://example.com/> .

:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JohnDoe :firstName "John" .
:JaneDoe :knows _:b1 .
_:b1 :knows :RichardRoe .

:RichardRoe :knows :JaneDoe .
:RichardRoe :firstName "Richard" .

_:s1 rdf:type rdf:Statement .
_:s1 rdf:subject :JaneDoe .
_:s1 rdf:predicate :knows .
_:s1 rdf:object :JohnDoe .
_:s1 :knowsFrom "Berlin" .

:ref_s2 rdf:type rdf:Statement .
:ref_s2 rdf:subject :JaneDoe .
:ref_s2 rdf:predicate :knows .
:ref_s2 rdf:object :JohnDoe .
:ref_s2 :knowsSince 1988 .
```

以下の例では、以下のような SPARQL クエリを使用してリソース `:JaneDoe` の説明が要求されていることを前提としています。

```
DESCRIBE <https://example.com/JaneDoe>
```

## `describeMode` SPARQL クエリヒント
<a name="sparql-query-hints-describeMode"></a>

`hint:describeMode` SPARQL クエリヒントは、Neptune によってサポートされる次の SPARQL `DESCRIBE` モードのいずれかを選択するために使用されます。

### `ForwardOneStep` DESCRIBE モード
<a name="sparql-query-hints-describeMode-ForwardOneStep"></a>

次のような `describeMode` クエリヒントで `ForwardOneStep` モードを呼び出します。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "ForwardOneStep"
}
```

`ForwardOneStep` モードは、記述されるリソースの属性と転送リンクのみを返します。この例では、これは、記述されるリソース `:JaneDoe` をサブジェクトとして持つトリプルを返すことを意味します。

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b301990159 .
```

DESCRIBE クエリは、入力データセットと比較して、`_:b301990159` など、毎回異なる ID を持つ空白のノードのトリプルを返す場合があることに注意してください。

### `SymmetricOneStep` DESCRIBE モード
<a name="sparql-query-hints-describeMode-SymmetricOneStep"></a>

`SymmetricOneStep` は、クエリヒントを指定しなかった場合のデフォルトの DESCRIBE モードです。また、次のような `describeMode` クエリヒントを使って明示的に呼び出すこともできます。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SymmetricOneStep"
}
```

`SymmetricOneStep` セマンティクスでは、`DESCRIBE` は、記述されるリソースの属性、送信リンク、逆リンクを返します。

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b318767375 .

_:b318767631 rdf:subject :JaneDoe .

:RichardRoe :knows :JaneDoe .

:ref_s2 rdf:subject :JaneDoe .
```

### Concise Bounded Description (`CBD`) DESCRIBE モード
<a name="sparql-query-hints-describeMode-CBD"></a>

Concise Bounded Description (`CBD`) モードは、次のような `describeMode` クエリヒントを使用して呼び出されます。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "CBD"
}
```

`CBD` セマンティクスでは、`DESCRIBE` は、記述されるリソースの Concise Bounded Description ([W3C によって定義](http://www.w3.org/Submission/CBD)) を返します。

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b285212943 .
_:b285212943 :knows :RichardRoe .

_:b285213199 rdf:subject :JaneDoe .
_:b285213199 rdf:type rdf:Statement .
_:b285213199 rdf:predicate :knows .
_:b285213199 rdf:object :JohnDoe .
_:b285213199 :knowsFrom "Berlin" .

:ref_s2 rdf:subject :JaneDoe .
```

RDF リソース (つまり RDF グラフ内のノード) の Concise Bounded Description は、そのノードを中心として独立できる最小のサブグラフです。実際には、このグラフを、指定されたノードをルートとするツリーと考えると、そのツリーの葉のような空白のノード (bnode) は存在しないということです。bnode は外部からアドレス指定することも、後続のクエリで使用することもできないため、現在のノードから次のシングルホップを見つけるには、グラフをブラウズするだけでは不十分です。また、後続のクエリで使用できるもの (つまり、bnode 以外のもの) を見つけるにも、十分に調査する必要があります。

#### CBD の計算
<a name="sparql-query-hints-describeMode-CBD-computing"></a>

ソース RDF グラフ内の特定のノード (開始ノードまたはルート) が指定されると、そのノードの CBD は次のように計算されます。

1. ステートメントの*サブジェクト*が開始ノードであるソースグラフ内のすべてのステートメントをサブグラフに含めます。

1. 再帰的に、サブグラフ内のこれまでに空白のノード*オブジェクト*を持つすべてのステートメントについて、ソースグラフ内の、ステートメントの*サブジェクト*がその空白のノードであり、サブグラフにまだ含まれていないすべてのステートメントをサブグラフに含めます。

1. 再帰的に、それまでにサブグラフに含まれていたすべてのステートメントについて、ソースグラフ内のこれらのステートメントのすべての具象化について、各具象化の `rdf:Statement` ノードから始まる CBD を含めます。

その結果、*オブジェクト*ノードが IRI 参照またはリテラルのいずれかであるサブグラフ、または空白のノードがグラフ内のどのステートメントの*サブジェクト*にもなっていないサブグラフになります。CBD は、単一の SPARQL SELECT または CONSTRUCT クエリーでは計算できないことに注意してください。

### Symmetric Concise Bounded Description (`SCBD`) DESCRIBE モード
<a name="sparql-query-hints-describeMode-SCBD"></a>

Symmetric Concise Bounded Description (`SCBD`) モードは、次のような `describeMode` クエリヒントを使用して呼び出されます。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SCBD"
}
```

`SCBD` セマンティクスでは、`DESCRIBE` は、リソースの Symmetric Concise Bounded Description (W3C によって「[リンクされたデータセットを VoID ボキャブラリで記述する](http://www.w3.org/TR/void/)」で定義) を返します 。

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b335544591 .
_:b335544591 :knows :RichardRoe .

:RichardRoe :knows :JaneDoe .

_:b335544847 rdf:subject :JaneDoe .
_:b335544847 rdf:type rdf:Statement .
_:b335544847 rdf:predicate :knows .
_:b335544847 rdf:object :JohnDoe .
_:b335544847 :knowsFrom "Berlin" .

:ref_s2 rdf:subject :JaneDoe .
```

CBD と SCBD が `ForwardOneStep` および `SymmetricOneStep` モードより優れている点は、空白のノードが常にその表現を含むように拡張される点です。SPARQL を使用して空白のノードをクエリすることはできないため、これは重要な利点かもしれません。さらに、CBD モードと SCBD モードでは具象化も考慮されます。

`describeMode` クエリヒントは `WHERE` 句の一部にもなることに注意してください。

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE ?s
WHERE {
  hint:Query hint:describeMode "CBD" .
  ?s rdf:type <https://example.com/Person>
}
```

## `describeIterationLimit` SPARQL クエリヒント
<a name="sparql-query-hints-describeIterationLimit"></a>

`hint:describeIterationLimit` SPARQL クエリヒントは、CBD や SCBD などの反復的な DESCRIBE アルゴリズムで実行される反復拡張の最大回数に関する**オプション**制約となります。

DESCRIBE 制限は AND 処理されます。したがって、反復制限とステートメント制限の両方が指定された場合、DESCRIBE クエリを切断する前に両方の制限を満たす必要があります。

この値のデフォルトは 5 です。ゼロ (0) に設定すると、反復拡張の回数に制限がないように指定できます。

## `describeStatementLimit` SPARQL クエリヒント
<a name="sparql-query-hints-describeStatementLimit"></a>

`hint:describeStatementLimit` SPARQL クエリヒントは、DESCRIBE クエリレスポンスに含めることができるステートメントの最大数を**オプションで**制限できます。CBD や SCBD のような反復的な DESCRIBE アルゴリズムにのみ適用されます。

DESCRIBE 制限は AND 処理されます。したがって、反復制限とステートメント制限の両方が指定された場合、DESCRIBE クエリを切断する前に両方の制限を満たす必要があります。

この値のデフォルトは 5000 です。ゼロ (0) に設定すると、返されるステートメントの数に制限がないように指定できます。

# SPARQL DESCRIBE のデフォルトグラフに対する動作
<a name="sparql-default-describe"></a>

SPARQL [https://www.w3.org/TR/sparql11-query/#describe](https://www.w3.org/TR/sparql11-query/#describe) クエリフォームを使用すると、データの構造を知らなくても、またクエリを作成しなくても、リソースに関する情報を取得できます。この情報をどのように組み立てるかは、SPARQL の実装に任されています。Neptune には、`DESCRIBE` が使用できるさまざまなモードやアルゴリズムを呼び出す[クエリヒントがいくつか](sparql-query-hints-for-describe.md)用意されています。

Neptune の実装では、モードに関係なく、`DESCRIBE` は [SPARQL デフォルトグラフ](feature-sparql-compliance.md#sparql-default-graph)にあるデータのみを使用します。これは SPARQL がデータセットを扱う方法と一致しています (SPARQL 仕様の「[RDF データセットの指定](https://www.w3.org/TR/sparql11-query/#specifyingDataset)」を参照) 。

Neptune では、`FROM` や `FROM NAMED` 句を使用して特定の名前付きグラフが指定されない限り、デフォルトのグラフには、データベース内のすべての名前付きグラフの和集合に含まれるすべてのユニークなトリプルが含まれます。Neptune のすべての RDF データは、名前付きのグラフに保存されます。名前付きグラフのコンテキストなしでトリプルが挿入された場合、Neptune は `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph` という名前付きグラフに格納します。

`FROM` 句を使用して 1 つ以上の名前付きグラフが指定された場合、デフォルトのグラフは、それらの名前付きグラフに含まれるすべてのユニークなトリプルを結合したグラフになります。`FROM` 句がなく、`FROM NAMED` 句が 1 つ以上ある場合、デフォルトのグラフは空になります。

## SPARQL `DESCRIBE` の例
<a name="sparql-default-describe-examples"></a>

以下のデータを考慮します。

```
PREFIX ex: <https://example.com/>

GRAPH ex:g1 {
    ex:s ex:p1 "a" .
    ex:s ex:p2 "c" .
}

GRAPH ex:g2 {
    ex:s ex:p3 "b" .
    ex:s ex:p2 "c" .
}

ex:s ex:p3 "d" .
```

このクエリでは:

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s
FROM ex:g1
FROM NAMED ex:g2
WHERE {
  GRAPH ex:g2 { ?s ?p "b" . }
}
```

Neptune は以下を返します。

```
ex:s ex:p1 "a" .
ex:s ex:p2 "c" .
```

ここでは、グラフパターン `GRAPH ex:g2 { ?s ?p "b" }` が最初に評価され、その結果として `?s` のバインディングが行われ、次に `DESCRIBE` 部分がデフォルトのグラフ (現在は `ex:g1`) に対して評価されます。

ただし、このクエリでは:

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
FROM NAMED ex:g1 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

Neptune は何も返しません。なぜなら、`FROM NAMED` 句があり、`FROM` 句がない場合、デフォルトのグラフは空になるからです。

次のクエリでは、`DESCRIBE` が使用され、`FROM` または `FROM NAMED` 句はありません。

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

この状況では、デフォルトのグラフは、データベース内のすべての名前付きグラフの和集合に含まれるすべてのユニークなトリプルで構成されます（正式にはRDFマージ）。そのため、Neptune は次のように返します。

```
ex:s ex:p1 "a" . 
ex:s ex:p2 "c" . 
ex:s ex:p3 "b" .
ex:s ex:p3 "d" .
```

# SPARQL クエリステータス API
<a name="sparql-api-status"></a>

SPARQL クエリのステータスを取得するには、HTTP `GET` または `POST` を使用して、`https://your-neptune-endpoint:port/sparql/status` エンドポイントにリクエストを送信します。

## SPARQL クエリステータスのリクエストパラメータ
<a name="sparql-api-status-get-request"></a>

**queryId (オプション)**  
実行中の SPARQL クエリの ID。指定したクエリのステータスのみを表示します。

## SPARQL クエリステータスのレスポンスの構文
<a name="sparql-api-status-get-response-syntax"></a>

```
{
    "acceptedQueryCount": integer,
    "runningQueryCount": integer,
    "queries": [
      {
        "queryId":"guid",
        "queryEvalStats":
          {
            "subqueries": integer,
            "elapsed": integer,
            "cancelled": boolean
          },
        "queryString": "string"
      }
    ]
}
```

## SPARQL クエリステータスのレスポンス値
<a name="sparql-api-status-get-response-values"></a>

**acceptedQueryCount**  
Neptune エンジンの最後の再起動以降に受け入れられたクエリの数。

**runningQueryCount**  
現在実行中の SPARQL クエリの数。

**クエリ**  
現在の SPARQL クエリのリスト。

**queryId**  
クエリの GUID ID。Neptune は、この ID 値を各クエリに自動的に割り当てます。または、独自の ID を割り当てることもできます ([Neptune Gremlin または SPARQL クエリにカスタム ID を挿入する](features-query-id.md)を参照)。

**queryEvalStats**  
このクエリの統計情報。

**subqueries**  
このクエリのサブクエリの数。

**elapsed**  
これまでクエリが実行されていた時間 (マイクロ秒)。

**キャンセル済み**  
True はクエリがキャンセルされたことを示します。

**queryString**  
送信されたクエリ。

## SPARQL クエリステータスの例
<a name="sparql-api-status-get-example"></a>

以下は、`curl` と HTTP `GET` を使用したステータスコマンドの例です。

```
curl https://your-neptune-endpoint:port/sparql/status
```

この出力には、実行中の単一のクエリが表示されます。

```
{
    "acceptedQueryCount":9,
    "runningQueryCount":1,
    "queries": [
        {
            "queryId":"fb34cd3e-f37c-4d12-9cf2-03bb741bf54f",
            "queryEvalStats":
                {
                    "subqueries": 0,
                    "elapsed": 29256,
                    "cancelled": false
                },
            "queryString": "SELECT ?s ?p ?o WHERE {?s ?p ?o}"
        }
    ]
}
```

# SPARQL クエリのキャンセル
<a name="sparql-api-status-cancel"></a>

SPARQL クエリのステータスを取得するには、HTTP `GET` または `POST` を使用して、`https://your-neptune-endpoint:port/sparql/status` エンドポイントにリクエストを送信します。

## SPARQL クエリのキャンセルリクエストパラメータ
<a name="sparql-api-status-cancel-request"></a>

**cancelQuery**  
(必須) クエリをキャンセルするようステータスコマンドに指示します。このパラメータは値を取りません。

**queryId**  
(必須) キャンセルする実行中の SPARQL クエリの ID。

**silent**  
(オプション) `silent=true` の場合、実行中のクエリはキャンセルされます。HTTP レスポンスコードは 200 です。`silent` が存在しない場合、または `silent=false` である場合、クエリは HTTP 500 ステータスコードでキャンセルされます。

## SPARQL クエリのキャンセルの例
<a name="sparql-api-status-cancel-example"></a>

**例 1: `silent=false` でのキャンセル**  
次に示すのは、`curl` を使用し、`silent` パラメータを `false` に設定してクエリをキャンセルするステータスコマンドの例です。

```
curl https://your-neptune-endpoint:port/sparql/status \
  -d "cancelQuery" \
  -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47" \
  -d "silent=false"
```

クエリが既に結果のストリーミングを開始していない限り、キャンセルされたクエリは、次のようなレスポンスを持つ HTTP 500 コードを返します。

```
{
  "code": "CancelledByUserException",
  "requestId": "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47",
  "detailedMessage": "Operation terminated (cancelled by user)"
}
```

クエリが既に HTTP 200 コード (OK) を返し、キャンセルされる前に結果のストリーミングを開始した場合、タイムアウト例外情報が通常の出力ストリームに送信されます。

**例 2: `silent=true` でのキャンセル**  
次に示すのは、`silent` パラメータが `true` に設定されている場合を除いて、上記と同じステータスコマンドの例です。

```
curl https://your-neptune-endpoint:port/sparql/status \
  -d "cancelQuery" \
  -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47" \
  -d "silent=true"
```

このコマンドは `silent=false` の場合と同じレスポンスを返しますが、キャンセルされたクエリは次のようなレスポンスを伴う HTTP 200 コードを返すようになります。

```
{
  "head" : {
    "vars" : [ "s", "p", "o" ]
  },
  "results" : {
    "bindings" : [ ]
  }
}
```

# Amazon Neptune での SPARQL 1.1 グラフストア HTTP プロトコル (GSP) の使用
<a name="sparql-graph-store-protocol"></a>

[SPARQL 1.1 グラフストア HTTP プロトコル](https://www.w3.org/TR/sparql11-http-rdf-update/)レコメンデーションでは、W3C は RDF グラフを管理するための HTTP プロトコルを定義しました。RDF グラフコンテンツの削除、作成、および置き換え、および既存のコンテンツに RDF ステートメントを追加する操作を定義します。

グラフストアプロトコル (GSP) は、複雑な SPARQL クエリを記述することなく、グラフ全体を操作する便利な方法を提供します。

Neptune はこのプロトコルを完全にサポートしています。

グラフストアプロトコル (GSP) のエンドポイントは次のとおりです。

```
https://your-neptune-cluster:port/sparql/gsp/
```

GSP でデフォルトのグラフにアクセスするには、以下を使用します。

```
https://your-neptune-cluster:port/sparql/gsp/?default
```

GSP で名前付きグラフにアクセスするには、以下を使用します。

```
https://your-neptune-cluster:port/sparql/gsp/?graph=named-graph-URI
```

## Neptune GSP 実装の特別な詳細
<a name="sparql-graph-store-protocol-special"></a>

Neptune はGSPを定義する [W3C レコメンデーション](https://www.w3.org/TR/sparql11-http-rdf-update/)を完全に実装しています。ただし、仕様がカバーしていない状況はいくつかあります。

その 1 つは、`PUT` または `POST` リクエストが、リクエスト本文に、リクエスト URL で指定されたグラフとは異なる名前付きグラフを 1 つ以上指定する場合です。これは、リクエスト本文 RDF 形式がたとえば、`Content-Type: application/n-quads` または `Content-Type: application/trig` を使って名前付きグラフをサポートしている場合にのみ発生します。

この状況では、Neptune は、URL で指定された名前付きグラフだけでなく、本文に存在するすべての名前付きグラフを追加または更新します。

たとえば、空のデータベースから開始して、3 つのグラフにアップサートするよう `PUT` リクエストを送ります。1つの名前付き `urn:votes` は、すべての選挙年度からの全得票を含みます。他の2つ、名前付き `urn:votes:2005` および `urn:votes:2019` は、特定の選挙年の投票を含めます。リクエストとそのペイロードは次のようになります。

```
PUT "http://your-Neptune-cluster:port/sparql/gsp/?graph=urn:votes"
  Host: example.com
  Content-Type: application/n-quads

  PAYLOAD:

  <urn:JohnDoe> <urn:votedFor> <urn:Labour> <urn:votes:2005>
  <urn:JohnDoe> <urn:votedFor> <urn:Conservative> <urn:votes:2019>
  <urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes:2005>
  <urn:JaneSmith> <urn:votedFor> <urn:Conservative> <urn:votes:2019>
```

リクエストが実行されると、データベース内のデータは次のようになります。

```
<urn:JohnDoe>   <urn:votedFor> <urn:Labour>           <urn:votes:2005>
<urn:JohnDoe>   <urn:votedFor> <urn:Conservative>     <urn:votes:2019>
<urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes:2005>
<urn:JaneSmith> <urn:votedFor> <urn:Conservative>     <urn:votes:2019>
<urn:JohnDoe>   <urn:votedFor> <urn:Labour>           <urn:votes>
<urn:JohnDoe>   <urn:votedFor> <urn:Conservative>     <urn:votes>
<urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes>
<urn:JaneSmith> <urn:votedFor> <urn:Conservative>     <urn:votes>
```

別のあいまいな状況は、`PUT`、`POST`、`GET` または `DELETE` を使って、リクエストURL自体に複数のグラフが指定されている場合です。例: 

```
POST "http://your-Neptune-cluster:port/sparql/gsp/?graph=urn:votes:2005&graph=urn:votes:2019"
```

または:

```
GET "http://your-Neptune-cluster:port/sparql/gsp/?default&graph=urn:votes:2019"
```

この状況では、Neptune はリクエスト URL に指定できるグラフが 1 つだけであることを示すメッセージを含む HTTP 400 を返します。

# SPARQL `explain` を使用して Neptune クエリ実行を分析する
<a name="sparql-explain"></a>

Amazon Neptune に *explain* という名前の SPARQL 機能が追加されました。この機能は、Neptune エンジンが使用する実行アプローチを理解するためのセルフサービスツールです。SPARQL クエリを送信する HTTP コールに `explain` パラメータを追加してこれを呼び出します。

`explain` 機能は、クエリ実行プランの論理構造に関する情報を提供します。この情報を使用して潜在的な評価と実行障害を明らかにします。次に、「[クエリに関するヒント](sparql-query-hints.md)」を使用して、クエリ実行プランを改善できます。

**Topics**
+ [Neptune における SPARQL クエリエンジンの仕組み](sparql-explain-engine.md)
+ [Neptune クエリ実行の分析に SPARQL `explain` を使用する方法](sparql-explain-using.md)
+ [Neptune の SPARQL `explain` を呼び出す例](sparql-explain-examples.md)
+ [Neptune SPARQL `explain` 演算子](sparql-explain-operators.md)
+ [Neptune での SPARQL `explain` の制約事項](sparql-explain-limitations.md)

# Neptune における SPARQL クエリエンジンの仕組み
<a name="sparql-explain-engine"></a>

SPARQL `explain` 機能が提供する情報を使用するには、Amazon Neptune SPARQL クエリエンジンの仕組みについてのいくつかの詳細を理解する必要があります。

エンジンはすべての SPARQL クエリを演算子のパイプラインに変換します。最初の演算子から始まり、*バインドリスト*として知られる中間ソリューションはこの演算子パイプラインを介して進みます。バインドリストは、テーブルヘッダーがクエリ内で使用される変数のサブセットであるテーブルとして考えることができます。テーブルの各行は、評価ポイントまでの結果を表します。

使用するデータには 2 つの名前空間プレフィックスが定義されていると仮定します。

```
  @prefix ex:   <http://example.com> .
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
```

以下に示しているのは、このコンテキストのシンプルなバインドの例です。

```
  ?person       | ?firstName
  ------------------------------------------------------
  ex:JaneDoe    | "Jane"
  ex:JohnDoe    | "John"
  ex:RichardRoe | "Richard"
```

3 人ごとに、このリストは `?person` 変数をこの人物の識別子にバインドし、`?firstName` 変数をこの人物の名前にバインドします。

一般的なケースでは、たとえばデータに値がないクエリに変数の `OPTIONAL` 選択がある場合には、変数はバインドしないままにできます。

`PipelineJoin` 演算子は、`explain` 出力にある Neptune クエリエンジン演算子の例です。ここでは、前の演算子からの一連の着信バインドを入力として使用し、これを 3 つのパターン (つまり、`(?person, foaf:lastName, ?lastName)`) に結合します。この演算では、入力ストリームに `?person` 変数のバインドを使用し、これを 3 つのパターンに置き換えて、データベースから 3 つを検索します。

前のテーブルからの着信バインドのコンテキストで実行するとき、`PipelineJoin` は次に示す 3 つの検索を評価します。

```
  (ex:JaneDoe,    foaf:lastName, ?lastName)
  (ex:JohnDoe,    foaf:lastName, ?lastName)
  (ex:RichardRoe, foaf:lastName, ?lastName)
```

このアプローチは*アズバウンド*評価と呼ばれます。この評価プロセスのソリューションは、検出された `?lastName` を着信ソリューションに当てはめて、着信ソリューションに再び結合されます。3 人の人物のすべての姓が見つかったとすると、演算子は次のような送信バインドリストを生成します。

```
  ?person       | ?firstName | ?lastName
  ---------------------------------------
  ex:JaneDoe    | "Jane"     | "Doe"
  ex:JohnDoe    | "John"     | "Doe"
  ex:RichardRoe | "Richard"  | "Roe"
```

次に、この送信バインドリストは、パイプラインの次の入力として機能します。最終的に、パイプラインの最後の演算子の出力はクエリの結果を定義します。

演算子パイプラインは多くの場合に直線的です。つまり、各演算子は単一に接続された演算子のソリューションを発行します。ただし、一部の場合、よる複雑な構造になることができます。たとえば、SPARQL クエリの `UNION` 演算子は `Copy` 演算にマッピングされます。この演算はバインドを複製し、このコピーを 2 つのサブプラン (1 つは `UNION` の左側、もう 1 つは右側) に転送します。

演算子についての詳細は、「[Neptune SPARQL `explain` 演算子](sparql-explain-operators.md)」を参照してください。

# Neptune クエリ実行の分析に SPARQL `explain` を使用する方法
<a name="sparql-explain-using"></a>

SPARQL の `explain` 機能は、Neptune エンジンが使用する実行アプローチを理解するために役立つ Amazon Neptune のセルフサービスツールです。`explain` を呼び出すには、パラメータを `explain=mode` フォームで HTTP あるいは HTTPS リクエストに渡します。

モードの値は `static`、`dynamic`、`details` のいずれかです。
+ *静的*モードでは、`explain` はクエリプランの静的構造のみを表示します。
+ *動的*モードでは、`explain` にはクエリプランの動的な要素も含まれます。以上には、演算子を介して通過する中間バインドの数、送信バインドに対する着信バインドの割合、演算子の所要合計時間が含まれる場合があります。
+ *詳細*モードの場合、`explain` は `dynamic` モードで表示される情報に加えて、実際の SPARQL クエリ文字列や、結合演算子が基づくパターンの推定範囲数などの詳細を出力します。

Neptune は `explain` を使用して [W3C SPARQL 1.1 プロトコル](https://www.w3.org/TR/sparql11-protocol/#query-operation)仕様に挙げられている 3 つの SPARQL クエリアクセスプロトコルはすべてサポートしています。すなわち次です。

1. HTTP GET

1. URL エンコードパラメータを使用した HTTP POST

1. テキストパラメータを使用した HTTP POST

SPARQL クエリエンジンの詳細については、「[Neptune における SPARQL クエリエンジンの仕組み](sparql-explain-engine.md)」を参照してください。

SPARQL `explain` を呼び出すことで生成される出力の種類については、「[Neptune の SPARQL `explain` を呼び出す例](sparql-explain-examples.md)」を参照してください。

# Neptune の SPARQL `explain` を呼び出す例
<a name="sparql-explain-examples"></a>

このセクションの例では、Amazon Neptune のクエリ実行を分析するために、SPARQL `explain` 機能を呼び出して生成できるさまざまな種類の出力を示しています。

**Topics**
+ [Explain 出力を理解する](#sparql-explain-example-output)
+ [詳細モード出力の例](#sparql-explain-example-details)
+ [静的モード出力の例](#sparql-explain-example-static)
+ [パラメータをエンコードするさまざま方法](#sparql-explain-example-parameters)
+ [テクスト/プレーンの他の出力タイプ](#sparql-explain-output-options)
+ [DFE が無効の場合の SPARQL `explain` 出力の例](#sparql-explain-output-dfe)

## Explain 出力を理解する
<a name="sparql-explain-example-output"></a>

この例では、Jane Doe は 2 人の人 (John Doe と Richard Roe) を知っています。

```
@prefix ex: <http://example.com> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

ex:JaneDoe foaf:knows ex:JohnDoe .
ex:JohnDoe foaf:firstName "John" .
ex:JohnDoe foaf:lastName "Doe" .
ex:JaneDoe foaf:knows ex:RichardRoe .
ex:RichardRoe foaf:firstName "Richard" .
ex:RichardRoe foaf:lastName "Roe" .
.
```

Jane Doe が知っているすべての人々の名前を確認するには、次のクエリを記述できます。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -H "Accept: text/csv"
```

このシンプルなクエリは次を返します。

```
firstName
John
Richard
```

次に、`-d "explain=dynamic"` を追加し、`text/csv` の代わりにデフォルトの出力タイプを使用して `curl` コマンドを変更し、`explain` を呼び出します。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=dynamic"
```

このクエリは ASCII 形式 (HTTP コンテンツタイプ `text/plain`) の適切な出力を変えすようになります。これはデフォルトの出力タイプです。

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        │ 1        │ 2         │ 2.00  │ 1         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        │ 2        │ 2         │ 1.00  │ 1         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   │ 2        │ 2         │ 1.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value │ 2        │ 2         │ 1.00  │ 1         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

`Name` 列およびその引数における演算についての詳細は、「[EXPLAIN 演算子](sparql-explain-operators.md)」を参照してください。

以下に行ごとの出力行を説明します。

1. 主要なクエリの最初のステップでは常に、`SolutionInjection` 演算子を使用してソリューションを挿入します。次に、このソリューションは評価プロセスを介して最終結果へと拡大します。

   この場合、ユニバーサルソリューションと呼ばれる `{ }` を挿入します。`VALUES` 句 あるいは `BIND` がある場合、このステップではより複雑な変数バインドを挿入して始めることもできます。

   `Units Out` 列は、この単一のソリューションが演算子から流出したことを示しています。`Out #1` 列は、この演算子が結果を出す先の演算子を指定します。この例では、すべての演算子はテーブル内に続く演算子に接続しています。

1. 2 番目のステップは `PipelineJoin` です。これは、前の演算子 (`Units In := 1`) によって生成された単一のユニバーサル (完全に制約がない) ソリューションを入力として受け取ります。これは、`pattern` 引数によって定義されるタプルパターンに結合します。これは、パターンのシンプルな探索に対応します。この場合、3 つのパターンは以下のように定義されます。

   ```
   distinct( ex:JaneDoe, foaf:knows, ?person )
   ```

   `joinType := join` 引数は、これが通常の結合であることを示します (他のタイプには `optional` 結合、`existence check` 結合などが含まれます)。

   `distinct := true` 引数は、データベースから重複を排除した一致のみ (重複なし) を抽出し、重複を除外した一致を 変数 `joinProjectionVars := ?person` に重複してバインドすることを示します。

   `Units Out` 列の値が 2 であることは、2 つのソリューションが流出していることを示しています。具体的には、これらは `?person` 変数のバインドであり、Jane Doe が知っているとデータが示す 2 人を反映します。

   ```
    ?person
    -------------
    ex:JohnDoe
    ex:RichardRoe
   ```

1. ステージ 2 の 2 つのソリューションは、入力 (`Units In := 2`) として 2 番目の `PipelineJoin` になります。この演算子は、次の 3 つのパターンに前の 2 つのソリューションを結合します。

   ```
   distinct(?person, foaf:firstName, ?firstName)
   ```

   `?person` 変数は、演算子の着信ソリューションによって `ex:JohnDoe` あるいは `ex:RichardRoe` のいずれかにバインドされることになります。この結果、`PipelineJoin` は名前である John と Richard を抽出します。2 つの発信ソリューション (Units Out:=2) は、次のようになります。

   ```
    ?person       | ?firstName
    ---------------------------
    ex:JohnDoe    | John
    ex:RichardRoe | Richard
   ```

1. 次の射影演算子は入力としてステージ 3 の 2 つのソリューションを用い (`Units In := 2`) を用いて、`?firstName` 変数に射影します。これによって、マッピング内の他のすべての変数バインドが排除され、2 つのバインドに渡されます (`Units Out := 2`)。

   ```
    ?firstName
    ----------
    John
    Richard
   ```

1. パフォーマンスを向上させるため、Neptune は、文字列自身ではなく、URI や文字列リテラルなどの項目に割り当てることが可能な内部の識別子で機能します。最後の演算子 `TermResolution` は、これらの内部の識別子から対応する項目の文字列に戻ってマッピングを実行します。

   通常の (explain ではない) クエリ評価では、最後の演算子によって計算された結果はリクエストされたシリアル化形式にシリアル化され、クライアントにストリームされます。

## 詳細モード出力の例
<a name="sparql-explain-example-details"></a>

*動的*モードではなく*詳細*モードの前と同じクエリを実行するとします。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=details"
```

この例に示すように、出力は同じですが、出力の上部にあるクエリ文字列や `PipelineJoin` 演算子の `patternEstimate` カウントなど、いくつかの詳細が追加されています。

```
Query:
PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/>
SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }

╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        │ 1        │ 2         │ 2.00  │ 13        ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          │          │           │       │           ║
║    │        │        │                   │ patternEstimate=2                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        │ 2        │ 2         │ 1.00  │ 3         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          │          │           │       │           ║
║    │        │        │                   │ patternEstimate=2                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   │ 2        │ 2         │ 1.00  │ 1         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value │ 2        │ 2         │ 1.00  │ 7         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

## 静的モード出力の例
<a name="sparql-explain-example-static"></a>

*静的*モード (デフォルト) ではなく*詳細*モードの前と同じクエリを実行するとします。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=static"
```

この例に示すように、出力は、最後の 3 つの列が除外されていることを除いて、同じになります。

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        ║
║    │        │        │                   │ joinType=join                                         │          ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        ║
║    │        │        │                   │ joinType=join                                         │          ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╝
```

## パラメータをエンコードするさまざま方法
<a name="sparql-explain-example-parameters"></a>

次のクエリの例では、SPARQL `explain` を呼び出すときにパラメータをエンコードする 2 つの異なる方法を示しています。

**URL エンコードを使用する** – この例は、パラメータの URL エンコードを使用し、*動的*出力を指定します。

```
curl -XGET "http(s)://your_server:your_port/sparql?query=SELECT%20*%20WHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20%7D%20LIMIT%20%31&explain=dynamic"
```

**パラメータを直接指定する** - これは、POST を介してパラメータを直接渡すことを除き、前のクエリと同じです。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic"
```

## テクスト/プレーンの他の出力タイプ
<a name="sparql-explain-output-options"></a>

上記の例では、デフォルト `text/plain` 出力タイプを使用しています。Neptune は SPARQL `explain` 出力もフォーマット他の 2 つの MIME タイプのフォーマット、すなわち `text/csv` および `text/html` に出力できます。HTTP `Accept` ヘッダーを設定することがこれらを呼び出します。次に示すように、`curl` で `-H` フラグを使用することでこれを実行できます。

```
  -H "Accept: output type"
```

次に例を示します。

**`text/csv` 出力**  
このクエリは、`-H "Accept: text/csv"` を指定して CSV MIME タイプの出力を呼び出します。

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic" \
   -H "Accept: text/csv"
```

スプレッドシートやデータベースへのインポートに便利な CSV 形式は、次に示すようにファイルを `explain` 行ごとにセミコロン (`;`) で分離します。

```
ID;Out #1;Out #2;Name;Arguments;Mode;Units In;Units Out;Ratio;Time (ms)
0;1;-;SolutionInjection;solutions=[{}];-;0;1;0.00;0
1;2;-;PipelineJoin;pattern=distinct(?s, ?p, ?o),joinType=join,joinProjectionVars=[?s, ?p, ?o];-;1;6;6.00;1
2;3;-;Projection;vars=[?s, ?p, ?o];retain;6;6;1.00;2
3;-;-;Slice;limit=1;-;1;1;1.00;1
```

 

**`text/html` 出力**  
`-H "Accept: text/html"` を指定すると、`explain` は HTML テーブルを生成します。

```
<!DOCTYPE html>
<html>
  <body>
    <table border="1px">
      <thead>
        <tr>
          <th>ID</th>
          <th>Out #1</th>
          <th>Out #2</th>
          <th>Name</th>
          <th>Arguments</th>
          <th>Mode</th>
          <th>Units In</th>
          <th>Units Out</th>
          <th>Ratio</th>
          <th>Time (ms)</th>
        </tr>
      </thead>

      <tbody>
        <tr>
          <td>0</td>
          <td>1</td>
          <td>-</td>
          <td>SolutionInjection</td>
          <td>solutions=[{}]</td>
          <td>-</td>
          <td>0</td>
          <td>1</td>
          <td>0.00</td>
          <td>0</td>
        </tr>

        <tr>
          <td>1</td>
          <td>2</td>
          <td>-</td>
          <td>PipelineJoin</td>
          <td>pattern=distinct(?s, ?p, ?o)<br>
              joinType=join<br>
              joinProjectionVars=[?s, ?p, ?o]</td>
          <td>-</td>
          <td>1</td>
          <td>6</td>
          <td>6.00</td>
          <td>1</td>
        </tr>

        <tr>
          <td>2</td>
          <td>3</td>
          <td>-</td>
          <td>Projection</td>
          <td>vars=[?s, ?p, ?o]</td>
          <td>retain</td>
          <td>6</td>
          <td>6</td>
          <td>1.00</td>
          <td>2</td>
        </tr>

        <tr>
          <td>3</td>
          <td>-</td>
          <td>-</td>
          <td>Slice</td>
          <td>limit=1</td>
          <td>-</td>
          <td>1</td>
          <td>1</td>
          <td>1.00</td>
          <td>1</td>
        </tr>
      </tbody>
    </table>
  </body>
</html>
```

HTML はブラウザに次のようにレンダリングされます。

![\[SPARQL Explain HTML 出力サンプル。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/sparql-explain-dynamic-html-output.png)


## DFE が無効の場合の SPARQL `explain` 出力の例
<a name="sparql-explain-output-dfe"></a>

DFE 代替クエリエンジンが有効な場合の SPARQL `explain` レポート例を次に示します。

```
╔════╤════════╤════════╤═══════════════════╤═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                                                                                                                                                                                               │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                                                                                                                                                                                          │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ HashIndexBuild    │ solutionSet=solutionSet1                                                                                                                                                                                                │ -        │ 1        │ 1         │ 1.00  │ 22        ║
║    │        │        │                   │ joinVars=[]                                                                                                                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │ sourceType=pipeline                                                                                                                                                                                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFENode           │ DFE Stats=                                                                                                                                                                                                                    │ -        │ 101      │ 100       │ 0.99  │ 32        ║
║    │        │        │                   │ ====> DFE execution time (measured by DFEQueryEngine)                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ accepted [micros]=127                                                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ ready [micros]=2                                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ running [micros]=5627                                                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ finished [micros]=0                                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> DFE execution time (measured in DFENode)                                                                                                                                                                           │          │          │           │       │           ║
║    │        │        │                   │ -> setupTime [ms]=1                                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │ -> executionTime [ms]=14                                                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │ -> resultReadTime [ms]=0                                                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> Static analysis statistics                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 35907 micros spent in parser.                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ --> 7643 micros spent in range count estimation                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 2895 micros spent in value resolution                                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 39974925 micros spent in optimizer loop                                                                                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ DFEJoinGroupNode[ children={                                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │   DFEPatternNode[(?1, TERM[117442062], ?2, ?3) . project DISTINCT[?1, ?2] {rangeCountEstimate=100},                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │     OperatorInfoWithAlternative[                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       rec=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_PIPELINE_JOIN,                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0002,comp=0.0000,mem=0],                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0002,comp=0.0000,mem=0]]],                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │       alt=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_HASH_JOIN,                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0003,comp=0.0000,mem=3212],                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0003,comp=0.0000,mem=3212]]]]],                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │   DFEPatternNode[(?1, TERM[150997262], ?4, ?5) . project DISTINCT[?1, ?4] {rangeCountEstimate=100},                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │     OperatorInfoWithAlternative[                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       rec=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_HASH_JOIN,                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0003,comp=0.0000,mem=6400],                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0003,comp=0.0000,mem=6400]]],                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       alt=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_PIPELINE_JOIN,                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0010,comp=0.0000,mem=0],                                                                                                                      │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0010,comp=0.0000,mem=0]]]]]                                                                                                          │          │          │           │       │           ║
║    │        │        │                   │ },                                                                                                                                                                                                                      │          │          │           │       │           ║
║    │        │        │                   │ ]                                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> DFE configuration:                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │ solutionChunkSize=5000                                                                                                                                                                                                  │          │          │           │       │           ║
║    │        │        │                   │ ouputQueueSize=20                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ numComputeCores=3                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ maxParallelIO=10                                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ numInitialPermits=12                                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ====> DFE configuration (reported back)                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │ numComputeCores=3                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ maxParallelIO=2                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ numInitialPermits=12                                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> Statistics & operator histogram                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │ ==> Statistics                                                                                                                                                                                                          │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 3668 micros total elapsed (incl. wait / excl. wait)                                                                                                                                                           │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 3 millis total elapse (incl. wait / excl. wait)                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 0 secs total elapsed (incl. wait / excl. wait)                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │ ==> Operator histogram                                                                                                                                                                                                  │          │          │           │       │           ║
║    │        │        │                   │ -> 47.66% of total time (excl. wait): pipelineScan (2 instances)                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ -> 10.99% of total time (excl. wait): merge (1 instances)                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │ -> 41.17% of total time (excl. wait): symmetricHashJoin (1 instances)                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ -> 0.19% of total time (excl. wait): drain (1 instances)                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ nodeId | out0   | out1 | opName            | args                                             | rowsIn | rowsOut | chunksIn | chunksOut | elapsed* | outWait | outBlocked | ratio    | rate* [M/s] | rate [M/s] | %     │          │          │           │       │           ║
║    │        │        │                   │ ------ | ------ | ---- | ----------------- | ------------------------------------------------ | ------ | ------- | -------- | --------- | -------- | ------- | ---------- | -------- | ----------- | ---------- | ----- │          │          │           │       │           ║
║    │        │        │                   │ node_0 | node_2 | -    | pipelineScan      | (?1, TERM[117442062], ?2, ?3) DISTINCT [?1, ?2]  | 0      | 100     | 0        | 1         | 874      | 0       | 0          | Infinity | 0.1144      | 0.1144     | 23.83 │          │          │           │       │           ║
║    │        │        │                   │ node_1 | node_2 | -    | pipelineScan      | (?1, TERM[150997262], ?4, ?5) DISTINCT [?1, ?4]  | 0      | 100     | 0        | 1         | 874      | 0       | 0          | Infinity | 0.1144      | 0.1144     | 23.83 │          │          │           │       │           ║
║    │        │        │                   │ node_2 | node_4 | -    | symmetricHashJoin |                                                  | 200    | 100     | 2        | 2         | 1510     | 73      | 0          | 0.50     | 0.0662      | 0.0632     | 41.17 │          │          │           │       │           ║
║    │        │        │                   │ node_3 | -      | -    | drain             |                                                  | 100    | 0       | 1        | 0         | 7        | 0       | 0          | 0.00     | 0.0000      | 0.0000     | 0.19  │          │          │           │       │           ║
║    │        │        │                   │ node_4 | node_3 | -    | merge             |                                                  | 100    | 100     | 2        | 1         | 403      | 0       | 0          | 1.00     | 0.2481      | 0.2481     | 10.99 │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ HashIndexJoin     │ solutionSet=solutionSet1                                                                                                                                                                                                │ -        │ 100      │ 100       │ 1.00  │ 4         ║
║    │        │        │                   │ joinType=join                                                                                                                                                                                                           │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ Distinct          │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ -        │ 100      │ 100       │ 1.00  │ 9         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ Projection        │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ retain   │ 100      │ 100       │ 1.00  │ 2         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ -      │ -      │ TermResolution    │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ id2value │ 100      │ 100       │ 1.00  │ 11        ║
╚════╧════════╧════════╧═══════════════════╧═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Neptune SPARQL `explain` 演算子
<a name="sparql-explain-operators"></a>

以下のセクションでは、Amazon Neptune で現在使用できる SPARQL `explain` 機能の演算子とパラメータについて説明しています。

**重要**  
SPARQL `explain` 機能は今後も改良されます。ここに記載されている演算子とパラメータは、今後のバージョンで変更される可能性があります。

**Topics**
+ [`Aggregation`operator](#sparql-explain-operator-aggregation)
+ [`ConditionalRouting`operator](#sparql-explain-operator-conditional-routing)
+ [`Copy`operator](#sparql-explain-operator-copy)
+ [`DFENode`operator](#sparql-explain-operator-dfenode)
+ [`Distinct`operator](#sparql-explain-operator-distinct)
+ [`Federation`operator](#sparql-explain-operator-federation)
+ [`Filter`operator](#sparql-explain-operator-filter)
+ [`HashIndexBuild`operator](#sparql-explain-operator-hash-index-build)
+ [`HashIndexJoin`operator](#sparql-explain-operator-hash-index-join)
+ [`MergeJoin`operator](#sparql-explain-operator-merge-join)
+ [`NamedSubquery`operator](#sparql-explain-operator-named-subquery)
+ [`PipelineJoin`operator](#sparql-explain-operator-pipeline-join)
+ [`PipelineCountJoin`operator](#sparql-explain-operator-pipeline-count-join)
+ [`PipelinedHashIndexJoin`operator](#sparql-explain-operator-pipeline-hash-index-join)
+ [`Projection`operator](#sparql-explain-operator-projection)
+ [`PropertyPath`operator](#sparql-explain-operator-property-path)
+ [`TermResolution`operator](#sparql-explain-operator-term-resolution)
+ [`Slice`operator](#sparql-explain-operator-slice)
+ [`SolutionInjection`operator](#sparql-explain-operator-solution-injection)
+ [`Sort`operator](#sparql-explain-operator-sort)
+ [`VariableAlignment`operator](#sparql-explain-operator-variable-alignment)

## `Aggregation`operator
<a name="sparql-explain-operator-aggregation"></a>

SPARQL 集約演算のセマンティクス (`count`、`max`、`min`、`sum` など) を実装した 1 つ以上の集計を実行します。

`Aggregation` には、オプションとして `groupBy` を使用したグループ化、およびオプションとして `having` 制約が用意されています。

**引数**
+ `groupBy` – (*オプション*) 着信ソリューションのグループ化の基盤となる連続式を指定する `groupBy` 句を提供します。
+ `aggregates` –  (*必須*) 集約式の順序リストを指定します。
+ `having` – (*オプション*) SPARQL クエリ内の `having` 句に指定されるように、グループに制約フィルターを追加します。

## `ConditionalRouting`operator
<a name="sparql-explain-operator-conditional-routing"></a>

指定された条件に基づいて、受信ソリューションをルーティングします。条件を満たすソリューションは、`Out #1` に参照されるオペレーター ID にルーティングされます。条件を満たさないソリューションは、`Out #2` に参照されるオペレーターにルーティングされません。

**引数**
+ `condition` – (*必須*) ルーティング条件。

## `Copy`operator
<a name="sparql-explain-operator-copy"></a>

指定されたモードに示されるように、ソリューションストームを委任します。

**モード**
+ `forward` – ソリューションを `Out #1` によって識別されるダウンストリーム演算子に転送します。
+ `duplicate` – ソリューションを複製し、それぞれを `Out #1` および `Out #2` によって識別される 2 つの演算子に転送します。

`Copy` には引数がありません。

## `DFENode`operator
<a name="sparql-explain-operator-dfenode"></a>

この演算子は、DFE 代替クエリエンジンによって実行されるプランの抽象化です。詳細な DFE 計画は、この演算子の引数に概説されています。引数は現在、DFE プランの詳細なランタイム統計を含むようにオーバーロードされています。これには、DFE によるクエリ実行のさまざまなステップに費やされた時間が含まれます。

DFE クエリプランの論理最適化抽象構文ツリー (AST) には、計画中に考慮された演算子タイプに関する情報と、演算子の実行に関連する最良および最悪の場合のコストが出力されます。AST は、現時点で次のタイプのノードで構成されています。
+ `DFEJoinGroupNode`   –   1 つ以上の `DFEPatternNodes` の結合を表します。
+ `DFEPatternNode` - 基礎となるデータベースから一致するタプルが投影される基になるパターンを括弧で囲みます。

サブセクション、`Statistics & Operator histogram` には、各オペレータが使用するCPU時間の `DataflowOp` 計画と内訳の実行時間に関する詳細が含まれています。この下に、DFE によって実行されるプランの詳細なランタイム統計を出力する表があります。

**注記**  
DFE はラボモードでリリースされる実験的な機能なので、`explain` 出力は変更される可能性があります。

## `Distinct`operator
<a name="sparql-explain-operator-distinct"></a>

変数のサブセットにおける個別の射影を計算し、重複を排除します。その結果、流入するソリューションの数は流出するソリューションの数より大きいかあるいは等しくなります。

**引数**
+ `vars` – (*必須*) `Distinct` 射影を適用する変数。

## `Federation`operator
<a name="sparql-explain-operator-federation"></a>

指定されたクエリを指定されたリモート SPARQL エンドポイントに渡します。

**引数**
+ `endpoint` – (*必須*) SPARQL `SERVICE` ステートメントのエンドポイント URL。これは定数文字列にすることができます。または、クエリエンドポイントが同じクエリ内の変数に基づいて決定される場合は、変数名にすることができます。
+ `query` – (*必須*) リモートエンドポイントに送信される、再構築されたクエリ文字列。エンジンは、クライアントが指定されていない場合でも、このクエリにデフォルトのプレフィックスを追加します。
+ `silent` – (*必須*) `SILENT` キーワードがキーワードの後に表示されるかどうかを示すブール値。`SILENT` は、リモート `SERVICE` 部分が失敗してもクエリ全体が失敗しないようにエンジンに指示します。

## `Filter`operator
<a name="sparql-explain-operator-filter"></a>

着信ソリューションをフィルタリングします。フィルタリング条件を満たすソリューションのみがアップストリームに転送され、その他すべては削除されます。

**引数**
+ `condition` – (*必須*) フィルタリング条件。

## `HashIndexBuild`operator
<a name="sparql-explain-operator-hash-index-build"></a>

バインドのリストを取得し、`solutionSet` 引数で定義される名前を持つハッシュインデックスにこのリストをスプールします。通常は、以降の演算子の実行は、名前を参照して、この一連のソリューションに対して結合します。

**引数**
+ `solutionSet` – (*必須*) 一連のハッシュインデックスソリューションの名前。
+ `sourceType` – (*必須*) ハッシュインデックスに保存されるバインドが取得される元のソースのタイプ。
  + `pipeline` – 演算子パイプラインのダウンストリーム演算子から着信するソリューションをハッシュインデックスにスプールします。
  + `binding set` – `sourceBindingSet` 引数によって指定される一連の固定バインドをハッシュインデックスにスプールします。
+ `sourceBindingSet` – (*オプション*) `sourceType` 引数の値が `binding set` の場合、この引数はハッシュインデックスにスプールされる一連の静的バインドを指定します。

## `HashIndexJoin`operator
<a name="sparql-explain-operator-hash-index-join"></a>

`solutionSet` 引数によって識別されるハッシュインデックスに対する着信ソリューションを結合します。

**引数**
+ `solutionSet` – (*必須*) 結合するソリューションの名前。これは、`HashIndexBuild` 演算子を使用して前のステップで作成したハッシュインデックスである必要があります。
+ `joinType` – (*必須*) 実行する結合のタイプ。
  + `join` – 共有するすべての変数間における完全な一致を必要とする、通常結合です。
  + `optional` – SPARQL `OPTIONAL` 演算子セマンティクスを使用する `optional` 結合。
  + `minus` – SPARQL `MINUS` 演算子セマンティクスを使用した、結合パートナーが存在しないマッピングがある `minus` 演算。
  + `existence check` – 結合パートナーがあるかどうかを確認し、この確認の結果に `existenceCheckResultVar` 変数をバインドします。
+ `constraints` – (*オプション*) 結合中に考慮される追加の結合制約。これらの制約を満たさない結合は、除外されます。
+ `existenceCheckResultVar` – (*オプション*) `joinType` が `existence check` と等しくなる結合のみに使用されます (前の `joinType` 引数を参照)。

## `MergeJoin`operator
<a name="sparql-explain-operator-merge-join"></a>

`solutionSets` 引数によって識別される、一連の複数のソリューション間のマージ結合。

**引数**
+ `solutionSets` –  (*必須*) 一緒に結合する一連のソリューション。

## `NamedSubquery`operator
<a name="sparql-explain-operator-named-subquery"></a>

`subQuery` 引数によって識別されるサブクエリの評価をトリガーし、その結果を `solutionSet` 引数によって指定される一連のソリューション内にスプールします。演算子の着信ソリューションはサブクエリに転送され、その後次の演算子に転送されます。

**引数**
+ `subQuery` –  (*必須*) 評価するサブクエリの名前。サブクエリは出力で明示的にレンダリングされます。
+ `solutionSet` –  (*必須*) サブクエリの結果を保存する一連のソリューションの名前。

## `PipelineJoin`operator
<a name="sparql-explain-operator-pipeline-join"></a>

前の演算子の出力を入力として受け取り、これを `pattern` 引数によって定義されるタプルパターンに結合します。

**引数**
+ `pattern` –  (*必須*) subject-predicate-object の形式となるパターン。オプションで -graph tuple が結合の基礎となります。パターンに `distinct` が指定されている場合、この結合は、すべての一致するソリューションではなく、`projectionVars` 引数によって指定される射影変数からの重複排除ソリューションのみを抽出します。
+ `inlineFilters` – (*オプション*) パターンで変数に適用される一連のフィルター。パターンはこれらのフィルターと組み合わせて評価されます。
+ `joinType` – (*必須*) 実行する結合のタイプ。
  + `join` – 共有するすべての変数間における完全な一致を必要とする、通常結合です。
  + `optional` – SPARQL `OPTIONAL` 演算子セマンティクスを使用する `optional` 結合。
  + `minus` – SPARQL `MINUS` 演算子セマンティクスを使用した、結合パートナーが存在しないマッピングがある `minus` 演算。
  + `existence check` – 結合パートナーがあるかどうかを確認し、この確認の結果に `existenceCheckResultVar` 変数をバインドします。
+ `constraints` – (*オプション*) 結合中に考慮される追加の結合制約。これらの制約を満たさない結合は、除外されます。
+ `projectionVars` – (*オプション*) 射影変数。`distinct := true` と組み合わせて使用され、指定した一連の変数から重複を排除した射影の抽出を強制します。
+ `cutoffLimit` – (*オプション*) 抽出された結合パートナーの数のカットオフ制限。デフォルトによる制限はありませんが、結合パートナーがあることを証明あるいは否定するために十分な場合に、`FILTER (NOT) EXISTS` 句を実装する結合を実行するときにこれを 1 に設定できます。

## `PipelineCountJoin`operator
<a name="sparql-explain-operator-pipeline-count-join"></a>

`PipelineJoin` の変形。結合の代わりに、一致する結合パートナーを単にカウントし、`countVar` 引数によって指定される変数にこのカウントをバインドします。

**引数**
+ `countVar` –  (*必須*) カウントの結果の変数、つまり結合パートナーの数がバインドされる必要があります。
+ `pattern` –  (*必須*) subject-predicate-object の形式となるパターン。オプションで -graph tuple が結合の基礎となります。パターンに `distinct` が指定されている場合、この結合は、すべての一致するソリューションではなく、`projectionVars` 引数によって指定される射影変数からの重複排除ソリューションのみを抽出します。
+ `inlineFilters` – (*オプション*) パターンで変数に適用される一連のフィルター。パターンはこれらのフィルターと組み合わせて評価されます。
+ `joinType` – (*必須*) 実行する結合のタイプ。
  + `join` – 共有するすべての変数間における完全な一致を必要とする、通常結合です。
  + `optional` – SPARQL `OPTIONAL` 演算子セマンティクスを使用する `optional` 結合。
  + `minus` – SPARQL `MINUS` 演算子セマンティクスを使用した、結合パートナーが存在しないマッピングがある `minus` 演算。
  + `existence check` – 結合パートナーがあるかどうかを確認し、この確認の結果に `existenceCheckResultVar` 変数をバインドします。
+ `constraints` – (*オプション*) 結合中に考慮される追加の結合制約。これらの制約を満たさない結合は、除外されます。
+ `projectionVars` – (*オプション*) 射影変数。`distinct := true` と組み合わせて使用され、指定した一連の変数から重複を排除した射影の抽出を強制します。
+ `cutoffLimit` – (*オプション*) 抽出された結合パートナーの数のカットオフ制限。デフォルトによる制限はありませんが、結合パートナーがあることを証明あるいは否定するために十分な場合に、`FILTER (NOT) EXISTS` 句を実装する結合を実行するときにこれを 1 に設定できます。

## `PipelinedHashIndexJoin`operator
<a name="sparql-explain-operator-pipeline-hash-index-join"></a>

これはオールインワンのビルドハッシュインデックスおよび結合演算子です。バインディングのリストを取得してハッシュインデックスにスプールし、そのハッシュインデックスに対して受信ソリューションを結合します。

**引数**
+ `sourceType` – (*必須*) ハッシュインデックスに保存されるバインドが取得される元のソースのタイプ。
  + `pipeline` – `PipelinedHashIndexJoin` は、演算子パイプラインのダウンストリームの演算子から着信するソリューションをハッシュインデックスにスプールします。
  + `binding set` – `PipelinedHashIndexJoin` は、`sourceBindingSet` 引数によって指定された固定バインドセットをハッシュインデックスにスプールします。
+ `sourceSubQuery ` — (*オプション*) `sourceType` 引数の値が `pipeline` の場合、この引数は、評価されてハッシュインデックスにスプールされるサブクエリを指定します。
+ `sourceBindingSet ` – (*オプション*) `sourceType` 引数の値が `binding set` の場合、この引数はハッシュインデックスにスプールされる静的バインドセットを指定します。
+ `joinType` – (*必須*) 実行される結合のタイプ。
  + `join` – 共有するすべての変数間における完全な一致を必要とする、通常結合です。
  + `optional` – SPARQL `OPTIONAL` 演算子セマンティクスを使用する `optional` 結合。
  + `minus` – SPARQL `MINUS` 演算子セマンティクスを使用した、結合パートナーが存在しないマッピングがある `minus` 演算。
  + `existence check` – 結合パートナーがあるかどうかを確認し、この確認の結果に `existenceCheckResultVar` 変数をバインドします。
+ `existenceCheckResultVar` – (*オプション*) `joinType` が `existence check` に等しい場合にのみ、結合に使用されます (前の joinType 引数を参照)。

## `Projection`operator
<a name="sparql-explain-operator-projection"></a>

変数のサブセット間で射影を行います。流入するソリューションの数は流出するソリューションの数と同じですが、ソリューションの形はモードの設定に応じて異なります。

**モード**
+ `retain` – `vars` 引数によって指定される変数のみをソリューションに保持します。
+ `drop` – `vars` 引数によって指定されるすべての変数を除外します。

**引数**
+ `vars` –  (*必須*) モード設定に応じて、変数を保持あるいは除外します。

## `PropertyPath`operator
<a name="sparql-explain-operator-property-path"></a>

次のような再帰的なプロパティパスを有効にします。`+` または`*`。Neptune は、`iterationTemplate` 引数によって指定されるテンプレートに基づく固定小数点反復アプローチを実装します。既知の左側または右側の変数は、新しいソリューションが見つからなくなるまで、すべての固定小数点反復のテンプレートにバインドされます。

**引数**
+ `iterationTemplate` –  (*必須*) 固定小数点反復を実装するために使用されるサブクエリテンプレートの名前です。
+ `leftTerm` –  (*必須*) プロパティパスの左側の項目 (変数あるいは定数) です。
+ `rightTerm` –  (*必須*) プロパティパスの右側の項目 (変数あるいは定数) です。
+ `lowerBound` –  (*必須*) 固定小数点反復の下限 (`*` クエリでは `0`、または `+` クエリでは `1`)。

## `TermResolution`operator
<a name="sparql-explain-operator-term-resolution"></a>

モードに応じて、内部文字列識別子の値を対応する外部の文字列に変換するか、または外部文字列を内部文字列識別子の値に変換します。

**モード**
+ `value2id` – 内部 ID の値に対応するリテラルや URI などのマップ項目 (内部値にエンコード)。
+ `id2value` – 内部 ID をリテラルや URI など対応する項目にマッピングします (内部値にデコード)。

**引数**
+ `vars` –  (*必須*) マップする必要がある文字列あるいは内部文字列 ID の変数を指定します。

## `Slice`operator
<a name="sparql-explain-operator-slice"></a>

SPARQL の `LIMIT` および `OFFSET` 句のセマンティクスを使用して、着信ソリューションストリームにスライスを実装します。

**引数**
+ `limit` – (*オプション*) 転送されるソリューションの制限。
+ `offset` – (*オプション*) ソリューションが転送のために評価されるオフセット。

## `SolutionInjection`operator
<a name="sparql-explain-operator-solution-injection"></a>

入力を受け取りません。クエリプランにソリューションを静的に挿入し、これを `solutions` 引数に記録します。

クエリプランは常にこの静的挿入で始まります。静的バインドの複数のソースを組み合わせることで (`VALUES` や `BIND` 句からなど)、挿入する静的ソリューションがクエリ自身から配信されることができる場合、`SolutionInjection` 演算子は配信されたこれらの静的ソリューションを挿入します。シンプルなケースでは、これらは外部の `VALUES` 句によって示されるバインドを反映します。

クエリから配信される静的ソリューションがない場合、`SolutionInjection` はユニバーサルソリューションと呼ばれる空を挿入します。これは、クエリ評価プロセスを通して展開し、乗算されます。

**引数**
+ `solutions` –  (*必須*) 演算子によって挿入されるソリューションのシーケンス。

## `Sort`operator
<a name="sparql-explain-operator-sort"></a>

指定されたソート条件を使用して、一連のソリューションをソートします。

**引数**
+ `sortOrder` –  (*必須*) 変数の注文リスト。各変数には `ASC` (昇順) または `DESC` (降順) 識別子が含まれ、一連のソリューションをソートするために順次使用されます。

## `VariableAlignment`operator
<a name="sparql-explain-operator-variable-alignment"></a>

ソリューションを 1 つ 1 つ検査し、2 つの変数 (指定された `sourceVar` および 指定された `targetVar`) でそれぞれに配列を実行します。

ソリューションの `sourceVar` および `targetVar` に同じ値がある場合、この変数は同調している考慮され、このソリューションは転送されます。重複した `sourceVar` は排除されます。

変数が異なる値にバインドされる場合、このソリューションは全体的に除外されます。

**引数**
+ `sourceVar` –  (*必須*) ターゲット変数と比較されるソース変数。ソリューションで同調に成功した場合、これは、2 つの変数に同じ値があり、ソース変数が排除されることになります。
+ `targetVar` –  (*必須*) ソース変数が比較されるターゲット変数。同調に成功した場合でも保持されます。

# Neptune での SPARQL `explain` の制約事項
<a name="sparql-explain-limitations"></a>

Neptune SPARQL `explain` 機能のリリースには以下の制限があります。

**Neptune は現在 SPARQL SELECT クエリのみで Explain をサポートしています**  
他のクエリフォーム (`ASK`、`CONSTRUCT`、`DESCRIBE`、`SPARQL UPDATE` クエリなど) の評価プロセスに関する情報については、これらのクエリを SELECT クエリに変換できます。次に、`explain` を使用して対応する SELECT クエリを代わりに検査します。

たとえば、`ASK WHERE {...}` クエリに関する `explain` 情報を取得するには、対応する `SELECT WHERE {...} LIMIT 1` クエリを `explain` を使用して実行します。

同様に、`CONSTRUCT {...} WHERE {...}` クエリについては、`CONSTRUCT {...}` 部分を除外し、2 番目の `WHERE {...}` 句で `explain` を使用して `SELECT` クエリを実行します。通常の場合、2 番目の `WHERE` 句を評価すると、`CONSTRUCT` クエリの処理の主要な課題が明らかになります。これは、2 番目の `WHERE` から `CONSTRUCT` テンプレートに流出するソリューションが通常簡単な置換のみを必要とするためです。

**Explain 演算子は今後のリリースで変更される可能性があります**  
SPARQL `explain` 演算子とそのパラメータは、今後のリリースで変更される可能性があります。

**Explain 出力は今後のリリースで変更される可能性があります**  
たとえば、列ヘッダーが変更され、より多くの列がテーブルに追加される可能性があります。

# `SERVICE` 拡張を使用した Neptune での SPARQL フェデレーティッドクエリ
<a name="sparql-service"></a>

Amazon Neptune は、`SERVICE` キーワードを使用する SPARQL フェデレーティッドクエリ拡張を完全にサポートします。(詳細については、[SPARQL 1.1 Federated Query](https://www.w3.org/TR/sparql11-federated-query/) を参照してください。)

`SERVICE` キーワードは、リモート SPARQL エンドポイントに対してクエリの一部を実行し、最終的なクエリ結果を構成するように SPARQL クエリエンジンに指示します。`READ` オペレーションのみ可能です。`WRITE` および `DELETE` オペレーションはサポートされていません。Neptune は、仮想プライベートクラウド (VPC) 内の SPARQL エンドポイントに対してのみフェデレーティッドクエリを実行できます。ただし、VPC のリバースプロキシを使用して、VPC 内で外部データソースにアクセスできるようにすることもできます。

**注記**  
SPARQL `SERVICE` を使用して、同じ VPC 内の 2 つ以上の Neptune クラスターにクエリをフェデレートする場合、それらのすべての Neptune クラスターが相互に通信できるようにセキュリティグループを設定する必要があります。

**重要**  
SPARQL 1.1 フェデレーションは、クエリとパラメータを外部 SPARQL エンドポイントに渡すときに、ユーザーに代わってサービスリクエストを行います。外部 SPARQL エンドポイントがアプリケーションのデータ処理とセキュリティ要件を満たしていることを確認するのはお客様の責任です。

## Neptune フェデレーティッドクエリの例
<a name="sparql-service-example-1"></a>

以下の簡単な例は、SPARQL フェデレーティッドクエリがどのように機能するかを示しています。

顧客が次のクエリを `http://neptune-1:8182/sparql` で*Neptune-1*に送信するとします。

```
SELECT * WHERE {
   ?person rdf:type foaf:Person .
   SERVICE <http://neptune-2:8182/sparql> {
       ?person foaf:knows ?friend .
    }
}
```

1. *Neptune-1*は最初のクエリパターン (`?person rdf:type foaf:Person`) を評価し (*Q 1*)、結果を使用して `?person` を *Q-2* (`?person foaf:knows ?friend`) で解決します。それから結果のパターンを `http://neptune-2:8182/sparql` で *Neptune-2* へ送ります。

1. *Neptune-2* は *Q-2* を評価し、結果を *Neptune-1* に返します。

1. *Neptune-1* は両方のパターンのソリューションに参加し、結果をお客様に返します。

このフローを、次の図に示します。

![\[評価中の SPARQL フェデレーティッドクエリパターンとクライアントへの応答を示すフロー図。\]](http://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/images/federated.png)


**注記**  
「デフォルトでは、オプティマイザは、クエリ実行のどの時点で `SERVICE` 命令が実行されるかを決定します。この配置は、[joinOrder](sparql-query-hints-joinOrder.md) クエリのヒントを使って上書きできます。

## Neptune でのフェデレーティッドクエリのアクセスコントロール
<a name="sparql-service-auth"></a>

Neptune は、認証および認可に AWS Identity and Access Management (IAM) を使用します。フェデレーティッドクエリのアクセスコントロールには、複数の Neptune DB インスタンスが含まれる場合があります。これらのインスタンスは、アクセスコントロールに関する要件が異なる場合があります。特定の状況では、これによってフェデレーティッドクエリの実行が制限される場合があります。

前のセクションで説明した簡単な例を考えてみましょう。*Neptune-1* は呼び出されたのと同じクレデンシャルで *Neptune 2* を呼び出します。
+ *Neptune-1* に IAM 認証と認可が必要な場合について、*Neptune-2* では必要ありません。ユーザーに必要であるのは、*Neptune-1* がフェデレーティッドクエリを行うための適切な IAM アクセス許可のみです。
+ *Neptune-1* と *Neptune-2* の両方で IAM 認証と認可が必要な場合は、両方のデータベースに IAM 許可をアタッチしてフェデレーティッドクエリを作成する必要があります。両方のクラスターも同じ AWS アカウントと同じリージョンに存在する必要があります。クロスリージョンまたはクロスアカウントフェデレーティッドクエリアーキテクチャは、現在サポートされていません。
+ ただし、 *Neptune-1* の IAM が有効ではなく、*Neptune-2* が有効な場合は、フェデレーティッドクエリを作成することはできません。これは、*Neptune-1* が IAM 認証情報を取得できず、クエリの 2 番目の部分を認可するために *Neptune-2* に渡すことができないためです。