

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Interrogation d'un graphe Neptune
<a name="access-graph-queries"></a>

Neptune prend en charge deux langages d'interrogation pour accéder à un graphe :
+ [Gkremlin](https://tinkerpop.apache.org/gremlin.html), défini par [Apache TinkerPop](https://tinkerpop.apache.org/) pour créer et interroger des graphes de propriétés.

  Dans Gremlin, une requête est une traversée composée d'étapes distinctes, chacune suivant une arête jusqu'à un nœud.

  Consultez [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md) pour en savoir plus sur l'utilisation de Gremlin dans Neptune, et [Conformité d'Amazon Neptune avec les normes Gremlin](access-graph-gremlin-differences.md) pour obtenir des informations spécifiques sur l'implémentation Neptune de Gremlin.
+ [openCypher](access-graph-opencypher.md) est un langage de requête déclaratif pour les graphes de propriétés initialement développé par Neo4j, puis rendu open source en 2015. Il a contribué au projet [openCypher](http://www.opencypher.org/) sous une licence open source Apache 2. Sa syntaxe est documentée dans la spécification [openCypher](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).
+ [SPARQL](https://www.w3.org/TR/sparql11-overview/) est un langage déclaratif basé sur la correspondance de modèles de graphes pour interroger des données [RDF](https://www.w3.org/2001/sw/wiki/RDF). Il est pris en charge par le [World Wide Web Consortium](https://www.w3.org/).

  Consultez [Accès au graphe Neptune avec SPARQL](access-graph-sparql.md) pour en savoir plus sur l'utilisation de SPARQL dans Neptune, et [Conformité d'Amazon Neptune avec les normes SPARQL](feature-sparql-compliance.md) pour obtenir des informations spécifiques sur l'implémentation Neptune de SPARQL.

**Note**  
Gremlin et openCypher peuvent tous deux être utilisés pour interroger toutes les données de graphes de propriétés stockées dans Neptune, quelle que soit la manière dont elles ont été chargées.

**Topics**
+ [Mise en file d'attente des requêtes dans Amazon Neptune](access-graph-queuing.md)
+ [Cache du plan de requête dans Amazon Neptune](access-graph-qpc.md)
+ [Injection d'un ID personnalisé dans une requête Neptune Gremlin ou SPARQL](features-query-id.md)
+ [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md)
+ [Accès au graphe Neptune avec openCypher](access-graph-opencypher.md)
+ [Accès au graphe Neptune avec SPARQL](access-graph-sparql.md)

# Mise en file d'attente des requêtes dans Amazon Neptune
<a name="access-graph-queuing"></a>

Lors du développement et du réglage d'applications graphiques, il peut être utile de connaître les implications de la façon dont les requêtes sont mises en file d'attente par la base de données. Dans Amazon Neptune, la mise en file d'attente des requêtes présente les caractéristiques suivantes :
+ Le nombre maximal de requêtes pouvant être mises en file d'attente par instance, quelle que soit la taille de l'instance, est de 8 192. Toutes les requêtes au-delà de ce nombre sont rejetées et échouent avec une exception `ThrottlingException`.
+ Le nombre maximum de requêtes pouvant être exécutées simultanément est déterminé par le nombre de threads de travail affectés, qui est généralement défini sur le double du nombre de cœurs de processeur virtuels (vCPUs) disponibles.
+ La latence de requête inclut le temps passé par une requête dans la file d'attente, ainsi que le retour sur le réseau et le temps d'exécution réel.

## Comment déterminer le nombre de requêtes présentes dans votre file d'attente à un moment donné
<a name="access-graph-queuing-count"></a>

La `MainRequestQueuePendingRequests` CloudWatch métrique enregistre le nombre de demandes en attente dans la file d'entrée avec une granularité de cinq minutes (voir[Métriques Neptune CloudWatch](cw-metrics.md)).

Pour Gremlin, vous pouvez obtenir le nombre actuel de requêtes dans la file d'attente en utilisant la valeur `acceptedQueryCount` renvoyée par l'[API de statut des requêtes Gremlin](gremlin-api-status.md). Notez toutefois que la valeur `acceptedQueryCount` renvoyée par l'[API de statut des requêtes SPARQL](sparql-api-status.md) inclut toutes les requêtes acceptées depuis le démarrage du serveur, y compris les requêtes terminées.

## Comment la mise en file d'attente des requêtes peut affecter les délais d'expiration
<a name="access-graph-queuing-timeouts"></a>

Comme indiqué précédemment, la latence de requête inclut le temps passé par une requête dans la file d'attente, ainsi que le temps d'exécution.

Étant donné que le délai d'expiration d'une requête est généralement mesuré à partir du moment où elle entre dans la file d'attente, une file d'attente lente peut faire expirer de nombreuses requêtes dès qu'elles sont retirées de la file d'attente. Ceci n'est évidemment pas souhaitable. Il est donc bon d'éviter de mettre en file d'attente un grand nombre de requêtes, à moins qu'elles ne puissent être exécutées rapidement.

# Cache du plan de requête dans Amazon Neptune
<a name="access-graph-qpc"></a>

 Lorsqu'une requête est soumise à Neptune, la chaîne de requête est analysée, optimisée et transformée en un plan de requête, qui est ensuite exécuté par le moteur. Les applications sont souvent soutenues par des modèles de requête courants instanciés avec des valeurs différentes. Le cache des plans de requêtes peut réduire la latence globale en mettant en cache les plans de requêtes et en évitant ainsi l'analyse et l'optimisation pour de tels modèles répétés. 

 Le cache du plan de requête peut être utilisé pour les **OpenCypher**requêtes, qu'elles soient paramétrées ou non paramétrées. Il est activé pour READ, HTTP et Bolt. Il **n'est pas** pris en charge pour les requêtes de mutation OC. Il **n'est pas** pris en charge pour les requêtes Gkremlin ou SPARQL. 

## Comment forcer l'activation ou la désactivation du cache du plan de requêtes
<a name="access-graph-qpc-enable"></a>

 Le cache du plan de requêtes est activé par défaut pour les requêtes paramétrées à faible latence. **Un plan pour une requête paramétrée est mis en cache uniquement lorsque la latence est inférieure au seuil de 100 ms.** Ce comportement peut être remplacé par requête (paramétré ou non) par le Query Hint au niveau de la requête. `QUERY:PLANCACHE` Il doit être utilisé avec la `USING` clause. L'indice de requête accepte `enabled` ou `disabled` en tant que valeur. 

```
# 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"
```

## Comment déterminer si un plan est mis en cache ou non
<a name="access-graph-qpc-status"></a>

 Pour HTTP READ, si la requête a été soumise et que le plan a été mis en cache, `explain` les détails relatifs au cache du plan de requête seront affichés. 

```
% 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).
```

 Lorsque vous utilisez Bolt, la fonction d'explication n'est pas prise en charge. 

## Expulsion
<a name="access-graph-qpc-eviction"></a>

 Un plan de requête est supprimé en fonction de la durée de vie du cache (TTL) ou lorsqu'un nombre maximum de plans de requêtes mis en cache est atteint. Lorsque le plan de requête est atteint, le TTL est actualisé. Les valeurs par défaut sont les suivantes : 
+  1000 : nombre maximum de plans pouvant être mis en cache par instance. 
+  TTL - 300 000 millisecondes ou 5 minutes. L'accès au cache redémarre le TTL et le réinitialise à 5 minutes. 

## Conditions empêchant le plan d'être mis en cache
<a name="access-graph-qpc-conditions"></a>

 Le cache du plan de requête ne serait pas utilisé dans les conditions suivantes : 

1.  Lorsqu'une requête est soumise à l'aide de l'indice de requête`QUERY:PLANCACHE "disabled"`. Vous pouvez réexécuter la requête et la supprimer `QUERY:PLANCACHE "disabled"` pour activer le cache du plan de requête. 

1.  Si la requête soumise n'est pas une requête paramétrée et ne contient pas l'indice. `QUERY:PLANCACHE "enabled"` 

1.  Si le temps d'évaluation de la requête est supérieur au seuil de latence, la requête n'est pas mise en cache et est considérée comme une requête de longue durée qui ne bénéficierait pas du cache du plan de requêtes. 

1.  Si la requête contient un modèle qui ne renvoie aucun résultat. 
   +  c'est-à-dire `MATCH (n:nonexistentLabel) return n` lorsqu'il n'y a aucun nœud avec l'étiquette spécifiée. 
   +  c'est-à-dire `MATCH (n {name: $param}) return n` `parameters={"param": "abcde"}` lorsqu'il n'y a aucun nœud contenant`name=abcde`. 

1.  Si le paramètre de requête est un type composite, tel que a `list` ou `map` a. 

   ```
   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.  Si le paramètre de requête est une chaîne qui n'a pas fait partie d'une opération de chargement ou d'insertion de données. Par exemple, s'il `CREATE (n {name: "X"})` est exécuté pour insérer`"X"`, `RETURN "X"` il est mis en cache, alors qu'`RETURN "Y"`il ne le serait pas, car il n'`"Y"`a pas été inséré et n'existe pas dans la base de données. 

# Injection d'un ID personnalisé dans une requête Neptune Gremlin ou SPARQL
<a name="features-query-id"></a>

Par défaut, Neptune attribue une valeur `queryId` unique à chaque requête. Vous pouvez utiliser cet ID pour obtenir des informations sur une requête en cours d'exécution (voir [API de statut des requêtes Gremlin](gremlin-api-status.md) ou [API de statut des requêtes SPARQL](sparql-api-status.md)) ou pour l'annuler (voir [Annulation de requêtes Gremlin](gremlin-api-status-cancel.md) ou [Annulation de requêtes SPARQL](sparql-api-status-cancel.md)).

Neptune vous permet également de spécifier votre propre valeur `queryId` pour une requête Gremlin ou SPARQL, soit dans l'en-tête HTTP, soit pour une requête SPARQL à l'aide de l'indicateur de requête `queryId`. L'attribution de votre propre `queryID` permet de suivre facilement une requête afin d'obtenir son statut ou de l'annuler.

## Injection d'une valeur `queryId` personnalisée à l'aide de l'en-tête HTTP
<a name="features-query-id-header"></a>

Pour Gremlin et SPARQL, l'en-tête HTTP peut être utilisé pour injecter votre propre valeur `queryId` dans une requête.

**Exemple Gremlin**

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

**Exemple SPARQL**

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

## Injection d'une valeur `queryId` personnalisée à l'aide d'un indicateur de requête SPARQL
<a name="features-query-id-hint"></a>

Voici un exemple d'utilisation de l'indicateur de requête `queryId` SPARQL pour injecter une valeur `queryId` personnalisée dans une requête SPARQL :

```
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}}"
```

## Utilisation de la valeur `queryId` pour vérifier le statut de la requête
<a name="features-query-id-check-status"></a>

**Exemple Gremlin**

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

**Exemple SPARQL**

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

# Accès au graphe Neptune avec Gremlin
<a name="access-graph-gremlin"></a>

Amazon Neptune est compatible avec Apache TinkerPop et Gkremlin. Cela signifie que vous pouvez vous connecter à une instance de base de données Neptune et utiliser le langage de traversée Gremlin pour interroger le graphe (voir The Graph dans [la documentation d'Apache](https://tinkerpop.apache.org/docs/current/reference/#graph)). TinkerPop Pour voir les différences dans l'implémentation Neptune de Gremlin, consultez [Conformité avec les normes Gremlin](access-graph-gremlin-differences.md).

 Une *traversée* dans Gremlin est une série d'étapes chaînées. Elle commence à un sommet (ou arc). Elle parcourt le graphe en suivant les arêtes extérieures de chaque sommet, puis les arêtes extérieures de ces sommets. Chaque étape représente une opération de la traversée. Pour plus d'informations, consultez [The Traversal](https://tinkerpop.apache.org/docs/current/reference/#traversal) dans la TinkerPop documentation.

Les différentes versions du moteur Neptune prennent en charge différentes versions de Gremlin. Consultez la [page de version du moteur](engine-releases.md) de la version de Neptune que vous utilisez pour déterminer quelle version de Gremlin est prise en charge ou consultez le tableau suivant qui répertorie les versions les plus anciennes et les plus récentes TinkerPop prises en charge par les différentes versions du moteur Neptune :


| Version du moteur Neptune |  TinkerPop Version minimale |  TinkerPop Version maximale | 
| --- | --- | --- | 
| `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 les clients sont généralement rétrocompatibles au sein d'une série (par exemple`3.6.x`, ou`3.7.x`) et bien qu'ils puissent souvent travailler au-delà de ces limites, le tableau ci-dessus recommande les combinaisons de versions à utiliser pour une expérience et une compatibilité optimales. Sauf avis contraire, il est généralement préférable de respecter ces directives et de mettre à niveau les applications clientes pour qu'elles correspondent à la version TinkerPop que vous utilisez.

Lors de la mise à niveau des TinkerPop versions, il est toujours important [TinkerPopde consulter la documentation de mise](http://tinkerpop.apache.org/docs/current/upgrade/) à niveau qui vous aidera à identifier les nouvelles fonctionnalités dont vous pouvez tirer parti, mais également les problèmes dont vous devrez peut-être être conscient à l'approche de votre mise à niveau. Vous devez généralement vous attendre à ce que les requêtes et fonctionnalités existantes fonctionnent après la mise à niveau, sauf si un problème particulier est indiqué comme un problème à prendre en compte. Enfin, il est important de noter que si vous mettez à niveau une version pour intégrer une nouvelle fonctionnalité, vous ne pourrez peut-être pas l'utiliser si elle provient d'une version ultérieure à celle prise en charge par Neptune.

Il existe des variantes du langage Gremlin et une prise en charge de l'accès Gremlin dans les différents langages de programmation. Pour plus d'informations, voir À [propos des variantes linguistiques de Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants) dans la TinkerPop documentation.

Cette documentation décrit comment accéder à Neptune avec les variantes et langages de programmation suivants :
+ [Configuration de la console Gremlin pour se connecter à une instance de base de données Neptune](access-graph-gremlin-console.md)
+ [Utilisation du point de terminaison HTTP REST pour se connecter à une instance de base de données Neptune](access-graph-gremlin-rest.md)
+ [Clients Gremlin basés sur Java à utiliser avec Amazon Neptune](access-graph-gremlin-client.md)
+ [Utilisation de Python pour se connecter à une instance de base de données Neptune](access-graph-gremlin-python.md)
+ [Utilisation de .NET pour se connecter à une instance de base de données Neptune](access-graph-gremlin-dotnet.md)
+ [Utilisation de Node.js pour se connecter à une instance de base de données Neptune](access-graph-gremlin-node-js.md)
+ [Utilisation de Go pour se connecter à une instance de base de données Neptune](access-graph-gremlin-go.md)

Comme indiqué dans la section[Chiffrement des connexions à votre base de données Amazon Neptune avec SSL/HTTPS](security-ssl.md), vous devez utiliser le protocole TLS/SSL (Transport Security/Secure Layer Sockets Layer) lorsque vous vous connectez à Neptune dans toutes les régions. AWS 

Avant de commencer, les prérequis suivants doivent être remplis :
+ Vous devez disposer d'une instance de base de données Neptune. Pour plus d'informations sur la création d'une instance de base de données Neptune, consultez [Création d'un cluster Amazon Neptune](get-started-create-cluster.md).
+ Vous devez disposer d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) que l'instance de base de données Neptune.

Pour plus d'informations sur le chargement des données dans Neptune, y compris les prérequis, les formats de chargement et les paramètres de chargement, consultez [Chargement de données dans Amazon Neptune](load-data.md).

**Topics**
+ [Configuration de la console Gremlin pour se connecter à une instance de base de données Neptune](access-graph-gremlin-console.md)
+ [Utilisation du point de terminaison HTTP REST pour se connecter à une instance de base de données Neptune](access-graph-gremlin-rest.md)
+ [Clients Gremlin basés sur Java à utiliser avec Amazon Neptune](access-graph-gremlin-client.md)
+ [Utilisation de Python pour se connecter à une instance de base de données Neptune](access-graph-gremlin-python.md)
+ [Utilisation de .NET pour se connecter à une instance de base de données Neptune](access-graph-gremlin-dotnet.md)
+ [Utilisation de Node.js pour se connecter à une instance de base de données Neptune](access-graph-gremlin-node-js.md)
+ [Utilisation de Go pour se connecter à une instance de base de données Neptune](access-graph-gremlin-go.md)
+ [Utiliser le AWS SDK pour exécuter des requêtes Gremlin](access-graph-gremlin-sdk.md)
+ [Indicateurs de requête Gremlin](gremlin-query-hints.md)
+ [API de statut des requêtes Gremlin](gremlin-api-status.md)
+ [Annulation de requêtes Gremlin](gremlin-api-status-cancel.md)
+ [Prise en charge des sessions basées sur des scripts Gremlin](access-graph-gremlin-sessions.md)
+ [Transactions Gremlin dans Neptune](access-graph-gremlin-transactions.md)
+ [Utilisation de l'API Gremlin avec Amazon Neptune](gremlin-api-reference.md)
+ [Mise en cache des résultats de requête dans Amazon Neptune Gremlin](gremlin-results-cache.md)
+ [Réalisation d'upserts efficaces avec les étapes Gremlin `mergeV()` et `mergeE()`](gremlin-efficient-upserts.md)
+ [Réalisation d'upserts Gremlin efficaces avec `fold()/coalesce()/unfold()`](gremlin-efficient-upserts-pre-3.6.md)
+ [Analyse de l'exécution des requêtes à l'aide de Gremlin `explain`](gremlin-explain.md)
+ [Utilisation de Gremlin avec le moteur de requêtes Neptune DFE](gremlin-with-dfe.md)

# Configuration de la console Gremlin pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-console"></a>

La console G705 vous permet d'expérimenter avec TinkerPop des graphes et des requêtes dans un environnement REPL (read-eval-print boucle).

## Installation de la console Gremlin et mode de connexion habituel
<a name="access-graph-gremlin-console-usual-connect"></a>

Vous pouvez utiliser la console Gremlin pour vous connecter à une base de données distante orientée graphe. La section suivante vous guide dans l’installation et la configuration de la console Gremlin pour une connexion à distance à une instance de base de données Neptune. Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Pour obtenir de l'aide sur la connexion à Neptune avec SSL/TLS (obligatoire), consultez. [Configuration SSL/TLS](access-graph-gremlin-java.md#access-graph-gremlin-java-ssl)

**Note**  
Si l'[authentification IAM est activée](iam-auth-enable.md) sur votre cluster de bases de données Neptune, suivez les instructions décrites dans [Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec la console Gremlin](iam-auth-connecting-gremlin-console.md) pour installer la console Gremlin plutôt que celles indiquées ici.

**Pour installer la console Gremlin et vous connecter à Neptune**

1. Les fichiers binaires de la console Gremlin nécessitent Java 8 ou Java 11. Ces instructions supposent l'utilisation de Java 11. Vous pouvez installer Java 11 sur une instance EC2 comme suit :
   + Si vous utilisez [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2) :

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + Si vous utilisez [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
     ```
   + Pour les autres distributions, utilisez l'instruction qui convient le mieux parmi les suivantes :

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

     ou :

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

1. Entrez la commande suivante pour définir Java 8 en tant qu'environnement d'exécution par défaut sur votre instance EC2.

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

   Lorsque vous y êtes invité, saisissez le nombre correspondant à Java 11.

1. Téléchargez la version appropriée de la console Gremlin depuis le site Web d'Apache. Vous pouvez vérifier si votre version de [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md) Neptune est prise en charge par votre version de Gremlin. Par exemple, si vous avez besoin de la version 3.7.2, vous pouvez télécharger la [console Gremlin](https://archive.apache.org/dist/tinkerpop/3.7.2/apache-tinkerpop-gremlin-console-3.7.2-bin.zip) depuis le site Web [Apache Tinkerpop](https://tinkerpop.apache.org/download.html) sur votre instance EC2 comme suit :

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

1. Décompressez le fichier zip Gremlin Console.

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

1. Modifiez les répertoires du répertoire décompressé.

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

1. Dans le sous-répertoire `conf` du répertoire extrait, créez un fichier nommé `neptune-remote.yaml` avec le texte suivant. *your-neptune-endpoint*Remplacez-le par le nom d'hôte ou l'adresse IP de votre instance de base de données Neptune. Les crochets (`[ ]`) sont obligatoires.
**Note**  
Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver le nom d'hôte de votre instance de base de données Neptune.

   ```
   hosts: [your-neptune-endpoint]
   port: 8182
   connectionPool: { enableSsl: true }
   serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1,
                 config: { serializeResultToString: true }}
   ```
**Note**  
 Les sérialiseurs ont été déplacés du `gremlin-driver` module vers le nouveau `gremlin-util` module dans la version 3.7.0. Le package est passé de org.apache.tinkerpop.gremlin.driver.ser à org.apache.tinkerpop.gremlin.util.ser. 

1. Dans un terminal, accédez au répertoire Gremlin Console (`apache-tinkerpop-gremlin-console-3.7.2`), puis entrez la commande suivante pour exécuter la console Gremlin.

   ```
   bin/gremlin.sh
   ```

   Vous devriez voir la sortie suivante :

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

   Vous êtes maintenant à l'invite `gremlin>`. Vous entrez les étapes restantes à cette invite.

1. À l'invite de commande `gremlin>`, saisissez le texte suivant pour vous connecter à l'instance de base de données Neptune.

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

1. À l'invite `gremlin>`, entrez ce qui suit pour passer en mode distant. Toutes les requêtes Gremlin sont alors envoyées à la connexion distante.

   ```
   :remote console
   ```

1. Saisissez la commande suivante pour envoyer une requête au graphe Gremlin.

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

1. Lorsque vous avez terminé, saisissez la commande suivante pour quitter la console Gremlin.

   ```
   :exit
   ```

**Note**  
Utilisez un point-virgule (`;`) ou un caractère de saut de ligne (`\n`) pour séparer chaque instruction.   
Chaque traversée précédant la traversée finale doit se terminer par l'exécution de `next()`. Seules les données de la traversée finale sont renvoyées.

Pour plus d'informations sur l'implémentation Neptune de Gremlin, consultez [Conformité d'Amazon Neptune avec les normes Gremlin](access-graph-gremlin-differences.md).

# Autre mode de connexion à la console Gremlin
<a name="access-graph-gremlin-console-connect"></a>

**Inconvénients de l'approche de connexion habituelle**

La méthode la plus courante pour se connecter à la console Gremlin est expliquée ci-dessus et utilise des commandes comme celle-ci à l'invite `gremlin>` :

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

Elle est opérationnelle et vous permet d'envoyer des requêtes à Neptune. Cependant, elle exclut le moteur de script Groovy, de sorte que Neptune traite toutes les requêtes comme si elles étaient entièrement écrites dans Gremlin. Par conséquent, les types de requête suivants échouent :

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

Le meilleur moyen d'utiliser une variable lorsque vous êtes connecté de cette façon consiste à utiliser la variable `result` gérée par la console et d'envoyer la requête en utilisant `:>`, comme ceci :

```
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]
```

 

**Autre mode de connexion**

Vous pouvez également vous connecter à la console Gremlin d'une autre manière, que vous trouverez peut-être plus agréable, comme ceci :

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

`neptune.properties` prend ici la forme suivante :

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

Le fichier `my-cluster.yaml` doit ressembler à ceci :

```
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 }
```

**Note**  
 Les sérialiseurs ont été déplacés du `gremlin-driver` module vers le nouveau `gremlin-util` module dans la version 3.7.0. Le package est passé de org.apache.tinkerpop.gremlin.driver.ser à org.apache.tinkerpop.gremlin.util.ser. 

En configurant ainsi la connexion à la console Gremlin, vous pouvez effectuer avec succès les types de requêtes suivants :

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

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

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

Pour éviter d'afficher le résultat, procédez comme suit :

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

Toutes les méthodes habituelles d'interrogation (sans l'étape terminale) continuent de fonctionner. Par exemple :

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

Vous pouvez même utiliser l'étape [https://tinkerpop.apache.org/docs/current/reference/#io-step](https://tinkerpop.apache.org/docs/current/reference/#io-step) pour charger un fichier avec ce type de connexion.

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion depuis la console Gremlin, consultez[Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec la console Gremlin](iam-auth-connecting-gremlin-console.md).

# Utilisation du point de terminaison HTTP REST pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-rest"></a>

Amazon Neptune fournit un point de terminaison HTTP pour les requêtes Gremlin. L'interface REST est compatible avec n'importe quelle version Gremlin de votre cluster de bases de données (consultez la [page de mise à jour](engine-releases.md) correspondant à la version de moteur Neptune que vous exécutez pour déterminer la version Gremlin prise en charge).

**Note**  
Comme indiqué dans [Chiffrement des connexions à votre base de données Amazon Neptune avec SSL/HTTPS](security-ssl.md), vous devez désormais vous connecter via HTTPS au lieu de HTTP dans Neptune. En outre, Neptune ne prend actuellement pas en charge le HTTP/2 pour les requêtes d'API REST. Les clients doivent utiliser HTTP/1.1 lorsqu'ils se connectent aux points de terminaison.

Les instructions suivantes vous guident à travers la connexion au point de terminaison Gremlin à l'aide de la commande `curl` et de HTTPS. Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Le point de terminaison HTTPS pour les requêtes Gremlin dans une instance de base de données Neptune est `https://your-neptune-endpoint:port/gremlin`.

**Note**  
Pour découvrir comment trouver le nom d'hôte de l'instance de base de données Neptune, consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md).

## Pour se connecter à Neptune à l'aide du point de terminaison HTTP REST
<a name="access-graph-gremlin-rest-connect"></a>

L'exemple suivant utilise **curl** pour soumettre une requête Gremlin via HTTP **POST**. La requête est soumise au format JSON dans le corps de la publication en tant que propriété `gremlin`.

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

L'exemple précédent renvoie le premier sommet du graphe en utilisant la traversée `g.V().limit(1)`. Pour interroger autre chose, remplacez cette traversée par une autre traversée Gremlin.

**Important**  
Par défaut, le point de terminaison REST renvoie tous les résultats dans un seul ensemble de résultats JSON. Si cet ensemble de résultats est trop volumineux, une exception `OutOfMemoryError` peut être générée dans l'instance de base de données Neptune.  
Pour éviter cette exception, activez les réponses segmentées (résultats renvoyés sous la forme d'une série de réponses distinctes). Consultez [Utilisation d'en-têtes de suivi HTTP facultatifs pour activer les réponses Gremlin en plusieurs parties](access-graph-gremlin-rest-trailing-headers.md).

Bien que les demandes HTTP **POST** soient recommandées pour envoyer des requêtes Gremlin, il est également possible d'utiliser des demandes HTTP **GET** :

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

**Note**  
Neptune ne prend pas en charge la propriété `bindings`.

# Utilisation d'en-têtes de suivi HTTP facultatifs pour activer les réponses Gremlin en plusieurs parties
<a name="access-graph-gremlin-rest-trailing-headers"></a>

Par défaut, la réponse HTTP aux requêtes Gremlin est renvoyée dans un seul ensemble de résultats JSON. Un ensemble de résultats très volumineux peut générér une exception `OutOfMemoryError` dans l'instance de base de données.

Vous pouvez toutefois activer les *réponses segmentées* (réponses renvoyées en plusieurs parties distinctes). Pour ce faire, incluez un en-tête « trailer » (`te: trailers`) d'encodage de transfert (TE) dans la demande. Consultez la [page MDN (sur les en-têtes de demande TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)) pour plus d'informations sur ces en-têtes.

Lorsqu'une réponse est renvoyée en plusieurs parties, il peut être difficile de diagnostiquer un problème qui survient après la réception de la première partie, car la première partie arrive avec le code de statut HTTP `200` (OK). En cas d'échec ultérieur, le corps du message contient généralement une réponse corrompue, à la fin de laquelle Neptune ajoute un message d'erreur.

Pour faciliter la détection et le diagnostic de ce type d'échec, Neptune inclut également deux nouveaux champs d'en-tête dans les en-têtes suivants de chaque segment de réponse :
+ `X-Neptune-Status` : contient le code de réponse suivi d'un nom court. Par exemple, en cas de réussite, l'en-tête final serait : `X-Neptune-Status: 200 OK`. En cas d'échec, le code de réponse est l'un des [codes d'erreur du moteur Neptune](errors-engine-codes.md), tel que `X-Neptune-Status: 500 TimeLimitExceededException`.
+ `X-Neptune-Detail` : est vide pour les demandes qui ont abouti. En cas d'erreur, il contient le message d'erreur JSON. Étant donné que seuls les caractères ASCII sont autorisés dans les valeurs d'en-tête HTTP, la chaîne JSON est encodée en URL.

**Note**  
Neptune ne prend actuellement pas en charge la compression `gzip` des réponses segmentées. Si le client demande à la fois un encodage et une compression segmentés, Neptune ignore la compression.

# Clients Gremlin basés sur Java à utiliser avec Amazon Neptune
<a name="access-graph-gremlin-client"></a>

[Vous pouvez utiliser l'un des deux clients G705 open source basés sur Java avec Amazon Neptune : le client [Apache TinkerPop Java G705 ou le client G705](https://search.maven.org/artifact/org.apache.tinkerpop/gremlin-driver) pour Amazon Neptune.](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client)

## Client Apache TinkerPop Java Garmlin
<a name="access-graph-gremlin-java-driver"></a>

Le [pilote Apache TinkerPop Java gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java) est le client Gremlin standard et officiel qui fonctionne avec n'importe quelle TinkerPop base de données de graphes compatible. Utilisez ce client lorsque vous avez besoin d'une compatibilité maximale avec l'ensemble de l'espace de TinkerPop développement, lorsque vous travaillez avec plusieurs systèmes de base de données de graphes ou lorsque vous n'avez pas besoin des fonctionnalités avancées de gestion des clusters et d'équilibrage de charge spécifiques à Neptune. Ce client convient également aux applications simples qui se connectent à une seule instance Neptune ou lorsque vous préférez gérer l'équilibrage de charge au niveau de l'infrastructure plutôt qu'au sein du client.

**Important**  
Le choix de la bonne version du pilote Apache TinkerPop Gremlin est essentiel pour garantir la compatibilité avec la version de votre moteur Neptune. L'utilisation d'une version incompatible peut entraîner des échecs de connexion ou un comportement inattendu. Pour obtenir des informations détaillées sur la compatibilité des versions, consultez[Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

**Note**  
Le tableau qui vous aide à déterminer la TinkerPop version correcte d'Apache à utiliser avec Neptune a été déplacé vers. [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md) Ce tableau se trouvait auparavant sur cette page depuis de nombreuses années et est désormais plus centralisé à titre de référence pour tous les langages de programmation pris TinkerPop en charge.

## Client Java Gremlin pour Amazon Neptune
<a name="access-graph-neptune-gremlin-client"></a>

Le client Gremlin pour Amazon Neptune est [un client Gremlin open source basé sur Java](https://github.com/aws/neptune-gremlin-client) qui remplace directement le client Java standard. TinkerPop 

Le client Gremlin Neptune est optimisé pour les clusters Neptune. Il vous permet de gérer la distribution du trafic entre plusieurs instances d'un cluster et s'adapte aux modifications de la topologie du cluster lorsque vous ajoutez ou supprimez un réplica. Vous pouvez même configurer le client pour distribuer les demandes sur un sous-ensemble d'instances du cluster, en fonction du rôle, du type d'instance, de la zone de disponibilité (AZ) ou des balises associées aux instances.

La [dernière version du client Java Gremlin Neptune](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client) est disponible sur Maven Central.

Pour plus d'informations sur le client Java Gremlin Neptune, consultez [ce billet de blog](https://aws.amazon.com/blogs/database/load-balance-graph-queries-using-the-amazon-neptune-gremlin-client/). Pour des exemples de code et des démos, consultez le [ GitHub projet du client](https://github.com/aws/neptune-gremlin-client).

Lorsque vous choisissez la version du client Neptune G705, vous devez prendre en compte la TinkerPop version sous-jacente par rapport à la version de votre moteur Neptune. Reportez-vous au tableau de compatibilité sur [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md) pour déterminer la TinkerPop version appropriée pour votre moteur Neptune, puis utilisez le tableau suivant pour sélectionner la version du client Neptune Gremlin appropriée :


**Compatibilité des versions du client Neptune Garmlin**  

| Version du client Neptune Garmlin | TinkerPop version | 
| --- | --- | 
| 3.x | 3.7.x (AWS SDK pour Java 2.x/1.x) | 
| 2.1.x | 3.7.x (AWS SDK pour Java 1.x) | 
| 2.0.x | 3,6. x | 
| 1.12 | 3.5.x | 

# Utilisation du client Java pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-java"></a>

La section suivante explique comment exécuter un exemple Java complet qui se connecte à une instance de base de données Neptune et effectue une traversée de G705 à l'aide du client Apache G705. TinkerPop

Vous devez suivre ces instructions à partir d'une instance Amazon EC2 située dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

**Pour se connecter à Neptune à l'aide de Java**

1. Installez Apache Maven sur votre instance EC2. Si vous utilisez Amazon Linux 2023 (de préférence), utilisez :

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

   Si vous utilisez Amazon Linux 2, téléchargez le dernier fichier binaire [sur 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. **Installez Java.** Les bibliothèques Gremlin nécessitent Java 8 ou 11. Vous pouvez installer Java 11 comme suit :
   + Si vous utilisez [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2) :

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + Si vous utilisez [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
     ```
   + Pour les autres distributions, utilisez l'instruction qui convient le mieux parmi les suivantes :

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

     ou :

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

1. **Définissez Java 11 comme environnement d'exécution par défaut sur votre instance EC2 :** entrez ce qui suit pour définir Java 8 comme environnement d'exécution par défaut sur l'instance EC2 :

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

   Lorsque vous y êtes invité, saisissez le nombre correspondant à Java 11.

1. **Créez un répertoire appelé `gremlinjava` :**

   ```
   mkdir gremlinjava
   cd gremlinjava
   ```

1.  Dans le répertoire `gremlinjava`, créez un fichier `pom.xml`, puis ouvrez-le dans un éditeur de texte:

   ```
   nano pom.xml
   ```

1. Copiez ce qui suit dans le fichier `pom.xml` et enregistrez-le:

   ```
   <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>
   ```
**Note**  
Si vous modifiez un projet Maven existant, la dépendance obligatoire est mise en évidence dans le code précédent.

1. Créez des sous-répertoires pour l'exemple de code source (`src/main/java/com/amazonaws/`) en saisissant ce qui suit sur la ligne de commande :

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

1. Dans le répertoire `src/main/java/com/amazonaws/`, créez un fichier `App.java`, puis ouvrez-le dans un éditeur de texte.

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

1. Copiez ce qui suit dans le fichier `App.java`. Remplacez *your-neptune-endpoint* par l'adresse de votre instance de base de données Neptune. N’incluez *pas* le préfixe `https://` dans la méthode `addContactPoint`.
**Note**  
Pour découvrir comment trouver le nom d'hôte de l'instance de base de données Neptune, consultez la section [Connexion aux points de terminaison 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();
     }
   }
   ```

   Pour obtenir de l'aide sur la connexion à Neptune avec SSL/TLS (obligatoire), consultez. [Configuration SSL/TLS](#access-graph-gremlin-java-ssl)

1. Compilez et exécutez l'exemple à l'aide de la commande Maven suivante :

   ```
   mvn compile exec:exec
   ```

L'exemple précédent renvoie une carte de la clé et les valeurs de chaque propriété pour les deux premiers vertex du graphe à l'aide de la traversée `g.V().limit(3).elementMap()`. Pour interroger quelque chose d'autre, remplacez la traversée par une autre traversée Gremlin avec l'une des méthodes de fin appropriées.

**Note**  
La partie finale de la requête Gremlin, `.toList()`, est obligatoire pour soumettre la traversée au serveur à des fins d'évaluation. Si vous n'incluez pas cette méthode ou une autre méthode équivalente, la requête ne sera pas soumise à l'instance de base de données Neptune.  
Vous devez également ajouter une terminaison appropriée lorsque vous ajoutez un sommet ou une arête, comme lorsque vous utilisez l'étape `addV( )`.

Les méthodes suivantes soumettent la requête à l'instance de base de données Neptune :
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

## Configuration SSL/TLS pour le client Java Gremlin
<a name="access-graph-gremlin-java-ssl"></a>

Neptune doit SSL/TLS être activé par défaut. Généralement, si le pilote Java est configuré avec `enableSsl(true)`, il peut se connecter à Neptune sans avoir à configurer `trustStore()` ou `keyStore()` avec une copie locale d'un certificat.

Toutefois, si l'instance à laquelle vous vous connectez ne dispose pas d'une connexion Internet permettant de vérifier un certificat public ou si le certificat que vous utilisez n'est pas public, vous pouvez suivre les étapes ci-dessous pour configurer une copie du certificat local :

**Configuration d'une copie du certificat local pour activer le protocole SSL/TLS**

1. Téléchargez et installez [keytool](https://docs.oracle.com/javase/9/tools/keytool.htm#JSWOR-GUID-5990A2E4-78E3-47B7-AE75-6D1826259549) depuis Oracle. Cela facilitera grandement la configuration du magasin de clés local.

1. Téléchargez le certificat CA `SFSRootCAG2.pem` (le kit SDK Java Gremlin a besoin d'un certificat pour vérifier le certificat à distance).

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

1. Créez un magasin de clés au format JKS ou PKCS12 au format. Cet exemple utilise JKS. Répondez aux questions qui suivent à l'invite. Le mot de passe que vous créez ici sera nécessaire ultérieurement :

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

1. Importez le fichier `SFSRootCAG2.pem` que vous avez téléchargé dans le magasin de clés que vous venez de créer :

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

1. Configurez l'objet `Cluster` par programmation :

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

   Vous pouvez faire la même chose dans un fichier de configuration si vous le souhaitez, comme vous pourriez le faire avec la console 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 }}
   ```

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion à partir d'un client Java, consultez[Connexion aux bases de données Amazon Neptune à l'aide d'IAM avec Gkremlin Java](iam-auth-connecting-gremlin-java.md).

# Exemple Java de connexion à une instance de base de données Neptune avec une logique de reconnexion
<a name="access-graph-gremlin-java-reconnect-example"></a>

L'exemple Java suivant montre comment se connecter au client Gremlin à l'aide d'une logique de reconnexion afin d'assurer la reprise après une déconnexion inattendue.

Il présente les dépendances suivantes :

```
<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>
```

Voici l'exemple de code :

**Important**  
 Le `CallExecutor` de Retry4j n'est peut-être pas thread-safe. Envisagez de demander à chaque thread d'utiliser sa propre `CallExecutor` instance ou d'utiliser une bibliothèque de nouvelles tentatives différente. 

**Note**  
 L'exemple suivant a été mis à jour pour inclure l'utilisation de RequestInterceptor (). Cela a été ajouté dans la version TinkerPop 3.6.6. Avant la TinkerPop version 3.6.6, l'exemple de code utilisait HandshakeInterceptor (), qui était obsolète avec cette version. 

```
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;
  };
}
```

# Utilisation de Python pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-python"></a>

**Important**  
Le choix de la bonne version du pilote TinkerPop Apache G705 est essentiel pour garantir la compatibilité avec la version de votre moteur Neptune. L'utilisation d'une version incompatible peut entraîner des échecs de connexion ou un comportement inattendu. Pour obtenir des informations détaillées sur la compatibilité des versions, consultez[Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

La section suivante vous accompagne dans l'exécution d'un exemple Python qui se connecte à une instance de base de données Amazon Neptune et effectue une traversée Gremlin.

Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Avant de commencer, vous devez exécuter les actions suivantes :
+ Téléchargez et installez Python 3.6 ou version ultérieure depuis le [site web Python.org](https://www.python.org/downloads/).
+ Vérifiez que vous avez installé **pip**. Si vous n'avez pas **pip** ou que vous n'en êtes pas certain, voir [Do I need to install pip? (Dois-je installer pip?](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) dans la documentation **pip**.
+ Si votre installation Python n'est pas déjà définie, téléchargez `futures` comme suit : `pip install futures`



**Pour se connecter à Neptune à l'aide de Python**

1. Entrez ce qui suit pour installer le package `gremlinpython` :

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

1. Créez un fichier nommé `gremlinexample.py` et ouvrez-le dans un éditeur de texte.

1. Copiez ce qui suit dans le fichier `gremlinexample.py`. Remplacez *your-neptune-endpoint* par l'adresse de votre cluster de base de données Neptune et *your-neptune-port* par le port de votre cluster de base de données Neptune (par défaut : 8182). 

   Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver l'adresse de votre instance de base de données Neptune.

    L'exemple ci-dessous montre comment se connecter à Garmlin 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. Pour exécuter l'exemple, entrez la commande suivante :

   ```
   python gremlinexample.py
   ```

   La requête Gremlin à la fin de cet exemple renvoie les vertex (`g.V().limit(2)`) dans une liste. Cette liste est ensuite imprimée avec la fonction standard Python `print`.
**Note**  
La partie finale de la requête Gremlin, `toList()`, est obligatoire pour soumettre la traversée au serveur à des fins d'évaluation. Si vous n'incluez pas cette méthode ou une autre méthode équivalente, la requête ne sera pas soumise à l'instance de base de données Neptune.

   Les méthodes suivantes soumettent la requête à l'instance de base de données Neptune :
   + `toList()`
   + `toSet()`
   + `next()`
   + `nextTraverser()`
   + `iterate()`

   

   L'exemple précédent renvoie les deux premier vertex du graphe en utilisant la traversée `g.V().limit(2).toList()`. Pour interroger quelque chose d'autre, remplacez la traversée par une autre traversée Gremlin avec l'une des méthodes de fin appropriées.

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion à partir d'un client Python, consultez[Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec Gremlin Python](gremlin-python-iam-auth.md).

# Utilisation de .NET pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-dotnet"></a>

**Important**  
Le choix de la bonne version du pilote TinkerPop Apache G705 est essentiel pour garantir la compatibilité avec la version de votre moteur Neptune. L'utilisation d'une version incompatible peut entraîner des échecs de connexion ou un comportement inattendu. Pour obtenir des informations détaillées sur la compatibilité des versions, consultez[Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

La section suivante contient un exemple de code écrit en C\$1 qui se connecte à une instance de base de données Neptune et effectue une traversée Gremlin.

Les connexions à Amazon Neptune doivent provenir d'une instance Amazon EC2 située dans le même cloud privé virtuel que votre instance de base de données Neptune. Cet exemple de code a été testé sur une instance Amazon EC2 exécutant Ubuntu.

Avant de commencer, vous devez exécuter les actions suivantes :
+ Installez .NET sur l'instance Amazon EC2. Pour obtenir des instructions sur la façon d'installer .NET sur plusieurs systèmes d'exploitation, notamment Windows, Linux et macOS, consultez [Mise en route avec .NET](https://www.microsoft.com/net/learn/get-started/).
+ Installez Gremlin.NET en exécutant `dotnet add package gremlin.net` pour votre package. Pour plus d'informations, consultez [Gremlin.net](https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet) dans la documentation. TinkerPop 



**Pour se connecter à Neptune à l'aide de Gremlin.NET**

1. Crée un projet .NET.

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

1. Modifiez les répertoires vers le nouveau répertoire de projet.

   ```
   cd gremlinExample
   ```

1. Copiez ce qui suit dans le fichier `Program.cs`. Remplacez *your-neptune-endpoint* par l'adresse de votre instance de base de données Neptune.

   Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver l'adresse de votre instance de base de données Neptune.

   ```
   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. Pour exécuter l'exemple, entrez la commande suivante :

   ```
   dotnet run
   ```

   La requête Gremlin à la fin de cet exemple renvoie le nombre d'un seul vertex à des fins de test. Elle est ensuite imprimée sur la console.
**Note**  
La partie finale de la requête Gremlin, `Next()`, est obligatoire pour soumettre la traversée au serveur à des fins d'évaluation. Si vous n'incluez pas cette méthode ou une autre méthode équivalente, la requête ne sera pas soumise à l'instance de base de données Neptune.

   Les méthodes suivantes soumettent la requête à l'instance de base de données Neptune :
   + `ToList()`
   + `ToSet()`
   + `Next()`
   + `NextTraverser()`
   + `Iterate()`

   Utilisez `Next()` si vous avez besoin que les résultats de la requête soient sérialisés et renvoyés, ou `Iterate()` dans le cas contraire.

   L'exemple précédent renvoie une liste à l'aide de la traversée `g.V().Limit(3).ToList()`. Pour interroger quelque chose d'autre, remplacez la traversée par une autre traversée Gremlin avec l'une des méthodes de fin appropriées.

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion à partir d'un client .NET, consultez[Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec Gremlin .NET](gremlin-dotnet-iam-auth.md).

# Utilisation de Node.js pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-node-js"></a>

**Important**  
Le choix de la bonne version du pilote TinkerPop Apache G705 est essentiel pour garantir la compatibilité avec la version de votre moteur Neptune. L'utilisation d'une version incompatible peut entraîner des échecs de connexion ou un comportement inattendu. Pour obtenir des informations détaillées sur la compatibilité des versions, consultez[Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

La section suivante vous accompagne dans l'exécution d'un exemple Node.js qui se connecte à une instance de base de données Amazon Neptune et effectue une traversée Gremlin.

Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Avant de commencer, vous devez exécuter les actions suivantes :
+ Vérifiez que la version 8.11 ou ultérieure de Node.js est installée. Dans le cas contraire, téléchargez et installez Node.js à partir du [site web Nodejs.org](https://nodejs.org).

**Pour se connecter à Neptune à l'aide de Node.js**

1. Entrez ce qui suit pour installer le package `gremlin-javascript` :

   ```
   npm install gremlin
   ```

1. Créez un fichier nommé `gremlinexample.js` et ouvrez-le dans un éditeur de texte.

1. Copiez ce qui suit dans le fichier `gremlinexample.js`. Remplacez *your-neptune-endpoint* par l'adresse de votre instance de base de données Neptune.

   Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver l'adresse de votre instance de base de données Neptune.

   ```
   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. Pour exécuter l'exemple, entrez la commande suivante :

   ```
   node gremlinexample.js
   ```

L'exemple précédent renvoie le nombre d'un seul sommet dans le graphique en utilisant la traversée `g.V().limit(1).count().next()`. Pour interroger quelque chose d'autre, remplacez la traversée par une autre traversée Gremlin avec l'une des méthodes de fin appropriées.

**Note**  
La partie finale de la requête Gremlin, `next()`, est obligatoire pour soumettre la traversée au serveur à des fins d'évaluation. Si vous n'incluez pas cette méthode ou une autre méthode équivalente, la requête ne sera pas soumise à l'instance de base de données Neptune.

Les méthodes suivantes soumettent la requête à l'instance de base de données Neptune :
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

Utilisez `next()` si vous avez besoin que les résultats de la requête soient sérialisés et renvoyés, ou `iterate()` dans le cas contraire.

**Important**  
Il s'agit d'un exemple Node.js autonome. Si vous envisagez d'exécuter un code de ce type dans une AWS Lambda fonction, consultez [Exemples de fonctions Lambda](lambda-functions-examples.md) pour plus de détails sur l'utilisation JavaScript efficace dans une fonction Neptune Lambda.

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion à partir d'un JavaScript client, consultez[Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec G705 JavaScript](gremlin-javascript-iam-auth.md).

# Utilisation de Go pour se connecter à une instance de base de données Neptune
<a name="access-graph-gremlin-go"></a>

**Important**  
Le choix de la bonne version du pilote TinkerPop Apache G705 est essentiel pour garantir la compatibilité avec la version de votre moteur Neptune. L'utilisation d'une version incompatible peut entraîner des échecs de connexion ou un comportement inattendu. Pour obtenir des informations détaillées sur la compatibilité des versions, consultez[Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

**Note**  
Les versions 3.5.x de gremlingo sont rétrocompatibles avec les versions 3.4.x tant que vous n'utilisez que les fonctionnalités TinkerPop 3.4.x dans les requêtes Gkremlin que vous écrivez.

La section suivante vous accompagne dans l'exécution d'un exemple Go qui se connecte à une instance de base de données Amazon Neptune et effectue une traversée Gremlin.

Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Avant de commencer, vous devez exécuter les actions suivantes :
+ Téléchargez et installez Go 1.17 ou version ultérieure depuis le site web [go.dev](https://go.dev/dl/).

**Pour se connecter à Neptune à l'aide de Go**

1. À partir d'un répertoire vide, initialisez un nouveau module Go :

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

1. Ajoutez gremlin-go comme dépendance du nouveau module :

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

1. Créez un fichier nommé `gremlinExample.go` et ouvrez-le dans un éditeur de texte.

1. Copiez ce qui suit dans le fichier `gremlinExample.go`, en remplaçant *`(your neptune endpoint)`* par l'adresse de l'instance de base de données Neptune :

   ```
   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())
     }
   }
   ```
**Note**  
Le format du certificat Neptune TLS n'est actuellement pas pris en charge sur Go 1.18 ou version supérieure avec macOS et peut générer une erreur 509 lorsque vous essayez d'établir une connexion. Pour les tests locaux, cela peut être ignoré en ajoutant « crypto/tls » aux importations et en modifiant les paramètres `DriverRemoteConnection` comme suit :  

   ```
   // 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. Pour exécuter l'exemple, entrez la commande suivante :

   ```
   go run gremlinExample.go
   ```

La requête Gremlin à la fin de cet exemple renvoie les sommets (`(g.V().Limit(2))`) dans une liste. Cette tranche est ensuite itérée et imprimée avec la fonction `fmt.Println` standard.

**Note**  
La partie finale de la requête Gremlin, `ToList()`, est obligatoire pour soumettre la traversée au serveur à des fins d'évaluation. Si vous n'incluez pas cette méthode ou une autre méthode équivalente, la requête ne sera pas soumise à l'instance de base de données Neptune.

Les méthodes suivantes soumettent la requête à l'instance de base de données Neptune :
+ `ToList()`
+ `ToSet()`
+ `Next()`
+ `GetResultSet()`
+ `Iterate()`

L'exemple précédent renvoie les deux premier vertex du graphe en utilisant la traversée `g.V().Limit(2).ToList()`. Pour interroger quelque chose d'autre, remplacez la traversée par une autre traversée Gremlin avec l'une des méthodes de fin appropriées.

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

Neptune prend en charge l'[authentification IAM](iam-auth-enable.md) pour contrôler l'accès à votre cluster de base de données. Si l'authentification IAM est activée, vous devez utiliser la signature Signature version 4 pour authentifier vos demandes. Pour obtenir des instructions détaillées et des exemples de code pour la connexion à partir d'un client Go, consultez[Connexion aux bases de données Amazon Neptune à l'aide de l'authentification IAM avec Gremlin Go](gremlin-go-iam-auth.md).

# Utiliser le AWS SDK pour exécuter des requêtes Gremlin
<a name="access-graph-gremlin-sdk"></a>

Avec le AWS SDK, vous pouvez exécuter des requêtes G705 sur votre graphe Neptune à l'aide du langage de programmation de votre choix. Le SDK de l'API de données Neptune (nom du service`neptunedata`) fournit l'[ExecuteGremlinQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteGremlinQuery.html)action permettant de soumettre des requêtes Gremlin.

Vous devez exécuter ces exemples depuis une instance Amazon EC2 dans le même cloud privé virtuel (VPC) que votre cluster de base de données Neptune, ou depuis un emplacement disposant d'une connectivité réseau avec le point de terminaison de votre cluster.

Vous trouverez ci-dessous des liens directs vers la documentation de référence `neptunedata` de l'API pour le service dans chaque langue du SDK :


| Langage de programmation | Référence de l'API neptunedata | 
| --- | --- | 
| 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) | 
| INTERFACE DE LIGNE DE COMMANDE (CLI) | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

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

Les exemples suivants montrent comment configurer un `neptunedata` client, exécuter une requête Gremlin et imprimer les résultats. Remplacez *YOUR\$1NEPTUNE\$1HOST* et *YOUR\$1NEPTUNE\$1PORT* par le point de terminaison et le port de votre cluster de base de données Neptune.

**Configuration du délai d'expiration et des nouvelles tentatives côté client**  
Le délai d'attente du client SDK contrôle le temps d'attente d'une réponse par le *client*. Il ne contrôle pas la durée d'exécution de la requête sur le serveur. Si le client expire avant la fin du serveur, la requête peut continuer à s'exécuter sur Neptune alors que le client n'a aucun moyen de récupérer les résultats.  
[Nous vous recommandons de définir le délai de lecture côté client sur `0` (aucun délai d'attente) ou sur une valeur supérieure d'au moins quelques secondes au paramètre neptune\$1query\$1timeout côté serveur sur votre cluster de base de données Neptune.](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) Cela permet à Neptune de contrôler l'expiration du délai d'expiration des requêtes.  
Nous recommandons également de fixer le nombre maximum de tentatives à `1` (aucune tentative). Si le SDK réessaie une requête toujours en cours d'exécution sur le serveur, cela peut entraîner des opérations dupliquées. Cela est particulièrement important pour les requêtes de mutation, où une nouvelle tentative peut entraîner des écritures dupliquées involontaires.

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

1. Suivez les [instructions d'installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html) pour installer Boto3.

1. Créez un fichier nommé `gremlinExample.py` et collez le code suivant :

   ```
   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. Exécutez l'exemple : `python gremlinExample.py`

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

1. Suivez les [instructions d'installation](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) pour configurer le AWS SDK for Java.

1. Utilisez le code suivant pour configurer une`NeptunedataClient`, exécuter une requête Gremlin et imprimer le résultat :

   ```
   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. Suivez les [instructions d'installation](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) pour configurer le AWS SDK pour JavaScript. Installez le package client neptunedata :. `npm install @aws-sdk/client-neptunedata`

1. Créez un fichier nommé `gremlinExample.js` et collez le code suivant :

   ```
   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. Exécutez l'exemple : `node gremlinExample.js`

------

# Indicateurs de requête Gremlin
<a name="gremlin-query-hints"></a>

Vous pouvez utiliser des indicateurs de requête afin de spécifier des stratégies d'optimisation et d'évaluation pour une requête Gremlin particulière dans Amazon Neptune. 

Les indicateurs de requête sont spécifiés en ajoutant une étape `withSideEffect` à la requête avec la syntaxe suivante.

```
g.withSideEffect(hint, value)
```
+ *hint* : identifie le type d'indicateur à appliquer.
+ *value* : détermine le comportement de l'aspect du système pris en compte.

Par exemple, le code suivant montre comment inclure un indicateur `repeatMode` dans une traversée Gremlin.

**Note**  
Tous les effets secondaires d'indicateurs de requête Gremlin sont préfixés avec `Neptune#`.

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

La requête précédente demande au moteur Neptune de parcourir le graphe *en profondeur en premier* (`DFS`) au lieu du mode par défaut, *dans la largeur en premier* (`BFS`).

Les sections suivantes fournissent de plus amples informations sur les indicateurs de requête disponibles et leur utilisation.

**Topics**
+ [Indicateur de requête Gremlin repeatMode](gremlin-query-hints-repeatMode.md)
+ [Indicateur de requête Gremlin noReordering](gremlin-query-hints-noReordering.md)
+ [Indicateur de requête Gremlin typePromotion](gremlin-query-hints-typePromotion.md)
+ [Indicateur de requête Gremlin useDFE](gremlin-query-hints-useDFE.md)
+ [Indicateurs de requête Gremlin pour l'utilisation du cache de résultats](gremlin-query-hints-results-cache.md)

# Indicateur de requête Gremlin repeatMode
<a name="gremlin-query-hints-repeatMode"></a>

L’indicateur de requête Neptune `repeatMode` indique la façon dont le moteur Neptune évalue l’étape `repeat()` dans une traversée Gremlin : largeur en premier, profondeur en premier ou profondeur en premier par blocs.

Le mode d'évaluation de l'étape `repeat()` est important lorsqu'il est utilisé pour rechercher ou suivre un chemin, au lieu de simplement répéter une étape un nombre limité de fois.

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

L'indicateur de requête `repeatMode` est spécifié en ajoutant une étape `withSideEffect` à la requête.

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

**Note**  
Tous les effets secondaires d'indicateurs de requête Gremlin sont préfixés avec `Neptune#`.

**Modes disponibles**
+ `BFS`

  (Breadth-First Search) Recherche dans la largeur en premier

  Mode d'exécution par défaut pour l'étape `repeat()`. Ce mode permet d'obtenir tous les nœuds de même niveau avant d'aller plus en profondeur dans le chemin.

  Cette version est gourmande en mémoire et les frontières peuvent être très étendues. Le risque que la requête manque de mémoire et soit annulée par le moteur Neptune est plus élevé. Ce mode correspond au plus près aux autres implémentations Gremlin.
+ `DFS`

  (Depth-First Search) Recherche en profondeur en premier

  Suit chaque chemin jusqu'à la profondeur maximale avant de passer à la solution suivante.

  Ce mode utilise moins de mémoire. Il peut offrir de meilleures performances dans des situations comme la recherche d'un chemin unique à partir d'un point de départ vers plusieurs tronçons.
+ `CHUNKED_DFS`

  (Chunked Depth-First Search) Recherche en profondeur en premier par blocs

  Approche hybride qui explore le graphe en profondeur en premier par blocs de 1 000 nœuds, plutôt que 1 nœud (`DFS`) ou tous les nœuds (`BFS)`.

  Le moteur Neptune extrait jusqu'à 1 000 nœuds à chaque niveau avant de suivre le chemin plus en profondeur.

  Cela constitue un bon compromis entre la vitesse et l'utilisation de la mémoire. 

  Cette approche s'avère également utile si vous souhaitez utiliser la mode `BFS`, mais la que requête utilise trop de mémoire.



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

La section suivante décrit l'effet du mode de répétition sur un parcours Gremlin.

Dans Neptune, le mode par défaut pour l'étape `repeat()` consiste à effectuer une stratégie d'exécution dans la largeur en premier (`BFS`) pour toutes les traversées. 

Dans la plupart des cas, l' TinkerGraph implémentation utilise la même stratégie d'exécution, mais dans certains cas, elle modifie l'exécution d'une traversée. 

Par exemple, l' TinkerGraph implémentation modifie la requête suivante.

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

L'étape `repeat()` de ce parcours est « déroulée » dans le parcours suivant, ce qui se traduit par une stratégie en profondeur en premier (`DFS`).

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

**Important**  
Le moteur de requête Neptune ne procède pas ainsi automatiquement.

Breadth-first (`BFS`) est la stratégie d'exécution par défaut et est similaire TinkerGraph dans la plupart des cas. Cependant, il y a certains cas où les stratégies en profondeur en premier (`DFS`) sont préférables.

 

**BFS (valeur par défaut)**  
BFS (dans la largeur en premier) est la stratégie d'exécution par défaut pour l'opérateur `repeat()`.

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

Le moteur Neptune explore entièrement les premières frontières à neuf tronçons avant de rechercher une solution à partir du dixième tronçon. Cette approche est efficace dans de nombreux cas, notamment dans celui d'une requête au chemin le plus court.

Cependant, dans l'exemple précédent, le parcours serait beaucoup plus rapide à l'aide du mode profondeur en premier (`DFS`) pour l'opérateur `repeat()`.

**DFS**  
La requête suivante utilise le mode `DFS` (profondeur en premier) pour l'opérateur `repeat()`.

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

Ce mode suit chaque solution jusqu'à la profondeur maximale avant d'explorer la solution suivante. 

# Indicateur de requête Gremlin noReordering
<a name="gremlin-query-hints-noReordering"></a>

Lorsque vous soumettez une traversée Gremlin, le moteur de requête Neptune étudie sa structure et réorganise les parties de la requête, en tentant de réduire la quantité de travail nécessaire pour l'évaluation et les temps de réponse de la requête. Par exemple, un parcours avec plusieurs contraintes, telles que plusieurs étapes `has()`, n'est généralement pas évalué dans l’ordre donné. Au lieu de cela, il est réorganisé une fois que la requête a été vérifiée avec une analyse statique.

Le moteur de requête Neptune essaie d'identifier la contrainte la plus sélective et exécute celle-ci en premier. Cela se traduit souvent par de meilleures performances, mais l'ordre dans lequel Neptune choisit d'évaluer la requête peut ne pas toujours être optimal.

Si vous connaissez les caractéristiques exactes des données et que vous souhaitez imposer manuellement l'ordre d'exécution de la requête, vous pouvez utiliser l'indicateur de requête Neptune `noReordering` pour demander que la requête soit évaluée dans l'ordre donné.

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

L'indicateur de requête `noReordering` est spécifié en ajoutant une étape `withSideEffect` à la requête.

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

**Note**  
Tous les effets secondaires d'indicateurs de requête Gremlin sont préfixés avec `Neptune#`.

**Valeurs disponibles**
+ `true`
+ `false`

# Indicateur de requête Gremlin typePromotion
<a name="gremlin-query-hints-typePromotion"></a>

Lorsque vous soumettez une traversée Gremlin qui filtre une valeur ou une plage numérique, le moteur de requête Neptune doit normalement utiliser la promotion de type lorsqu'il exécute la requête. Autrement dit, il doit examiner les valeurs de tous les types susceptibles de contenir la valeur sur laquelle porte le filtre.

Par exemple, si vous filtrez les valeurs égales à 55, le moteur doit rechercher les entiers égaux à 55, les entiers longs égaux à 55L, les nombres flottants égaux à 55,0, etc. Chaque promotion de type implique une recherche supplémentaire au niveau du stockage, ce qui peut entraîner un délai étonnamment long pour terminer une requête apparemment simple.

Supposons que vous recherchiez tous les sommets dont la propriété correspondant à l'âge du client est supérieure à 5 :

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

Pour exécuter cette traversée de manière approfondie, Neptune doit développer la requête afin d'examiner tous les types numériques vers lesquels la valeur que vous recherchez pourrait être promue. Dans ce cas, le filtre `gt` doit être appliqué pour tout entier supérieur à 5, tout long supérieur à 5L, tout flottant supérieur à 5,0 et tout double supérieur à 5,0. Étant donné que chacune de ces promotions nécessite une recherche supplémentaire sur le stockage, vous verrez plusieurs filtres par filtre numérique lorsque vous exécuterez l'[API Gremlin `profile`](gremlin-profile-api.md) pour cette requête, et son exécution prendra beaucoup plus de temps que prévu.

Souvent, la promotion de type n'est pas nécessaire, car vous savez déjà que vous n'avez besoin de trouver que les valeurs d'un type spécifique. Dans ce cas, vous pouvez accélérer considérablement les requêtes en utilisant l'indicateur de requête `typePromotion` afin de désactiver la promotion de type.

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

L'indicateur de requête `typePromotion` est spécifié en ajoutant une étape `withSideEffect` à la requête.

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

**Note**  
Tous les effets secondaires d'indicateurs de requête Gremlin sont préfixés avec `Neptune#`.

**Valeurs disponibles**
+ `true`
+ `false`

Pour désactiver la promotion de type pour la requête ci-dessus, vous devez utiliser :

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

# Indicateur de requête Gremlin useDFE
<a name="gremlin-query-hints-useDFE"></a>

Utilisez cet indicateur de requête afin d'activer l'utilisation du DFE pour exécuter la requête. Par défaut, Neptune n'utilise pas le DFE sans que cet indicateur de requête ne soit défini sur `true`, car le paramètre d'instance [neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) est défini par défaut sur `viaQueryHint`. Si vous définissez ce paramètre d'instance sur `enabled`, le moteur DFE est utilisé pour toutes les requêtes, à l'exception de celles dont l'indicateur de requête `useDFE` est défini sur `false`.

Exemple d'activation du DFE pour une requête :

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

# Indicateurs de requête Gremlin pour l'utilisation du cache de résultats
<a name="gremlin-query-hints-results-cache"></a>

Les indicateurs de requête suivants peuvent être utilisés lorsque le [cache des résultats de requête](gremlin-results-cache.md) est activé.

## Indicateur de requête Gremlin `enableResultCache`
<a name="gremlin-query-hints-results-cache-enableResultCache"></a>

Lorsque l'indicateur de requête `enableResultCache` a une valeur égale à `true`, les résultats de la requête sont renvoyés à partir du cache s'ils ont déjà été mis en cache. Dans le cas contraire, de nouveaux résultats sont renvoyés et mis en cache jusqu'à ce qu'ils soient effacés de celui-ci. Par exemple :

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

Plus tard, vous pourrez accéder aux résultats mis en cache en émettant à nouveau exactement la même requête.

Si la valeur de cet indicateur de requête est `false` ou si elle n'est pas présente, les résultats de la requête ne sont pas mis en cache. Toutefois, l'utilisation du paramètre `false` n'efface pas les résultats mis en cache existants. Pour effacer les résultats mis en cache, utilisez l'indicateur `invalidateResultCache` ou `invalidateResultCachekey`.

## Indicateur de requête Gremlin `enableResultCacheWithTTL`
<a name="gremlin-query-hints-results-cache-enableResultCacheWithTTL"></a>

L'indicateur de requête `enableResultCacheWithTTL` renvoie également les résultats mis en cache s'il y en a, sans affecter la durée de vie (TTL) des résultats déjà présents dans le cache. S'il n'y a actuellement aucun résultat mis en cache, la requête renvoie de nouveaux résultats et les met en cache pendant la durée de vie (TTL) spécifiée par l'indicateur de requête `enableResultCacheWithTTL`. Cette durée de vie est spécifiée en secondes. Par exemple, la requête suivante spécifie une durée de vie de 60 secondes :

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

Avant la fin des 60 secondes time-to-live, vous pouvez utiliser la même requête (ici`g.V().has('genre','drama').in('likes')`) avec l'indice `enableResultCache` ou l'indice de `enableResultCacheWithTTL` requête pour accéder aux résultats mis en cache.

**Note**  
La durée de vie spécifiée avec `enableResultCacheWithTTL` n'affecte pas les résultats déjà mis en cache.  
Si les résultats ont déjà été mis en cache avec `enableResultCache`, le cache doit d'abord être explicitement vidé avant qu'`enableResultCacheWithTTL` génère de nouveaux résultats et les mette en cache pour le TTL qu'il spécifie.
Si les résultats ont déjà été mis en cache à l'aide de l'indicateur `enableResultCachewithTTL`, cette durée de vie précédente, ou TTL, doit d'abord expirer avant qu'`enableResultCacheWithTTL` génère de nouveaux résultats et les mette en cache pour la durée de vie qu'il spécifie.

Une fois la durée de vie écoulée, les résultats mis en cache pour la requête sont effacés, et toute instance ultérieure de la même requête renverra de nouveaux résultats. Si `enableResultCacheWithTTL` est attaché à cette requête ultérieure, les nouveaux résultats sont mis en cache avec le TTL spécifié.

## Indicateur de requête Gremlin `invalidateResultCacheKey`
<a name="gremlin-query-hints-results-cache-invalidateResultCacheKey"></a>

L'indicateur de requête `invalidateResultCacheKey` peut avoir la valeur `false` ou `true`. Une valeur `true` entraîne l'effacement des résultats mis en cache pour la requête à laquelle `invalidateResultCacheKey` est attaché. Par exemple, dans l'exemple suivant, les résultats mis en cache pour la clé de requête `g.V().has('genre','drama').in('likes')` sont effacés :

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

L'exemple de requête ci-dessus n'entraîne pas la mise en cache de ses nouveaux résultats. Vous pouvez inclure `enableResultCache` (ou `enableResultCacheWithTTL`) dans la même requête si vous souhaitez mettre en cache les nouveaux résultats après avoir effacé les résultats existants dans le cache :

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

## Indicateur de requête Gremlin `invalidateResultCache`
<a name="gremlin-query-hints-results-cache-invalidateResultCache"></a>

L'indicateur de requête `invalidateResultCache` peut avoir la valeur `false` ou `true`. Une valeur `true` entraîne l'effacement de tous les résultats du cache de résultats. Par exemple :

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

L'exemple de requête ci-dessus n'entraîne pas la mise en cache de ses résultats. Vous pouvez inclure `enableResultCache` (ou `enableResultCacheWithTTL`) dans la même requête si vous souhaitez mettre en cache les nouveaux résultats après avoir entièrement vidé le cache existant :

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

## Indicateur de requête Gremlin `numResultsCached`
<a name="gremlin-query-hints-results-cache-numResultsCached"></a>

L'indicateur de requête `numResultsCached` ne peut être utilisé qu'avec les requêtes contenant `iterate()`. Il indique le nombre maximal de résultats à mettre en cache pour la requête à laquelle il est attaché. Notez que les résultats mis en cache lorsque `numResultsCached` est présent ne sont pas renvoyés, mais uniquement mis en cache.

Par exemple, la requête suivante spécifie que jusqu'à 100 de ses résultats doivent être mis en cache, mais aucun de ces résultats mis en cache n'est renvoyé :

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

Vous pouvez ensuite utiliser une requête comme celle-ci pour récupérer une série de résultats mis en cache (ici, les dix premiers) :

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

## Indicateur de requête Gremlin `noCacheExceptions`
<a name="gremlin-query-hints-results-cache-noCacheExceptions"></a>

L'indicateur de requête `noCacheExceptions` peut avoir la valeur `false` ou `true`. Une valeur `true` entraîne la suppression de toutes les exceptions liées au cache de résultats. Par exemple :

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

Elle supprime notamment l'exception `QueryLimitExceededException`, qui est déclenchée si les résultats d'une requête sont trop volumineux pour tenir dans le cache de résultats.

# API de statut des requêtes Gremlin
<a name="gremlin-api-status"></a>

Pour obtenir le statut des requêtes Gremlin, utilisez HTTP `GET` ou `POST` pour effectuer une requête au point de terminaison `https://your-neptune-endpoint:port/gremlin/status`. 

## Paramètres des demandes de statut des requêtes Gremlin
<a name="gremlin-api-status-get-request"></a>
+ **queryID** (*facultatif*) : ID d'une requête Gremlin en cours d'exécution. Affiche uniquement le statut de la requête indiquée.
+ **includeWaiting** (*facultatif*) : renvoie le statut de toutes les requêtes en attente.

  Normalement, seules les requêtes en cours sont incluses dans la réponse, mais lorsque le paramètre `includeWaiting` est spécifié, le statut de toutes les requêtes en attente est également renvoyé.

## Syntaxe des réponses de statut des requêtes 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"
    }
  ]
}
```

## Valeurs des réponses de statut des requêtes Gremlin
<a name="gremlin-api-status-get-response-values"></a>
+ **acceptedQueryCount**— Le nombre de requêtes acceptées mais non encore terminées, y compris les requêtes dans la file d'attente.
+ **runningQueryCount**— Le nombre de requêtes Gkremlin en cours d'exécution.
+ **queries** : requêtes Gremlin actuelles.
+ **queryID** : identifiant GUID de la requête. Neptune attribue automatiquement cette valeur d'ID à chaque requête, mais vous pouvez également attribuer votre propre ID (voir [Injection d'un ID personnalisé dans une requête Neptune Gremlin ou SPARQL](features-query-id.md)).
+ **queryEvalStats**— Statistiques pour cette requête.
+ **subqueries** : nombre de sous-requêtes de cette requête.
+ **elapsed** : nombre de microsecondes d'exécution de la requête jusqu'au moment T.
+ **cancelled** : true indique que la requête a été annulée.
+ **queryString** : requête soumise. Celle-ci est tronquée à 1 024 caractères si elle est plus longue que cela.
+ **waited** : indique la durée d'attente de la requête, en millisecondes.

## Exemple de statut de requête Gremlin
<a name="gremlin-api-status-get-example"></a>

Voici un exemple de commande de demande du statut utilisant `curl` et la demande HTTP `GET`.

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

Cette sortie affiche une seule requête en cours d'exécution.

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

# Annulation de requêtes Gremlin
<a name="gremlin-api-status-cancel"></a>

Pour obtenir le statut des requêtes Gremlin, utilisez HTTP `GET` ou `POST` pour effectuer une requête au point de terminaison `https://your-neptune-endpoint:port/gremlin/status`.

## Paramètres des demandes d'annulation des requêtes Gremlin
<a name="gremlin-api-status-cancel-request"></a>
+ **cancelQuery** : obligatoire pour l'annulation. Ce paramètre n'a aucune valeur correspondante.
+ **queryId** : ID de la requête Gremlin en cours d'exécution à annuler.

## Exemple d'annulation de requêtes Gremlin
<a name="gremlin-api-status-cancel-example"></a>

Voici un exemple de commande `curl` pour annuler une requête.

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

L'annulation réussie renvoie le code HTTP `200` OK.

# Prise en charge des sessions basées sur des scripts Gremlin
<a name="access-graph-gremlin-sessions"></a>

Vous pouvez utiliser des sessions Gremlin avec des transactions implicites dans Amazon Neptune. Pour plus d'informations sur les sessions G705, consultez la section [Considering Sessions](http://tinkerpop.apache.org/docs/current/reference/#sessions) dans la TinkerPop documentation Apache. Les sections ci-dessous décrivent comment utiliser les sessions Gremlin avec Java.

**Important**  
Actuellement, Neptune peut conserver une session basée sur des scripts ouverte jusqu'à 10 minutes. Si vous ne fermez pas votre session avant cela, la session expire et tout ce qu'elle contient est annulé.

**Topics**
+ [Sessions Gremlin dans la console Gremlin](#access-graph-gremlin-sessions-console)
+ [Sessions Gremlin dans la variante du langage Gremlin](#access-graph-gremlin-sessions-glv)

## Sessions Gremlin dans la console Gremlin
<a name="access-graph-gremlin-sessions-console"></a>

Si vous créez une connexion à distance sur la console Gremlin sans le paramètre `session`, la connexion à distance est créée en mode *sans session*. Dans ce mode, chaque demande envoyée au serveur est traitée comme une transaction complète en elle-même, et aucun état n'est enregistré entre les demandes. Si une demande échoue, seule cette demande est annulée.

Si vous créez une connexion à distance qui *utilise* le paramètre `session`, vous créez une session basée sur des scripts qui dure jusqu'à ce que vous fermiez la connexion distante. Chaque session est identifiée par un UUID unique que la console génère et renvoie.

Voici un exemple d'appel de console qui crée une session. Une fois les requêtes soumises, un autre appel ferme la session et valide les requêtes.

**Note**  
Le client Gremlin doit toujours être fermé pour libérer des ressources côté serveur.

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

Pour plus d'informations et des exemples, consultez la section [Sessions](http://tinkerpop.apache.org/docs/current/reference/#console-sessions) de la TinkerPop documentation.

Toutes les requêtes que vous exécutez au cours d'une session forment une seule transaction qui n'est pas validée tant que toutes les requêtes n'ont pas abouti et que vous n'avez pas fermé la connexion à distance. Si une requête échoue, ou si vous n'avez pas fermé la connexion avant la fin de la durée de vie de session prise en charge par Neptune, la transaction de session n’est pas validée, et toutes les requêtes qu’elle contient sont annulées.

## Sessions Gremlin dans la variante du langage Gremlin
<a name="access-graph-gremlin-sessions-glv"></a>

Dans la variante du langage Gremlin (GLV), vous devez créer un objet `SessionedClient` pour émettre plusieurs requêtes en une seule transaction, comme dans l'exemple suivant.

```
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();
}
```

La ligne 3 de l'exemple précédent crée l'objet `SessionedClient` selon les options de configuration définies pour le cluster en question. La *sessionName* chaîne que vous transmettez à la méthode de connexion devient le nom unique de la session. Pour éviter les collisions, utilisez un UUID pour le nom.

Le client démarre une transaction de session lorsqu'il est initialisé. Toutes les requêtes que vous exécutez au cours du formulaire de session ne sont validées que lorsque vous appelez `client.close( )`. Là encore, si une seule requête échoue ou si vous n'avez pas fermé la connexion avant la fin de la durée de vie de session prise en charge par Neptune, la transaction de session échoue, et toutes les requêtes qu’elle contient sont annulées.

**Note**  
Le client Gremlin doit toujours être fermé pour libérer des ressources côté serveur.

```
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();
    }
}
```

# Transactions Gremlin dans Neptune
<a name="access-graph-gremlin-transactions"></a>

Il existe plusieurs contextes dans lesquels les [transactions](transactions.md) Gremlin sont exécutées. Lorsque vous travaillez avec Gremlin, il est important de comprendre le contexte dans lequel vous évoluez et quelles en sont les implications :
+ **`Script-based`** : les demandes sont effectuées à l'aide de chaînes Gremlin basées sur du texte, comme ceci :
  + Avec le pilote Java et `Client.submit(string)`.
  + Avec la console Gremlin et `:remote connect`.
  + Avec l'API HTTP.
+ **`Bytecode-based`** : les demandes sont effectuées à l'aide du bytecode Gremlin sérialisé typique des [variantes du langage Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants) (GLV).

  Par exemple, avec le pilote Java, `g = traversal().withRemote(...)`.

Pour l'un ou l'autre des contextes ci-dessus, il existe un contexte supplémentaire dans lequel la demande est envoyée sans session ou liée à une session.

**Note**  
 Les transactions Gremlin doivent toujours être validées ou annulées, afin que les ressources côté serveur puissent être libérées. En cas d'erreur lors de la transaction, il est important de réessayer l'ensemble de la transaction et pas uniquement la demande qui a échoué. 

## Demandes sans session
<a name="access-graph-gremlin-transactions-sessionless"></a>

 En l'absence de session, une demande équivaut à une transaction unique.

Pour les scripts, cela implique qu'une ou plusieurs déclarations Gremlin envoyées dans le cadre d'une seule demande sont validées ou annulées en tant que transaction unique. Par exemple :

```
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();
```

Pour le bytecode, une demande sans session est effectuée pour chaque traversée générée et exécutée à partir de `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();
```

## Demandes liées à une session
<a name="access-graph-gremlin-transactions-session-bound"></a>

Lorsqu'elles sont liées à une session, plusieurs demandes peuvent être appliquées dans le contexte d'une seule transaction.

Pour les scripts, cela implique qu'il n'est pas nécessaire de concaténer toutes les opérations du graphe en une seule valeur de chaîne intégrée :

```
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();
}
```

Pour le bytecode, après TinkerPop `3.5.x`, la transaction peut être contrôlée de manière explicite et la session gérée de manière transparente. Les variantes du langage Gremlin (GLV) prennent en charge la syntaxe `tx()` de Gremlin pour effectuer des opérations de type `commit()` ou `rollback()` d'une transaction, comme suit :

```
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();
    }
}
```

Bien que l'exemple ci-dessus soit écrit en Java, vous pouvez également utiliser cette syntaxe `tx()` en Python, Javascript et .NET.

**Avertissement**  
Les requêtes en lecture seule sans session sont exécutées sous un isolement [SNAPSHOT](transactions-isolation-levels.md), mais les requêtes en lecture seule exécutées dans le cadre d'une transaction explicite sont exécutées sous un isolement [SERIALIZABLE](transactions-isolation-levels.md). Les requêtes en lecture seule exécutées sous un isolement `SERIALIZABLE` entraînent une surcharge plus importante et peuvent bloquer les écritures simultanées ou être bloquées par ces dernières, contrairement à celles exécutées sous un isolement `SNAPSHOT`.

# Utilisation de l'API Gremlin avec Amazon Neptune
<a name="gremlin-api-reference"></a>

**Note**  
Amazon Neptune ne prend pas en charge la propriété `bindings`.

Les demandes HTTPS Gremlin utilisent un point de terminaison unique : `https://your-neptune-endpoint:port/gremlin`. Toutes les connexions Neptune doivent utiliser HTTPS.

Vous pouvez connecter la console Gkremlin à un graphe Neptune directement via. WebSockets

Pour plus d'informations sur la connexion au point de terminaison Gremlin, consultez [Accès au graphe Neptune avec Gremlin](access-graph-gremlin.md).

L'implémentation Amazon Neptune de Gremlin implique des détails et des différences spécifiques que vous devez prendre en compte. Pour de plus amples informations, veuillez consulter [Conformité d'Amazon Neptune avec les normes Gremlin](access-graph-gremlin-differences.md).

Pour plus d'informations sur le langage Gremlin et les traversales, consultez The [Traversal dans la documentation](https://tinkerpop.apache.org/docs/current/reference/#traversal) d'Apache. TinkerPop 

# Mise en cache des résultats de requête dans Amazon Neptune Gremlin
<a name="gremlin-results-cache"></a>

Amazon Neptune prend en charge un cache de résultats pour les requêtes Gremlin.

Vous pouvez activer ce cache, puis utiliser un indicateur de requête pour mettre en cache les résultats d'une requête Gremlin en lecture seule.

Toute réexécution de la requête permet ensuite de récupérer les résultats mis en cache avec une faible latence et sans I/O frais, tant qu'ils sont toujours dans le cache. Ce comportement s'applique pour les requêtes soumises à la fois sur un point de terminaison HTTP et à l'aide de Websockets, sous forme de bytecode ou de chaîne.

**Note**  
Les requêtes envoyées au point de terminaison de profil ne sont pas mises en cache même lorsque le cache de requêtes est activé.

Vous pouvez contrôler le comportement du cache des résultats de requête Neptune de plusieurs manières. Par exemple :
+ Vous pouvez obtenir les résultats mis en cache paginés, par blocs.
+ Vous pouvez spécifier le time-to-live (TTL) pour les requêtes spécifiées.
+ Vous pouvez vider le cache pour certaines requêtes.
+ Vous pouvez vider tout le cache.
+ Vous pouvez configurer le cache afin d'être averti si les résultats dépassent sa taille.

Le cache est maintenu selon une politique least-recently-used (LRU), ce qui signifie qu'une fois que l'espace alloué au cache est plein, les least-recently-used résultats sont supprimés pour faire de la place lorsque de nouveaux résultats sont mis en cache.

**Important**  
Le cache des résultats de requête n'est pas disponible sur les types d'instance `t3.medium` et `t4.medium`.

## Activation du cache des résultats de requête dans Neptune
<a name="gremlin-results-cache-enabling"></a>

 Le cache des résultats des requêtes peut être activé sur toutes les instances d'un cluster ou par instance. Pour activer le cache des résultats sur toutes les instances d'un cluster, définissez le `neptune_result_cache` paramètre dans le cluster `cluster-parameter-group` sur`1`. Pour l'activer sur une instance spécifique, définissez le `neptune_result_cache` paramètre de l'instance `instance-parameter-group` sur`1`. Le paramètre du groupe de paramètres du cluster remplacera la valeur du groupe de paramètres d'instance. 

 Un redémarrage est nécessaire sur toutes les instances concernées pour que les paramètres du cache de résultats soient appliqués. Bien que vous puissiez activer le cache des résultats sur toutes les instances d'un cluster via le`cluster-parameter-group`, chaque instance conserve son propre cache. La fonctionnalité de cache des résultats de requête n'est pas un cache à l'échelle du cluster. 

Une fois le cache des résultats activé, Neptune réserve une partie de la mémoire actuelle à la mise en cache des résultats de requête. Plus le type d'instance que vous utilisez est grand et plus la quantité de mémoire disponible est importante, plus Neptune réserve de mémoire au cache.

Si la mémoire cache des résultats est pleine, Neptune supprime automatiquement least-recently-used (LRU) les résultats mis en cache pour faire place à de nouveaux.

Vous pouvez vérifier le statut actuel du cache de résultats à l'aide de la commande [Statut d’une instance](access-graph-status.md).

## Utilisation d'indicateurs pour mettre en cache les résultats de requête
<a name="gremlin-results-cache-using"></a>

Une fois le cache des résultats de requête activé, vous pouvez utiliser des indicateurs de requête pour contrôler la mise en cache des requêtes. Tous les exemples ci-dessous s'appliquent à la même traversée de requêtes, à savoir :

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

### Utilisation de `enableResultCache`
<a name="using-enableResultCache"></a>

Lorsque le cache des résultats de requête est activé, vous pouvez mettre en cache les résultats d'une requête Gremlin à l'aide de l'indicateur de requête `enableResultCache`, comme suit :

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

Neptune vous renvoie ensuite les résultats de la requête et les met également en cache. Plus tard, vous pourrez accéder aux résultats mis en cache en émettant à nouveau exactement la même requête :

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

La clé de cache qui identifie les résultats mis en cache est la chaîne de requête elle-même, à savoir :

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

### Utilisation de `enableResultCacheWithTTL`
<a name="using-enableResultCacheWithTTL"></a>

Vous pouvez spécifier la durée pendant laquelle les résultats de la requête doivent être mis en cache à l'aide de l'indicateur de requête `enableResultCacheWithTTL`. Par exemple, la requête suivante indique que les résultats de la requête doivent expirer au bout de 120 secondes :

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

Là aussi, la clé de cache qui identifie les résultats mis en cache est la chaîne de requête de base :

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

Et là aussi, vous pouvez accéder aux résultats mis en cache à l'aide de cette chaîne de requête avec l'indicateur de requête `enableResultCache` :

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

Si 120 secondes ou plus se sont écoulées depuis la mise en cache des résultats, cette requête renverra de nouveaux résultats, et les mettra en cache, sans aucun time-to-live.

Vous pouvez également accéder aux résultats mis en cache en émettant à nouveau la même requête avec l'indicateur de requête `enableResultCacheWithTTL`. Par exemple :

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

Tant que 120 secondes ne se sont pas écoulées (ce qui correspond au TTL actuellement en vigueur), cette nouvelle requête avec l'indicateur `enableResultCacheWithTTL` renvoie les résultats mis en cache. Après 120 secondes, il renverrait de nouveaux résultats et les mettrait en cache avec un time-to-live délai de 140 secondes.

**Note**  
Si les résultats d'une clé de requête sont déjà mis en cache, la même clé de requête `enableResultCacheWithTTL` ne génère pas de nouveaux résultats et n'a aucun effet sur les time-to-live résultats actuellement mis en cache.  
Si les résultats ont déjà été mis en cache avec `enableResultCache`, le cache doit d'abord être explicitement vidé avant qu'`enableResultCacheWithTTL` génère de nouveaux résultats et les mette en cache pour le TTL qu'il spécifie.
Si les résultats ont déjà été mis en cache à l'aide de l'indicateur `enableResultCachewithTTL`, cette durée de vie précédente, ou TTL, doit d'abord expirer avant qu'`enableResultCacheWithTTL` génère de nouveaux résultats et les mette en cache pour la durée de vie qu'il spécifie.

### Utilisation de `invalidateResultCacheKey`
<a name="using-invalidateResultCacheKey"></a>

Vous pouvez utiliser l'indicateur de requête `invalidateResultCacheKey` pour effacer les résultats mis en cache pour une requête particulière. Par exemple :

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

Cette requête vide la partie du cache correspondant à la clé de requête, `g.V().has('genre','drama').in('likes')`, et renvoie de nouveaux résultats pour cette requête.

Vous pouvez également combiner `invalidateResultCacheKey` avec `enableResultCache` ou `enableResultCacheWithTTL`. Par exemple, la requête suivante efface les résultats actuellement mis en cache, met en cache les nouveaux résultats et les renvoie :

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

### Utilisation de `invalidateResultCache`
<a name="using-invalidateResultCache"></a>

Vous pouvez utiliser l'indicateur de requête `invalidateResultCache` pour effacer tous les résultats mis en cache dans le cache des résultats de requête. Par exemple :

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

Cette requête vide l'intégralité du cache de résultats et renvoie de nouveaux résultats pour la requête.

Vous pouvez également combiner `invalidateResultCache` avec `enableResultCache` ou `enableResultCacheWithTTL`. Par exemple, la requête suivante vide l'intégralité du cache de résultats, met en cache les nouveaux résultats pour cette requête et les renvoie :

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

## Pagination des résultats de requête mis en cache
<a name="gremlin-results-cache-paginating"></a>

Supposons que vous ayez déjà mis en cache un grand nombre de résultats comme suit :

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

Supposons maintenant que vous émettiez la requête de plage suivante :

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

Neptune recherche d'abord la clé de cache complète, à savoir `g.V().has('genre','drama').in('likes').range(0,10)`. Si elle n'existe pas, Neptune vérifie ensuite s'il existe une clé pour cette chaîne de requête sans la plage (à savoir `g.V().has('genre','drama').in('likes')`). Lorsqu'il trouve cette clé, Neptune extrait les dix premiers résultats de son cache, conformément à la plage spécifiée.

**Note**  
Si vous utilisez l'indicateur `invalidateResultCacheKey` avec une requête contenant une plage à la fin, Neptune vide la partie du cache correspondant à une requête sans plage s'il ne trouve pas de correspondance exacte entre cette requête et cette plage.

### Utilisation d’`numResultsCached` avec `.iterate()`
<a name="gremlin-results-cache-paginating-numResultsCached"></a>

À l'aide de l'indicateur de requête `numResultsCached`, vous pouvez remplir le cache de résultats sans avoir à renvoyer tous les résultats mis en cache, ce qui peut être utile lorsque vous préférez paginer un grand nombre de résultats.

L'indicateur de requête `numResultsCached` ne fonctionne qu'avec les requêtes se terminant par `iterate()`.

Par exemple, si vous souhaitez mettre en cache les 50 premiers résultats de cet exemple de requête :

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

Dans ce cas, la clé de requête dans le cache est : `g.with("Neptune#numResultsCached", 50).V().has('genre','drama').in('likes')`. Vous pouvez désormais récupérer les 10 premiers résultats mis en cache avec cette requête :

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

Et vous pouvez récupérer les 10 résultats suivants de la requête comme suit :

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

N'oubliez pas d'inclure l'indicateur `numResultsCached`. Il s'agit d'un élément essentiel de la clé de requête. Il doit donc être présent pour pouvoir accéder aux résultats mis en cache.

**Voici quelques points à garder à l'esprit lorsque vous utilisez `numResultsCached` :**
+ **Le nombre que vous indiquez avec `numResultsCached` est appliqué à la fin de la requête.**   Cela signifie, par exemple, que la requête suivante met réellement en cache les résultats dans la plage `(1000, 1500)` :

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```
+ **Le nombre que vous indiquez avec `numResultsCached` spécifie le nombre maximum de résultats à mettre en cache.**   Cela signifie, par exemple, que la requête suivante met réellement en cache les résultats dans la plage `(1000, 2000)` :

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 100000)
   .V().range(1000, 2000).iterate()
  ```
+ **Les résultats mis en cache par les requêtes se terminant par `.range().iterate()` ont leur propre plage.**   Supposons, par exemple, que vous mettiez en cache les résultats à l'aide d'une requête comme celle-ci :

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

  Pour récupérer les 100 premiers résultats du cache, vous devriez écrire une requête comme celle-ci :

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

  Ces cent résultats seraient équivalents aux résultats de la requête de base de la plage `(1000, 1100)`.

## Clés de cache de requête utilisées pour localiser les résultats mis en cache
<a name="gremlin-results-cache-query-keys"></a>

Une fois que les résultats d'une requête ont été mis en cache, les requêtes suivantes avec la même *clé de cache de requête* récupèrent les résultats du cache au lieu d'en générer de nouveaux. La clé de cache d'une requête est évaluée comme suit :

1. Tous les indicateurs de requête liés au cache sont ignorés, à l'exception de `numResultsCached`.

1. Une dernière étape `iterate()` est ignorée.

1. Le reste de la requête est ordonné en fonction de sa représentation en bytecode.

La chaîne générée est comparée à un index des résultats de requête déjà présents dans le cache afin de déterminer la requête a accédé au cache.

Prenons, par exemple, cette requête :

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

Elle sera stockée en tant que version bytecode de celle-ci :

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

## Exceptions liées au cache de résultats
<a name="gremlin-results-cache-exceptions"></a>

Si les résultats d'une requête que vous essayez de mettre en cache sont trop importants pour tenir dans la mémoire du cache, même après avoir supprimé tout ce qui était déjà mis en cache, Neptune signale une erreur `QueryLimitExceededException`. Aucun résultat n'est renvoyé, et l'exception génère le message d'erreur suivant :

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

Vous pouvez supprimer ce message à l'aide de l'indicateur de requête `noCacheExceptions`, comme suit :

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

# Réalisation d'upserts efficaces avec les étapes Gremlin `mergeV()` et `mergeE()`
<a name="gremlin-efficient-upserts"></a>

Une insertion conditionnelle (également appelée « upsert ») réutilise un sommet ou une arête qui existe déjà, ou crée l'objet nécessaire dans le cas contraire. Des upserts efficaces peuvent faire une différence significative dans les performances des requêtes Gremlin.

Les upserts vous permettent d'écrire des opérations d'insertion idempotentes : quel que soit le nombre de fois que vous exécutez cette opération, le résultat global est le même. Cela est utile dans les scénarios d'écriture hautement simultanés où les modifications simultanées apportées à la même partie du graphe peuvent forcer une ou plusieurs transactions à revenir en arrière avec une exception `ConcurrentModificationException`, nécessitant ainsi de nouvelles tentatives.

Par exemple, la requête suivante insère un sommet en utilisant l'élément `Map` fourni pour essayer d'abord de trouver un sommet avec le `T.id` `"v-1"`. Si ce sommet est trouvé, il est renvoyé. Dans le cas contraire, un sommet contenant cet `id` et cette propriété est créé par le biais de la clause `onCreate`.

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

## Exécution d'upserts par lots pour améliorer le débit
<a name="gremlin-upserts-batching"></a>

Pour les scénarios d'écriture à haut débit, vous pouvez enchaîner les étapes `mergeV()` et `mergeE()` pour effectuer l'upsert en bloc des sommets et des arêtes. Le traitement par lots réduit la charge transactionnelle liée à l'insertion par upsert d'un grand nombre de sommets et d'arêtes. Vous pouvez ainsi améliorer davantage le débit en augmentant les demandes d'upserts par lots en parallèle à l'aide de plusieurs clients.

En règle générale, nous recommandons d'insérer par upsert environ 200 enregistrements par demande par lots. Un enregistrement correspond à une étiquette ou propriété individuelle de sommet ou d'arête. Par exemple, un sommet doté d'une seule étiquette et de quatre propriétés génère cinq enregistrements. Une arête dotée d'une étiquette et d'une seule propriété génère deux enregistrements. Si vous souhaitez insérer par upsert des lots de sommets, chacun avec une seule étiquette et quatre propriétés, vous devez commencer par une taille de lot de 40, car `200 / (1 + 4) = 40`.

Vous pouvez tester différentes tailles de lots. 200 enregistrements par lot constituent un bon point de départ, mais la taille de lot idéale peut être supérieure ou inférieure en fonction de votre charge de travail. Notez toutefois que Neptune peut limiter le nombre total d'étapes Gremlin par demande. Cette limite n'est pas documentée, mais par mesure de sécurité, essayez de faire en sorte que les demandes ne contiennent pas plus de 1 500 étapes Gremlin. Neptune peut rejeter des demandes en bloc volumineuses comportant plus de 1 500 étapes.

Pour augmenter le débit, vous pouvez insérer par upsert des lots en parallèle à l'aide de plusieurs clients (voir [Création d'écritures Gremlin multithreads efficaces](best-practices-gremlin-multithreaded-writes.md)). Le nombre de clients doit être identique au nombre de threads de travail sur votre instance Neptune Writer, qui est généralement 2 fois le nombre de v CPUs sur le serveur. Par exemple, une `r5.8xlarge` instance possède 32 V CPUs et 64 threads de travail. Pour les scénarios d'écriture à haut débit utilisant une instance `r5.8xlarge`, vous devez utiliser 64 clients écrivant des upserts par lots sur Neptune en parallèle.

Chaque client doit soumettre une demande par lots et attendre qu'elle soit terminée avant de soumettre une autre demande. Bien que les différents clients fonctionnent en parallèle, chacun d'eux soumet des demandes en série. Cela garantit que le serveur reçoit un flux constant de demandes qui occupent tous les threads de travail sans encombrer la file d'attente des demandes côté serveur (voir [Dimensionnement des instances de base de données dans un cluster de bases de données Neptune](feature-overview-db-clusters.md#feature-overview-sizing-instances)).

## Essayer d'éviter les étapes qui génèrent plusieurs traverseurs
<a name="gremlin-upserts-single-traverser"></a>

Lorsqu'une étape Gremlin s'exécute, elle utilise un traverseur entrant et émet un ou plusieurs traverseurs de sortie. Le nombre de traverseurs émis par une étape détermine le nombre de fois que l'étape suivante sera exécutée.

Généralement, lorsque vous effectuez des opérations par lots, vous souhaitez que chaque opération, telle que l'upsert du sommet A, soit exécutée une seule fois, de sorte que la séquence des opérations ressemble à ceci : upsert du sommet A, puis upsert du sommet B, puis upsert du sommet C, etc. Tant qu'une étape ne crée ou ne modifie qu'un seul élément, elle n'émet qu'un seul traverseur, et les étapes représentant l'opération suivante ne sont exécutées qu'une seule fois. Si, en revanche, une opération crée ou modifie plusieurs éléments, elle émet plusieurs traverseurs, ce qui entraîne l'exécution des étapes suivantes plusieurs fois, une fois par traverseur émis. Cela peut obliger la base de données à effectuer des tâches supplémentaires inutiles et, dans certains cas, à créer des sommets, des arêtes ou des valeurs de propriétés supplémentaires superflus.

La requête `g.V().addV()` est un bon exemple de cas où la situation peut dégénérer. Cette requête simple ajoute un sommet pour chaque sommet du graphe, car `V()` émet un traverseur pour chaque sommet du graphe et chacun de ces traverseurs déclenche un appel à `addV()`.

Consultez [Combinaison d'upserts et d'insertions](#gremlin-upserts-and-inserts) pour découvrir comment gérer les opérations qui peuvent émettre plusieurs traverseurs.

## Insertion de sommets par upsert
<a name="gremlin-upserts-vertices"></a>

L'étape `mergeV()` est spécialement conçue pour l'upsert de sommets. Elle utilise comme argument un objet `Map` qui représente les éléments correspondant aux sommets existants dans le graphe. Si aucun élément n'est trouvé, elle utilise cet objet `Map` pour créer un sommet. Cette étape vous permet également de modifier le comportement en cas de création ou de correspondance. Le modulateur `option()` peut alors être associé à des jetons `Merge.onCreate` et `Merge.onMatch` pour contrôler ces comportements respectifs. Consultez la [documentation de TinkerPop référence](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step) pour plus d'informations sur l'utilisation de cette étape.

Vous pouvez utiliser un ID de sommet pour déterminer si un sommet spécifique existe. Il s'agit de l'approche préférée, car Neptune optimise les upserts pour les cas d'utilisation très concurrents. IDs Par exemple, la requête suivante crée un sommet avec un ID de sommet donné s'il n'existe pas déjà, ou le réutilise s'il existe déjà :

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

Notez que cette requête se termine par une étape `id()`. Bien que cela ne soit pas strictement nécessaire pour réaliser l'upsert du sommet, une étape `id()` à la fin d'une requête d'upsert garantit que le serveur ne sérialise pas toutes les propriétés du sommet vers le client, ce qui contribue à réduire le coût de verrouillage de la requête.

Vous pouvez également utiliser une propriété de sommet pour identifier un sommet :

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

Si possible, utilisez les sommets fournis par l'utilisateur IDs pour créer des sommets, et utilisez-les IDs pour déterminer si un sommet existe lors d'une opération de remontée. Cela permet à Neptune d'optimiser les upserts. Un upsert basé sur un ID peut être nettement plus efficace qu'un upsert basé sur des propriétés lorsque des modifications simultanées sont courantes.

### Enchaînement d'upserts de sommets
<a name="gremlin-upserts-vertices-chaining"></a>

Vous pouvez enchaîner des upserts de sommets pour les insérer dans un lot :

```
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()
```

Vous pouvez également utiliser cette syntaxe `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'])
```

Cependant, comme cette forme de requête inclut des éléments dans les critères de recherche qui sont superflus par rapport à la recherche de base par `id`, elle n'est pas aussi efficace que la requête précédente.

## Exécution d'upserts d'arêtes
<a name="gremlin-upserts-edges"></a>

L'étape `mergeE()` est spécialement conçue pour l'upsert d'arêtes. Elle utilise comme argument un objet `Map` qui représente les éléments correspondant aux arêtes existantes dans le graphe. Si aucun élément n'est trouvé, elle utilise cet objet `Map` pour créer une arête. Cette étape vous permet également de modifier le comportement en cas de création ou de correspondance. Le modulateur `option()` peut alors être associé à des jetons `Merge.onCreate` et `Merge.onMatch` pour contrôler ces comportements respectifs. Consultez la [documentation de TinkerPop référence](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step) pour plus d'informations sur l'utilisation de cette étape.

Vous pouvez utiliser une arête IDs pour insérer des arêtes de la même manière que vous insérez des sommets à l'aide d'un sommet personnalisé. IDs Là aussi, il s'agit de l'approche préférée, car elle permet à Neptune d'optimiser la requête. Par exemple, la requête suivante crée une arête en fonction de son ID d'arête si elle n'existe pas déjà, ou la réutilise si elle existe déjà. La requête utilise également IDs les `Direction.to` sommets `Direction.from` et si elle doit créer une nouvelle arête :

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

Notez que cette requête se termine par une étape `id()`. Bien que cela ne soit pas strictement nécessaire pour réaliser l'upsert de l'arête, une étape `id()` à la fin d'une requête d'upsert garantit que le serveur ne sérialise pas toutes les propriétés de l'arête vers le client, ce qui contribue à réduire le coût de verrouillage de la requête.

De nombreuses applications utilisent un sommet personnalisé IDs, mais laissent à Neptune le soin de générer l'arête. IDs Si vous ne connaissez pas l'ID d'une arête, mais que vous connaissez le `to` sommet `from` et IDs, vous pouvez utiliser ce type de requête pour modifier une arête :

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

Tous les sommets référencés par `mergeE()` doivent exister pour que l'étape crée l'arête.

### Enchaînement d'upserts d'arêtes
<a name="gremlin-upserts-edges-chaining"></a>

Comme pour les upserts de sommets, il est simple d'enchaîner les étapes `mergeE()` pour les demandes en bloc :

```
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()
```

## Combinaison d'upserts de sommets et d'arêtes
<a name="gremlin-upserts-vertexes-and-edges"></a>

Parfois, il peut être utile d'insérer par upsert à la fois les sommets et les arêtes qui les relient. Vous pouvez combiner les exemples de lots présentés ici. L'exemple suivant insère par upsert trois sommets et deux arêtes :

```
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()
```

## Combinaison d'upserts et d'insertions
<a name="gremlin-upserts-and-inserts"></a>

Parfois, il peut être utile d'insérer par upsert à la fois les sommets et les arêtes qui les relient. Vous pouvez combiner les exemples de lots présentés ici. L'exemple suivant insère par upsert trois sommets et deux arêtes :

Les upserts traitent généralement un élément à la fois. Si vous vous en tenez aux modèles d'upsert présentés ici, chaque opération d'upsert émet un seul traverseur, ce qui entraîne l'exécution de l'opération suivante une seule fois.

Cependant, il peut arriver que vous souhaitiez combiner des upserts avec des insertions. Cela peut notamment être le cas si vous utilisez des arêtes pour représenter des instances d'actions ou d'événements. Une demande peut utiliser des upserts pour s'assurer que tous les sommets nécessaires existent, puis utiliser des insertions pour ajouter des arêtes. Avec les demandes de ce type, soyez attentif au nombre potentiel de traverseurs émis par chaque opération.

Prenons l'exemple suivant, qui combine des upserts et des insertions pour ajouter des arêtes représentant des événements dans le graphe :

```
// 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()
```

La requête doit insérer cinq arêtes : deux arêtes SUIVIES et trois arêtes VISITÉES. Cependant, la requête telle qu'elle est écrite insère huit arêtes : deux arêtes SUIVIES et six arêtes VISITÉES. Cela est dû au fait que l'opération qui insère les deux arêtes suivies émet deux traverseurs, ce qui entraîne l'exécution de l'opération suivante d'insertion de trois arêtes deux fois.

La solution consiste à ajouter une étape `fold()` après chaque opération susceptible d'émettre plusieurs traverseurs :

```
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()
```

Nous avons inséré ici une étape `fold()` après l'opération qui insère les arêtes SUIVIES. Il en résulte un seul traverseur, et l'opération suivante n'est donc exécutée qu'une seule fois.

L'inconvénient de cette approche est que la requête n'est plus entièrement optimisée, car `fold()` n'est pas optimisé. L'opération d'insertion qui suit `fold()` ne sera maintenant pas optimisée non plus.

Si vous devez utiliser `fold()` pour réduire le nombre de traverseurs lors des étapes suivantes, essayez d'organiser les opérations de manière à ce que les moins coûteuses occupent la partie non optimisée de la requête.

## Configuration de la cardinalité
<a name="gremlin-upserts-setting-cardinality"></a>

 La cardinalité par défaut pour les propriétés des sommets dans Neptune est définie, ce qui signifie que lors de l'utilisation de mergeV (), les valeurs fournies sur la carte recevront toutes cette cardinalité. Pour utiliser la cardinalité unique, vous devez être explicite dans son utilisation. À partir de la TinkerPop version 3.7.0, une nouvelle syntaxe permet de fournir la cardinalité dans le cadre de la carte, comme indiqué dans l'exemple suivant : 

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

 Vous pouvez également définir la cardinalité par défaut `option` comme suit : 

```
// 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)
```

 Il existe moins d'options pour définir la cardinalité dans les versions `mergeV()` antérieures à 3.7.0. L'approche générale consiste à revenir à l'`property()`étape suivante : 

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

**Note**  
 Cette approche ne fonctionnera que `mergeV()` si elle est utilisée avec une étape de démarrage. Vous ne pourriez donc pas `mergeV()` enchaîner une seule traversée, car la première étape utilisant cette syntaxe `mergeV()` après le début produira une erreur si le traverseur entrant est un élément graphique. Dans ce cas, vous souhaiterez diviser vos `mergeV()` appels en plusieurs demandes, chacune pouvant constituer une étape de départ. 

# Réalisation d'upserts Gremlin efficaces avec `fold()/coalesce()/unfold()`
<a name="gremlin-efficient-upserts-pre-3.6"></a>

Une insertion conditionnelle (également appelée « upsert ») réutilise un sommet ou une arête qui existe déjà, ou crée l'objet nécessaire dans le cas contraire. Des upserts efficaces peuvent faire une différence significative dans les performances des requêtes Gremlin.

Cette page montre comment utiliser le modèle Gremlin `fold()/coalesce()/unfold()` pour réaliser des upserts efficaces. Cependant, avec la sortie de la TinkerPop version 3.6.x introduite dans Neptune dans la version [1.2.1.0](engine-releases-1.2.1.0.md) du moteur, les nouvelles `mergeE()` étapes sont préférables dans la plupart `mergeV()` des cas. Le modèle `fold()/coalesce()/unfold()` décrit ici peut encore être utile dans certaines situations complexes, mais en régle générale, utilisez `mergeV()` et `mergeE()` si vous le pouvez, comme décrit dans [Réalisation d'upserts efficaces avec les étapes Gremlin `mergeV()` et `mergeE()`](gremlin-efficient-upserts.md).

Les upserts vous permettent d'écrire des opérations d'insertion idempotentes : quel que soit le nombre de fois que vous exécutez cette opération, le résultat global est le même. Cela est utile dans les scénarios d'écriture hautement simultanés où les modifications simultanées apportées à la même partie du graphe peuvent forcer une ou plusieurs transactions à revenir en arrière avec une exception `ConcurrentModificationException`, nécessitant ainsi une nouvelle tentative.

Par exemple, la requête suivante insère un sommet en recherchant d'abord le sommet spécifié dans le jeu de données, puis en regroupant les résultats dans une liste. Dans la première traversée fournie à l'étape `coalesce()`, la requête déplie ensuite cette liste. Si la liste dépliée n'est pas vide, les résultats sont émis à partir de `coalesce()`. Toutefois, si `unfold()` renvoie une collection vide parce que le sommet n'existe pas, `coalesce()` passe à l'évaluation de la deuxième traversée avec laquelle il a été fourni, et dans cette deuxième traversée, la requête crée le sommet manquant.

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

## Utilisation d'une forme optimisée de `coalesce()` pour les upserts
<a name="gremlin-upserts-pre-3.6-coalesce"></a>

Neptune peut optimiser l'idiome `fold().coalesce(unfold(), ...)` pour effectuer des mises à jour à haut débit, mais cette optimisation ne fonctionne que si les deux parties de l'idiome `coalesce()` renvoient un sommet ou une arête, mais rien d'autre. Si vous essayez de renvoyer quelque chose de différent, tel qu'une propriété, à partir de n'importe quelle partie du `coalesce()`, l'optimisation Neptune n'a pas lieu. La requête peut aboutir, mais elle ne fonctionnera pas aussi bien qu'une version optimisée, en particulier pour les vastes jeux de données.

Étant donné que les requêtes d'upsert non optimisées augmentent les temps d'exécution et réduisent le débit, il est utile d'utiliser le point de terminaison Gremlin `explain` pour déterminer si une requête d'upsert est entièrement optimisée. Lorsque vous examinez les plans `explain`, recherchez les lignes commençant par `+ not converted into Neptune steps` et `WARNING: >>`. Par exemple :

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

Ces avertissements peuvent vous aider à identifier les parties d'une requête qui empêchent son optimisation complète.

Parfois, il n'est pas possible d'optimiser complètement une requête. Dans ces situations, vous devez essayer de placer les étapes qui ne peuvent pas être optimisées à la fin de la requête, afin de permettre au moteur d'optimiser autant d'étapes que possible. Cette technique est utilisée dans certains exemples d'upserts en bloc, où tous les upserts optimisés pour un ensemble de sommets ou d'arêtes sont effectués avant que des modifications supplémentaires potentiellement non optimisées ne soient appliquées aux mêmes sommets ou arêtes.

## Exécution d'upserts par lots pour améliorer le débit
<a name="gremlin-upserts-pre-3.6-batching"></a>

Pour les scénarios d'écriture à haut débit, vous pouvez enchaîner les étapes d'upsert pour effectuer l'upsert en bloc des sommets et des arêtes. Le traitement par lots réduit la charge transactionnelle liée à l'insertion par upsert d'un grand nombre de sommets et d'arêtes. Vous pouvez ainsi améliorer davantage le débit en augmentant les demandes d'upserts par lots en parallèle à l'aide de plusieurs clients.

En règle générale, nous recommandons d'insérer par upsert environ 200 enregistrements par demande par lots. Un enregistrement correspond à une étiquette ou propriété individuelle de sommet ou d'arête. Par exemple, un sommet doté d'une seule étiquette et de quatre propriétés génère cinq enregistrements. Une arête dotée d'une étiquette et d'une seule propriété génère deux enregistrements. Si vous souhaitez insérer par upsert des lots de sommets, chacun avec une seule étiquette et quatre propriétés, vous devez commencer par une taille de lot de 40, car `200 / (1 + 4) = 40`.

Vous pouvez tester différentes tailles de lots. 200 enregistrements par lot constituent un bon point de départ, mais la taille de lot idéale peut être supérieure ou inférieure en fonction de votre charge de travail. Notez toutefois que Neptune peut limiter le nombre total d'étapes Gremlin par demande. Cette limite n'est pas documentée, mais par mesure de sécurité, essayez de faire en sorte que les demandes ne contiennent pas plus de 1 500 étapes Gremlin. Neptune peut rejeter des demandes en bloc volumineuses comportant plus de 1 500 étapes.

Pour augmenter le débit, vous pouvez insérer par upsert des lots en parallèle à l'aide de plusieurs clients (voir [Création d'écritures Gremlin multithreads efficaces](best-practices-gremlin-multithreaded-writes.md)). Le nombre de clients doit être identique au nombre de threads de travail sur votre instance Neptune Writer, qui est généralement 2 fois le nombre de v CPUs sur le serveur. Par exemple, une `r5.8xlarge` instance possède 32 V CPUs et 64 threads de travail. Pour les scénarios d'écriture à haut débit utilisant une instance `r5.8xlarge`, vous devez utiliser 64 clients écrivant des upserts par lots sur Neptune en parallèle.

Chaque client doit soumettre une demande par lots et attendre qu'elle soit terminée avant de soumettre une autre demande. Bien que les différents clients fonctionnent en parallèle, chacun d'eux soumet des demandes en série. Cela garantit que le serveur reçoit un flux constant de demandes qui occupent tous les threads de travail sans encombrer la file d'attente des demandes côté serveur (voir [Dimensionnement des instances de base de données dans un cluster de bases de données Neptune](feature-overview-db-clusters.md#feature-overview-sizing-instances)).

## Essayer d'éviter les étapes qui génèrent plusieurs traverseurs
<a name="gremlin-upserts-pre-3.6-single-traverser"></a>

Lorsqu'une étape Gremlin s'exécute, elle utilise un traverseur entrant et émet un ou plusieurs traverseurs de sortie. Le nombre de traverseurs émis par une étape détermine le nombre de fois que l'étape suivante sera exécutée.

Généralement, lorsque vous effectuez des opérations par lots, vous souhaitez que chaque opération, telle que l'upsert du sommet A, soit exécutée une seule fois, de sorte que la séquence des opérations ressemble à ceci : upsert du sommet A, puis upsert du sommet B, puis upsert du sommet C, etc. Tant qu'une étape ne crée ou ne modifie qu'un seul élément, elle n'émet qu'un seul traverseur, et les étapes représentant l'opération suivante ne sont exécutées qu'une seule fois. Si, en revanche, une opération crée ou modifie plusieurs éléments, elle émet plusieurs traverseurs, ce qui entraîne l'exécution des étapes suivantes plusieurs fois, une fois par traverseur émis. Cela peut obliger la base de données à effectuer des tâches supplémentaires inutiles et, dans certains cas, à créer des sommets, des arêtes ou des valeurs de propriétés supplémentaires superflus.

La requête `g.V().addV()` est un bon exemple de cas où la situation peut dégénérer. Cette requête simple ajoute un sommet pour chaque sommet du graphe, car `V()` émet un traverseur pour chaque sommet du graphe et chacun de ces traverseurs déclenche un appel à `addV()`.

Consultez [Combinaison d'upserts et d'insertions](#gremlin-upserts-pre-3.6-and-inserts) pour découvrir comment gérer les opérations qui peuvent émettre plusieurs traverseurs.

## Insertion de sommets par upsert
<a name="gremlin-upserts-pre-3.6-vertices"></a>

Vous pouvez utiliser un ID de sommet pour déterminer s'il existe un sommet correspondant. Il s'agit de l'approche préférée, car Neptune optimise les upserts pour les cas d'utilisation très concurrents. IDs Par exemple, la requête suivante crée un sommet avec un ID de sommet donné s'il n'existe pas déjà, ou le réutilise s'il existe déjà :

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

Notez que cette requête se termine par une étape `id()`. Bien que cela ne soit pas strictement nécessaire pour réaliser l'upsert du sommet, l'ajout d'une étape `id()` à la fin d'une requête d'upsert garantit que le serveur ne sérialise pas toutes les propriétés du sommet vers le client, ce qui contribue à réduire le coût de verrouillage de la requête.

Vous pouvez également utiliser une propriété de sommet pour déterminer si le sommet existe :

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

Si possible, utilisez les sommets fournis par l'utilisateur IDs pour créer des sommets, et utilisez-les IDs pour déterminer si un sommet existe lors d'une opération de remontée. Cela permet à Neptune d'optimiser les upserts autour du. IDs Un upsert basé sur un ID peut être nettement plus efficace qu'un upsert basé sur des propriétés dans les scénarios où les modifications simultanées sont nombreuses.

### Enchaînement d'upserts de sommets
<a name="gremlin-upserts-pre-3.6-vertices-chaining"></a>

Vous pouvez enchaîner des upserts de sommets pour les insérer dans un lot :

```
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()
```

## Exécution d'upserts d'arêtes
<a name="gremlin-upserts-pre-3.6-edges"></a>

Vous pouvez utiliser une arête IDs pour insérer des arêtes de la même manière que vous insérez des sommets à l'aide d'un sommet personnalisé. IDs Là aussi, il s'agit de l'approche préférée, car elle permet à Neptune d'optimiser la requête. Par exemple, la requête suivante crée une arête en fonction de son ID d'arête si elle n'existe pas déjà, ou la réutilise si elle existe déjà. La requête utilise également IDs les `to` sommets `from` et si elle doit créer une nouvelle arête.

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

De nombreuses applications utilisent un sommet personnalisé IDs, mais laissent à Neptune le soin de générer l'arête. IDs Si vous ne connaissez pas l'identifiant d'une arête, mais que vous connaissez le `to` sommet `from` et IDs, vous pouvez utiliser cette formulation pour surdimensionner une arête :

```
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()
```

Notez que l'étape du sommet dans la clause `where()` doit être `inV()` (ou `outV()` si vous avez utilisé `inE()` pour trouver l'arête), non pas `otherV()`. N'utilisez pas `otherV()` ici. Dans le cas contraire, la requête ne sera pas optimisée, et les performances en pâtiront. Par exemple, Neptune n'optimiserait pas la requête suivante :

```
// 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()
```

Si vous ne connaissez pas l'arête ou le sommet situé IDs à l'avant, vous pouvez l'inverser à l'aide des propriétés du sommet :

```
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()
```

Comme pour les points ascendants, il est préférable d'utiliser des éléments ascendants basés sur un identifiant d'arête ou un `to` sommet IDs, plutôt que des points ascendants basés sur `from` des propriétés, afin que Neptune puisse optimiser pleinement l'upsert.

### Vérification de l'existence de sommets `from` et `to`
<a name="gremlin-upserts-pre-3.6-edges-checking"></a>

Notez la structure des étapes qui créent une arête : `addE().from().to()`. Cette structure garantit que la requête vérifie l'existence à la fois du sommet `from` et du sommet `to`. S'ils n'existent pas, la requête renvoie le message d'erreur suivant :

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

S'il est possible que le sommet `from` ou `to` n'existe pas, vous devez essayer de les placer par upsert avant de réaliser l'upsert de l'arête qui les sépare. Consultez [Combinaison d'upserts de sommets et d'arêtes](#gremlin-upserts-pre-3.6-vertexes-and-edges).

Une autre structure permet de créer une arête que vous ne devez pas utiliser : `V().addE().to()`. Elle ajoute une arête uniquement si le sommet `from` existe. Si le sommet `to` n'existe pas, la requête génère une erreur, comme décrit précédemment, mais si le sommet `from` n'existe pas, l'upsert de l'arête échoue en arrière-plan, sans générer d'erreur. Par exemple, si le sommet `from` n'existe pas, l'upsert suivant a lieu sans effectuer l'upsert d'une arête :

```
// 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()
```

### Enchaînement d'upserts d'arêtes
<a name="gremlin-upserts-pre-3.6-edges-chaining"></a>

Si vous souhaitez enchaîner des points d'arête pour créer une demande par lots, vous devez commencer chaque insertion par une recherche de sommet, même si vous connaissez déjà l'arête. IDs

Si vous connaissez déjà les IDs arêtes que vous souhaitez insérer, ainsi que les IDs `to` sommets `from` et, vous pouvez utiliser cette formulation :

```
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()
```

Le scénario d'inversion d'arêtes par lots le plus courant est peut-être que vous connaissez le `to` sommet `from` et IDs, mais que vous ne connaissez pas les IDs arêtes que vous souhaitez inverser. Dans ce cas, utilisez la formulation suivante :

```
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()
```

Si vous connaissez IDs les arêtes que vous souhaitez insérer, mais que vous ne connaissez pas les IDs `to` sommets `from` et les sommets (c'est inhabituel), vous pouvez utiliser cette formulation :

```
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()
```

## Combinaison d'upserts de sommets et d'arêtes
<a name="gremlin-upserts-pre-3.6-vertexes-and-edges"></a>

Parfois, il peut être utile d'insérer par upsert à la fois les sommets et les arêtes qui les relient. Vous pouvez combiner les exemples de lots présentés ici. L'exemple suivant insère par upsert trois sommets et deux arêtes :

```
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()
```

## Combinaison d'upserts et d'insertions
<a name="gremlin-upserts-pre-3.6-and-inserts"></a>

Parfois, il peut être utile d'insérer par upsert à la fois les sommets et les arêtes qui les relient. Vous pouvez combiner les exemples de lots présentés ici. L'exemple suivant insère par upsert trois sommets et deux arêtes :

Les upserts traitent généralement un élément à la fois. Si vous vous en tenez aux modèles d'upsert présentés ici, chaque opération d'upsert émet un seul traverseur, ce qui entraîne l'exécution de l'opération suivante une seule fois.

Cependant, il peut arriver que vous souhaitiez combiner des upserts avec des insertions. Cela peut notamment être le cas si vous utilisez des arêtes pour représenter des instances d'actions ou d'événements. Une demande peut utiliser des upserts pour s'assurer que tous les sommets nécessaires existent, puis utiliser des insertions pour ajouter des arêtes. Avec les demandes de ce type, soyez attentif au nombre potentiel de traverseurs émis par chaque opération.

Prenons l'exemple suivant, qui combine des upserts et des insertions pour ajouter des arêtes représentant des événements dans le graphe :

```
// 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()
```

La requête doit insérer cinq arêtes : deux arêtes SUIVIES et trois arêtes VISITÉES. Cependant, la requête telle qu'elle est écrite insère huit arêtes : deux arêtes SUIVIES et six arêtes VISITÉES. Cela est dû au fait que l'opération qui insère les deux arêtes suivies émet deux traverseurs, ce qui entraîne l'exécution de l'opération suivante d'insertion de trois arêtes deux fois.

La solution consiste à ajouter une étape `fold()` après chaque opération susceptible d'émettre plusieurs traverseurs :

```
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()
```

Nous avons inséré ici une étape `fold()` après l'opération qui insère les arêtes SUIVIES. Il en résulte un seul traverseur, et l'opération suivante n'est donc exécutée qu'une seule fois.

L'inconvénient de cette approche est que la requête n'est plus entièrement optimisée, car `fold()` n'est pas optimisé. L'opération d'insertion qui suit `fold()` ne sera maintenant pas optimisée non plus.

Si vous devez utiliser `fold()` pour réduire le nombre de traverseurs lors des étapes suivantes, essayez d'organiser les opérations de manière à ce que les moins coûteuses occupent la partie non optimisée de la requête.

## Upserts qui modifient les sommets et les arêtes existants
<a name="gremlin-upserts-pre-3.6-that-modify"></a>

Parfois, vous souhaitez créer un sommet ou une arête qui n'existe pas, puis y ajouter une propriété ou mettre à jour une propriété qui lui est associée, qu'il s'agisse d'un sommet ou d'une arête qui existe déjà ou pas encore.

Pour ajouter ou modifier une propriété, utilisez l'étape `property()`. Utilisez cette étape en dehors de l'étape `coalesce()`. Si vous essayez de modifier la propriété d'un sommet ou d'une arête qui existe déjà dans l'étape `coalesce()`, il est possible que la requête ne soit pas optimisée par le moteur de requêtes Neptune.

La requête suivante ajoute ou met à jour une propriété de compteur sur chaque sommet faisant l'objet d'un upsert. Chaque étape `property()` possède une cardinalité unique afin de garantir que les nouvelles valeurs remplacent toutes les valeurs existantes, plutôt que d'être ajoutées à un ensemble de valeurs existantes.

```
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()
```

Si vous avez une valeur de propriété, telle qu'une valeur d'horodatage `lastUpdated`, qui s'applique à tous les éléments ajoutés par upsert, vous pouvez l'ajouter ou la mettre à jour à la fin de la requête :

```
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()
```

Si d'autres conditions déterminent si un sommet ou une arête doit être encore modifié, vous pouvez utiliser une étape `has()` pour filtrer les éléments auxquels une modification sera appliquée. L'exemple suivant utilise une étape `has()` pour filtrer les sommets ajoutés par upsert en fonction de la valeur de leur propriété `version`. La requête fait ainsi passer à 3 la `version` de tout sommet dont l'élément `version` est inférieur à 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()
```

# Analyse de l'exécution des requêtes à l'aide de Gremlin `explain`
<a name="gremlin-explain"></a>

Amazon Neptune a ajouté une fonctionnalité Gremlin nommée *explain*. Cette fonctionnalité est un outil en libre-service qui vous aide à comprendre l'approche d'exécution adoptée par le moteur Neptune. Vous l'appelez en ajoutant un paramètre `explain` à un appel HTTP qui soumet une requête Gremlin.

La fonction `explain` fournit des informations sur la structure logique des plans d'exécution de requête. Vous pouvez utiliser ces informations pour identifier les goulots d'étranglement potentiels liés à l'évaluation et à l'exécution, comme expliqué dans [Réglage des requêtes Gremlin](gremlin-traversal-tuning.md). Vous pouvez aussi utiliser des [indicateurs de requête](gremlin-query-hints.md) pour améliorer les plans d'exécution de requêtes.

**Topics**
+ [Présentation du fonctionnement des requêtes Gremlin dans Neptune](gremlin-explain-background.md)
+ [Utilisation de l'API Gremlin `explain` dans Neptune](gremlin-explain-api.md)
+ [API Gremlin `profile` dans Neptune](gremlin-profile-api.md)
+ [Réglage des requêtes Gremlin à l'aide d'`explain` et de `profile`](gremlin-traversal-tuning.md)
+ [Prise en charge des étapes Gremlin natives dans Amazon Neptune](gremlin-step-support.md)

# Présentation du fonctionnement des requêtes Gremlin dans Neptune
<a name="gremlin-explain-background"></a>

Pour tirer pleinement parti des rapports Gremlin `explain` et `profile` dans Amazon Neptune, il est utile de comprendre certaines informations contextuelles sur les requêtes Gremlin.

**Topics**
+ [Déclarations Gremlin dans Neptune](gremlin-explain-background-statements.md)
+ [Comment Neptune traite les requêtes Gremlin à l'aide d'index d'instruction](gremlin-explain-background-indexing-examples.md)
+ [Traitement des requêtes Gremlin dans Neptune](gremlin-explain-background-querying.md)

# Déclarations Gremlin dans Neptune
<a name="gremlin-explain-background-statements"></a>

Les données de graphe de propriétés d'Amazon Neptune sont composées de déclarations à quatre positions (quadruplets). Chacune de ces instructions représente une unité atomique individuelle des données de graphe de propriété. Pour de plus amples informations, veuillez consulter [Modèle de données de graphe de Neptune](feature-overview-data-model.md). À l'instar du modèle de données RDF (Resource Description Framework), ces quatre positions sont les suivantes :
+ `subject (S)`
+ `predicate (P)`
+ `object (O)`
+ `graph (G)`

Chaque instruction est une assertion sur une ou plusieurs ressources. Par exemple, une instruction peut déclarer l'existence d'une relation entre deux ressources ou attacher une propriété (paire clé/valeur) à une ressource.

Vous pouvez considérer la position de prédicat (predicate) comme le verbe de l'instruction, qui décrit le type de relation ou de propriété. L'objet est la cible de la relation ou la valeur de la propriété. La position du graphe est facultative et peut être utilisée de nombreuses manières. Pour les données de graphe de propriétés (PG), elle est soit inutilisée (graphe null), soit utilisée pour représenter l'identifiant d'une arête. Un graphe est constitué d'un ensemble de déclarations avec des identifiants de ressources partagées.

Il existe trois classes de déclarations dans le modèle de données de graphe de propriétés Neptune :

**Topics**
+ [Instructions d'étiquette de sommet](#gremlin-explain-background-vertex-labels)
+ [Instructions d'arc](#gremlin-explain-background-edge-statements)
+ [Instructions de propriété](#gremlin-explain-background-property-statements)

## Instructions d'étiquette de sommet Gremlin
<a name="gremlin-explain-background-vertex-labels"></a>

Les déclarations d'étiquette de sommet dans Neptune ont deux objectifs :
+ Elles permettent d'assurer le suivi des étiquettes d'un sommet.
+ La présence d'au moins une de ces instructions implique l'existence d'un sommet particulier dans le graphe.

Le sujet de ces instructions est un identifiant de sommet et l'objet est une étiquette, ces deux éléments étant spécifiés par l'utilisateur. Vous utilisez un prédicat fixe spécial pour ces instructions, affiché sous la forme `<~label>`, et un identifiant de graphe par défaut (graphe null), affiché sous la forme `<~>`.

Considérons par exemple la traversée `addV` suivante.

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

Cette traversée entraîne l'ajout de l'instruction suivante au graphe.

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

## Instructions d'arc Gremlin
<a name="gremlin-explain-background-edge-statements"></a>

Une déclaration d'arête Gremlin implique l'existence d'une arête entre deux sommets dans un graphe dans Neptune. Le sujet (S) d'une instruction d'arc est le sommet source `from`. Le prédicat (P) est une étiquette d'arc fournie par l'utilisateur. L'objet (O) est le sommet cible `to`. Le graphe (G) est un identifiant d'arc fourni par l'utilisateur.

Considérons par exemple la traversée `addE` suivante.

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

La traversée se traduit par l'ajout de l'instruction suivante au graphe.

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

## Instructions de propriété Gremlin
<a name="gremlin-explain-background-property-statements"></a>

Une déclaration de propriété Gremlin dans Neptune définit une valeur de propriété individuelle pour un sommet ou une arête. Le sujet est un identifiant d'arc ou de sommet fourni par l'utilisateur. Le prédicat est le nom de propriété (clé) et l'objet est la valeur de propriété individuelle. Le graphe (G) est à nouveau l'identifiant de graphe par défaut, le graphe null, affiché sous la forme `<~>`.

Prenons l'exemple de propriété de sommet suivant.

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

Cette instruction aboutit aux résultats suivants.

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

Les instructions de propriété diffèrent des autres en ce sens que leur objet est une valeur primitive (`string`, `date`, `byte`, `short`, `int`, `long`, `float` ou `double`). Leur objet n'est pas un identifiant de ressource pouvant être utilisé comme sujet d'une autre assertion.

Dans le cas de propriétés multiples, chaque valeur de propriété individuelle de l'ensemble reçoit sa propre instruction.

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

La sortie obtenue est la suivante.

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

Les propriétés des arêtes sont gérées de la même manière que les propriétés des sommets, mais elles utilisent l'identifiant de bord en position (S). Par exemple, ajouter une propriété à une arête :

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

Cela entraîne l'ajout de l'instruction suivante au graphique.

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

# Comment Neptune traite les requêtes Gremlin à l'aide d'index d'instruction
<a name="gremlin-explain-background-indexing-examples"></a>

Les instructions sont accessibles dans Amazon Neptune au moyen de trois index d'instruction, comme indiqué dans [Comment les instructions sont indexées dans Neptune](feature-overview-storage-indexing.md). Neptune extrait un *modèle* d'instruction à partir d'une requête Gremlin dans laquelle certaines positions sont connues, tandis que les autres peuvent être découvertes via une recherche par index.

Neptune présume que le schéma de graphe de propriétés est de petite taille. Par conséquent, le nombre d'étiquettes d'arête et de noms de propriété distincts est relativement faible, ce qui se traduit par un faible nombre total de prédicats distincts. Neptune suit les prédicats distincts dans un index séparé. Il utilise ce cache de prédicats pour effectuer une analyse d'union de `{ all P x POGS }` au lieu d'utiliser un index OSGP. Le fait d'éviter d'avoir besoin d'un index OSGP de traversée inverse permet d'économiser de l'espace de stockage et du débit de charge.

L' Explain/Profile API Neptune Gkremlin vous permet d'obtenir le nombre de prédicats dans votre graphique. Vous pouvez ensuite déterminer si votre application invalide l'hypothèse Neptune selon laquelle le schéma de votre graphe de propriété est de petite taille.

Les exemples suivants illustrent la façon dont Neptune utilise les index pour traiter les requêtes Gremlin.

**Question : Quelles sont les étiquettes du sommet `v1` ?**

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

**Question : Quelles sont les arêtes sortantes « knows » du sommet `v1` ?**

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

**Question : Quels sont les sommets qui ont une étiquette de sommet `Person` ?**

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

**Question : Quels sont les from/to sommets d'une arête donnée ? `e1`**

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

Neptune **ne possède pas** d'index de déclarations tel qu'un index OSGP de traversée inverse. Ce type d'index peut être utilisé pour collecter toutes les arêtes entrantes sur toutes les étiquettes d'arête, comme dans l'exemple suivant.

**Question : Quels sont les sommets adjacents entrants `v1` ?**

```
  Gremlin code:      g.V('v1').in()
  Pattern:           (?, ?, <v1>, ?)
  Known positions:   O
  Lookup positions:  SPG
  Index:             OSGP  // <-- Index does not exist
```

# Traitement des requêtes Gremlin dans Neptune
<a name="gremlin-explain-background-querying"></a>

Dans Amazon Neptune, les traversées plus complexes peuvent être représentées par une série de modèles qui créent une relation basée sur la définition de variables nommées pouvant être partagées entre des modèles pour créer des jointures. Voici un exemple :

**Question : Quel est le voisinage à deux sauts du sommet `v1` ?**

```
  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
```

En partageant la variable `?2` entre les deux modèles (à la position O dans le premier modèle et à la position S dans le second modèle), vous créez une jointure entre les voisins à un premier saut et les voisins à deux sauts. Chaque solution Neptune possède des liaisons pour les trois variables nommées, qui peuvent être utilisées pour recréer un [TinkerPopTraverser](http://tinkerpop.apache.org/docs/current/reference/#_the_traverser) (y compris les informations de chemin).

```
```

[La première étape du traitement des requêtes Gkremlin consiste à analyser la requête pour en faire un objet TinkerPop [Traversal](http://tinkerpop.apache.org/docs/current/reference/#traversal), composé d'une série d'étapes. TinkerPop ](http://tinkerpop.apache.org/docs/current/reference/#graph-traversal-steps) Ces étapes, qui font partie du [ TinkerPop projet open source Apache](http://tinkerpop.apache.org/), sont à la fois les opérateurs logiques et physiques qui composent une traversée Gremlin dans l'implémentation de référence. Elles sont toutes deux utilisées pour représenter le modèle de la requête. Il s'agit d'opérateurs exécutables qui peuvent produire des solutions en fonction de la sémantique de l'opérateur qu'ils représentent. Par exemple, `.V()` est à la fois représenté et exécuté par le TinkerPop [GraphStep](http://tinkerpop.apache.org/docs/current/reference/#graph-step).

Ces off-the-shelf TinkerPop étapes étant exécutables, un tel TinkerPop Traversal peut exécuter n'importe quelle requête Gremlin et produire la bonne réponse. Cependant, lorsqu'elles sont exécutées sur un graphique de grande taille, TinkerPop les étapes peuvent parfois être très inefficaces et lentes. Au lieu de les utiliser, Neptune essaie alors de convertir la traversée en forme déclarative composée de groupes de modèles, comme décrit précédemment.

Neptune ne prend actuellement pas en charge tous les opérateurs Gremlin (étapes) dans son moteur de requête natif. Il essaie donc de réduire autant d'étapes que possible en une seule étape `NeptuneGraphQueryStep`, qui contient le plan de requête logique déclaratif pour toutes les étapes qui ont été converties. Idéalement, toutes les étapes sont converties. Mais lorsqu'une étape ne peut pas être convertie, Neptune sort de l'exécution native et reporte l'exécution de toutes les requêtes à partir de ce point jusqu'aux étapes. TinkerPop Il n'essaie pas de jongler avec et sans l'exécution native.

Une fois que les étapes sont converties en plan de requête logique, Neptune exécute une série d'optimiseurs de requête qui réécrivent le plan de requête en fonction de l'analyse statique et des cardinalités estimées. Ces optimiseurs effectuent des opérations telles que la réorganisation des opérateurs en fonction du nombre de plages, la suppression des opérateurs superflus ou redondants, la réorganisation des filtres, le transfert des opérateurs dans différents groupes, etc.

Une fois qu'un plan de requête optimisé est généré, Neptune crée un pipeline d'opérateurs physiques qui effectuent le travail d'exécution de la requête. Cela inclut la lecture des données à partir des index d'instruction, l'exécution de jointures de différents types, le filtrage, l'organisation, etc. Le pipeline produit un flux de solution qui est ensuite reconverti en un flux d'objets TinkerPop Traverser.

## Sérialisation des résultats de requête
<a name="gremlin-explain-background-querying-serialization"></a>

Amazon Neptune s'appuie actuellement sur les sérialiseurs de messages de TinkerPop réponse pour convertir les résultats des requêtes (TinkerPop Traversers) en données sérialisées à renvoyer par câble au client. Ces formats de sérialisation ont tendance à être assez verbeux.

Par exemple, pour sérialiser le résultat d'une requête de sommet telle que `g.V().limit(1)`, le moteur de requête Neptune doit effectuer une seule recherche pour générer le résultat. Toutefois, le sérialiseur `GraphSON` effectue un grand nombre de recherches supplémentaires pour empaqueter le sommet dans le format de sérialisation. Il doit effectuer une recherche pour obtenir l'étiquette, une recherche pour obtenir les clés de propriété et une recherche par clé de propriété pour que le sommet puisse obtenir toutes les valeurs de chaque clé.

Certains formats de sérialisation sont plus efficaces, mais tous nécessitent des recherches supplémentaires. De plus, les TinkerPop sérialiseurs n'essaient pas d'éviter les recherches dupliquées, ce qui entraîne souvent la répétition inutile de nombreuses recherches.

Il est donc très important d'écrire vos requêtes afin qu'elles demandent spécifiquement les informations dont elles ont besoin. Par exemple, `g.V().limit(1).id()` renvoie uniquement l'ID de sommet et élimine toutes les recherches de sérialiseur supplémentaires. L'[API Gremlin `profile` dans Neptune](gremlin-profile-api.md) vous permet de voir combien d'appels de recherche sont effectués pendant l'exécution de la requête et pendant la sérialisation.

# Utilisation de l'API Gremlin `explain` dans Neptune
<a name="gremlin-explain-api"></a>

L'API Amazon Neptune Gremlin `explain` renvoie le plan de requête qui serait exécuté si une requête spécifique était exécutée. Comme l'API n'exécute pas réellement la requête, le plan est renvoyé presque instantanément.

Elle diffère de l'étape TinkerPop .explain () afin de pouvoir rapporter des informations spécifiques au moteur Neptune.

## Informations qui se trouvent dans un rapport Gremlin `explain`
<a name="gremlin-explain-api-results"></a>

Un rapport `explain` contient les informations suivantes :
+ Chaîne de requête demandée.
+ **Traversée d'origine.** Il s'agit de l'objet TinkerPop Traversal produit en analysant la chaîne de requête en TinkerPop étapes. Elle est équivalente à la requête d'origine produite en exécutant la requête `.explain()` sur le TinkerPop TinkerGraph.
+ **Traversée convertie.** Il s'agit du Neptune Traversal produit en convertissant le TinkerPop Traversal en représentation logique du plan de requêtes Neptune. Dans de nombreux cas, l'intégralité de la TinkerPop traversée est convertie en deux étapes Neptune : l'une qui exécute la requête complète `NeptuneGraphQueryStep` () et l'autre qui reconvertit la sortie du moteur de requêtes Neptune en Traversers (). TinkerPop `NeptuneTraverserConverterStep`
+ **Traversée optimisée.** Il s'agit de la version optimisée du plan de requête Neptune une fois qu'il a été exécuté via une série d'optimiseurs statiques de réduction du travail qui réécrivent la requête en fonction de l'analyse statique et des cardinalités estimées. Ces optimiseurs effectuent des opérations telles que la réorganisation des opérateurs en fonction du nombre de plages, la suppression des opérateurs superflus ou redondants, la réorganisation des filtres, le transfert des opérateurs dans différents groupes, etc.
+ **Nombre de prédicats.** En raison de la stratégie d'indexation Neptune décrite précédemment, le fait d'avoir un grand nombre de prédicats différents peut entraîner des problèmes de performances. Cela est particulièrement vrai pour les requêtes qui utilisent des opérateurs de traversée inverse sans étiquette d'arc (`.in` ou `.both`). Si ces opérateurs sont utilisés et que le nombre de prédicats est suffisamment élevé, le rapport `explain` affiche un message d'avertissement.
+ **Informations DFE.** Lorsque le moteur alternatif DFE est activé, les composants de traversée suivants peuvent apparaître dans la traversée optimisée :
  + **`DFEStep`** : étape DFE optimisée pour Neptune dans la traversée qui contient un objet `DFENode` enfant. `DFEStep` représente la partie du plan de requête exécutée dans le moteur DFE.
  + **`DFENode`** : contient la représentation intermédiaire sous la forme d'un ou de plusieurs objets `DFEJoinGroupNodes` enfants.
  + **`DFEJoinGroupNode`** : représente une jointure d'un ou de plusieurs éléments `DFENode` ou `DFEJoinGroupNode`.
  + **`NeptuneInterleavingStep`** : étape DFE optimisée pour Neptune dans la traversée qui contient un objet `DFEStep` enfant.

    Contient également un élément `stepInfo` comportant des informations sur la traversée, telles que l'élément frontière, les éléments de chemin utilisés, etc. Ces informations sont utilisées pour traiter l'objet `DFEStep` enfant.

  Un moyen simple de savoir si votre requête est évaluée par le DFE est de vérifier si la sortie `explain` contient un objet `DFEStep`. Toute partie de la traversée qui n'en fait pas partie ne `DFEStep` sera pas exécutée par DFE et sera exécutée par le TinkerPop moteur.

  Consultez [Exemple avec le DFE activé](#gremlin-explain-dfe) pour voir un exemple de rapport.

## Syntaxe Gremlin `explain`
<a name="gremlin-explain-api-syntax"></a>

La syntaxe de l'API `explain` est identique à celle de l'API HTTP de la requête, sauf qu'elle utilise `/gremlin/explain` comme point de terminaison au lieu de `/gremlin`, comme dans l'exemple suivant.

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

La requête précédente génèrerait la sortie suivante.

```
*******************************************************
                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
```

## Étapes non converties TinkerPop
<a name="gremlin-explain-unconverted-steps"></a>

Idéalement, toutes les TinkerPop étapes d'une traversée bénéficient d'une couverture native de l'opérateur Neptune. Lorsque ce n'est pas le cas, Neptune recourt à l'exécution par TinkerPop étapes pour combler les lacunes dans la couverture de ses opérateurs. Si une traversée utilise une étape pour laquelle Neptune n'a pas encore de couverture native, le rapport `explain` affiche un avertissement indiquant où l'écart s'est produit.

Lorsqu'une étape sans opérateur Neptune natif correspondant est rencontrée, la totalité de la traversée à partir de ce point est exécutée par TinkerPop étapes, même si les étapes suivantes comportent des opérateurs Neptune natifs.

L'exception est lorsque la recherche en texte intégral Neptune est appelée. Il NeptuneSearchStep implémente des étapes sans équivalents natifs sous forme d'étapes de recherche en texte intégral.

## Exemple de sortie `explain` où toutes les étapes d'une requête ont des équivalents natifs
<a name="gremlin-explain-all-steps-converted"></a>

Voici un exemple de rapport `explain` concernant une requête pour laquelle toutes les étapes ont des équivalents natifs :

```
*******************************************************
                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
```

## Exemple où certaines étapes d'une requête n'ont pas d'équivalents natifs
<a name="gremlin-explain-not-all-steps-converted"></a>

Neptune gère `GraphStep` et `VertexStep` en mode natif, mais si vous introduisez un élément `FoldStep` et un élément `UnfoldStep` , la sortie `explain` générée est différente :

```
*******************************************************
                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
```

Dans ce cas, l'élément `FoldStep` vous fait quitter l'exécution native. Même l'étape `VertexStep` suivante n'est plus gérée en mode natif, car elle apparaît en aval des étapes `Fold/Unfold`.

Pour des raisons de performances et de réduction des coûts, il est important que vous essayiez de formuler des traversées de manière à ce que le maximum de travail possible soit effectué de manière native dans le moteur de requêtes Neptune, plutôt que de procéder à des implémentations étape par étape. TinkerPop 

## Exemple de requête utilisant Neptune full-text-search
<a name="gremlin-explain-full-text-search-steps"></a>

La requête suivante utilise la recherche en texte intégral 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*")
```

La partie `.has("name", "Neptune#fts mark*")` limite la recherche aux sommets avec `name`, alors que `.has("Person", "name", "Neptune#fts mark*")` limite la recherche aux sommets avec `name` et l'étiquette `Person`. Le résultat est la traversée suivante dans le rapport `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}
    }
}]
```

## Exemple d'utilisation d'`explain` lorsque le DFE est activé
<a name="gremlin-explain-dfe"></a>

Voici un exemple de rapport `explain` lorsque le moteur de requête alternatif DFE est activé :

```
*******************************************************
                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
```

Consultez [Informations dans `explain`](#gremlin-explain-api-results) pour voir une description des sections spécifiques au DFE dans le rapport.

# API Gremlin `profile` dans Neptune
<a name="gremlin-profile-api"></a>

L'API Neptune Gremlin `profile` effectue une traversée Gremlin spécifique, collecte différentes métriques sur l'exécution et génère en sortie un rapport de profil.

Elle diffère de l'étape TinkerPop .profile () afin de pouvoir rapporter des informations spécifiques au moteur Neptune.

Le rapport de profil inclut les informations suivantes concernant le plan de requête :
+ Le pipeline de l'opérateur physique
+ Les opérations d'index pour l'exécution et la sérialisation des requêtes
+ La taille du résultat

L'API `profile` utilise une version étendue de la syntaxe d'API HTTP pour les requêtes, avec `/gremlin/profile` comme point de terminaison au lieu de `/gremlin`.

## Paramètres spécifiques à Neptune Gremlin `profile`
<a name="gremlin-profile-api-parameters"></a>
+ **profile.results** – `boolean`, valeurs autorisées : `TRUE` et `FALSE`, valeur par défaut : `TRUE`.

  Si le paramètre est défini true, les résultats de la requête sont collectés et affichés dans le rapport `profile`. Si le paramètre a pour valeur false, seul le nombre de résultats s'affiche.
+ **profile.chop** – `int`, valeur par défaut : 250.

  Si la valeur du paramètre est différente de zéro, la chaîne de résultats est tronquée à ce nombre de caractères. Cela ne empêche pas la capture de tous les résultats. Cela limite simplement la taille de la chaîne dans le rapport de profil. Si la valeur est zéro, la chaîne contient tous les résultats.
+ **profile.serializer** – `string`, valeur par défaut : `<null>`.

  Si la valeur du paramètre est différente de null, les résultats collectés sont renvoyés dans un message de réponse sérialisé au format spécifié par ce paramètre. Le nombre d'opérations d'index nécessaires pour générer ce message de réponse est signalé, ainsi que la taille en octets à envoyer au client.

  Les valeurs autorisées sont `<null>` ou n'importe laquelle des valeurs d'énumération valides du type MIME ou TinkerPop du pilote « Serializers ».

  ```
  "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`, valeurs autorisées : `TRUE` et `FALSE`, valeur par défaut : `FALSE`.

  Si ce paramètre a la valeur true, il affiche un rapport détaillé de toutes les opérations d'index qui ont eu lieu au cours de l'exécution et de la sérialisation des requêtes. Avertissement : ce rapport peut être très détaillé.



## Exemple de sortie de Neptune Gremlin `profile`
<a name="gremlin-profile-sample-output"></a>

Voici un exemple de requête `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"}'
```

Cette requête génère le rapport `profile` suivant lorsqu'elle est exécutée sur l'exemple de graphe des lignes aériennes provenant du billet de blog, [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/).

```
*******************************************************
                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
```

Outre les plans de requête renvoyés par un appel à Neptune `explain`, les résultats de la requête `profile` incluent des statistiques sur l'exécution des requêtes. Chaque opération de jointure est balisée avec le temps nécessaire à l'exécution de sa jointure, ainsi que le nombre réel de solutions qui lui ont été transmises.

La sortie de `profile` inclut le temps nécessaire à la phase d'exécution de la requête principale, ainsi qu'à la phase de sérialisation si l'option `profile.serializer` a été spécifiée.

La répartition des opérations d'index effectuées au cours de chaque phase est également incluse au bas de la sortie `profile`.

Notez que les exécutions consécutives d'une même requête peuvent afficher des résultats différents en termes d'opérations d'exécution et d'index en raison de la mise en cache.

Pour les requêtes utilisant l'étape `repeat()`, une répartition de la frontière sur chaque itération est disponible si l'étape `repeat()` a été réduite et intégrée dans une étape `NeptuneGraphQueryStep`.

## Différences entre les rapports `profile` lorsque le DFE est activé
<a name="gremlin-profile-dfe-output"></a>

Lorsque le moteur de requête alternatif DFE Neptune est activé, la sortie `profile` est quelque peu différente :

**Traversée optimisée :** cette section est similaire à celle de la sortie `explain`, mais contient des informations supplémentaires. Cela inclut le type d'opérateurs DFE pris en compte lors de la planification, ainsi que les estimations de coûts associées au pire et au meilleur scénario.

**Pipeline physique :** cette section capture les opérateurs utilisés pour exécuter la requête. Les éléments `DFESubQuery` procèdent à l'abstraction du plan physique utilisé par le DFE pour exécuter la partie du plan dont il est responsable. Les éléments `DFESubQuery` sont présentés dans la section suivante où les statistiques DFE sont répertoriées.

**DFEQueryStatistiques du moteur :** cette section s'affiche uniquement lorsqu'au moins une partie de la requête est exécutée par DFE. Elle décrit diverses statistiques d'exécution spécifiques au DFE et contient une répartition détaillée du temps passé dans les différentes parties de l'exécution de la requête, par `DFESubQuery`.

Les sous-requêtes imbriquées dans différents éléments `DFESubQuery` ne sont pas hiérarchisées dans cette section, et les identifiants uniques sont marqués d'un en-tête commençant par `subQuery=`.

**Métriques de traversée :** cette section présente les métriques de traversée au niveau des étapes et, lorsque le moteur DFE exécute la totalité ou une partie de la requête, affiche les métriques pour `DFEStep` et/ou `NeptuneInterleavingStep`. Consultez [Réglage des requêtes Gremlin à l'aide d'`explain` et de `profile`](gremlin-traversal-tuning.md).

**Note**  
Le DFE est une fonctionnalité expérimentale publiée en mode laboratoire, de sorte que le format exact de la sortie `profile` est toujours sujet à modification.

## Exemple de sortie `profile` lorsque le moteur Neptune Dataflow (DFE) est activé
<a name="gremlin-profile-sample-dfe-output"></a>

Lorsque le moteur DFE est utilisé pour exécuter des requêtes Gremlin, la sortie de l'[API Gremlin `profile`](#gremlin-profile-api) est mise en forme comme indiqué dans l'exemple ci-dessous.

Interrogation :

```
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
```

**Note**  
Le moteur DFE étant une fonctionnalité expérimentale publiée en mode laboratoire, le format exact de la sortie `profile` peut changer.

# Réglage des requêtes Gremlin à l'aide d'`explain` et de `profile`
<a name="gremlin-traversal-tuning"></a>

[Vous pouvez souvent ajuster vos requêtes Gremlin dans Amazon Neptune pour obtenir de meilleures performances, en utilisant les informations mises à votre disposition dans les rapports fournis par le biais de l'explication et du profil de [Neptune](gremlin-explain-api.md).](gremlin-profile-api.md) APIs Pour ce faire, il est utile de comprendre comment Neptune traite les traversées Gremlin.

**Important**  
Une modification a été apportée à TinkerPop la version 3.4.11 qui améliore l'exactitude du traitement des requêtes, mais qui, pour le moment, peut parfois avoir un impact sérieux sur les performances des requêtes.  
Par exemple, une requête de ce type peut être beaucoup plus lente :  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  out()
```
Les sommets après le pas de limite sont désormais récupérés de manière non optimale en raison de la modification 3.4.11. TinkerPop Pour éviter cela, vous pouvez modifier la requête en ajoutant l'étape barrier() à tout moment après `order().by()`. Par exemple :  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  barrier().
  out()
```
TinkerPop [La version 3.4.11 a été activée dans la version 1.0.5.0 du moteur Neptune.](engine-releases-1.0.5.0.md)

## Comprendre le traitement des traversées Gremlin dans Neptune
<a name="gremlin-traversal-processing"></a>

Lorsqu'une traversée Gremlin est envoyée à Neptune, trois processus principaux la convertissent en un plan d'exécution sous-jacent à exécuter par le moteur. Il s'agit de l'analyse, de la conversion et de l'optimisation :

![\[Trois processus convertissent une requête Gremlin en plan d'exécution.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/Gremlin_traversal_processing.png)


### Processus d'analyse des traversées
<a name="gremlin-traversal-processing-parsing"></a>

La première étape du traitement d'une traversée consiste à l'analyser dans un langage commun. [Dans Neptune, ce langage commun est l'ensemble des TinkerPop étapes qui font partie de l'TinkerPopAPI.](http://tinkerpop.apache.org/javadocs/3.4.8/full/org/apache/tinkerpop/gremlin/process/traversal/Step.html) Chacune de ces étapes représente une unité de calcul au sein de la traversée.

Vous pouvez envoyer une traversée Gremlin à Neptune sous forme de chaîne ou de bytecode. Le point de terminaison REST et la méthode `submit()` du pilote client Java envoient des traversées sous forme de chaînes, comme dans cet exemple :

```
client.submit("g.V()")
```

Les applications et les pilotes de langage utilisant les [variantes du langage Gremlin (GLV)](https://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/) envoient les traversées sous forme de bytecode.

### Processus de conversion des traversées
<a name="gremlin-traversal-processing-conversion"></a>

La deuxième étape du traitement d'une traversée consiste à convertir ses TinkerPop étapes en un ensemble d'étapes Neptune converties et non converties. La plupart des étapes du langage de requête TinkerPop Apache Gkremlin sont converties en étapes spécifiques à Neptune optimisées pour s'exécuter sur le moteur Neptune sous-jacent. Lorsqu'une TinkerPop étape sans équivalent Neptune est rencontrée dans une traversée, cette étape et toutes les étapes suivantes de la traversée sont traitées par le moteur de requête. TinkerPop 

Pour plus d'informations sur les étapes qui peuvent être converties et dans quelles circonstances, consultez [Prise en charge des étapes Gremlin](gremlin-step-support.md).

### Processus d'optimisation des traversées
<a name="gremlin-traversal-processing-optimization"></a>

La dernière étape du traitement des traversées consiste à exécuter la série d'étapes converties et non converties via l'optimiseur, afin de déterminer le meilleur plan d'exécution. Le résultat de cette optimisation est le plan d'exécution traité par le moteur Neptune.

## Utilisation de l'API Neptune Gremlin `explain` pour ajuster les requêtes
<a name="gremlin-traversal-tuning-explain"></a>

L'API Neptune explain n'est pas identique à l'étape Gremlin `explain()`. Elle renvoie le plan d'exécution final que le moteur Neptune peut traiter lors de l'exécution de la requête. Comme elle n'effectue aucun traitement, elle renvoie le même plan quels que soient les paramètres utilisés, et sa sortie ne contient aucune statistique sur l'exécution réelle.

Prenons l'exemple de la traversée simple suivante qui permet de trouver tous les sommets de l'aéroport pour Anchorage :

```
g.V().has('code','ANC')
```

Il existe deux façons d'exécuter cette traversée via l'API Neptune `explain`. La première méthode consiste à effectuer un appel REST au point de terminaison explain, comme suit :

```
curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().has('code','ANC')"}'
```

La deuxième méthode consiste à utiliser la magie cellulaire [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) du workbench Neptune avec le paramètre `explain`. Cela transmet le parcours contenu dans le corps de la cellule à l'API Neptune `explain`, puis affiche le résultat obtenu lorsque vous exécutez la cellule :

```
%%gremlin explain

g.V().has('code','ANC')
```

La sortie d'API `explain` qui en résulte décrit le plan d'exécution de Neptune pour la traversée. Comme vous pouvez le voir sur l'image ci-dessous, le plan inclut chacune des trois étapes du pipeline de traitement :

![\[Sortie d'API explain pour une traversée Gremlin simple.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/Gremlin_explain_output_1.png)


### Réglage d'une traversée en examinant les étapes qui ne sont pas converties
<a name="gremlin-traversal-tuning-explain-non-converted-steps"></a>

L'une des premières choses à rechercher dans la sortie de l'API Neptune `explain` concerne les étapes Gremlin qui ne sont pas converties en étapes natives Neptune. Dans un plan de requête, lorsqu'une étape ne peut pas être convertie en étape native Neptune, elle est traitée par le serveur Gremlin, ainsi que toutes les étapes suivantes du plan.

Dans l'exemple ci-dessus, toutes les étapes de la traversée ont été converties. Examinons la sortie d'API `explain` pour cette traversée :

```
g.V().has('code','ANC').out().choose(hasLabel('airport'), values('code'), constant('Not an airport'))
```

Comme vous pouvez le voir sur l'image ci-dessous, Neptune n'a pas pu convertir l'étape `choose()` :

![\[Sortie d'API explain dans laquelle les étapes ne peuvent pas toutes être converties.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/Gremlin_explain_output_2.png)


Il existe plusieurs façons d'ajuster les performances de la traversée. La première consiste à la réécrire de manière à éliminer l'étape qui n'a pas pu être convertie. Une autre solution consiste à déplacer l'étape vers la fin de la traversée afin que toutes les autres étapes puissent être converties en étapes natives.

Un plan de requête dont les étapes ne sont pas converties n'a pas toujours besoin d'être ajusté. Si les étapes qui ne peuvent pas être converties se situent à la fin de la traversée et sont liées à la mise en forme de la sortie plutôt qu'à la manière dont le graphe est parcouru, elles peuvent avoir peu d'effet sur les performances.

### 
<a name="gremlin-traversal-tuning-explain-unindexed-lookups"></a>

Lorsque vous examinez la sortie de l'API Neptune `explain`, tenez aussi compte des étapes qui n'utilisent pas d'index. La traversée suivante permet de trouver tous les aéroports dont les vols atterrissent à Anchorage :

```
g.V().has('code','ANC').in().values('code')
```

La sortie de l'API explain pour cette traversée est la suivante :

```
*******************************************************
                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
```

Le message `WARNING` au bas de la sortie apparaît parce que l'étape `in()` de la traversée ne peut pas être gérée à l'aide de l'un des trois index gérés par Neptune (voir [Comment les instructions sont indexées dans Neptune](feature-overview-storage-indexing.md) et [Déclarations Gremlin dans Neptune](gremlin-explain-background-statements.md)). Comme l'étape `in()` ne contient aucun filtre d'arête, elle ne peut pas être résolue à l'aide de l'index `SPOG`, `POGS` ou `GPSO`. À la place, Neptune doit effectuer une analyse d'union pour trouver les sommets demandés, ce qui est beaucoup moins efficace.

Dans cette situation, vous pouvez ajuster la traversée de deux façons. La première consiste à ajouter un ou plusieurs critères de filtrage à l'étape `in()` afin qu'une recherche indexée puisse être utilisée pour résoudre la requête. Concernant l'exemple ci-dessus, cela peut être :

```
g.V().has('code','ANC').in('route').values('code')
```

La sortie de l'API Neptune `explain` pour la traversée révisée ne contient plus le message `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
```

Si vous exécutez de nombreuses traversées de ce type, vous pouvez également les exécuter dans un cluster de bases de données Neptune dont l'index `OSGP` facultatif est activé (voir [Activation d'un index OSGP](feature-overview-storage-indexing.md#feature-overview-storage-indexing-osgp)). L'activation d'un index `OSGP` présente des inconvénients :
+ Elle doit être activée dans un cluster de bases de données avant tout chargement de données.
+ Les taux d'insertion des sommets et des arêtes peuvent ralentir de jusqu'à 23 %.
+ L'utilisation du stockage augmente d'environ 20 %.
+ Les requêtes de lecture qui répartissent les demandes sur tous les index peuvent accroître les temps de latence.

L'utilisation d'un index `OSGP` est tout à fait justifiée pour un ensemble restreint de modèles de requêtes, mais à moins que vous ne les exécutiez fréquemment, il est généralement préférable de faire en sorte que les traversées que vous écrivez puissent être résolues à l'aide des trois index principaux.

### Utilisation d'un grand nombre de prédicats
<a name="gremlin-traversal-tuning-explain-many-predicates"></a>

Neptune traite chaque étiquette d'arête et chaque nom de propriété de sommet ou d'arête distinct dans le graphe comme un prédicat. Il est conçu par défaut pour fonctionner avec un nombre relativement faible de prédicats distincts. Lorsque les données du graphe contiennent plus de quelques milliers de prédicats, les performances peuvent se dégrader.

La sortie Neptune `explain` vous en avertit si c'est le cas :

```
Predicates
==========
# of predicates: 9549
WARNING: high predicate count (# of distinct property names and edge labels)
```

S'il n'est pas pratique de retravailler votre modèle de données pour réduire le nombre d'étiquettes et de propriétés, et donc le nombre de prédicats, le meilleur moyen d'ajuster les traversées consiste à les exécuter dans un cluster de bases de données dont l'index `OSGP` est activé, comme indiqué ci-dessus.

## Utilisation de l'API Neptune Gremlin `profile` pour ajuster les traversées
<a name="gremlin-traversal-tuning-profile"></a>

L'API Neptune `profile` est très différente de l'étape Gremlin `profile()`. Comme l'API `explain`, sa sortie inclut le plan de requête que le moteur Neptune utilisera lors de l'exécution de la traversée. En outre, la sortie `profile` inclut les statistiques d'exécution réelles de la traversée, compte tenu de la façon dont ses paramètres sont définis.

Là aussi, prenons l'exemple de la traversée simple qui permet de trouver tous les sommets de l'aéroport pour Anchorage :

```
g.V().has('code','ANC')
```

Comme avec l'API `explain`, vous pouvez invoquer l'API `profile` à l'aide d'un appel REST :

```
curl -X POST https://your-neptune-endpoint:port/gremlin/profile -d '{"gremlin":"g.V().has('code','ANC')"}'
```

Utilisez également la magie cellulaire [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) du workbench Neptune avec le paramètre `profile`. Cela transmet le parcours contenu dans le corps de la cellule à l'API Neptune `profile`, puis affiche le résultat obtenu lorsque vous exécutez la cellule :

```
%%gremlin profile

g.V().has('code','ANC')
```

La sortie d'API `profile` qui en résulte contient à la fois le plan d'exécution de Neptune pour la traversée et les statistiques relatives à l'exécution du plan, comme vous pouvez le voir sur cette image :

![\[Exemple de sortie de l'API Neptune profile.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/Gremlin_profile_output_1.png)


Dans la sortie `profile`, la section du plan d'exécution contient uniquement le plan d'exécution final de la traversée, et non les étapes intermédiaires. La section du pipeline contient les opérations physiques du pipeline qui ont été effectuées ainsi que le temps réel (en millisecondes) nécessaire à l'exécution de la traversée. La métrique d'exécution est extrêmement utile pour comparer le temps nécessaire à deux versions différentes d'une traversée lorsque vous les optimisez.

**Note**  
La durée d'exécution initiale d'une traversée est généralement plus longue que celle des exécutions suivantes, car la première entraîne la mise en cache des données pertinentes.

La troisième section de la sortie `profile` contient les statistiques d'exécution et les résultats de la traversée. Pour voir comment ces informations peuvent être utiles pour ajuster une traversée, prenons l'exemple de la traversée suivante, qui permet de trouver tous les aéroports dont le nom commence par « Anchora » et tous les aéroports accessibles en deux étapes à partir de ces aéroports, en renvoyant le code des aéroports, les itinéraires de vol et les distances :

```
%%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'))
```

### Métriques de traversée dans la sortie de l'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-traversal-metrics"></a>

Le premier ensemble de métriques disponible dans toutes les sorties `profile` est celui des métriques de traversée. Elles sont similaires aux métriques de l'étape Gremlin `profile()`, à quelques différences près :

```
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        -
```

La première colonne du tableau des métriques de traversée répertorie les étapes exécutées par la traversée. Les deux premières étapes sont généralement les étapes spécifiques à Neptune, `NeptuneGraphQueryStep` et `NeptuneTraverserConverterStep`.

`NeptuneGraphQueryStep` représente le temps d'exécution pour toute la partie de la traversée qui pourrait être convertie et exécutée nativement par le moteur Neptune.

`NeptuneTraverserConverterStep`représente le processus de conversion de la sortie de ces étapes converties en TinkerPop traverseurs qui permettent de traiter les étapes qui n'ont pas pu être converties, le cas échéant, ou de renvoyer les résultats dans un format TinkerPop compatible.

Dans l'exemple ci-dessus, nous avons plusieurs étapes non converties. Nous voyons donc que chacune de ces TinkerPop étapes (`ProjectStep`,`PathStep`) apparaît alors sous forme de ligne dans le tableau.

La deuxième colonne du tableau indique le nombre de traversers *représentés* qui sont passés par l'étape, tandis que la troisième colonne indique le nombre de traverseurs qui sont passés par cette étape, comme expliqué dans la documentation de l'[étape du TinkerPop profil](https://tinkerpop.apache.org/docs/current/reference/#profile-step). `Count` `Traversers`

Dans notre exemple, 3 856 sommets et 3 856 traverseurs sont renvoyés par `NeptuneGraphQueryStep`, et ces nombres restent les mêmes pendant le reste du traitement car `ProjectStep` et `PathStep` mettent en forme les résultats, sans les filtrer.

**Note**  
Contrairement à cela TinkerPop, le moteur Neptune n'optimise pas les performances en augmentant le nombre de ses *étapes et de* ses `NeptuneGraphQueryStep` étapes. `NeptuneTraverserConverterStep` Le groupage est l' TinkerPopopération qui combine des traverseurs situés sur le même sommet afin de réduire la surcharge opérationnelle, et c'est ce qui explique la différence entre les `Traversers` nombres `Count` et. Comme le groupage ne se produit que par étapes déléguées TinkerPop par Neptune, et non par étapes gérées nativement par Neptune, `Count` les colonnes et diffèrent rarement. `Traverser`

La colonne Temps indique le nombre de millisecondes que l'étape a duré, tandis que la colonne `% Dur` indique le pourcentage du temps de traitement total que l'étape a pris. Ces métriques vous indiquent sur quoi concentrer vos efforts de réglage en présentant les étapes qui ont pris le plus de temps.

### Métriques d'opérations d'index dans la sortie de l'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-index-operations"></a>

Les opérations d'indexation constituent un autre ensemble de métriques figurant dans les résultats de l'API de profil Neptune :

```
Index Operations
================
Query execution:
    # of statement index ops: 23191
    # of unique statement index ops: 5960
    Duplication ratio: 3.89
    # of terms materialized: 0
```

Ces métriques fournissent les informatons suivantes :
+ Nombre total de recherches d'index.
+ Nombre de recherches d'index uniques effectuées.
+ Ratio entre le nombre total de recherches d'index et le nombre total de recherches uniques. Un ratio inférieur indique une redondance moindre.
+ Nombre de termes matérialisés à partir du dictionnaire.

### Métriques de répétitions dans la sortie de l'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-repeat-metrics"></a>

Si votre traversée utilise une étape `repeat()` comme dans l'exemple ci-dessus, une section contenant des métriques de répétition apparaît dans la sortie `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
```

Ces métriques fournissent les informatons suivantes :
+ Nombre de boucles pour une ligne (colonne `Iteration`)
+ Nombre d'éléments auxquels la boucle a accédé (colonne `Visited`)
+ Nombre d'éléments générés par la boucle (colonne `Output`)
+ Dernier élément généré par la boucle (colonne `Until`)
+ Nombre d'éléments émis par la boucle (colonne `Emit`)
+ Nombre d'éléments étant passés de la boucle à la boucle suivante (colonne `Next`)

Ces métriques de répétition sont très utiles pour comprendre le facteur de ramification de la traversée. Elles vous permettent de vous faire une idée de la quantité de travail effectuée par la base de données. Vous pouvez utiliser ces chiffres pour diagnostiquer les problèmes de performances, en particulier lorsqu'une même traversée fonctionne de manière radicalement différente selon les paramètres.

### Métriques de recherche en texte intégral dans la sortie de l'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-fts-metrics"></a>

Lorsqu'une traversée utilise une [recherche en texte intégral](full-text-search.md), comme dans l'exemple ci-dessus, une section contenant les métriques de recherche en texte intégral (FTS) apparaît dans la sortie `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
```

Cela montre la requête envoyée au cluster ElasticSearch (ES) et indique plusieurs mesures relatives à l'interaction avec ElasticSearch lesquelles vous pouvez identifier les problèmes de performances liés à la recherche en texte intégral :
+ Informations récapitulatives sur les appels dans l' ElasticSearch index :
  + Nombre total de millisecondes requis par tous les appels à distance pour satisfaire la requête (`total`).
  + Nombre moyen de millisecondes passées dans un appel à distance (`avg`).
  + Nombre minimum de millisecondes passées dans un appel à distance (`min`).
  + Nombre maximum de millisecondes passées dans un appel à distance (`max`).
+ Durée totale consommée par RemoteCalls to ElasticSearch ()`remoteCallTime`.
+ Le nombre d'appels à distance effectués vers ElasticSearch ()`remoteCalls`.
+ Le nombre de millisecondes passées à joindre les ElasticSearch résultats (). `joinTime`
+ Nombre de millisecondes passées dans les recherches d'index (`indexTime`).
+ Le nombre total de résultats renvoyés par ElasticSearch (`remoteResults`).

# Prise en charge des étapes Gremlin natives dans Amazon Neptune
<a name="gremlin-step-support"></a>

Le moteur Amazon Neptune n'offre actuellement pas de prise en charge native complète pour toutes les étapes Gremlin, comme expliqué dans [Réglage des requêtes Gremlin](gremlin-traversal-tuning.md). La prise en charge actuelle se divise en quatre catégories :
+ [Étapes Gremlin qui peuvent toujours être converties en opérations natives du moteur Neptune](#gremlin-steps-always)
+ [Étapes Gremlin qui peuvent être converties en opérations natives du moteur Neptune dans certains cas](#gremlin-steps-sometimes) 
+ [Étapes Gremlin qui sont jamais converties en opérations natives du moteur Neptune](#gremlin-steps-never) 
+ [Étapes Gremlin qui ne sont pas du tout prises en charge dans Neptune](#neptune-gremlin-steps-unsupported) 

## Étapes Gremlin qui peuvent toujours être converties en opérations natives du moteur Neptune
<a name="gremlin-steps-always"></a>

De nombreuses étapes Gremlin peuvent être converties en opérations natives du moteur Neptune tant qu'elles répondent aux conditions suivantes :
+ Elles ne sont pas précédées dans la requête d'une étape qui ne peut pas être convertie.
+ Leur étape parent, le cas échéant, peut être convertie.
+ Toutes leurs traversées enfants, le cas échéant, peuvent être converties.

Les étapes Gremlin suivantes sont toujours converties en opérations natives du moteur Neptune si elles répondent à ces conditions :
+ [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)

## Étapes Gremlin qui peuvent être converties en opérations natives du moteur Neptune dans certains cas
<a name="gremlin-steps-sometimes"></a>

Certaines étapes Gremlin peuvent être converties en opérations natives du moteur Neptune dans certaines situations, mais pas dans d'autres :
+ [addE( )](http://tinkerpop.apache.org/docs/current/reference/#addedge-step) : l'étape `addE()` peut généralement être convertie en une opération native du moteur Neptune, à moins qu'elle ne soit immédiatement suivie d'une étape `property()` contenant une traversée en tant que clé.
+ [addV( )](http://tinkerpop.apache.org/docs/current/reference/#addvertex-step) : l'étape `addV()` peut généralement être convertie en une opération native du moteur Neptune, à moins qu'elle ne soit immédiatement suivie d'une étape `property()` contenant une traversée en tant que clé ou à moins que plusieurs étiquettes ne soient attribuées.
+ [aggregate( )](http://tinkerpop.apache.org/docs/current/reference/#store-step) : l'étape `aggregate()` peut généralement être convertie en une opération native du moteur Neptune, sauf si elle est utilisée dans une traversée ou une sous-traversée secondaire, ou à moins que la valeur stockée ne soit autre qu'un sommet, une arête, un ID, une étiquette ou une valeur de propriété.

  Dans l'exemple ci-dessous, l'étape `aggregate()` n'est pas convertie, car elle est utilisée dans une traversée enfant :

  ```
  g.V().has('code','ANC').as('a')
       .project('flights').by(select('a')
       .outE().aggregate('x'))
  ```

  Dans cet exemple, l'étape aggregate() n'est pas convertie, car ce qui est stocké est une valeur `min()` :

  ```
  g.V().has('code','ANC').outE().aggregate('x').by(values('dist').min())
  ```
+ [barrier( )](http://tinkerpop.apache.org/docs/current/reference/#barrier-step) : l'étape `barrier()` peut généralement être convertie en une opération native du moteur Neptune, sauf si l'étape qui la suit n'est pas convertie.
+ [cap( )](http://tinkerpop.apache.org/docs/current/reference/#cap-step) : le seul cas où l'étape `cap()` est convertie est lorsqu'elle est combinée à l'étape `unfold()` pour renvoyer une version dépliée d'un agrégat de valeurs de sommet, d'arête, d'ID ou de propriété. Dans cet exemple, `cap()` sera converti, car il est suivi de `.unfold()` :

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```

  Toutefois, si vous supprimez `.unfold()`, `cap()` ne sera pas converti :

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport')
  ```
+ [coalesce ()](http://tinkerpop.apache.org/docs/current/reference/#coalesce-step) [— Le seul cas où l'`coalesce()`étape est convertie est lorsqu'elle suit le [modèle Upsert](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) recommandé sur la TinkerPop page des recettes.](http://tinkerpop.apache.org/docs/current/recipes/) Les autres modèles coalesce() ne sont pas autorisés. La conversion est limitée au cas où toutes les traversées enfants peuvent être converties, où elles génèremt toutes le même type de sortie (sommet, arête, ID, valeur, clé ou étiquette), où elles mènent toutes à un nouvel élément et où elles ne contiennent pas l'étape `repeat()`.
+ [constant( )](http://tinkerpop.apache.org/docs/current/reference/#constant-step) : l'étape constant() n'est actuellement convertie que si elle est utilisée dans une partie `sack().by()` d'une traversée pour attribuer une valeur de constante, comme ceci :

  ```
  g.V().has('code','ANC').sack(assign).by(constant(10)).out().limit(2)
  ```
+ [cyclicPath( )](http://tinkerpop.apache.org/docs/current/reference/#cyclicpath-step) : l'étape `cyclicPath()` peut généralement être convertie en opération native du moteur Neptune, sauf si l'étape est utilisée avec des modulateurs `by()`, `from()` ou `to()`. Dans les requêtes suivantes, par exemple, `cyclicPath()` n'est pas converti :

  ```
  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) : l'étape `drop()` peut généralement être convertie en opération native du moteur Neptune, sauf si l'étape est utilisée dans une étape `sideEffect(`) ou `optional()`.
+ [fold ()](http://tinkerpop.apache.org/docs/current/reference/#fold-step) — L'étape fold () ne peut être convertie que dans deux situations, à savoir lorsqu'elle est utilisée selon le [modèle Upsert](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) recommandé sur la [page des TinkerPop recettes](http://tinkerpop.apache.org/docs/current/recipes/) et lorsqu'elle est utilisée dans un `group().by()` contexte comme celui-ci :

  ```
  g.V().has('code','ANC').out().group().by().by(values('code', 'city').fold())
  ```
+  [has ()](http://tinkerpop.apache.org/docs/current/reference/#has-step) — L'étape `has () `peut généralement être convertie en une opération native du moteur Neptune à condition que les requêtes avec `T` utilisent le prédicat `P.eq`, `P.neq` ou `P.Contains`. Attendez-vous à des variations de `has () `qui impliquent que les instances de `P` soient également converties en mode natif, comme `hasId ('id1234')` qui est équivalent à `has (eq, T.id, 'id1234') `. 
+ [id( )](http://tinkerpop.apache.org/docs/current/reference/#id-step) : l'étape `id()` est convertie sauf si elle est utilisée au niveau d'une propriété, comme ceci :

  ```
  g.V().has('code','ANC').properties('code').id()
  ```
+  [MerGee ()](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step) — L'`mergeE()`étape peut être convertie en une opération native du moteur Neptune si les paramètres (la condition de fusion, `onCreate` `onMatch` et) sont constants (`null`soit une constante, soit une constante, soit une `Map` valeur de `Map` a). `select()` Tous les exemples d'[arêtes ascendantes](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-efficient-upserts.html#gremlin-upserts-edges) peuvent être convertis. 
+  [mergeV ()](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step) — L'étape mergeV () peut être convertie en un fonctionnement natif du moteur Neptune si les paramètres (la condition de fusion, `onCreate` et`onMatch`) sont constants (soit une constante, soit une constante`null`, soit une valeur de a). `Map` `select()` `Map` Tous les exemples de [sommets ascendants peuvent être convertis](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) : l'étape `order()` peut généralement être convertie en opération native du moteur Neptune, sauf si l'une des conditions suivantes est vraie :
  + L'étape `order()` se trouve dans une traversée enfant imbriquée, comme ceci :

    ```
    g.V().has('code','ANC').where(V().out().order().by(id))
    ```
  + L'ordre local est utilisé (par exemple, avec `order(local)`).
  + Un comparateur personnalisé est utilisé dans la modulation `by()` pour effectuer le tri. Voici un exemple de l'utilisation de `sack()` :

    ```
    g.withSack(0).
      V().has('code','ANC').
          repeat(outE().sack(sum).by('dist').inV()).times(2).limit(10).
          order().by(sack())
    ```
  + Il existe plusieurs ordres pour le même élément.
+ [project( )](http://tinkerpop.apache.org/docs/current/reference/#project-step) : l'étape `project()` peut généralement être convertie en opération native du moteur Neptune, sauf si le nombre d'instructions `by()` qui suivent `project()` ne correspond pas au nombre d'étiquettes spécifié, comme ici :

  ```
  g.V().has('code','ANC').project('x', 'y').by(id)
  ```
+ [range( )](http://tinkerpop.apache.org/docs/current/reference/#range-step) : l'étape `range()` n'est convertie que lorsque la limite inférieure de la plage en question est égale à zéro (par exemple, `range(0,3)`).
+ [repeat( )](http://tinkerpop.apache.org/docs/current/reference/#repeat-step) : l'étape `repeat()` peut généralement être convertie en opération native du moteur Neptune, sauf si elle est imbriquée dans une autre étape `repeat()`, comme ceci :

  ```
  g.V().has('code','ANC').repeat(out().repeat(out()).times(2)).times(2)
  ```
+ [sack( )](http://tinkerpop.apache.org/docs/current/reference/#sack-step) : l'étape `sack()` peut généralement être convertie en opération native du moteur Neptune, sauf dans les cas suivants :
  + Si un opérateur sack non numérique est utilisé.
  + Si un opérateur sack non numérique autre que `+`, `-`, `mult`, `div`, `min` et `max` est utilisé.
  + Si `sack()` est utilisé dans une étape `where()` pour filtrer les données en fonction d'une valeur sack, comme ici :

    ```
    g.V().has('code','ANC').sack(assign).by(values('code')).where(sack().is('ANC'))
    ```
+ [sum( )](http://tinkerpop.apache.org/docs/current/reference/#sum-step) : l'étape `sum()` peut généralement être convertie en opération native du moteur Neptune, mais pas lorsqu'elle est utilisée pour calculer une somme globale, comme ceci :

  ```
  g.V().has('code','ANC').outE('routes').values('dist').sum()
  ```
+ [union( )](http://tinkerpop.apache.org/docs/current/reference/#union-step) : l'étape `union()` peut être convertie en opération native du moteur Neptune tant qu'il s'agit de la dernière étape de la requête en dehors de l'étape terminale.
+ [unfold ()](http://tinkerpop.apache.org/docs/current/reference/#unfold-step) — L'`unfold()`étape ne peut être convertie en une opération native du moteur Neptune que lorsqu'elle est utilisée selon [le modèle Upsert](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) recommandé sur [TinkerPopla page des recettes](http://tinkerpop.apache.org/docs/current/recipes/), et lorsqu'elle est utilisée conjointement avec `cap()` ceci :

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```
+ [where( )](http://tinkerpop.apache.org/docs/current/reference/#where-step) : l'étape `where()` peut généralement être convertie en opération native du moteur Neptune, sauf dans les cas suivants :
  + Lorsque des modulations by() sont utilisées, comme ceci :

    ```
    g.V().hasLabel('airport').as('a')
         .where(gt('a')).by('runways')
    ```
  + Lorsque des opérateurs de comparaison autres que `eq`, `neq`, `within` et `without` sont utilisés.
  + Lorsque des agrégations fournies par l'utilisateur sont utilisées.

## Étapes Gremlin qui sont jamais converties en opérations natives du moteur Neptune
<a name="gremlin-steps-never"></a>

Les étapes Gremlin suivantes sont prises en charge dans Neptune, mais ne sont jamais converties en opérations natives du moteur Neptune. Au lieu de cela, elles sont exécutées par le serveur 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)

## Étapes Gremlin qui ne sont pas du tout prises en charge dans Neptune
<a name="neptune-gremlin-steps-unsupported"></a>

Les étapes Gremlin suivantes ne sont pas du tout prises en charge dans Neptune. Dans la plupart des cas, cela est dû au fait qu'elles nécessitent un `GraphComputer`, ce que Neptune ne prend pas en charge actuellement.
+ [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)

L'étape `io()` est partiellement prise en charge, dans la mesure où elle peut être utilisée pour effectuer une opération de type `read()` à partir d'une URL, mais pas une opération de type `write()`.

# Utilisation de Gremlin avec le moteur de requêtes Neptune DFE
<a name="gremlin-with-dfe"></a>

Si vous activez le [moteur de requête alternatif](neptune-dfe-engine.md) de Neptune connu sous le nom de DFE en [mode laboratoire](features-lab-mode.md) (en définissant le paramètre du `neptune_lab_mode` cluster de base de données sur`DFEQueryEngine=enabled`), Neptune traduit G705 queries/traversals en lecture seule en une représentation logique intermédiaire et les exécute sur le moteur DFE chaque fois que cela est possible.

Cependant, le DFE ne prend pas encore en charge toutes les étapes Gremlin. Lorsqu'une étape ne peut pas être exécutée en mode natif sur le DFE, Neptune recourt à nouveau TinkerPop pour exécuter l'étape. Les rapports `explain` et `profile` incluent des avertissements lorsque cela se produit.

# Couverture des étapes de Garmlin en PDF
<a name="gremlin-step-coverage-in-DFE"></a>

 Gremlin DFE est une fonctionnalité en mode laboratoire qui peut être utilisée soit en activant le paramètre de cluster, soit en utilisant l'`Neptune#useDFE`indice de requête. Pour plus d'informations, reportez-vous à la section [Utilisation de Gremlin avec le moteur de requêtes Neptune DFE](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-with-dfe.html). 

 Les étapes suivantes peuvent être utilisées dans Gremlin DFE. 

## Trajectoire et étapes de traversée :
<a name="DFE-path-and-traversal"></a>

 [asDate ()](https://tinkerpop.apache.org/docs/current/reference/#asDate-step) [https://tinkerpop.apache.org/docs/current/reference/#order-step](https://tinkerpop.apache.org/docs/current/reference/#order-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 (), [select ()](https://tinkerpop.apache.org/docs/current/reference/#select-step)](https://tinkerpop.apache.org/docs/current/reference/#sample-step), [sideEffect (), split ()](https://tinkerpop.apache.org/docs/current/reference/#sideeffect-step)[, unfold ()](https://tinkerpop.apache.org/docs/current/reference/#split-step)[, union ()](https://tinkerpop.apache.org/docs/current/reference/#unfold-step)](https://tinkerpop.apache.org/docs/current/reference/#union-step) 

## Étapes d'agrégation et de collecte :
<a name="DFE-aggregate-and-collection"></a>

 [agréger (global)](https://tinkerpop.apache.org/docs/current/reference/#aggregate-step), [combiner ()](https://tinkerpop.apache.org/docs/current/reference/#combine-step), [compter ()](https://tinkerpop.apache.org/docs/current/reference/#count-step), [déduplication ()](https://tinkerpop.apache.org/docs/current/reference/#dedup-step), [déduplication (local), pliage ()](https://tinkerpop.apache.org/docs/current/reference/#dedup-step)[, groupe ()](https://tinkerpop.apache.org/docs/current/reference/#fold-step)[, [groupCount](https://tinkerpop.apache.org/docs/current/reference/#groupcount-step) ()](https://tinkerpop.apache.org/docs/current/reference/#group-step), 

## Étapes mathématiques :
<a name="DFE-mathematical"></a>

 [max ()](https://tinkerpop.apache.org/docs/current/reference/#max-step), [moyenne ()](https://tinkerpop.apache.org/docs/current/reference/#mean-step), [min ()](https://tinkerpop.apache.org/docs/current/reference/#min-step), [somme ()](https://tinkerpop.apache.org/docs/current/reference/#sum-step) 

## Étapes de l'élément :
<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), [élément ()](https://tinkerpop.apache.org/docs/current/reference/#element-step), [v (), out ()](https://tinkerpop.apache.org/docs/current/reference/#graph-step)[, in (), les deux (), OutE (), iNE (), BothE (), OutV (), InV (), BothV (), AutreV (](https://tinkerpop.apache.org/docs/current/reference/#vertex-step)) 

## Étapes de la propriété :
<a name="DFE-property"></a>

 [propriétés ()](https://tinkerpop.apache.org/docs/current/reference/#properties-step), [clé ()](https://tinkerpop.apache.org/docs/current/reference/#key-step), [valueMap ()](https://tinkerpop.apache.org/docs/current/reference/#propertymap-step), [valeur (](https://tinkerpop.apache.org/docs/current/reference/#value-step)) 

## Étapes du filtre :
<a name="DFE-filter"></a>

 [et ()](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 (), not](https://tinkerpop.apache.org/docs/current/reference/#none-step) [()](https://tinkerpop.apache.org/docs/current/reference/#not-step), [ou ()](https://tinkerpop.apache.org/docs/current/reference/#or-step), [où](https://tinkerpop.apache.org/docs/current/reference/#where-step) () 

## Étapes de manipulation des chaînes :
<a name="DFE-string-manipulation"></a>

 [concat ()](https://tinkerpop.apache.org/docs/current/reference/#concat-step) [https://tinkerpop.apache.org/docs/current/reference/#toUpper-step](https://tinkerpop.apache.org/docs/current/reference/#toUpper-step) 

## Prédicats :
<a name="DFE-predicates"></a>
+  [Comparez : eq, neq, lt, lte, gt, gte](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [Contient : dedans, sans](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [texTP : se terminant par, contenant,,, notStartingWith non contenant notEndingWith](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [P : et, ou, entre, à l'extérieur, à l'intérieur](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 

## Limitations
<a name="gremlin-with-dfe-limitations"></a>

 Répéter avec limite. Les libellés contenus dans la procédure de traversée répétée et de déduplication ne sont pas encore pris en charge dans 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'))
```

 Les chemins comportant des répétitions imbriquées ou des étapes de branchement ne sont pas encore pris en charge. 

```
// 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')
```

## Entrelacement de la planification des requêtes
<a name="gremlin-with-dfe-interleaving"></a>

Lorsque le processus de conversion identifie une étape Gremlin qui n'a pas d'opérateur DFE natif correspondant, avant de revenir à Tinkerpop, il essaie de trouver d'autres parties de requête intermédiaires pouvant être exécutées nativement sur le moteur DFE. Pour ce faire, il applique une logique d'entrelacement à la traversée de niveau supérieur. De la sorte, les étapes prises en charge sont utilisées dans la mesure du possible.

Toute conversion de requête intermédiaire sans préfixe est représentée à l'aide de `NeptuneInterleavingStep` dans les sorties `explain` et `profile`.

Pour comparer les performances, vous pouvez désactiver l'entrelacement dans une requête, tout en utilisant le moteur DFE pour exécuter la partie avec préfixe. Vous pouvez également utiliser uniquement le TinkerPop moteur pour l'exécution de requêtes sans préfixe. Pour ce faire, vous avez besoin d'un indicateur de requête `disableInterleaving`.

Tout comme l'indicateur de requête [useDFE](gremlin-query-hints-useDFE.md) avec la valeur `false` empêche totalement l'exécution d'une requête sur le DFE, l'indicateur requête `disableInterleaving` avec la valeur `true` désactive l'entrelacement DFE pour la conversion d'une requête. Par exemple :

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

## Mise à jour de la sortie Gremlin `explain` et `profile`
<a name="gremlin-with-dfe-explain-update"></a>

Gremlin [explain](gremlin-explain.md) fournit des informations sur la traversée optimisée que Neptune utilisera pour exécuter une requête. Consultez l'[exemple de sortie DFE `explain`](gremlin-explain-api.md#gremlin-explain-dfe) pour voir ce à quoi ressemble la sortie `explain` lorsque le moteur DFE est activé.

L'[API Gremlin `profile`](gremlin-profile-api.md) effectue une traversée Gremlin spécifiée, collecte diverses métriques relatives à l'exécution et génère un rapport de profil contenant des informations sur le plan de requête optimisé et les statistiques d'exécution de différents opérateurs. Consultez l'[exemple de sortie DFE `profile`](gremlin-profile-api.md#gremlin-profile-sample-dfe-output) pour voir ce à quoi ressemble la sortie `profile` lorsque le moteur DFE est activé.

**Note**  
Le moteur DFE étant une fonctionnalité expérimentale publiée en mode laboratoire, le format exact de la sortie `explain` et `profile` peut changer.

# Accès au graphe Neptune avec openCypher
<a name="access-graph-opencypher"></a>

Neptune prend en charge la création d'applications de graphe à l'aide d'openCypher, qui est actuellement l'un des langages de requête les plus populaires pour les développeurs travaillant avec des bases de données orientées graphe. Les développeurs, les analystes et les scientifiques des données apprécient la syntaxe d'openCypher inspirée de SQL, car sa structure familière facilite la composition des requêtes pour les applications de graphe.

**openCypher** est un langage de requête déclaratif pour les graphes de propriétés initialement développé par Neo4j, puis rendu open source en 2015. Il a contribué au projet [openCypher](http://www.opencypher.org/) sous une licence open source Apache 2. Sa syntaxe est documentée dans [Cypher Query Language Reference, Version 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf) (Référence du langage de requête Cypher, version 9).

Pour connaître les limites et les différences de prise en charge de la spécification openCypher dans Neptune, consultez [Conformité aux spécifications OpenCypher dans Amazon Neptune](feature-opencypher-compliance.md).

**Note**  
L'implémentation actuelle du langage de requête Cypher dans Neo4j s'écarte à certains égards de la spécification openCypher. Si vous migrez le code Neo4j Cypher actuel vers Neptune, consultez [Compatibilité de Neptune avec Neo4j](migration-compatibility.md) et [Réécriture des requêtes Cypher pour les exécuter dans openCypher sur Neptune](migration-opencypher-rewrites.md) pour obtenir de l'aide.

À partir de la version 1.1.1.0 du moteur, openCypher est disponible pour une utilisation en production dans Neptune.

## Comparaison de Gremlin et openCypher : similarités et différences
<a name="access-graph-opencypher-overview-with-gremlin"></a>

Gremlin et openCypher sont tous deux des langages de requête basés sur des graphes de propriétés. Ils sont complémentaires à bien des égards.

Gremlin est destiné aux programmeurs et s'intègre parfaitement dans le code. Par conséquent, Gremlin utilise une syntaxe impérative dès sa conception, tandis que la syntaxe déclarative d'openCypher peut sembler plus familière aux personnes ayant de l'expérience en SQL ou en SPARQL. Gremlin peut sembler plus naturel à un scientifique des données utilisant Python dans un bloc-notes Jupyter, tandis qu'openCypher peut sembler plus intuitif à un professionnel ayant une certaine expérience en SQL.

L'avantage est que **vous n'avez pas à choisir** entre Gremlin et openCypher dans Neptune. Les requêtes dans l'un ou l'autre de ces langages fonctionnent sur le même graphe, quelle que soit le langage utilisé pour entrer ces données. Vous trouverez peut-être plus pratique d'utiliser Gremlin pour certaines tâches et openCypher pour d'autres, selon ce que vous faites.

Gremlin utilise une syntaxe impérative qui vous permet de contrôler la façon dont vous vous déplacez dans le graphe en une série d'étapes, chacune prenant en charge un flux de données, effectuant une action associée (à l'aide d'un filtre, d'un mappage, etc.), puis transmettant les résultats à l'étape suivante. Une requête Gremlin prend généralement la forme `g.V()`, suivie d'étapes supplémentaires.

Dans openCypher, vous utilisez une syntaxe déclarative, inspirée de SQL, qui spécifie un modèle de nœuds et de relations à rechercher dans le graphe à l'aide d'une syntaxe de motif (comme `()-[]->()`). Une requête openCypher commence souvent par une clause `MATCH`, suivie d'autres clauses telles que `WHERE`, `WITH`, et `RETURN`

# Premiers pas avec openCypher
<a name="access-graph-opencypher-overview-getting-started"></a>

Vous pouvez interroger les données du graphe de propriétés dans Neptune à l'aide d'openCypher, quelle que soit la manière dont elles ont été chargées, mais vous ne pouvez pas utiliser openCypher pour interroger des données chargées au format RDF.

Le [chargeur en bloc Neptune](bulk-load.md) accepte les données du graphe de propriétés [au format CSV pour Gremlin](bulk-load-tutorial-format-gremlin.md) et au [format CSV pour openCypher](bulk-load-tutorial-format-opencypher.md). Bien entendu, vous pouvez également ajouter des données de propriété à votre graphique à l'aide des requêtes and/or OpenCypher de Gremlin.

De nombreux didacticiels en ligne permettent d'apprendre le langage de requête Cypher. Voici quelques exemples rapides de requêtes openCypher qui vous aideront à vous familiariser avec ce langage, mais le moyen le plus efficace et le plus simple de commencer à utiliser openCypher pour interroger le graphe Neptune est d'utiliser les blocs-notes openCypher dans le [workbench Neptune](graph-notebooks.md). Le workbench est open source et est hébergé sur GitHub . [https://github.com/aws-samples/amazon-neptune-samples](https://github.com/aws-samples/amazon-neptune-samples/)

[Vous trouverez les blocs-notes OpenCypher dans le référentiel Neptune GitHub graph-notebook.](https://github.com/aws/graph-notebook/tree/main/src/graph_notebook/notebooks) Consultez en particulier la [visualisation des routes aériennes](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/Air-Routes-openCypher.ipynb) et les blocs-notes [English Premier Teams](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/EPL-openCypher.ipynb) pour openCypher.

Les données traitées par OpenCypher prennent la forme d'une série non ordonnée de cartes. key/value Le principal moyen d'affiner, de manipuler et d'augmenter ces cartes consiste à utiliser des clauses qui exécutent des tâches telles que la correspondance de modèles, l'insertion, la mise à jour et la suppression sur les key/value paires.

openCypher contient plusieurs clauses permettant de trouver des modèles de données dans le graphe. `MATCH` est la plus courante. `MATCH` vous permet de spécifier le modèle de nœuds, de relations et de filtres que vous souhaitez rechercher dans le graphe. Par exemple :
+ **Obtenir tous les nœuds**

  ```
  MATCH (n) RETURN n
  ```
+ **Trouver les nœuds connectés**

  ```
  MATCH (n)-[r]->(d) RETURN n, r, d
  ```
+ **Trouver un chemin**

  ```
  MATCH p=(n)-[r]->(d) RETURN p
  ```
+ **Obtenir tous les nœuds avec une étiquette**

  ```
  MATCH (n:airport) RETURN n
  ```

Notez que la première requête ci-dessus renvoie tous les nœuds du graphe, et les deux suivantes renvoient tous les nœuds ayant une relation, ce qui n'est généralement pas recommandé. Dans presque tous les cas, il est utile d'affiner les données renvoyées. Pour ce faire, spécifiez les étiquettes et les propriétés des nœuds ou des relations, comme dans le quatrième exemple.

Vous trouverez un aide-mémoire pratique pour la syntaxe d'openCypher dans le [référentiel Github d'exemples](https://github.com/aws-samples/amazon-neptune-samples/tree/master/opencypher/Cheatsheet.md) Neptune.

# Servlet de statut Neptune openCypher et point de terminaison de statut
<a name="access-graph-opencypher-status"></a>

Le point de terminaison de statut openCypher permet d'accéder aux informations relatives aux requêtes qui sont en cours d'exécution sur le serveur ou en attente d'exécution. Il vous permet également d'annuler ces requêtes. Le point de terminaison est :

```
https://(the server):(the port number)/openCypher/status
```

Vous pouvez utiliser les méthodes HTTP `GET` et `POST` pour obtenir le statut actuel à partir du serveur ou pour annuler une requête. Vous pouvez également utiliser la méthode `DELETE` pour annuler une requête en cours ou en attente.

## Paramètres des demandes de statut
<a name="access-graph-opencypher-status-parameters"></a>

**Paramètres des requêtes de statut**
+ **`includeWaiting`** (`true`ou`false`) : lorsque ce paramètre est défini sur `true` et que d'autres paramètres ne sont pas présents, des informations de statut pour les requêtes en attente ainsi que pour les requêtes en cours d'exécution sont renvoyées.
+ **`cancelQuery`** : utilisé uniquement avec les méthodes `GET` et `POST` pour indiquer qu'il s'agit d'une demande d'annulation. La méthode `DELETE` n'a pas besoin de ce paramètre.

  La valeur du paramètre `cancelQuery` n'est pas utilisée, mais lorsque `cancelQuery` est présent, le paramètre `queryId` est obligatoire pour identifier la requête à annuler.
+ **`queryId`** : contient l'ID d'une requête spécifique.

  Lorsque ce paramètre est utilisé avec la méthode `GET` ou `POST` et que le paramètre `cancelQuery` n'est pas présent, les informations de statut sont renvoyées par `queryId` pour la requête spécifique qu'il identifie. Si le paramètre `cancelQuery` est présent, la requête spécifique identifiée par `queryId` est annulée.

  Lorsqu'il est utilisé avec la méthode `DELETE`, `queryId` indique toujours une requête spécifique à annuler.
+ **`silent`** : utilisé uniquement lors de l'annulation d'une requête. Si ce paramètre est défini sur `true`, l'annulation se produit silencieusement.

## Champs de réponse aux demandes de statut
<a name="access-graph-opencypher-status-response-fields"></a>

**Champs de réponse relatifs au statut si l'ID d'une requête spécifique n'est pas fourni**
+ **acceptedQueryCount**— Le nombre de requêtes acceptées mais non encore terminées, y compris les requêtes dans la file d'attente.
+ **runningQueryCount**— Le nombre de requêtes OpenCypher en cours d'exécution.
+ **queries** : requêtes openCypher actuelles.

**Champs de réponse relatifs au statut pour une requête spécifique**
+ **queryID** : identifiant GUID de la requête. Neptune attribue automatiquement cette valeur d'ID à chaque requête, mais vous pouvez également attribuer votre propre ID (voir [Injection d'un ID personnalisé dans une requête Neptune Gremlin ou SPARQL](features-query-id.md)).
+ **queryString** : requête soumise. Celle-ci est tronquée à 1 024 caractères si elle est plus longue que cela.
+ **queryEvalStats**— Statistiques pour cette requête :
  + **waited** : indique la durée d'attente de la requête, en millisecondes.
  + **elapsed** : nombre de microsecondes d'exécution de la requête jusqu'au moment T.
  + **cancelled** : `True` indique que la requête a été annulée, ou `False` qu'elle n'a pas été annulée.

## Exemples de demandes de statut et de réponses
<a name="access-graph-opencypher-status-samples"></a>
+ **Demande de statut de toutes les requêtes, y compris celles en attente :**

  ```
  curl https://server:port/openCypher/status \
    --data-urlencode "includeWaiting=true"
  ```

  *Réponse :*

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **Demande de statut des requêtes en cours, **à l'exclusion** de celles en attente :**

  ```
  curl https://server:port/openCypher/status
  ```

  *Réponse :*

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **Demande de statut d'une seule requête :**

  ```
  curl https://server:port/openCypher/status \
   --data-urlencode "queryId=eadc6eea-698b-4a2f-8554-5270ab17ebee"
  ```

  *Réponse :*

  ```
  {
    "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
    }
  }
  ```
+ **Demandes d'annulation d'une requête**

  1. En utilisant `POST` :

  ```
  curl -X POST https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=f43ce17b-db01-4d37-a074-c76d1c26d7a9"
  ```

  *Réponse :*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  2. En utilisant `GET` :

  ```
  curl -X GET https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=588af350-cfde-4222-bee6-b9cedc87180d"
  ```

  *Réponse :*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  3. En utilisant `DELETE` :

  ```
  curl -X DELETE \
    -s "https://server:port/openCypher/status?queryId=b9a516d1-d25c-4301-bb80-10b2743ecf0e"
  ```

  *Réponse :*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

# Le point de terminaison HTTPS Amazon Neptune OpenCypher
<a name="access-graph-opencypher-queries"></a>

**Topics**
+ [OpenCypher lire et écrire des requêtes sur le point de terminaison HTTPS](#access-graph-opencypher-queries-read-write)
+ [Le format de résultats OpenCypher JSON par défaut](#access-graph-opencypher-queries-results-simple-JSON)
+ [En-têtes de suivi HTTP facultatifs pour les réponses en plusieurs parties OpenCypher](#optional-http-trailing-headers)

**Note**  
Neptune ne prend actuellement pas en charge le HTTP/2 pour les requêtes d'API REST. Les clients doivent utiliser HTTP/1.1 lorsqu'ils se connectent aux points de terminaison.

## OpenCypher lire et écrire des requêtes sur le point de terminaison HTTPS
<a name="access-graph-opencypher-queries-read-write"></a>

Le point de terminaison OpenCypher HTTPS prend en charge les requêtes de lecture et de mise à jour en utilisant à la fois la `POST` méthode `GET` et. Les méthodes `DELETE` et `PUT` ne sont pas prises en charge.

Les instructions suivantes vous indiquent comment vous connecter au point de OpenCypher terminaison à l'aide de la `curl` commande et du protocole HTTPS. Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

La syntaxe est la suivante :

```
HTTPS://(the server):(the port number)/openCypher
```

Voici des exemples de requêtes de lecture, l'une avec `POST` et l'autre avec `GET` :

1. En utilisant `POST` :

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n1) RETURN n1;"
```

2. En utilisant `GET` (la chaîne de requête est encodée en URL) :

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n1)%20RETURN%20n1"
```

Voici des exemples de write/update requêtes, une qui utilise `POST` et une qui utilise `GET` :

1. En utilisant `POST` :

```
curl HTTPS://server:port/openCypher \
  -d "query=CREATE (n:Person { age: 25 })"
```

2. En utilisant `GET` (la chaîne de requête est encodée en URL) :

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=CREATE%20(n%3APerson%20%7B%20age%3A%2025%20%7D)"
```

## Le format de résultats OpenCypher JSON par défaut
<a name="access-graph-opencypher-queries-results-simple-JSON"></a>

Le format JSON suivant est renvoyé par défaut ou en définissant explicitement l'en-tête de demande sur `Accept: application/json`. Ce format est conçu pour être facilement analysé en objets à l'aide des fonctionnalités du langage natif de la plupart des bibliothèques.

Le document JSON renvoyé contient un champ, `results`, qui comporte les valeurs renvoyées par la requête. Les exemples ci-dessous montrent la mise en forme JSON pour les valeurs courantes.

**Exemple de réponse pour une valeur :**

```
{
  "results": [
    {
      "count(a)": 121
    }
  ]
}
```

**Exemple de réponse pour un nœud :**

```
{
  "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
        }
      }
    }
  ]
}
```

**Exemple de réponse pour une relation :**

```
{
  "results": [
    {
      "r": {
        "~id": "7389",
        "~entityType": "relationship",
        "~start": "22",
        "~end": "151",
        "~type": "route",
        "~properties": {
          "dist": 956
        }
      }
    }
  ]
}
```

**Exemple de réponse pour un chemin :**

```
{
  "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
          }
        }
      ]
    }
  ]
}
```

## En-têtes de suivi HTTP facultatifs pour les réponses en plusieurs parties OpenCypher
<a name="optional-http-trailing-headers"></a>

 [Cette fonctionnalité est disponible à partir de la version 1.4.5.0 du moteur Neptune.](https://docs.aws.amazon.com/releases/release-1.4.5.0.xml) 

 La réponse HTTP aux OpenCypher requêtes et aux mises à jour est généralement renvoyée en plusieurs parties. Lorsque des défaillances surviennent après l'envoi des segments de réponse initiaux (avec un code d'état HTTP de 200), il peut être difficile de diagnostiquer le problème. Par défaut, `Neptune signale ces défaillances en ajoutant un message d'erreur dans le corps du message, qui peut être corrompu en raison de la nature en streaming de la réponse. 

**Utilisation des en-têtes de suivi**  
 Pour améliorer la détection et le diagnostic des erreurs, vous pouvez activer les en-têtes de suivi en incluant un en-tête de remorques à codage de transfert (TE) (te : trailers) dans votre demande. De cette manière, Neptune inclura deux nouveaux champs d'en-tête dans les en-têtes de suivi des fragments de réponse : 
+  `X-Neptune-Status`— contient le code de réponse suivi d'un nom court. Par exemple, en cas de réussite, l'en-tête final serait : `X-Neptune-Status: 200 OK`. En cas de panne, le code de réponse serait un code d'erreur du moteur Neptune tel que. `X-Neptune-Status: 500 TimeLimitExceededException` 
+  `X-Neptune-Detail`— est vide pour les demandes réussies. En cas d'erreur, il contient le message d'erreur JSON. Étant donné que seuls les caractères ASCII sont autorisés dans les valeurs d'en-tête HTTP, la chaîne JSON est encodée en URL. Le message d'erreur est également toujours ajouté au corps du message de réponse. 

 Pour plus d'informations, consultez la [page MDN sur les en-têtes de requête TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE). 

**OpenCypher exemple d'utilisation des en-têtes de suivi**  
 Cet exemple montre comment les en-têtes de fin permettent de diagnostiquer une requête qui dépasse sa limite de temps : 

```
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
```

**Répartition des réponses :**  
 L'exemple précédent montre comment une OpenCypher réponse avec des en-têtes de fin peut aider à diagnostiquer les échecs de requête. Nous voyons ici quatre parties séquentielles : (1) les en-têtes initiaux avec un statut 200 OK indiquant le début du streaming, (2) les résultats JSON partiels (cassés) diffusés avec succès avant l'échec, (3) le message d'erreur ajouté indiquant le délai d'expiration, et (4) les en-têtes suivants contenant l'état final (500) et des informations d'erreur détaillées. TimeLimitExceededException 

# Utilisation du AWS SDK pour exécuter des requêtes OpenCypher
<a name="access-graph-opencypher-sdk"></a>

Avec le AWS SDK, vous pouvez exécuter des requêtes OpenCypher sur votre graphe Neptune en utilisant le langage de programmation de votre choix. Le SDK de l'API de données Neptune (nom du service`neptunedata`) fournit l'[ExecuteOpenCypherQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteOpenCypherQuery.html)action permettant de soumettre des requêtes OpenCypher.

Vous devez exécuter ces exemples depuis une instance Amazon EC2 dans le même cloud privé virtuel (VPC) que votre cluster de base de données Neptune, ou depuis un emplacement disposant d'une connectivité réseau avec le point de terminaison de votre cluster.

Vous trouverez ci-dessous des liens directs vers la documentation de référence `neptunedata` de l'API pour le service dans chaque langue du SDK :


| Langage de programmation | Référence de l'API neptunedata | 
| --- | --- | 
| 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) | 
| INTERFACE DE LIGNE DE COMMANDE (CLI) | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

## Exemples du SDK OpenCypher AWS
<a name="access-graph-opencypher-sdk-examples"></a>

Les exemples suivants montrent comment configurer un `neptunedata` client, exécuter une requête OpenCypher et imprimer les résultats. Remplacez *YOUR\$1NEPTUNE\$1HOST* et *YOUR\$1NEPTUNE\$1PORT* par le point de terminaison et le port de votre cluster de base de données Neptune.

**Configuration du délai d'expiration et des nouvelles tentatives côté client**  
Le délai d'attente du client SDK contrôle le temps d'attente d'une réponse par le *client*. Il ne contrôle pas la durée d'exécution de la requête sur le serveur. Si le client expire avant la fin du serveur, la requête peut continuer à s'exécuter sur Neptune alors que le client n'a aucun moyen de récupérer les résultats.  
[Nous vous recommandons de définir le délai de lecture côté client sur `0` (aucun délai d'attente) ou sur une valeur supérieure d'au moins quelques secondes au paramètre neptune\$1query\$1timeout côté serveur sur votre cluster de base de données Neptune.](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) Cela permet à Neptune de contrôler l'expiration du délai d'expiration des requêtes.  
Nous recommandons également de fixer le nombre maximum de tentatives à `1` (aucune tentative). Si le SDK réessaie une requête toujours en cours d'exécution sur le serveur, cela peut entraîner des opérations dupliquées. Cela est particulièrement important pour les requêtes de mutation, où une nouvelle tentative peut entraîner des écritures dupliquées involontaires.

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

1. Suivez les [instructions d'installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html) pour installer Boto3.

1. Créez un fichier nommé `openCypherExample.py` et collez le code suivant :

   ```
   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. Exécutez l'exemple : `python openCypherExample.py`

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

1. Suivez les [instructions d'installation](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) pour configurer le AWS SDK for Java.

1. Utilisez le code suivant pour configurer une`NeptunedataClient`, exécuter une requête OpenCypher et imprimer le résultat :

   ```
   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. Suivez les [instructions d'installation](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) pour configurer le AWS SDK pour JavaScript. Installez le package client neptunedata :. `npm install @aws-sdk/client-neptunedata`

1. Créez un fichier nommé `openCypherExample.js` et collez le code suivant :

   ```
   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. Exécutez l'exemple : `node openCypherExample.js`

------

# Utilisation du protocole Bolt pour envoyer des requêtes openCypher à Neptune
<a name="access-graph-opencypher-bolt"></a>

[Bolt](https://boltprotocol.org/) [est un client/server protocole orienté instructions initialement développé par Neo4j et distribué sous licence Creative Commons 3.0 Attribution. ShareAlike](https://creativecommons.org/licenses/by-sa/3.0/) Il est axé sur le client, ce qui signifie que le client initie toujours les échanges de messages.

Pour vous connecter à Neptune à l'aide des pilotes Bolt de Neo4j, remplacez simplement l'URL et le numéro de port par les points de terminaison de votre cluster à l'aide du schéma d'URI `bolt`. Si vous n'avez qu'une seule instance Neptune en cours d'exécution, utilisez le point de terminaison read\$1write. Si plusieurs instances sont en cours d'exécution, deux pilotes sont recommandés, l'un pour l'enregistreur et l'autre pour tous les réplicas en lecture. Si vous ne disposez que des deux points de terminaison par défaut, un pilote read\$1write et un pilote read\$1only sont suffisants, mais si vous avez également des points de terminaison personnalisés, envisagez de créer une instance de pilote pour chacun d'eux.

**Note**  
Bien que la spécification Bolt indique que Bolt peut se connecter en utilisant TCP ou, WebSockets Neptune ne prend en charge que les connexions TCP pour Bolt.

Neptune autorise jusqu'à 1 000 connexions Bolt simultanées sur toutes les tailles d'instance, à l'exception de t3.medium et t4g.medium. Sur les instances t3.medium et t4g.medium, seules 512 connexions sont autorisées.

Pour obtenir des exemples de requêtes openCypher dans différents langages utilisant les pilotes Bolt, consultez les [guides spécifiques aux pilotes et aux langages](https://neo4j.com/developer/language-guides/) de Neo4j.

**Important**  
Les pilotes Neo4j Bolt pour Python JavaScript, .NET et Golang ne prenaient pas initialement en charge le renouvellement automatique des jetons d'authentification AWS Signature v4. Autrement dit, après l'expiration de la signature (souvent au bout de cinq minutes), le pilote ne parvenait pas à s'authentifier et les demandes suivantes échouaient. Les exemples Python JavaScript, .NET et Go ci-dessous étaient tous concernés par ce problème.  
Consultez le [numéro \$1834 du pilote Python Neo4j, le numéro](https://github.com/neo4j/neo4j-python-driver/issues/834) [\$1664 du pilote Neo4j .NET, le problème](https://github.com/neo4j/neo4j-dotnet-driver/issues/664) \$1993 du pilote [Neo4j et le numéro \$1429 JavaScript du pilote](https://github.com/neo4j/neo4j-javascript-driver/issues/993) [Neo4j](https://github.com/neo4j/neo4j-go-driver/issues/429) GoLang pour plus d'informations.  
À partir de la version 5.8.0 du pilote, une nouvelle version préliminaire de l'API de réauthentification a été publiée pour le pilote Go (voir [v5.8.0 - Feedback wanted on re-authentication](https://github.com/neo4j/neo4j-go-driver/discussions/482)).

## Utilisation de Bolt pour se connecter à Neptune
<a name="access-graph-opencypher-bolt-java"></a>

Vous pouvez télécharger un pilote pour la version que vous souhaitez utiliser à partir du [référentiel Maven MVN](https://mvnrepository.com/artifact/org.neo4j.driver/neo4j-java-driver), ou ajouter cette dépendance à votre projet :

```
<dependency>
  <groupId>org.neo4j.driver</groupId>
  <artifactId>neo4j-java-driver</artifactId>
  <version>4.3.3</version>
</dependency>
```

Ensuite, pour vous connecter à Neptune en Java à l'aide de l'un de ces pilotes Bolt, créez une instance de pilote pour l' primary/writer instance de votre cluster à l'aide d'un code tel que celui-ci :

```
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());
```

Si vous possédez un ou plusieurs réplicas de lecteurs, vous pouvez également créer une instance de pilote pour ceux-ci à l'aide d'un code similaire à ce qui suit :

```
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());
```

Ou, avec un délai d'expiration :

```
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());
```

Si vous avez des points de terminaison personnalisés, il peut également être intéressant de créer une instance de pilote pour chacun d'entre eux.

## Exemple de requête openCypher en Python avec Bolt
<a name="access-graph-opencypher-bolt-python"></a>

Voici comment créer une requête openCypher en Python avec Bolt :

```
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)
```

Notez que les paramètres `auth` sont ignorés.

## Exemple de requête openCypher dans NET avec Bolt
<a name="access-graph-opencypher-bolt-dotnet"></a>

Pour effectuer une requête OpenCypher dans .NET à l'aide de Bolt, la première étape consiste à installer le pilote Neo4j à l'aide de. NuHet Pour passer des appels synchrones, utilisez la version `.Simple` comme suit :

```
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();
      }
    }
  }
}
```

## Exemple de requête Java openCypher à l'aide de Bolt avec l'authentification IAM
<a name="access-graph-opencypher-bolt-java-iam-auth"></a>

Le code Java ci-dessous montre comment créer des requêtes openCypher en Java à l'aide de Bolt avec l'authentification IAM. Le JavaDoc commentaire décrit son utilisation. Une fois qu'une instance de pilote est disponible, vous pouvez l'utiliser pour effectuer plusieurs demandes authentifiées.

```
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);
  }
}
```

## Exemple de requête Python openCypher à l'aide de Bolt avec l'authentification IAM
<a name="access-graph-opencypher-bolt-python-iam-auth"></a>

La classe Python ci-dessous vous permet d'effectuer des requêtes openCypher en Python à l'aide de Bolt avec l'authentification IAM :

```
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)
```

Utilisez cette classe pour créer un pilote comme suit :

```
  authToken = NeptuneAuthToken(creds, REGION, URL)
  driver = GraphDatabase.driver(URL, auth=authToken, encrypted=True)
```

## Exemple Node.js utilisant l'authentification IAM et Bolt
<a name="access-graph-opencypher-bolt-nodejs-iam-auth"></a>

Le code Node.js ci-dessous utilise le AWS SDK de la JavaScript version 3 et la ES6 syntaxe pour créer un pilote qui authentifie les demandes :

```
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();
}
```

## Exemple de requête .NET openCypher à l'aide de Bolt avec l'authentification IAM
<a name="access-graph-opencypher-bolt-dotnet-iam-auth"></a>

Pour activer l'authentification IAM en .NET, vous devez signer une demande lors de l'établissement de la connexion. L'exemple ci-dessous montre comment créer un assistant `NeptuneAuthToken` pour générer un jeton d'authentification :

```
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);
    }
  }
}
```

Voici comment créer une requête openCypher en .NET à l'aide de Bolt avec l'authentification IAM. L'exemple ci-dessous utilise l'assistant `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);
      }
    }
  }
}
```

Cet exemple peut être lancé en exécutant le code ci-dessous sur `.NET 6` ou `.NET 7` avec les packages suivants :
+ **`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();
    }
  }
}
```

## Exemple de requête Golang openCypher à l'aide de Bolt avec l'authentification IAM
<a name="access-graph-opencypher-bolt-golang-iam-auth"></a>

Le package Golang ci-dessous montre comment effectuer des requêtes openCypher dans le langage Go à l'aide de Bolt avec l'authentification IAM :

```
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)
}
```

## Comportement des connexions Bolt dans Neptune
<a name="access-graph-opencypher-bolt-connections"></a>

Voici quelques éléments à garder à l'esprit concernant les connexions Neptune Bolt :
+ Comme les connexions Bolt sont créées au niveau de la couche TCP, vous ne pouvez pas utiliser un [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html) devant elles, comme c'est le cas avec un point de terminaison HTTP.
+ Le port que Neptune utilise pour les connexions Bolt est le port de votre cluster de bases de données.
+ Sur la base du préambule Bolt qui lui a été transmis, le serveur Neptune sélectionne la version Bolt la plus appropriée (1, 2, 3 ou 4.0).
+ Le nombre maximum de connexions au serveur Neptune qu'un client peut ouvrir à tout moment est de 1 000.
+ Si le client ne ferme pas la connexion après une requête, celle-ci peut être utilisée pour exécuter la requête suivante.
+ Toutefois, si une connexion est inactive pendant 20 minutes, le serveur la ferme automatiquement.
+ Si l'authentification IAM n'est pas activée, vous pouvez utiliser `AuthTokens.none()` au lieu de les fournir un nom d'utilisateur et un mot de passe factices. Par exemple, en Java :

  ```
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(),
      Config.builder().withEncryption().withTrustStrategy(TrustStrategy.trustSystemCertificates()).build());
  ```
+ Lorsque l'authentification IAM est activée, une connexion Bolt est toujours déconnectée quelques minutes de plus que 10 jours après son établissement si elle n'a pas déjà été fermée pour une autre raison.
+ Si le client envoie une requête à exécuter via une connexion sans avoir consommé les résultats d'une requête précédente, la nouvelle requête est supprimée. Pour ignorer les résultats précédents, le client doit envoyer un message de réinitialisation via la connexion.
+ Une seule transaction à la fois peut être créée sur une connexion donnée.
+ Si une exception se produit au cours d'une transaction, le serveur Neptune annule cette transaction et ferme la connexion. Dans ce cas, le pilote crée une autre connexion pour la prochaine requête.
+ Sachez que les sessions ne sont pas adaptées aux threads. Diverses opérations parallèles doivent utiliser diverses sessions distinctes.

# Exemples de requêtes paramétrées openCypher
<a name="opencypher-parameterized-queries"></a>

Neptune prend en charge les requêtes openCypher paramétrées. Vous pouvez ainsi utiliser la même structure de requête plusieurs fois avec des arguments différents. Comme la structure de la requête ne change pas, Neptune peut mettre en cache son arbre syntaxique abstrait (AST) au lieu d'avoir à l'analyser plusieurs fois.

## Exemple de requête paramétrée openCypher avec le point de terminaison HTTPS
<a name="opencypher-http-parameterized-queries"></a>

Vous trouverez ci-dessous un exemple d'utilisation d'une requête paramétrée avec le point de terminaison HTTPS Neptune openCypher. Voici cette requête :

```
MATCH (n {name: $name, age: $age})
RETURN n
```

Les paramètres sont définis, comme suit :

```
parameters={"name": "john", "age": 20}
```

Avec `GET`, vous pouvez soumettre la requête paramétrée comme suit :

```
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"
```

Vous pouvez également utiliser `POST` :

```
curl -k \
  https://localhost:8182/openCypher \
  -d "query=MATCH (n {name: \$name, age: \$age}) RETURN n" \
  -d "parameters={\"name\": \"john\", \"age\": 20}"
```

Ou, en utilisant `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"
```

## Exemples de requêtes paramétrées openCypher avec Bolt
<a name="opencypher-bolt-parameterized-queries"></a>

Voici un exemple Python d'une requête paramétrée openCypher avec le protocole Bolt :

```
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()
```

Voici un exemple Java d'une requête paramétrée openCypher avec le protocole Bolt :

```
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);
```

# Modèle de données openCypher
<a name="access-graph-opencypher-data-model"></a>

Le moteur Neptune openCypher s'appuie sur le même modèle de graphe de propriétés que Gremlin. En particulier :
+ Chaque nœud a une ou plusieurs étiquettes. Si vous insérez un nœud sans étiquette, une étiquette par défaut nommée `vertex` est attachée. Si vous essayez de supprimer toutes les étiquettes d'un nœud, une erreur est générée.
+ Une relation est une entité qui possède exactement un seul type de relation et qui forme une connexion unidirectionnelle entre deux nœuds (c'est-à-dire d'un nœud *source* à un nœud *cible*).
+ Les nœuds et les relations peuvent avoir des propriétés, mais ce n'est pas obligatoire. Neptune prend en charge les nœuds et les relations n'ayant aucune propriété.
+ Neptune ne prend pas en charge les métapropriétés, qui ne sont pas non plus incluses dans la spécification openCypher.
+ Les propriétés du graphe peuvent avoir plusieurs valeurs si elles ont été créées à l'aide de Gremlin. En d'autres termes, une propriété de nœud ou de relation peut avoir un ensemble de valeurs différentes plutôt qu'une seule. Neptune a étendu la sémantique d'openCypher pour gérer les propriétés à valeurs multiples sans problème.

Les types de données pris en charge sont documentés dans [Format de données openCypher](bulk-load-tutorial-format-opencypher.md). Cependant, pour le moment, nous ne recommandons pas d'insérer des valeurs de propriétés `Array` dans un graphe openCypher. Bien qu'il soit possible d'insérer une valeur de propriété de tableau à l'aide du chargeur en bloc, la version actuelle de Neptune openCypher la traite comme un ensemble de propriétés à valeurs multiples plutôt que comme une valeur de liste unique.

Vous trouverez ci-dessous la liste des types de données pris en charge dans cette version :
+ `Bool`
+ `Byte`
+ `Short`
+ `Int` 
+ `Long`
+ `Float` (inclut Infinity et NaN plus et moins, mais pas INF)
+ `Double` (inclut Infinity et NaN plus et moins, mais pas INF)
+ `DateTime` 
+ `String`

# Fonctionnalité openCypher `explain`
<a name="access-graph-opencypher-explain"></a>

La fonctionnalité `explain` openCypher est un outil en libre-service dans Amazon Neptune qui vous aide à comprendre l'approche d'exécution adoptée par le moteur Neptune. Pour invoquer explain, vous devez transmettre un paramètre à une requête [HTTPS](access-graph-opencypher-queries.md) openCypher avec `explain=mode`, où la valeur `mode` peut être l'une des suivantes :

****
+ **`static`** : en mode `static`, `explain` affiche uniquement la structure statique du plan de requête. Il n'exécute pas réellement la requête.
+ **`dynamic`** : en mode `dynamic`, `explain` exécute également la requête et inclut les aspects dynamiques du plan de requête. Ces aspects peuvent inclure le nombre de liaisons intermédiaires transitant via les opérateurs et le ratio de liaisons sortantes par rapport aux liaisons entrantes, ainsi que le temps total pris par chaque opérateur.
+ **`details`** : en mode `details`, `explain` imprime les informations affichées en mode dynamique, ainsi que des détails supplémentaires tels que la chaîne de requête openCypher réelle et le nombre de plages estimé pour le modèle sous-jacent d'un opérateur de jointure.

  

Par exemple, avec `POST` :

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n) RETURN n LIMIT 1;" \
  -d "explain=dynamic"
```

Ou, en utilisant `GET` :

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n)%20RETURN%20n%20LIMIT%201&explain=dynamic"
```

## Limites pour openCypher `explain` dans Neptune
<a name="access-graph-opencypher-explain-limitations"></a>

La version actuelle d'openCypher explain présente les limites suivantes :
+ Les plans explain ne sont actuellement disponibles que pour les requêtes qui effectuent des opérations en lecture seule. Les requêtes qui effectuent n'importe quel type de mutation, telles que `CREATE`, `DELETE`, `MERGE`, `SET` etc. ne sont pas prises en charge.
+ Les opérateurs et les résultats d'un plan spécifique peuvent changer dans les versions ultérieures.

## Opérateurs DFE dans la sortie openCypher `explain`
<a name="access-graph-opencypher-dfe-operators"></a>

Pour utiliser les informations fournies par la fonctionnalité openCypher `explain`, vous devez comprendre certains détails sur le fonctionnement du [moteur de requêtes DFE](neptune-dfe-engine.md) (le DFE est le moteur utilisé par Neptune pour traiter les requêtes openCypher).

Le moteur DFE convertit chaque requête en un pipeline d'opérateurs. À partir du premier opérateur, des solutions intermédiaires circulent d'un opérateur au suivant dans ce pipeline d'opérateurs. Chaque ligne de la table explain représente un résultat, jusqu'au point d'évaluation.

Les opérateurs qui peuvent apparaître dans un plan de requête DFE sont les suivants :

**DFEApply**— Exécute la fonction spécifiée dans la section des arguments, sur la valeur stockée dans la variable spécifiée

**DFEBindRelation** — Lie les variables portant les noms spécifiés

**DFEChunkLocalSubQuery**— Il s'agit d'une opération non bloquante qui enveloppe les sous-requêtes en cours d'exécution.

**DFEDistinctColonne** — Renvoie le sous-ensemble distinct des valeurs d'entrée en fonction de la variable spécifiée.

**DFEDistinctRelation** — Renvoie le sous-ensemble distinct des solutions d'entrée en fonction de la variable spécifiée.

**DFEDrain**— Apparaît à la fin d'une sous-requête pour agir comme étape de fin pour cette sous-requête. Le nombre de solutions est enregistré en tant qu'`Units In`. `Units Out` est toujours égal à zéro.

**DFEForwardValeur** — Copie tous les segments d'entrée directement en tant que fragments de sortie à transmettre à son opérateur en aval.

**DFEGroupByHashIndex**— Effectue une opération de regroupement sur les solutions d'entrée en fonction d'un indice de hachage précédemment calculé (à l'aide de l'`DFEHashIndexBuild`opération). En tant que sortie, l’entrée donnée est prolongée par une colonne contenant une clé de groupe pour chaque solution d’entrée.

**DFEHashIndexBuild**— Construit un index de hachage sur un ensemble de variables comme effet secondaire. Cet indice de hachage est généralement réutilisé dans les opérations ultérieures. Consultez `DFEHashIndexJoin` ou `DFEGroupByHashIndex` pour savoir où cet index de hachage peut être utilisé.

**DFEHashIndexJoin**— Effectue une jointure entre les solutions entrantes par rapport à un index de hachage créé précédemment. Consultez `DFEHashIndexBuild` pour savoir où cet index de hachage peut être créé.

**DFEJoinExiste** — Prend une relation d'entrée gauche et droite et conserve les valeurs de la relation de gauche qui ont une valeur correspondante dans la relation de droite telle que définie par les variables de jointure données. 

**** : opération non bloquante qui agit comme un wrapper pour une sous-requête, ce qui permet de l’exécuter à plusieurs reprises pour une utilisation en boucle.

**DFEMergeFragments** : il s'agit d'une opération de blocage qui combine des segments provenant de son opérateur en amont en un seul bloc de solutions à transmettre à son opérateur en aval (inverse de). `DFESplitChunks`

**DFEMinus**— Prend une relation d'entrée gauche et droite et conserve les valeurs de la relation de gauche qui n'ont pas de valeur correspondante dans la relation de droite telle que définie par les variables de jointure données. S’il n’y a aucun chevauchement entre les variables des deux relations, cet opérateur renvoie simplement une relation vide.

**DFENotExiste** — Prend une relation d'entrée gauche et droite et conserve les valeurs de la relation de gauche qui n'ont pas de valeur correspondante dans la relation de droite telle que définie par les variables de jointure données. S’il n’y a aucun chevauchement entre les variables des deux relations, cet opérateur renvoie une relation vide.

**DFEOptionalJointure** — Effectue une jointure externe gauche (également appelée jointure FACULTATIVE) : les solutions du côté gauche qui ont au moins un partenaire de jointure sur le côté droit sont jointes, et les solutions du côté gauche sans partenaire de liaison sur le côté droit sont transmises telles quelles. Il s'agit d'une opération de blocage.

**DFEPipelineJoindre — Joint** l'entrée au modèle de tuple défini par l'`pattern`argument.

**DFEPipelineRangeCount**— Compte le nombre de solutions correspondant à un modèle donné et renvoie une seule solution uniaire contenant la valeur du comptage.

**DFEPipelineScan** — Analyse la base de données à la recherche de l'`pattern`argument donné, avec ou sans filtre donné sur les colonnes.

**DFEProject**— Prend plusieurs colonnes de saisie et ne projette que les colonnes souhaitées.

**DFEReduce**— Exécute la fonction d'agrégation spécifiée sur les variables spécifiées.

**DFERelationalJoindre — Joint** l'entrée de l'opérateur précédent en fonction des clés de modèle spécifiées à l'aide d'une jointure par fusion. Il s'agit d'une opération de blocage.

**DFERouteFragments** : prend des morceaux d'entrée depuis son bord entrant unique et achemine ces morceaux le long de ses multiples arêtes sortantes.

**DFESelectLignes** — Cet opérateur prend de manière sélective les lignes de ses solutions de relation d'entrée de gauche pour les transmettre à son opérateur en aval. Les lignes sont sélectionnées en fonction des identifiants de ligne fournis dans la relation d’entrée appropriée de l’opérateur.

**DFESerialize**— Sérialise les résultats finaux d'une requête dans une chaîne de caractères JSON, en mappant chaque solution d'entrée au nom de variable approprié. Pour les résultats relatifs aux nœuds et aux périphéries, ces résultats sont sérialisés dans une carte des propriétés et des métadonnées des entités.

**DFESort**— Prend une relation d'entrée et produit une relation triée en fonction de la clé de tri fournie.

**DFESplitByGroup**— Divise chaque segment d'entrée d'un bord entrant en petits morceaux de sortie correspondant aux groupes de lignes identifiés par ligne à IDs partir du segment d'entrée correspondant de l'autre bord entrant.

**DFESplitMorceaux** — Divise chaque segment d'entrée en morceaux de sortie plus petits (inverse de). `DFEMergeChunks`

**DFEStreamingHashIndexBuild**— Version en streaming de`DFEHashIndexBuild`.

**DFEStreamingGroupByHashIndex**— Version en streaming de`DFEGroupByHashIndex`.

**DFESubquery**— Cet opérateur apparaît au début de tous les plans et encapsule les parties du plan exécutées sur le [moteur DFE](neptune-dfe-engine.md), qui est le plan complet pour OpenCypher.

**DFESymmetricHashJoin**— Joint l'entrée de l'opérateur précédent en fonction des clés de modèle spécifiées à l'aide d'une jointure par hachage. Il s'agit d'une opération non bloquante.

**DFESync**— Cet opérateur est un opérateur de synchronisation prenant en charge les plans non bloquants. Il prend des solutions provenant de deux périphéries entrantes et les transmet aux périphéries aval appropriées. À des fins de synchronisation, les entrées situées le long de l’un de ces périphéries peuvent être mises en mémoire tampon en interne. 

**DFETee**— Il s'agit d'un opérateur de branchement qui envoie le même ensemble de solutions à plusieurs opérateurs.

**DFETermRésolution** — Effectue une opération de localisation ou de globalisation sur ses entrées, ce qui génère des colonnes d'identifiants localisés ou globalisés respectivement.

**** : déplie les listes de valeurs d’une colonne d’entrée dans la colonne de sortie sous forme d’éléments individuels.

**DFEUnion**— Prend au moins deux relations d'entrée et produit une union de ces relations en utilisant le schéma de sortie souhaité.

**SolutionInjection**— Apparaît avant tout le reste dans la sortie d'explication, avec une valeur de 1 dans la colonne Unités sorties. Cependant, il dessert une déclaration no-op et n’injecte aucune solution dans le moteur DFE.

**TermResolution**— Apparaît à la fin des plans et traduit les objets du moteur Neptune en objets OpenCypher.

## Colonnes de la sortie openCypher `explain`
<a name="access-graph-opencypher-explain-columns"></a>

Les informations du plan de requête que Neptune génère sous forme de sortie openCypher explain contiennent des tables avec un opérateur par ligne. Cette table possède les colonnes suivantes :

**ID** : identifiant numérique de cet opérateur dans le plan.

**Out \$11** (et **Out \$12**) : identifiant(s) des opérateur(s) qui se trouvent en aval de cet opérateur. Il peut y avoir au plus deux opérateurs en aval.

**Nom** : nom de cet opérateur.

**Arguments** : tous les détails pertinents concernant l'opérateur. Cela inclut des éléments tels que le schéma d'entrée, le schéma de sortie, le modèle (pour `PipelineScan` et `PipelineJoin`), etc.

**Mode** : étiquette décrivant le comportement fondamental de l'opérateur. Cette colonne est généralement vide (`-`). Une exception est `TermResolution`, où le mode peut être`id2value_opencypher`, indiquant une résolution entre l'ID et la valeur openCypher.

**Unités en entrée** : nombre de solutions transmises en entrée à cet opérateur. Les opérateurs sans opérateurs en amont, tels que `DFEPipelineScan`, `SolutionInjections` et `DFESubquery` sans valeur statique injectée, ont une valeur nulle.

**Unités en sortie** : nombre de solutions générées en sortie par cet opérateur. `DFEDrain` est un cas particulier, où le nombre de solutions drainées est enregistré dans `Units In`, et `Units Out` est toujours égal à zéro.

**Ratio** : ratio entre les éléments `Units Out` et `Units In`.

**Temps (ms)** : temps CPU consommé par cet opérateur, en millisecondes.

## Exemple de base de la sortie openCypher explain
<a name="access-graph-opencypher-explain-basic-example"></a>

Vous trouverez ci-dessous un exemple de base de la sortie openCypher `explain`. La requête est une recherche à nœud unique dans le jeu de données des routes aériennes pour un nœud dont le code d'aéroport `ATL` invoque `explain` avec le mode `details` au format de sortie ASCII par défaut :

```
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      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

Au niveau supérieur, `SolutionInjection` apparaît avant tout le reste, avec une unité en sortie. Notez qu'il n'injecte aucune solution. Vous pouvez voir que l'opérateur suivant, `DFESubquery`, n'a aucune unité en entrée.

Après `SolutionInjection` au niveau supérieur, figurent les opérateurs `DFESubquery` et `TermResolution`. `DFESubquery` encapsule les parties du plan d'exécution des requêtes qui sont transmises au [moteur DFE](neptune-dfe-engine.md) (pour les requêtes openCypher, le plan de requête complet est exécuté par le DFE). Tous les opérateurs du plan de requête sont imbriqués dans `subQuery1` qui est référencé par `DFESubquery`. La seule exception est celle qui `TermResolution` se matérialise en objets IDs OpenCypher entièrement sérialisés en interne.

Tous les opérateurs redirigés vers le moteur DFE ont des noms qui commencent par un préfixe `DFE`. Comme mentionné ci-dessus, l'ensemble du plan de requête openCypher est exécuté par le DFE. Par conséquent, tous les opérateurs, à l'exception de l'opérateur `TermResolution` final, commencent par `DFE`.

Dans `subQuery1`, il peut y avoir zéro opérateur `DFEChunkLocalSubQuery` ou `DFELoopSubQuery` ou plus encapsulant une partie du plan d'exécution transmis qui est exécuté dans un mécanisme limité à la mémoire. `DFEChunkLocalSubQuery` contient ici un seul élément `SolutionInjection` qui est utilisé comme entrée pour la sous-requête. Pour trouver la table correspondant à cette sous-requête dans la sortie, recherchez l'`subQuery=graph URI` spécifié dans la colonne `Arguments` pour l'opérateur `DFEChunkLocalSubQuery` ou `DFELoopSubQuery`.

Dans `subQuery1`, `DFEPipelineScan` avec l'`ID` 0 analyse la base de données à la recherche d'un modèle (`pattern`) spécifié. Le modèle recherche une entité dont la propriété `code` est enregistrée sous forme de variable `?n_code2` sur toutes les étiquettes (vous pouvez filtrer une étiquette spécifique en ajoutant `airport` à `n:airport`). L'argument `inlineFilters` indique que le filtrage de la propriété `code` est égal à `ATL`.

Ensuite, l'opérateur `DFEChunkLocalSubQuery` joint les résultats intermédiaires d'une sous-requête contenant `DFEPipelineJoin`. Cela garantit que `?n` est bien un nœud, puisque le l'opération `DFEPipelineScan` précédente analyse toute entité possédant la propriété `code`.

# Exemple de sortie `explain` pour une recherche de relation avec une limite
<a name="access-graph-opencypher-explain-example-2"></a>

Cette requête recherche les relations entre deux nœuds anonymes de type `route` et en renvoie au maximum 10. Encore une fois, le mode `explain` est `details`, et le format ASCII est le format de sortie par défaut. Voici la sortie `explain` :

Ici, `DFEPipelineScan` recherche les arêtes qui commencent par un nœud anonyme `?anon_node7` et se terminent par un autre nœud anonyme `?anon_node21`, avec un type de relation enregistré sous la forme `?p_type1`. Il existe un filtre pour les éléments `?p_type1` qui correspondent à `el://route` (où `el` désigne l'étiquette d'une arête), ce qui équivaut à `[p:route]` dans la chaîne de requête.

`DFEDrain` collecte la solution de sortie avec une limite de 10, comme indiqué dans sa colonne `Arguments`. `DFEDrain` prend fin une fois que la limite est atteinte ou que toutes les solutions sont générées, selon la situation qui survient en premier.

```
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      ║
╚════╧════════╧════════╧═════════════════╧═══════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Exemple de sortie `explain` pour une fonction d'expression de valeur
<a name="access-graph-opencypher-explain-example-3"></a>

La fonction est :

```
MATCH (a) RETURN DISTINCT labels(a)
```

Dans la sortie `explain` ci-dessous, `DFEPipelineScan` (ID 0) recherche toutes les étiquettes des nœuds. Cela correspond à `MATCH (a`.

`DFEChunkLocalSubquery` (ID 1) agrège l'étiquette de `?a` pour chaque `?a`. Cela correspond à `labels(a)`. Vous pouvez le voir via `DFEApply` et `DFEReduce`.

`BindRelation` (ID 2) est utilisé pour remplacer le nom de la valeur générique de colonne `?__gen_labelsOfa2` par `?labels(a)`.

`DFEDistinctRelation` (ID 4) récupère uniquement les étiquettes distinctes (plusieurs nœuds :airport donneraient des étiquettes (a): ["airport"] dupliquées). Cela correspond à `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      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Exemple de sortie `explain` pour une fonction d'expression de valeur mathématique
<a name="access-graph-opencypher-explain-example-4"></a>

Dans cet exemple, `RETURN abs(-10)` effectue une évaluation simple en prenant la valeur absolue d'une constante, `-10`.

`DFEChunkLocalSubQuery` (ID 1) effectue une injection de solution pour la valeur statique `-10`, qui est stockée dans la variable `?100`.

`DFEApply` (ID 2) est l'opérateur qui exécute la fonction de valeur absolue `abs()` au niveau de la valeur statique stockée dans la variable `?100`.

Voici la requête et la sortie `explain` obtenue :

```
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      ║
╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Exemple de sortie `explain` pour une requête de chemin de longueur variable (VLP)
<a name="access-graph-opencypher-explain-example-5"></a>

Il s'agit d'un exemple de plan de requête plus complexe pour gérer une requête de chemin de longueur variable. Pour plus de clarté, cet exemple ne montre qu'une partie de la sortie `explain`.

Dans `subQuery1`, `DFEPipelineScan` (ID 0) et `DFEChunkLocalSubQuery` (ID 1), qui injectent la sous-requête `...graph_1`, sont chargés de rechercher un nœud contenant le code `YPO`.

Dans `subQuery1`, `DFEChunkLocalSubQuery` (ID 2), qui injecte la sous-requête `...graph_2`, est chargé de rechercher un nœud contenant le code `LAX`.

Dans`subQuery1`, `DFEChunkLocalSubQuery` (ID 3) injecte la sous-requête `...graph3`, qui contient `DFELoopSubQuery` (ID 17), qui à son tour injecte la sous-requête `...graph5`. Cette opération est chargée de résoudre le modèle de longueur variable `-[*2]->` dans la chaîne de requête entre deux nœuds.

```
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      ║
...
```

# Transactions dans Neptune openCypher
<a name="access-graph-opencypher-transactions"></a>

L'implémentation openCypher dans Amazon Neptune utilise la [sémantique des transactions définie par Neptune](transactions-neptune.md). Cependant, les niveaux d'isolement fournis par le pilote Bolt ont des implications spécifiques sur la sémantique des transactions Bolt, comme décrit dans les sections ci-dessous.

## Requêtes de transaction Bolt en lecture seule
<a name="access-graph-opencypher-transactions-ro"></a>

Les requêtes en lecture seule peuvent être traitées de différentes manières, avec différents modèles de transaction et niveaux d'isolement, comme suit :

### Requêtes de transaction implicites en lecture seule
<a name="access-graph-opencypher-transactions-ro-implicit"></a>

Voici un exemple de transaction implicite en lecture seule :

```
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();
}
```

Comme les réplicas en lecture n'acceptent que les requêtes en lecture seule, toutes les requêtes portant sur ces réplicas s'exécutent sous forme de transactions implicites en lecture, quel que soit le mode d'accès défini dans la configuration de session. Neptune évalue les transactions implicites en lecture comme des [requêtes en lecture seule](transactions-neptune.md#transactions-neptune-read-only) selon la sémantique d'isolement `SNAPSHOT`.

En cas d'échec, les transactions implicites en lecture font par défaut l'objet d'une nouvelle tentative.

### Requêtes de transaction de validation automatique en lecture seule
<a name="access-graph-opencypher-transactions-ro-autocommit"></a>

Voici un exemple de transaction de validation automatique en lecture seule :

```
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();
}
```

Si le mode d'accès est défini sur `READ` dans la configuration de session, Neptune évalue les requêtes de transaction de validation automatique comme des [requêtes en lecture seule](transactions-neptune.md#transactions-neptune-read-only) selon une sémantique d'isolement `SNAPSHOT`. Notez que les réplicas en lecture n'acceptent que les requêtes en lecture seule.

Si vous ne transmettez pas de configuration de session, les requêtes de validation automatique sont traitées par défaut avec un isolement des requêtes de mutation. Il est donc important de transmettre une configuration de session qui définit explicitement le mode d'accès sur `READ`.

En cas d'échec, les requêtes de validation automatique en lecture seule ne font pas l'objet d'une nouvelle tentative.

### Requêtes de transaction explicites en lecture seule
<a name="access-graph-opencypher-transactions-ro-explicit"></a>

Voici un exemple de transaction explicite en lecture seule :

```
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();
}
```

Si le mode d'accès est défini sur `READ` dans la configuration de session, Neptune évalue les transactions explicites en lecture seule comme des [requêtes en lecture seule](transactions-neptune.md#transactions-neptune-read-only) selon une sémantique d'isolement `SNAPSHOT`. Notez que les réplicas en lecture n'acceptent que les requêtes en lecture seule.

Si vous ne transmettez pas de configuration de session, les transactions explicites en lecture seule sont traitées par défaut avec un isolement des requêtes de mutation. Il est donc important de transmettre une configuration de session qui définit explicitement le mode d'accès sur `READ`.

En cas d'échec, les requêtes explicites en lecture seule font par défaut l'objet d'une nouvelle tentative.

## Requêtes de transaction de mutation Bolt
<a name="access-graph-opencypher-transactions-wr"></a>

Comme pour les requêtes en lecture seule, les requêtes de mutation peuvent être traitées de différentes manières, avec différents modèles de transaction et niveaux d'isolement, comme suit :

### Requêtes de transaction de mutation implicites
<a name="access-graph-opencypher-transactions-wr-implicit"></a>

Voici un exemple de transaction de mutation implicite :

```
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();
}
```

Les lectures effectuées dans le cadre des requêtes de mutation sont exécutées avec un isolement `READ COMMITTED` avec les garanties habituelles applicables aux [transactions de mutation Neptune](transactions-neptune.md#transactions-neptune-mutation).

Que vous transmettiez spécifiquement ou non une configuration de session, la transaction est toujours traitée comme une transaction d'écriture.

Pour les conflits, voir [Résolution des conflits à l'aide de délais d'attente de verrouillage](transactions-neptune.md#transactions-neptune-conflicts).

### Requêtes de transaction de mutation à validation automatique
<a name="access-graph-opencypher-transactions-wr-autocommit"></a>

Les requêtes de validation automatique des mutations héritent du même comportement que les transactions implicites de mutation.

Si vous ne transmettez pas de configuration de session, la transaction est traitée comme une transaction d'écriture par défaut.

En cas d'échec, les requêtes de validation automatique des mutations ne font pas automatiquement l'objet de nouvelles tentatives.

### Requêtes de transaction de mutation explicites
<a name="access-graph-opencypher-transactions-wr-explicit"></a>

Voici un exemple de transaction de mutation explicite :

```
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();
}
```

Les requêtes de mutation explicites héritent du même comportement que les transactions de mutation implicites.

Si vous ne transmettez pas de configuration de session, la transaction est traitée comme une transaction d'écriture par défaut.

Pour les conflits, voir [Résolution des conflits à l'aide de délais d'attente de verrouillage](transactions-neptune.md#transactions-neptune-conflicts).

# Conseils de requête OpenCypher
<a name="opencypher-query-hints"></a>

**Important**  
 L'indice de requête OpenCypher n'est disponible qu'à partir des versions [1.3.2.0](https://docs.aws.amazon.com//neptune/latest/userguide/engine-releases-1.3.2.0.html) et ultérieures du moteur. 

 Dans Amazon Neptune, vous pouvez utiliser la `USING` clause pour spécifier des indices de requête pour les requêtes OpenCypher. Ces conseils vous permettent de contrôler les stratégies d'optimisation et d'évaluation. 

 La syntaxe des indices de requête est la suivante : 

```
USING {scope}:{hint} {value}
```

1.  `{scope}`définit la portée dans laquelle l'indice s'applique à : `Query` ou`Clause`. 

    Une valeur de portée égale à `Query` signifie que l'indice de requête s'applique à l'ensemble de la requête (au niveau de la requête). 

    Une valeur de portée égale à `Clause` signifie que l'indice de requête s'applique à la clause qu'il précède (au niveau de la clause). 

1.  `{hint}`est le nom de l'indice de requête appliqué. 

1.  `{value}`est l'argument en faveur du`{hint}`. 

 Les valeurs peuvent ne pas faire la distinction majuscules/majuscules. 

 Par exemple, pour activer le cache du plan de requête pour une requête : 

```
Using QUERY:PLANCACHE "enabled" 
MATCH (a:Person {firstName: "Erin", lastName: $lastName})
 RETURN a
```

**Note**  
 **Actuellement, les indications de **requête Query** Scope **PLANCACHE**, **TIMEOUTMILLISECONDS** et Types sont prises en charge. assumeConsistentData** Les conseils de requête pris en charge sont répertoriés ci-dessous. 

**Topics**
+ [Conseil de cache du plan de requête OpenCypher](opencypher-query-hints-qpc-hint.md)
+ [AssumeConsistentDataTypes indice](opencypher-query-hints-AssumeConsistentDataTypes.md)
+ [Indication du délai d'expiration de la requête OpenCypher](opencypher-query-hints-timeout-hint.md)

# Conseil de cache du plan de requête OpenCypher
<a name="opencypher-query-hints-qpc-hint"></a>

 Le comportement du cache du plan de requête peut être modifié par requête (paramétrée ou non) par un indice de requête au niveau de la requête. `QUERY:PLANCACHE` Il doit être utilisé avec la `USING` clause. L'indice de requête accepte `enabled` ou `disabled` en tant que valeur. Pour plus d'informations sur le cache du plan de requête, consultez[Cache du plan de requête dans 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 indice
<a name="opencypher-query-hints-AssumeConsistentDataTypes"></a>

 OpenCypher suit un paradigme dans lequel les correspondances de types de données numériques (par exemple, int, octet, short, long, etc.) sont effectuées selon une sémantique de promotion de type. Par exemple, lorsque vous recherchez toutes les propriétés avec une valeur d'entrée 10 avec un type court, sous sémantique de promotion de type, cela correspond également aux propriétés dont la valeur longue est 10. Dans certains cas, le changement de type peut entraîner une surcharge et entraîner des plans de requêtes moins efficaces qu'ils ne le seraient si aucun changement de type n'était effectué. En particulier dans les cas où les types de données sont utilisés de manière cohérente dans les données (par exemple, si l'âge de toutes les personnes est stocké sous forme de valeur longue), l'exécution de promotions de type entraîne une surcharge sans impact sur le résultat de la requête. 

 Pour permettre l'optimisation dans les cas où l'on sait que les valeurs des données de propriétés numériques stockées dans la base de données sont de type cohérent, un indice de requête appelé `assumeConsistentDataTypes` (avec valeur`true/false`, la valeur par défaut étant`false`) peut être utilisé. Lorsque cet indice de requête est fourni avec une valeur égale à`true`, le moteur suppose que les seules valeurs de propriété sont toujours longues ou doubles et ignore la sémantique de promotion du type. Les valeurs numériques spécifiées dans la requête sont considérées comme des valeurs longues (pour les valeurs non flottantes) ou comme des valeurs doubles (pour les valeurs à virgule flottante). 

 Si les données utilisent systématiquement un seul type de données (par exemple, tous les âges sont stockés sous forme`long`), l'utilisation de cet `assumeConsistentDataTypes` indice peut optimiser la requête en évitant les vérifications d'égalité inutiles pour les différents types numériques. Toutefois, si les données présentent des types de données incohérents pour la même propriété, l'utilisation de l'indice peut entraîner l'absence de certains résultats, car la requête ne correspondra qu'au seul type de données supposé par l'indice. 

```
# 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.
```

 La différence peut également être validée via l'explication. 

 Sans l'explication : 

```
# 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
```

 Avec l'indice : 

```
# 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
```

# Indication du délai d'expiration de la requête OpenCypher
<a name="opencypher-query-hints-timeout-hint"></a>

 Le comportement du délai d'expiration des requêtes peut être configuré par requête à l'aide d'un indice de requête au niveau de la requête. `QUERY:TIMEOUTMILLISECONDS` Il doit être utilisé avec la `USING` clause. L'indice de requête accepte une valeur longue non négative comme valeur. 

```
# Using query-level timeout hint 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 100 MATCH(n) RETURN n LIMIT 1"
```

 Le comportement de temporisation des requêtes prendra en compte le minimum du délai d'expiration au niveau du cluster et du délai d'expiration au niveau de la requête. Consultez les exemples ci-dessous pour comprendre le comportement d'expiration des requêtes. [Pour plus d'informations sur le délai d'expiration des requêtes au niveau du cluster, consultez 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"
```

# Limites Neptune openCypher
<a name="access-graph-opencypher-limitations"></a>

La version Amazon Neptune d'openCypher ne prend toujours pas en charge tout ce qui est spécifié dans la [version 9 de Cypher Query Language Reference](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf), comme indiqué dans [Conformité aux spécifications OpenCypher](feature-opencypher-compliance.md). Les prochaines versions devraient remédier à un grand nombre de ces limitations.

# Exceptions Neptune openCypher
<a name="access-graph-opencypher-exceptions"></a>

Lorsque vous utilisez openCypher sur Amazon Neptune, diverses exceptions peuvent se produire. Vous trouverez ci-dessous les exceptions courantes que vous pouvez recevoir à partir du point de terminaison HTTPS ou du pilote Bolt (toutes les exceptions du pilote Bolt sont signalées comme des exceptions d'état du serveur) :


| Code HTTP | Message d’erreur | Nouvelle tentative possible ? | Solution | 
| --- | --- | --- | --- | 
| 400 | *(erreur de syntaxe, propagée directement depuis l'analyseur openCypher)* | Non | Corrigez la syntaxe de la requête, puis réessayez. | 
| 500 | `Operation terminated (out of memory)` | Oui | Retravaillez la requête pour ajouter des critères de filtrage supplémentaires afin de réduire la mémoire requise. | 
| 500 | Opération suspendue (délai dépassé) | Oui | Augmentez le délai d'expiration de la requête dans le groupe de paramètres du cluster de bases de données ou [effectuez une nouvelle tentative](https://docs.aws.amazon.com/general/latest/gr/api-retries.html). | 
| 500 | Opération suspendue (annulée par l'utilisateur) | Oui | Réitérez la demande. | 
| 500 | La réinitialisation de la base de données est en cours. Réessayez la requête une fois que le cluster sera disponible. | Oui | Réessayez une fois la réinitialisation terminée. | 
| 500 | L'opération a échoué en raison d'opérations simultanées contradictoires (veuillez réessayer). Les transactions sont en cours d'annulation. | Oui | Réessayez en utilisant une [stratégie de backoff exponentiel et de nouvelle tentative](best-practices-opencypher-retry-logic.md). | 
| 400 | *(operation name)* operation/feature Exception non prise en charge | Non | L’opération spécifiée n’est pas prise en charge. | 
| 400 | Tentative de mise à jour d'openCypher sur un réplica en lecture seule | Non | Remplacez le point de terminaison cible par le point de terminaison de l'enregistreur. | 
| 400 | MalformedQueryException (Neptune n'affiche pas l'état interne de l'analyseur) | Non | Corrigez la syntaxe de la requête, puis réessayez. | 
| 400 | Impossible de supprimer le nœud, car il possède toujours des relations. Pour supprimer ce nœud, vous devez d'abord supprimer ses relations. | Non | Au lieu de `MATCH (n) DELETE n`, utilisez `MATCH(n) DETACH DELETE(n)` | 
| 400 | Opération non valide : tentative de suppression de la dernière étiquette d'un nœud. Un nœud doit avoir au moins une étiquette. | Non | Neptune exige que tous les nœuds aient au moins une étiquette, et si des nœuds sont créés sans étiquette explicite, une étiquette par défaut `vertex` est attribuée. Modifiez la logique de and/or l'application de requête afin de ne pas supprimer le dernier libellé. L’étiquette singleton d’un nœud peut être mise à jour en définissant une nouvelle étiquette, puis en supprimant l’ancienne étiquette. | 
| 500 | Nombre maximum de demandes dépassées, ConfiguredQueueCapacity = \$1\$1 pour ConnID = \$1\$1 | Oui | Actuellement, seules 8 192 demandes simultanées peuvent être traitées, quels que soient la pile et le protocole. | 
| 500 | Nombre maximal de connexions dépassé. | Oui | Seules 1 000 connexions Bolt simultanées par instance sont autorisées (pour le protocole HTTP, il n'y a pas de limite). | 
| 400 | [Nœud, relation ou chemin] attendu et obtention d'un littéral | Non | Vérifiez que vous transmettez le ou les arguments corrects, que la syntaxe de la requête est exacte, puis réessayez. | 
| 400 | La valeur de la propriété doit être un littéral simple. Ou : mappage attendu pour les propriétés de l'ensemble, mais mappage introuvable. | Non | Une clause SET n'accepte que les littéraux simples, et non les types composites. | 
| 400 | L'entité transmise pour la suppression est introuvable | Non | Vérifiez que l'entité que vous essayez de supprimer se trouve bien dans la base de données.  | 
| 400 | L'utilisateur n'a pas accès à la base de données. | Non | Vérifiez la politique relative au rôle IAM utilisé. | 
| 400 | Aucun jeton n'est transmis dans le cadre de la demande | Non | Un jeton correctement signé doit être transmis dans le cadre de la demande de requête sur un cluster compatible IAM. | 
| 400 | Le message d'erreur est propagé. | Non | Contactez le AWS Support à l'aide de l'ID de demande. | 
| 500 | Opération suspendue (erreur interne) | Oui | Contactez le AWS Support à l'aide de l'ID de demande. | 

# Extensions OpenCypher dans Amazon Neptune
<a name="access-graph-opencypher-extensions"></a>

 Amazon Neptune prend en charge la version 9 de référence de la spécification OpenCypher. Reportez-vous [Conformité aux spécifications OpenCypher dans Amazon Neptune](feature-opencypher-compliance.md) à Amazon Neptune pour plus de détails. En outre, Amazon Neptune prend en charge les fonctionnalités répertoriées ici. À moins que des versions spécifiques ne soient mentionnées, les fonctionnalités sont disponibles dans Neptune Database et Neptune Analytics. 

## Accès aux données S3 au moment de la requête
<a name="opencypher-compliance-neptune-read"></a>

Disponible dans Neptune Database 1.4.7.0 et versions ultérieures.

Neptune prend en charge la `neptune.read()` fonction permettant de lire les données CSV ou Parquet d'Amazon S3 directement dans les requêtes OpenCypher. Contrairement au chargeur groupé qui importe les données avant de les interroger, il `neptune.read()` accède aux données Amazon S3 au moment de l'exécution de la requête.

Pour une documentation complète, voir[neptune.read ()](access-graph-opencypher-21-extensions-s3-read.md).

## Fonction `join()` spécifique à Neptune
<a name="opencypher-compliance-join-function"></a>

Disponible dans Neptune Database et Neptune Analytics.

Neptune implémente une fonction `join()` qui ne se trouve pas dans la spécification openCypher. Cela crée un littéral de chaîne à partir d'une liste de littéraux de chaîne et d'un délimiteur de chaîne. Deux arguments sont donc utilisés :
+ Le premier argument est une liste de littéraux de chaîne.
+ Le deuxième argument est le délimiteur de chaîne, qui peut avoir un, aucune ou plusieurs caractères.

Exemple :

```
join(["abc", "def", "ghi"], ", ")    // Returns "abc, def, ghi"
```

## Fonction `removeKeyFromMap()` spécifique à Neptune
<a name="opencypher-compliance-removeKeyFromMap-function"></a>

Disponible dans Neptune Database et Neptune Analytics.

Neptune implémente une fonction `removeKeyFromMap()` qui ne se trouve pas dans la spécification openCypher. Il supprime une clé spécifiée dans un mappage et renvoie le nouveau mappage généré.

La fonction accepte deux arguments :
+ Le premier argument est le mappage à partir duquel la clé doit être supprimée.
+ Le premier argument est la clé à supprimer du mappage.

Cette fonction `removeKeyFromMap()` est particulièrement utile dans les situations où vous souhaitez définir les valeurs d'un nœud ou d'une relation en déroulant une liste de mappage. Par exemple :

```
UNWIND [{`~id`: 'id1', name: 'john'}, {`~id`: 'id2', name: 'jim'}] as val
CREATE (n {`~id`: val.`~id`})
SET n = removeKeyFromMap(val, '~id')
```

## Valeurs d'ID personnalisées pour les propriétés des nœuds et des relations
<a name="opencypher-compliance-custom-ids"></a>

Disponible dans Neptune Database 1.2.0.2 et versions ultérieures, et dans Neptune Analytics.

À partir de la [version 1.2.0.2 du moteur](engine-releases-1.2.0.2.md), Neptune a étendu la spécification openCypher afin que vous puissiez désormais spécifier les valeurs `id` des nœuds et des relations dans les clauses `CREATE`, `MERGE` et `MATCH`. Cela vous permet d'attribuer des chaînes conviviales plutôt que des chaînes générées par le système UUIDs pour identifier les nœuds et les relations.

Dans Neptune Analytics, les valeurs d'identification personnalisées ne sont pas disponibles pour les bords.

**Avertissement**  
Cette extension de la spécification openCypher est rétrocompatible, car `~id` est désormais considéré comme un nom de propriété réservé. Si vous l'utilisez déjà `~id` en tant que propriété dans vos données et requêtes, vous devez migrer la propriété existante vers une nouvelle clé de propriété et supprimer l'ancienne. Consultez [Que faire si vous utilisez actuellement `~id` en tant que propriété](#opencypher-compliance-custom-ids-migrating).

Voici un exemple montrant comment créer des nœuds et des relations dotés d'ID personnalisés :

```
CREATE (n {`~id`: 'fromNode', name: 'john'})
  -[:knows {`~id`: 'john-knows->jim', since: 2020}]
  ->(m {`~id`: 'toNode', name: 'jim'})
```

Si vous essayez de créer un ID personnalisé déjà utilisé, Neptune génère une erreur `DuplicateDataException`.

Voici un exemple d'utilisation d'ID personnalisé dans une clause `MATCH` :

```
MATCH (n {`~id`: 'id1'})
RETURN n
```

Voici un exemple d'utilisation de la personnalisation IDs dans une `MERGE` clause :

```
MATCH (n {name: 'john'}), (m {name: 'jim'})
MERGE (n)-[r {`~id`: 'john->jim'}]->(m)
RETURN r
```

### Que faire si vous utilisez actuellement `~id` en tant que propriété
<a name="opencypher-compliance-custom-ids-migrating"></a>

Avec la [version 1.2.0.2 du moteur](engine-releases-1.2.0.2.md), la clé `~id` dans les clauses openCypher est désormais traitée comme `id` plutôt que comme propriété. Dès lors, si vous avez une propriété nommée `~id`, il devient impossible d'y accéder.

Si vous utilisez une propriété `~id`, avant de passer à la version de moteur `1.2.0.2` ou à une version ultérieure, vous devez migrer la propriété `~id` existante vers une nouvelle clé de propriété, puis supprimer la propriété `~id`. Par exemple, la requête ci-dessous :
+ Crée une propriété nommée 'newId' pour tous les nœuds,
+ copie la valeur de la propriété '\$1id' dans la propriété 'newId'
+ et supprime la propriété '\$1id' des données

```
MATCH (n)
WHERE exists(n.`~id`)
SET n.newId = n.`~id`
REMOVE n.`~id`
```

La même approche doit être adoptée pour toutes les relations dans les données qui ont une propriété `~id`.

Vous devrez également modifier toutes les requêtes que vous utilisez qui font référence à une propriété `~id`. Par exemple, cette requête :

```
MATCH (n)
WHERE n.`~id` = 'some-value'
RETURN n
```

... serait remplacée par ce qui suit :

```
MATCH (n)
WHERE n.newId = 'some-value'
RETURN n
```

## Support des sous-requêtes CALL dans Neptune
<a name="call-subquery-support"></a>

 Disponible dans Neptune Database 1.4.1.0 et versions ultérieures, et dans Neptune Analytics. 

 Amazon Neptune prend en charge `CALL` les sous-requêtes. Une `CALL` sous-requête est une partie de la requête principale qui s'exécute dans une portée isolée pour chaque entrée de la `CALL` sous-requête. 

 Supposons, par exemple, qu'un graphique contienne des données sur les personnes, leurs amis et les villes dans lesquelles elles vivaient. Nous pouvons retrouver les deux plus grandes villes où vivait chaque ami d'une personne en utilisant une `CALL` sous-requête : 

```
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
```

 Dans cet exemple, la partie requête interne `CALL { ... }` est exécutée pour chaque `friend` élément correspondant à la clause MATCH précédente. Lorsque la requête interne est exécutée, les `LIMIT` clauses `ORDER` and sont locales aux villes où vivait un ami en particulier. Nous obtenons donc (au maximum) deux villes par ami. 

 Toutes les clauses de requête sont disponibles dans les `CALL` sous-requêtes. Cela inclut également les `CALL` sous-requêtes imbriquées. Certaines restrictions relatives à la première `WITH` clause et aux variables émises existent et sont expliquées ci-dessous. 

### Étendue des variables dans la sous-requête CALL
<a name="variable-scope-inside-call-subquery"></a>

 Les variables des clauses situées avant la `CALL` sous-requête et utilisées à l'intérieur de celle-ci doivent être importées par la `WITH` clause initiale. Contrairement aux `WITH` clauses ordinaires, elle ne peut contenir qu'une liste de variables, mais elle n'autorise pas l'aliasing et ne peut pas être utilisée avec `DISTINCT``ORDER BY`,`WHERE`,`SKIP`, ou`LIMIT`. 

### Variables renvoyées par la sous-requête CALL
<a name="variables-returned-call-subquery"></a>

 Les variables émises par la `CALL` sous-requête sont spécifiées dans la `RETURN` clause finale. Notez que les variables émises ne peuvent pas se chevaucher avec les variables avant la `CALL` sous-requête. 

### Limitations
<a name="call-subquery-limitations"></a>

 À l'heure actuelle, les mises à jour au sein d'une `CALL` sous-requête ne sont pas prises en charge. 

## Fonctions Neptune OpenCypher
<a name="opencypher-compliance-new-functions"></a>

 Disponible dans Neptune Database 1.4.1.0 et versions ultérieures, et dans Neptune Analytics. 

**textIndexOf**

 `textIndexOf(text :: STRING, lookup :: STRING, from = 0 :: INTEGER?, to = -1 :: INTEGER?) :: (INTEGER?)` 

 Renvoie l'indice de la première occurrence comprise entre le `text` décalage `from` (inclus) et le décalage `to` (exclusif). `lookup` Si la `to` valeur est -1, la plage continue jusqu'à la fin de`text`. L'indexation est basée sur zéro et est exprimée en valeurs scalaires Unicode (points de code non substituts). 

```
RETURN textIndexOf('Amazon Neptune', 'e')
{
  "results": [{
      "textIndexOf('Amazon Neptune', 'e')": 8
    }]
}
```

**collToSet**

 `collToSet(values :: LIST OF ANY?) :: (LIST? OF ANY?)` 

 Renvoie une nouvelle liste contenant uniquement les éléments uniques de la liste d'origine. L'ordre de la liste d'origine est **conservé** (par exemple, les `[1, 6, 5, 1, 5]` retours`[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?)` 

 Renvoie une nouvelle liste contenant tous les éléments uniques dont les éléments sont `first` exclus`second`. 

```
RETURN collSubtract([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collSubtract([2, 5, 1, 0], [1, 5])": [0, 2]
    }]
}
```

**Intersection de Coll**

 `collIntersection(first :: LIST? OF ANY?, second :: LIST? OF ANY?) :: (LIST? OF ANY?)` 

 Renvoie une nouvelle liste contenant tous les éléments uniques de l'intersection de `first` et`second`. 

```
RETURN collIntersection([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collIntersection([2, 5, 1, 0], [1, 5])": [1, 5]
    }]
}
```

## Fonctions de tri
<a name="sorting-functions"></a>

 Les sections suivantes définissent les fonctions permettant de trier les collections. Ces fonctions utilisent (dans certains cas facultatifs) des arguments de `config` carte, ou une liste de plusieurs cartes de ce type, qui définissent la clé de tri et and/or le sens du tri : 

```
{ key: STRING, order: STRING }
```

 `key`Voici une propriété de carte ou de nœud dont la valeur doit être utilisée pour le tri. `order`est « » ou `asc` « `desc` » (sans distinction majuscules/minuscules) pour spécifier un tri croissant ou décroissant, respectivement. Par défaut, le tri sera effectué par ordre croissant. 

**Coll Sort**

 `collSort(coll :: LIST OF ANY, config :: MAP?) :: (LIST? OF ANY?)` 

 Renvoie une nouvelle liste triée contenant les éléments de la liste `coll` d'entrée. 

```
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?)` 

 Renvoie une liste de cartes triées en fonction de la valeur de la `key` propriété spécifiée. 

```
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?)
```

 Renvoie une liste de cartes triées en fonction de la valeur des `key` propriétés spécifiées, en appliquant éventuellement une limite et un saut. 

```
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?)` 

 Renvoie une version triée de la liste `coll` d'entrée, triant les éléments du nœud en fonction des valeurs de leurs `key` propriétés respectives. 

```
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"
          }
        }]
    }]
}
```

## Fonctions temporelles
<a name="temporal-functions"></a>

 Les fonctions temporelles sont disponibles à partir de 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)` 

 Renvoie le `day` mois à partir d'une `date` valeur `datetime` ou. Pour `datetime` : les valeurs sont normalisées en UTC en fonction des entrées avant d'extraire le jour. Pour `date` : le jour est extrait en fonction du fuseau horaire. 

 L'`datetime`entrée est disponible à la fois dans Neptune Database et Neptune Analytics : 

```
RETURN day(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "day(datetime('2021-06-03T01:48:14Z'))": 3
    }]
}
```

 Ici, le `datetime` temps est normalisé en UTC, donc \$1 08:00 revient au 2 juin. 

```
RETURN day(datetime('2021-06-03T00:00:00+08:00'))
{
  "results": [{
      "day(datetime('2021-06-03T00:00:00+08:00'))": 2
    }]
}
```

 L'`date`entrée n'est disponible que dans Neptune Analytics : 

```
RETURN day(date('2021-06-03Z'))
{
  "results": [{
      "day(date('2021-06-03Z'))": 3
    }]
}
```

 Le fuseau horaire `date` préserve, en gardant le 3 juin. 

```
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)` 

 Renvoie le mois à partir d'une `date` valeur `datetime` ou (1-12). Pour `datetime` : les valeurs sont normalisées en UTC en fonction des entrées avant d'extraire le mois. Pour `date` : le mois est extrait en fonction du fuseau horaire. 

 L'`datetime`entrée est disponible à la fois dans Neptune Database et Neptune Analytics : 

```
RETURN month(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "month(datetime('2021-06-03T01:48:14Z'))": 6
    }]
}
```

 Ici, le `datetime` temps est normalisé en UTC, donc \$1 08:00 revient au 31 mai. 

```
RETURN month(datetime('2021-06-01T00:00:00+08:00'))
{
  "results": [{
      "month(datetime('2021-06-01T00:00:00+08:00'))": 5
    }]
}
```

 L'`date`entrée n'est disponible que dans Neptune Analytics : 

```
RETURN month(date('2021-06-03Z'))
{
  "results": [{
      "month(date('2021-06-03Z'))": 6
    }]
}
```

 Le fuseau horaire `date` préserve, en gardant le 1er juin. 

```
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)` 

 Renvoie l'année à partir d'une `date` valeur `datetime` ou. Pour `datetime` : les valeurs sont normalisées en UTC sur la base des données saisies avant d'extraire l'année. Pour `date` : l'année est extraite en fonction du fuseau horaire. 

 L'`datetime`entrée est disponible à la fois dans Neptune Database et Neptune Analytics : 

```
RETURN year(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "year(datetime('2021-06-03T01:48:14Z'))": 2021
    }]
}
```

 Ici, le `datetime` temps est normalisé en UTC, donc \$1 08:00 revient au 31 décembre 2020. 

```
RETURN year(datetime('2021-01-01T00:00:00+08:00'))
{
  "results": [{
      "year(datetime('2021-01-01T00:00:00+08:00'))": 2020
    }]
}
```

 L'`date`entrée n'est disponible que dans Neptune Analytics : 

```
RETURN year(date('2021-06-03Z'))
{
  "results": [{
      "year(date('2021-06-03Z'))": 2021
    }]
}
```

 Le fuseau horaire `date` préserve le mois de juin 2021. 

```
RETURN year(date('2021-01-01+08:00'))
{
  "results": [{
      "year(date('2021-01-01+08:00'))": 2021
    }]
}
```

### Fonctions Neptune OpenCypher
<a name="openCypher-functions"></a>

 Disponible dans Neptune Database 1.4.6.0 et versions ultérieures, et dans Neptune Analytics. 

#### réduire ()
<a name="openCypher-functions-reduce"></a>

 Reduce traite séquentiellement chaque élément de la liste en le combinant avec un total cumulé ou un « accumulateur ». En commençant par une valeur initiale, il met à jour l'accumulateur après chaque opération et utilise cette valeur mise à jour lors de l'itération suivante. 

 `for i in (0, ..., n) acc = acc X list[I], where X denotes any binary operator` 

 Une fois que tous les éléments ont été traités, il renvoie le résultat final cumulé. 

 Une structure de réduction () typique serait - `reduce(accumulator = initial , variable IN list | expression)` 

**Spécifications du type :**  
 `- 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 ` 

**Restrictions :**  
 Actuellement, l'`reduce()`expression ne prend en charge que : 
+  Multiplication numérique 
+  Addition numérique 
+  Concaténation de chaînes 
+  Concaténation de listes 

 Ils sont représentés par l'`*`opérateur `+` or. L'expression doit être une expression binaire comme indiqué ci-dessous - `expression pattern: accumulator + any variable or accumulator * any variable` 

**Gestion des débordements :**  
 Neptune détecte un dépassement numérique lors de l'`reduce()`évaluation et réagit différemment en fonction du type de données : 

```
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.
```

**Exemples :**  
Consultez les exemples suivants pour la fonction 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 prend en charge une `CALL` procédure `neptune.read` permettant de lire les données d'Amazon S3, puis d'exécuter une requête OpenCypher (lecture, insertion, mise à jour) à l'aide de ces données. La procédure génère chaque ligne du fichier en tant que ligne de variable de résultat déclarée. Il utilise les informations d'identification IAM de l'appelant pour accéder aux données dans Amazon S3. Consultez [Gérer les autorisations pour neptune.read ()](access-graph-opencypher-21-extensions-s3-read-permissions.md) pour configurer les autorisations. La AWS région du compartiment Amazon S3 doit se trouver dans la même région que celle où se trouve l'instance. Actuellement, les lectures entre régions ne sont pas prises en charge. 

 **Syntaxe** 

```
CALL neptune.read(
  {
    source: "string",
    format: "parquet/csv",
    concurrency: 10
  }
)
YIELD row
...
```

**Inputs**
+  **source** (obligatoire) - URI Amazon S3 vers un **seul** objet. Le préfixe Amazon S3 désignant plusieurs objets n'est pas pris en charge. 
+  **format** (obligatoire) - `parquet` et `csv` sont pris en charge. 
  +  Vous trouverez plus de détails sur le format Parquet pris en charge dans[Types de colonnes de parquet pris en charge](access-graph-opencypher-21-extensions-s3-read-parquet.md#access-graph-opencypher-21-extensions-s3-read-parquet-column-types). 
  +  Pour plus d'informations sur le format csv pris en charge, consultez[Format de chargement des données openCypher](bulk-load-tutorial-format-opencypher.md). 
+  **simultanéité** (facultatif) - Type : entier égal ou supérieur à 0. Valeur par défaut : 0. Spécifie le nombre de threads à utiliser pour lire le fichier. Si la valeur est 0, le nombre maximum de threads autorisés par la ressource sera utilisé. Pour le parquet, il est recommandé de définir un certain nombre de groupes de lignes. 

**Sorties**

 Le fichier neptune.read renvoie : 
+  **ligne** - Type : carte 
  +  Chaque ligne du fichier, où les clés sont les colonnes et les valeurs sont les données présentes dans chaque colonne. 
  +  Vous pouvez accéder aux données de chaque colonne sous la forme d'un accès aux propriétés (`row.col`). 

## Meilleures pratiques pour neptune.read ()
<a name="access-graph-opencypher-21-extensions-s3-read-best-practices"></a>

Les opérations de lecture de Neptune S3 peuvent être gourmandes en mémoire. Veuillez utiliser des types d'instance adaptés aux charges de travail de production, comme indiqué dans la section [Choix des types d'instance pour Amazon Neptune](instance-types.md).

L'utilisation de la mémoire et les performances des `neptune.read()` requêtes sont affectées par divers facteurs tels que la taille du fichier, le nombre de colonnes, le nombre de lignes et le format du fichier. Selon la structure, les petits fichiers (par exemple, les fichiers CSV de 100 Mo ou moins, les fichiers Parquet de 20 Mo ou moins) peuvent fonctionner de manière fiable sur la plupart des types d'instances adaptés à la production, tandis que les fichiers plus volumineux peuvent nécessiter une mémoire importante que les types d'instances plus petits ne peuvent pas fournir.

Lorsque vous testez cette fonctionnalité, il est recommandé de commencer par de petits fichiers et de procéder à une mise à l'échelle progressive afin de garantir que votre charge de travail de lecture puisse être adaptée à la taille de votre instance. Si vous remarquez que des `neptune.read()` demandes entraînent out-of-memory des exceptions ou des redémarrages d'instances, envisagez de diviser vos fichiers en plus petits morceaux, de réduire la complexité des fichiers ou de passer à des types d'instances plus importants.

# Exemples de requêtes utilisant du parquet
<a name="access-graph-opencypher-21-extensions-s3-read-parquet"></a>

L'exemple de requête suivant renvoie le nombre de lignes d'un fichier Parquet donné :

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
RETURN count(row)
```

Vous pouvez exécuter l'exemple de requête à l'aide de l'`execute-open-cypher-query`opération décrite dans le en AWS CLI exécutant le code suivant :

```
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
```

Une requête peut être flexible quant à l'utilisation des lignes lues à partir d'un fichier Parquet. Par exemple, la requête suivante crée un nœud dont le champ est défini sur la base des données trouvées dans le fichier Parquet :

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**Avertissement**  
Il n'est pas considéré comme une bonne pratique d'utiliser une clause volumineuse produisant des résultats comme `MATCH(n)` avant une `CALL` clause. Cela entraînerait une requête de longue durée, en raison d'un produit croisé entre les solutions entrantes issues des clauses précédentes et les lignes lues par neptune.read. Il est recommandé de démarrer la requête avec `CALL` neptune.read.

## Types de colonnes de parquet pris en charge
<a name="access-graph-opencypher-21-extensions-s3-read-parquet-column-types"></a>

**Types de données sur le parquet :**
+ NULL
+ BOOLEAN
+ FLOAT
+ DOUBLE
+ CHAÎNE
+ ENTIER SIGNÉ : UINT8, UINT16, UINT32, UINT64
+ MAP : ne prend en charge qu'un seul niveau. Ne prend pas en charge le mode imbriqué.
+ LISTE : ne prend en charge qu'un seul niveau. Ne prend pas en charge le mode imbriqué.

**Types de données spécifiques à Neptune :**

Contrairement aux en-têtes de colonne de propriétés au format CSV, les en-têtes de colonne de propriétés du format Parquet doivent uniquement contenir les noms des propriétés, il n'est donc pas nécessaire d'avoir les noms des types ni la cardinalité.

Certains types de colonnes spéciaux au format Parquet nécessitent toutefois une annotation dans les métadonnées, notamment le type Any, le type Date, le type DateTime et le type Geometry. L'objet suivant est un exemple de l'annotation de métadonnées requise pour les fichiers contenant des colonnes de ces types spéciaux :

```
"metadata": {
    "anyTypeColumns": ["UserCol1"],
    "dateTypeColumns": ["UserCol2"],
    "dateTimeTypeColumns": ["UserCol3"],
    "geometryTypeColumns": ["UserCol4"]
}
```

Vous trouverez ci-dessous des informations détaillées sur la charge utile attendue associée à ces types :
+ Un type de colonne Any est pris en charge dans les colonnes utilisateur. Un type quelconque est un « sucre syntaxique » pour tous les autres types que nous prenons en charge. C'est extrêmement utile si une colonne utilisateur contient plusieurs types. La charge utile d'une valeur de type Any est une liste de chaînes json comme suit :`{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`, qui contient un champ de valeur et un champ de type dans chaque chaîne json individuelle. La valeur de cardinalité d'une colonne Any est définie, ce qui signifie que la colonne peut accepter plusieurs valeurs. 
  + Neptune prend en charge les types suivants dans tous les types : Bool (ou Boolean), Byte, Short, Int, Long,,,,, Float UnsignedByte UnsignedShort, Double UnsignedInt, Date UnsignedLong, DateTime, String et Geometry.
  + Le type de vecteur n'est pris en charge dans aucun type.
  + Nested Tous les types ne sont pas pris en charge. Par exemple, `{"value": {"value": "10", "type": "Int"}, "type": "Any"}`.
+ Les colonnes de type Date et Datetime sont prises en charge dans les colonnes utilisateur. La charge utile de ces colonnes doit être fournie sous forme de chaînes suivant le format XSD ou l'un des formats ci-dessous : 
  + 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:SSS [\$1\$1-] hhmm
+ Un type de colonne de géométrie est pris en charge dans les colonnes utilisateur. La charge utile de ces colonnes ne doit contenir que des primitives de géométrie de type Point, fournies sous forme de chaînes au format WKT (texte connu). Par exemple, POINT (30 10) serait une valeur de géométrie valide.

## Exemple de sortie pour parquet
<a name="sample-parquet-output"></a>

Étant donné un fichier Parquet comme celui-ci :

```
<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   |
+--------+---------+-------------+----------------------+------------+------------+----------+
```

Voici un exemple de sortie renvoyée par neptune.read à l'aide de la requête suivante :

```
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"
 }
 }]
}
```

Il n'existe actuellement aucun moyen de définir une étiquette de nœud ou de bord pour un champ de données provenant d'un fichier Parquet. Il est recommandé de partitionner les requêtes en plusieurs requêtes, une pour chaque étiquette/type.

```
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)
```

# Exemples de requêtes à l'aide de CSV
<a name="access-graph-opencypher-21-extensions-s3-read-csv"></a>

Dans cet exemple, la requête renvoie le nombre de lignes d'un fichier CSV donné :

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
RETURN count(row)
```

Vous pouvez exécuter l'exemple de requête à l'aide de l' execute-open-cypher-queryopération décrite dans le en AWS CLI exécutant le code suivant :

```
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
```

Une requête peut être flexible quant à l'utilisation des lignes lues à partir d'un fichier CSV. Par exemple, la requête suivante crée un nœud avec un champ défini sur les données d'un fichier CSV :

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**Avertissement**  
Il n'est pas considéré comme une bonne pratique d'utiliser une clause de grande taille produisant des résultats telle que MATCH (n) avant une clause CALL. Cela entraînerait une requête de longue durée en raison d'un produit croisé entre les solutions entrantes issues des clauses précédentes et les lignes lues par neptune.read. Il est recommandé de démarrer la requête avec CALL neptune.read.

## En-têtes de colonnes de propriétés
<a name="property-column-headers"></a>

Vous pouvez spécifier une colonne (`:`) pour une propriété à l'aide de la syntaxe suivante. Les noms de type ne sont pas sensibles à la casse. Si deux points apparaissent dans le nom d'une propriété, il faut l'éviter en le faisant précéder d'une barre oblique inverse :. `\:`

```
propertyname:type
```

**Note**  
Les espaces, les virgules, le retour en chariot et les caractères de nouvelle ligne ne sont pas autorisés dans les en-têtes de colonne. Les noms de propriétés ne peuvent donc pas inclure ces caractères.
Vous pouvez spécifier une colonne pour un type de tableau en ajoutant `[]` au type :  

  ```
                          propertyname:type[]
  ```
Les propriétés d'arc ne peuvent avoir qu'une seule valeur et provoquent une erreur si un type de tableau ou une seconde valeur est spécifié. L'exemple suivant montre l'en-tête de colonne d'une propriété nommée age de type Int :  

  ```
  age:Int
  ```

Chaque ligne du fichier doit obligatoirement avoir un nombre entier dans cette position ou rester vide. Les tableaux de chaînes sont autorisés, mais les chaînes d'un tableau ne peuvent pas inclure le point-virgule (`;`) à moins qu'il ne soit évité par une barre oblique inverse (). `\;`

## Types de colonnes CSV pris en charge
<a name="supported-csv-column-types"></a>
+ **BOOL (ou BOOLEAN)** - Valeurs autorisées : true, false. Indique un champ booléen. Toute valeur autre que true sera traitée comme fausse.
+ **FLOAT** - Plage : virgule flottante IEEE 754 32 bits, y compris Infinity, INF, -Infinity, -INF et NaN (). not-a-number
+ **DOUBLE** : plage : virgule flottante IEEE 754 64 bits, y compris Infinity, INF, -Infinity, -INF et NaN (). not-a-number
+ **CHAÎNE** - 
  + Les guillemets sont facultatifs. Les virgules, les nouvelles lignes et les caractères renvoyant le chariot sont automatiquement ignorés s'ils sont inclus dans une chaîne entourée de guillemets doubles («). Exemple : « Bonjour tout le monde ».
  + Pour inclure des guillemets dans une chaîne entre guillemets, vous pouvez éviter les guillemets en utilisant deux guillemets d'affilée : « Hello «" World" "».
  + Les tableaux de chaînes sont autorisés, mais les chaînes d'un tableau ne peuvent pas inclure le point-virgule (;) à moins qu'il ne soit évité par une barre oblique inverse (\$1 ;).
  + Si vous souhaitez placer des chaînes d'un tableau entre guillemets, vous devez entourer la totalité du tableau par un ensemble de guillemets. Exemple : « Chaîne 1 ; Chaîne 2 ; Chaîne 3 ».
+ **DATE, DATETIME** - Les valeurs de date/heure peuvent être fournies au format XSD ou dans l'un des formats suivants : 
  + 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:SSS [\$1\$1-] hhmm
+ **ENTIER SIGNÉ** - 
  + Octet : -128 à 127
  + Court : -32768 à 32767
  + Int : -2^31 à 2^31-1
  + Longue : -2^63 à 2^63-1

**Types de colonnes spécifiques à Neptune :**
+ Un type de colonne Any est pris en charge dans les colonnes utilisateur. Un type quelconque est un « sucre syntaxique » pour tous les autres types que nous prenons en charge. C'est extrêmement utile si une colonne utilisateur contient plusieurs types. La charge utile d'une valeur de type Any est une liste de chaînes json comme suit :`{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`, qui contient un champ de valeur et un champ de type dans chaque chaîne json individuelle. L'en-tête de colonne d'un type Any est PropertyName:Any. La valeur de cardinalité d'une colonne Any est définie, ce qui signifie que la colonne peut accepter plusieurs valeurs. 
  + Neptune prend en charge les types suivants dans tous les types : Bool (ou Boolean), Byte, Short, Int, Long,,,,, Float UnsignedByte UnsignedShort, Double UnsignedInt, Date UnsignedLong, DateTime, String et Geometry.
  + Le type de vecteur n'est pris en charge dans aucun type.
  + Nested Tous les types ne sont pas pris en charge. Par exemple, `{"value": {"value": "10", "type": "Int"}, "type": "Any"}`.
+ Un type de colonne de géométrie est pris en charge dans les colonnes utilisateur. La charge utile de ces colonnes ne doit contenir que des primitives de géométrie de type Point, fournies sous forme de chaînes au format WKT (texte connu). Par exemple, POINT (30 10) serait une valeur de géométrie valide.

## Exemple de sortie CSV
<a name="sample-csv-output"></a>

Compte tenu du fichier CSV suivant :

```
<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
```

Cet exemple montre le résultat renvoyé par neptune.read à l'aide de la requête suivante :

```
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
      }
    }]
}
```

Il n'existe actuellement aucun moyen de définir une étiquette de nœud ou de bordure pour un champ de données provenant d'un fichier CSV. Il est recommandé de partitionner les requêtes en plusieurs requêtes, une pour chaque étiquette/type.

```
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)
```

# Gérer les autorisations pour neptune.read ()
<a name="access-graph-opencypher-21-extensions-s3-read-permissions"></a>

## Politiques IAM requises
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-iam"></a>

Pour exécuter les requêtes OpenCypher utilisées`neptune.read()`, vous devez disposer des autorisations appropriées pour accéder aux données de votre base de données Neptune. Les requêtes en lecture seule nécessitent cette action. `ReadDataViaQuery` Les requêtes qui modifient les données nécessitent `WriteDataViaQuery` des insertions ou `DeleteDataViaQuery` des suppressions. L'exemple ci-dessous autorise les trois actions sur le cluster spécifié.

En outre, vous devez disposer d'autorisations pour accéder au compartiment S3 contenant vos fichiers de données. La déclaration de politique de Neptunes3Access accorde les autorisations S3 requises :
+ **`s3:ListBucket`**: obligatoire pour vérifier l'existence du bucket et le contenu de la liste.
+ **`s3:GetObject`**: Nécessaire pour accéder à l'objet spécifié afin que son contenu puisse être lu en vue de son intégration dans les requêtes OpenCypher.

Si votre compartiment S3 utilise le chiffrement côté serveur avec AWS KMS, vous devez également accorder des autorisations KMS. La KMSAccess déclaration de politique de Neptunes3 permet à Neptune de déchiffrer les données et de générer des clés de données lors de l'accès à des objets S3 chiffrés. Cette condition limite les opérations KMS aux demandes provenant des services S3 et RDS de votre région.
+ **`kms:Decrypt`**: Nécessaire pour effectuer le déchiffrement de l'objet chiffré afin que ses données puissent être lues par Neptune.
+ **`kms:GenerateDataKey`**: également requis par l'API S3 utilisée pour récupérer les objets à lire.

```
{
  "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"
        ]
      }
  }
}
```

## Conditions préalables importantes
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-prerequisites"></a>

Ces autorisations et conditions préalables garantissent une intégration sûre et fiable des données S3 dans les requêtes OpenCypher, tout en maintenant des contrôles d'accès et des mesures de protection des données appropriés.
+ **Authentification IAM** : cette fonctionnalité n'est prise en charge que pour les clusters Neptune avec l'authentification IAM activée. Consultez [Sécurisation de votre base de données Amazon Neptune](security.md) pour obtenir des instructions détaillées sur la création et la connexion à des clusters compatibles avec l'authentification IAM.
+ **Point de terminaison VPC** :
  + Un point de terminaison VPC de type Gateway pour Amazon S3 est nécessaire pour permettre à Neptune de communiquer avec Amazon S3.
  + Pour utiliser un AWS KMS chiffrement personnalisé dans la requête, un point de terminaison VPC de type interface est requis AWS KMS pour permettre à Neptune de communiquer avec. AWS KMS
  + Pour obtenir des instructions détaillées sur la configuration de ce point de terminaison, consultez [Création du point de terminaison Amazon S3 VPC.](bulk-load-tutorial-IAM.md)

# Données spatiales
<a name="access-graph-opencypher-22-spatial-data"></a>

Amazon Neptune prend désormais en charge les requêtes spatiales, ce qui vous permet de stocker et d'analyser des données géométriques dans votre graphique. Bien qu'elles soient couramment utilisées pour les emplacements géographiques (comme les coordonnées sur une carte), les entités spatiales fonctionnent avec toutes les données bidimensionnelles où la position et la proximité sont importantes. Utilisez cette fonctionnalité pour répondre à des questions telles que « Quels magasins se trouvent dans un rayon de 8 km de ce client ? » , « Trouvez tous les itinéraires de livraison qui croisent cette zone de service » ou « Quels composants de ce plan d'étage chevauchent la zone CVC ? » Neptune met en œuvre le support spatial à l'aide de fonctions de types spatiaux standard qui fonctionnent avec des points, des polygones et d'autres formes géométriques. Vous pouvez stocker les données spatiales sous forme de propriétés sur les nœuds et les arêtes, puis utiliser des fonctions spatiales pour calculer les distances, vérifier si les points se situent dans les limites ou trouver des régions qui se chevauchent, le tout dans vos requêtes OpenCypher.

**Cas d’utilisation courants :**
+ **Applications géographiques** : recommandations basées sur la localisation, géofencing, planification d'itinéraires et analyse du territoire
+ **Gestion des installations et de l'espace** : disposition du plan d'étage, placement de l'équipement et couverture des zones
+ **Topologie du réseau** : cartographie de l'infrastructure physique, zones de couverture et limites de service
+ **Conception et CAO** : positionnement des composants, détection des collisions et relations spatiales dans les conceptions 2D
+ **Développement du jeu** : positionnement des personnages, détection des collisions et area-of-effect calculs

L'implémentation des types spatiaux dans Amazon Neptune suit les directives ISO/IEC 13249-3:2016, comme les autres bases de données. Ils [Fonctions spatiales](access-graph-opencypher-22-spatial-functions.md) sont disponibles dans le langage de requête OpenCypher.

## Système de coordonnées
<a name="access-graph-opencypher-22-spatial-data-coordinate-system"></a>

Neptune possède un identifiant de référence spatiale (SRID) pour l'ensemble d'une base de données. L'homogénéité du système de coordonnées réduit les erreurs des utilisateurs lors des requêtes et améliore les performances de la base de données. La première version (1.4.7.0) prend en charge le système de coordonnées cartésien, également appelé SRID 0.

L'implémentation Neptune du SRID 0 est compatible avec les valeurs de longitude et de latitude. `ST_DistanceSpheroid`À utiliser pour calculer les distances en fonction du WGS84 /SRID 4326.

L'implémentation actuelle prend en charge le stockage de coordonnées tridimensionnelles. Les fonctions spatiales ne prennent actuellement en charge que l'utilisation des coordonnées des axes x et y (bidimensionnelles). Les coordonnées de l'axe Z ne sont actuellement pas prises en charge par les fonctions spatiales disponibles.

## Stockage des données de localisation
<a name="storing-spatial-data"></a>

Stockez les données de localisation sur les nœuds et les arêtes à l'aide du type de propriété Geometry. Créez des valeurs géométriques à partir du format WKT (Known Text), une méthode standard pour représenter des formes géographiques sous forme de texte. Par exemple, pour enregistrer l'emplacement d'un point :

```
CREATE (n:airport {code: 'ATL', location: ST_GeomFromText('POINT (-84.4281 33.6367)')})
```

Lorsque vous travaillez avec des coordonnées géographiques, le premier argument (x) représente la longitude et le second argument (y) représente la latitude. Cela suit l'ordre de coordonnées standard utilisé dans les bases de données spatiales et la norme ISO 19125.

**Note**  
 Neptune prend désormais en charge un nouveau type de données appelé « Géométrie ». La propriété de géométrie d'un nœud ou d'une arête peut être créée à partir d'une chaîne WKT à l'aide de la `ST_GeomFromText` fonction.  
Neptune stockera automatiquement les données relatives aux points dans un index spatial spécialisé afin d'améliorer les performances des fonctions de types spatiaux. Par exemple, l'index spatial spécialisé accélère le processus `ST_Contains` utilisé pour trouver les points dans un polygone.  
[page Wikipedia sur la représentation textuelle bien connue de la géométrie](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry)

## Chargement de données spatiales en masse
<a name="loading-spatial-data-bulk"></a>

Lorsque vous chargez des données en bloc, spécifiez le type de géométrie dans votre en-tête CSV. Neptune analysera les chaînes WKT et créera les propriétés de géométrie appropriées :

```
: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)
```

Pour plus de détails sur le format CSV, voir Format de [chargement groupé OpenCypher](bulk-load-tutorial-format-opencypher.md).

## Interrogation des données spatiales
<a name="querying-spatial-data"></a>

Les exemples de requêtes suivants utilisent le jeu de [données des routes aériennes](https://github.com/krlawrence/graph/tree/main/sample-data) pour montrer comment utiliser les fonctions spatiales dans Neptune.

Si vos données possèdent des propriétés de latitude et de longitude distinctes au lieu d'une propriété de géométrie, vous pouvez les convertir en points au moment de la requête. Trouvez les 10 aéroports les plus proches d'un lieu donné :

```
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
```

Si vous avez déjà enregistré des emplacements`ST_Point`, vous pouvez utiliser ces valeurs de position directement :

1. Définition de la propriété 

   ```
   MATCH (a:airport)
   SET a.location = ST_GeomFromText('POINT (' + a.lon + ' ' + a.lat + ')')
   ```

1. Requête utilisant 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
   ```

### Utilisation du pilote Bolt
<a name="querying-spatial-data-bolt"></a>

La plupart des méthodes de requête renvoient les valeurs de géométrie sous forme de chaînes WKT, lisibles par l'homme. Si vous utilisez le pilote Bolt, les valeurs de géométrie sont renvoyées au format WKB (Known Binary) pour plus d'efficacité. Convertissez le WKB en objet de géométrie dans votre application :

```
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);
}
```

# Fonctions spatiales
<a name="access-graph-opencypher-22-spatial-functions"></a>

Les fonctions spatiales suivantes sont disponibles dans Neptune OpenCypher pour travailler avec des types de données géométriques :
+ [ST\$1Point](access-graph-opencypher-22-spatial-functions-st-point.md)
+ [ST\$1 GeomFromText](access-graph-opencypher-22-spatial-functions-st-geomfromtext.md)
+ [ST\$1 AsText](access-graph-opencypher-22-spatial-functions-st-astext.md)
+ [ST\$1 GeometryType](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\$1 DistanceSpheroid](access-graph-opencypher-22-spatial-functions-st-distancespheroid.md)
+ [ST\$1Enveloppe](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 renvoie un point à partir des valeurs de coordonnées en entrée.

**Syntaxe**

```
ST_Point(x, y, z)
```

**Arguments**
+ `x`- Une valeur de type de données DOUBLE PRECISION qui représente une première coordonnée.
+ `y`- Une valeur de type de données DOUBLE PRECISION qui représente une deuxième coordonnée.
+ `z`- (facultatif)

**Ordre de coordonnées**

Lorsque vous travaillez avec des coordonnées géographiques, le premier argument (`x`) représente la **longitude** et le second (`y`) représente la **latitude**. Cela suit l'ordre de coordonnées standard utilisé dans les bases de données spatiales et la norme 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
```

**Plages de coordonnées valides**

Pour les données géographiques, assurez-vous que les coordonnées se situent dans des plages valides :
+ Longitude (`x`) : -180 à 180
+ Latitude (`y`) : -90 à 90

Les coordonnées situées en dehors de ces plages seront renvoyées `NaN` (ce n'est pas un nombre) lorsqu'elles sont utilisées avec des fonctions de calcul de distance telles que`ST_DistanceSpheroid`.

**Type de retour**

GÉOMÉTRIE du sous-type POINT

Si x ou y est null, null est renvoyé.

**Exemples**

Ce qui suit construit une géométrie ponctuelle à partir des coordonnées en entrée.

```
RETURN ST_Point(5.0, 7.0); 
POINT(5 7)
```

# ST\$1 GeomFromText
<a name="access-graph-opencypher-22-spatial-functions-st-geomfromtext"></a>

ST\$1 GeomFromText construit un objet géométrique à partir d'une représentation textuelle connue (WKT) d'une géométrie d'entrée.

**Syntaxe**

```
ST_GeomFromText(wkt_string)
```

**Arguments**
+ `wkt_string`- Une valeur de type de données STRING qui est une représentation WKT d'une géométrie.

**Type de retour**

GEOMETRY

Si wkt\$1string est null, null est renvoyé.

Si wkt\$1string n'est pas valide, alors a BadRequestException est renvoyé.

**Exemples**

```
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\$1 AsText
<a name="access-graph-opencypher-22-spatial-functions-st-astext"></a>

ST\$1 AsText renvoie la représentation textuelle connue (WKT) d'une géométrie d'entrée.

**Syntaxe**

```
ST_AsText(geo)
```

**Arguments**
+ `geo`- Une valeur de type de données GEOMETRY, ou une expression qui correspond à une GEOMETRY.

**Type de retour**

CHAÎNE

Si geo est null, null est renvoyé.

Si le paramètre d'entrée n'est pas une géométrie, la valeur a BadRequestException est renvoyée.

Si le résultat est supérieur à une CHAÎNE de 64 Ko, une erreur est renvoyée.

**Exemples**

```
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\$1 GeometryType
<a name="access-graph-opencypher-22-spatial-functions-st-geometrytype"></a>

ST\$1 GeometryType renvoie le type de géométrie sous forme de chaîne.

**Syntaxe**

```
ST_GeometryType(geom)
```

**Arguments**
+ `geom`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.

**Type de retour**

CHAÎNE

Si geom est null, null est renvoyé.

Si le paramètre d'entrée n'est pas une géométrie, la valeur a BadRequestException est renvoyée.

**Exemples**

```
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 renvoie la valeur true si les projections 2D des géométries en entrée sont topologiquement égales. Les géométries sont considérées comme topologiquement égales si elles comportent des ensembles de points égaux. Dans des géométries topologiquement égales, l'ordre des sommets peut différer tout en maintenant cette égalité.

**Syntaxe**

```
ST_Equals(geom1, geom2)
```

**Arguments**
+ `geom1`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.
+ `geom2`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY. Cette valeur est comparée à geom1 afin de déterminer si elle est égale à geom1.

**Type de retour**

BOOLEAN

Si geom1 ou geom2 est null, null est renvoyé.

Si geom1 ou geom2 ne sont pas des géométries, alors a est renvoyé. BadRequestException 

**Exemples**

```
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
```

Ce qui suit vérifie si les deux chaînes de lignes sont géométriquement égales.

```
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 renvoie true si la projection 2D de la première géométrie en entrée contient la projection 2D de la deuxième géométrie en entrée. La géométrie A contient la géométrie B si chaque point de B est un point de A et que leur intérieur comporte une intersection non vide. ST\$1Contains (A, B) est équivalent à ST\$1Within (B, A).

**Syntaxe**

```
ST_Contains(geom1, geom2)
```

**Arguments**
+ `geom1`- Une valeur de type GEOMETRY ou une expression qui correspond à un type GEOMETRY.
+ `geom2`- Une valeur de type GEOMETRY ou une expression qui correspond à un type GEOMETRY. Cette valeur est comparée à geom1 afin de déterminer si elle est contenue dans geom1.

**Type de retour**

BOOLEAN

Si geom1 ou geom2 est null, null est renvoyé.

Si le paramètre d'entrée n'est pas une géométrie, la valeur a BadRequestException est renvoyée.

**Exemples**

```
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 renvoie true si les projections 2D des deux géométries d’entrée ont au moins un point en commun.

**Syntaxe**

```
ST_Intersects(geom1, geom2)
```

**Arguments**
+ `geom1`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.
+ `geom2`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.

**Type de retour**

BOOLEAN

Si geom1 ou geom2 est null, null est renvoyé.

Si le paramètre d'entrée n'est pas une géométrie, la valeur a BadRequestException est renvoyée.

**Exemples**

```
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>

Pour les géométries d’entrée, ST\$1Distance renvoie la distance euclidienne minimale entre les projections 2D des deux valeurs géométriques d’entrée.

**Syntaxe**

```
ST_Distance(geo1, geo2)
```

**Arguments**
+ `geo1`- Une valeur du type de données GEOMETRY, ou une expression qui correspond à un type GEOMETRY.
+ `geo2`- Une valeur de type de données GEOMETRY, ou une expression qui correspond à une GEOMETRY.

**Type de retour**

DOUBLE PRÉCISION dans les mêmes unités que les géométries d'entrée.

Si geo1 ou geo2 est nul, nul est renvoyé.

Si le paramètre d'entrée n'est pas une géométrie, la valeur a BadRequestException est renvoyée.

**Exemples**

```
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\$1 DistanceSpheroid
<a name="access-graph-opencypher-22-spatial-functions-st-distancespheroid"></a>

Renvoie la distance minimale en mètres entre deux lon/lat géométries. Le sphéroïde est WGS84 /SRID 4326.

**Syntaxe**

```
ST_DistanceSpheroid(geom1, geom2);
```

**Arguments**
+ `geom1`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.
+ `geom2`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.

**Type de retour**

FLOAT

Si geom est null, null est renvoyé.

**Exemples**

```
RETURN ST_DistanceSpheroid(
    ST_GeomFromText('POINT(-110 42)'),
    ST_GeomFromText('POINT(-118 38)'))
814278.77
```

# ST\$1Enveloppe
<a name="access-graph-opencypher-22-spatial-functions-st-envelope"></a>

ST\$1Envelope renvoie le cadre de délimitation minimal de la géométrie en entrée, comme suit :
+ Si la géométrie en entrée est vide, la géométrie renvoyée sera POINT EMPTY.
+ Si le cadre de délimitation minimal de la géométrie en entrée dégénère en un point, la géométrie renvoyée est un point.
+ Si aucune des réponses précédentes n'est vraie, la fonction renvoie un counter-clockwise-oriented polygone dont les sommets sont les coins du cadre de délimitation minimal.

Pour toutes les entrées non vides, la fonction fonctionne sur la projection 2D de la géométrie en entrée.

**Syntaxe**

```
ST_Envelope(geom)
```

**Arguments**
+ `geom`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.

**Type de retour**

GEOMETRY

Si geom est null, null est renvoyé.

**Exemples**

```
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 renvoie une géométrie 2D qui représente tous les points dont la distance par rapport à la géométrie d’entrée projetée sur le plan cartésien XY est inférieure ou égale à la distance d’entrée.

**Syntaxe**

```
ST_Buffer(geom, distance, number_of_segments_per_quarter_circle)
```

**Arguments**
+ `geom`- Une valeur du type de données GEOMETRY ou une expression qui correspond à un type GEOMETRY.
+ `distance`- Une valeur de type de données DOUBLE PRECISION qui représente la distance (ou le rayon) de la mémoire tampon.
+ `number_of_segments_per_quarter_circle`- Une valeur de type INTEGER (doit être supérieure ou égale à 0). Cette valeur détermine le nombre de points à approcher d’un quart de cercle autour de chaque sommet de la géométrie d’entrée. Les valeurs négatives ont pour valeur par défaut zéro. La valeur par défaut est de 8.

**Type de retour**

GEOMETRY

La fonction ST\$1Buffer renvoie une géométrie bidimensionnelle (2D) dans le plan cartésien XY.

**Exemples**

```
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))
```

Ce qui suit renvoie la zone tampon de la géométrie du point d'entrée qui correspond approximativement à un cercle. Étant donné que la commande spécifie 3 comme nombre de segments par quart de cercle, la fonction utilise trois segments pour approcher le quart de cercle.

```
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))
```

# Accès au graphe Neptune avec SPARQL
<a name="access-graph-sparql"></a>

SPARQL est un langage de requête pour RDF (Resource Description Framework), qui est un format de données de graphe conçu pour le web. Amazon Neptune est compatible avec SPARQL 1.1. En d'autres termes, vous pouvez vous connecter à une instance de base de données Neptune et interroger le graphe à l'aide du langage de requête décrit dans la spécification [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

 Une requête dans SPARQL se compose d'une clause `SELECT` pour spécifier les variables à renvoyer et une clause `WHERE` clause pour spécifier les données de correspondance du graphe. Si vous ne connaissez pas les requêtes SPARQL, consultez [Writing Simple Queries](https://www.w3.org/TR/sparql11-query/#WritingSimpleQueries) dans la section [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

**Important**  
Pour charger des données, `SPARQL UPDATE INSERT` peut fonctionner correctement pour un petit ensemble de données, mais si vous avez besoin de charger une quantité importante de données à partir d'un fichier, consultez [Utilisation du chargeur en vrac Amazon Neptune pour ingérer des données](bulk-load.md).

Pour plus d'informations sur les spécificités de l'implémentation SPARQL dans Neptune, consultez [Conformité avec les normes SPARQL](feature-sparql-compliance.md).

Avant de commencer, les prérequis suivants doivent être remplis :
+ Vous devez disposer d'une instance de base de données Neptune. Pour plus d'informations sur la création d'une instance de base de données Neptune, consultez [Création d'un cluster Amazon Neptune](get-started-create-cluster.md).
+ Vous devez disposer d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) que l'instance de base de données Neptune.

**Topics**
+ [Utilisation de la console RDF4 J pour se connecter à une instance de base de données Neptune](access-graph-sparql-rdf4j-console.md)
+ [Utilisation de RDF4 J Workbench pour se connecter à une instance de base de données Neptune](access-graph-sparql-rdf4j-workbench.md)
+ [Utilisation de Java pour se connecter à une instance de base de données Neptune](access-graph-sparql-java.md)
+ [API HTTP SPARQL](sparql-api-reference.md)
+ [Indicateurs de requête SPARQL](sparql-query-hints.md)
+ [Comportement de SPARQL DESCRIBE par rapport au graphe par défaut](sparql-default-describe.md)
+ [API de statut des requêtes SPARQL](sparql-api-status.md)
+ [Annulation de requêtes SPARQL](sparql-api-status-cancel.md)
+ [Utilisation du protocole HTTP SPARQL 1.1 Graph Store (GSP) dans Amazon Neptune](sparql-graph-store-protocol.md)
+ [Analyse de l'exécution des requêtes Neptune à l'aide de la fonctionnalité `explain` SPARQL](sparql-explain.md)
+ [Requêtes fédérées SPARQL dans Neptune à l'aide de l'extension `SERVICE`](sparql-service.md)

# Utilisation de la console RDF4 J pour se connecter à une instance de base de données Neptune
<a name="access-graph-sparql-rdf4j-console"></a>



La console RDF4 J vous permet d'expérimenter avec des graphes et des requêtes RDF (Resource Description Framework) dans un environnement REPL (read-eval-print boucle). 

Vous pouvez ajouter une base de données de graphes distante en tant que référentiel et l'interroger depuis la console RDF4 J. Cette section explique comment configurer la console RDF4 J pour se connecter à distance à une instance de base de données Neptune.

**Pour vous connecter à Neptune à l'aide de la console J RDF4**

1. Téléchargez le SDK RDF4 J depuis la [page de téléchargement](http://rdf4j.org/download/) du site Web de RDF4 J.

1. Décompressez le fichier zip du RDF4 J SDK.

1. Dans un terminal, accédez au répertoire RDF4 J SDK, puis entrez la commande suivante pour exécuter la console RDF4 J :

   ```
   bin/console.sh
   ```

   Vous devez voir des résultats similaires à ce qui suit :

   ```
   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.
   >
   ```

   Vous êtes maintenant à l'invite `>`. Il s'agit de l'invite générale pour la console RDF4 J. Vous utilisez cette invite pour configurer les référentiels et autres opérations. Un référentiel possède sa propre invite pour l'exécution des requêtes.

1. Saisissez ce qui suit à l'invite `>` afin de créer un répertoire SPARQL pour votre instance de base de données Neptune :

    

   ```
   create sparql
   ```

1. La console RDF4 J vous invite à saisir les valeurs des variables requises pour vous connecter au point de terminaison SPARQL.

   ```
   Please specify values for the following variables:
   ```

   Indiquez l’une des valeurs suivantes :    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/access-graph-sparql-rdf4j-console.html)

   Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver l'adresse de votre instance de base de données Neptune.

   Si l'opération est réussie, vous voyez le message suivant :

    

   ```
   Repository created
   ```

1. À l'invite de commande `>`, entrez ce qui suit pour vous connecter à l'instance de base de données Neptune.

   ```
   open neptune
   ```

   Si l'opération est réussie, vous voyez le message suivant :

    

   ```
   Opened repository 'neptune'
   ```

   Vous êtes maintenant à l'invite `neptune>`. À l'invite de commande, vous pouvez exécuter des requêtes par rapport au graphe Neptune.

    
**Note**  
Maintenant que vous avez ajouté le répertoire, la prochaine fois que vous exécuterez `bin/console.sh`, vous pourrez immédiatement exécuter la commande `open neptune` pour vous connecter à l'instance de base de données Neptune.

1. À l'`neptune>`invite, entrez ce qui suit pour exécuter une requête SPARQL renvoyant jusqu'à 10 des triples (subject-predicate-object) du graphe en utilisant la `?s ?p ?o` requête avec une limite de 10. Pour interroger quelque chose d'autre, remplacez le texte après la commande `sparql` par une autre requête SPARQL.

   ```
   sparql select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

# Utilisation de RDF4 J Workbench pour se connecter à une instance de base de données Neptune
<a name="access-graph-sparql-rdf4j-workbench"></a>

Cette section explique comment se connecter à une instance de base de données Amazon Neptune à l'aide de RDF4 J Workbench et RDF4 J Server. RDF4J Server est nécessaire car il agit comme un proxy entre le point de terminaison HTTP REST Neptune SPARQL et RDF4 J Workbench. 

RDF4J Workbench fournit une interface simple pour expérimenter avec un graphe, notamment pour charger des fichiers locaux. Pour plus d'informations, consultez la [section Ajouter](https://rdf4j.org/documentation/tools/server-workbench/#add) de la documentation RDF4 J.

**Conditions préalables**  
Avant de commencer, vous devez exécuter les actions suivantes :
+ Installez Java 1.8 ou version ultérieure.
+ Installez RDF4 J Server et RDF4 J Workbench. Pour plus d'informations, consultez la section [Installation de RDF4 J Server et de RDF4 J Workbench](https://rdf4j.org/documentation/tools/server-workbench/#installing-rdf4j-server-and-rdf4j-workbench).

**Pour utiliser RDF4 J Workbench pour vous connecter à Neptune**

1. Dans un navigateur Web, accédez à l'URL où l'application Web RDF4 J Workbench est déployée. Par exemple, si vous utilisez Apache Tomcat, l'URL est : [https : *ec2\$1hostname* //:8080/rdf4j-workbench/](http://localhost:8080/rdf4j-workbench/).

1. Si vous êtes invité à vous **connecter à RDF4 J Server**, vérifiez que **RDF4J Server** est installé, en cours d'exécution et que l'URL du serveur est correcte. Passez ensuite à l'étape suivante.

1. Dans le volet de gauche, sélectionnez **Nouveau référentiel**.

   Dans **Nouveau référentiel** :
   + Dans la liste déroulante **Type**, choisissez **Proxy de point de terminaison SPARQL**.
   + Pour **ID**, saisissez **neptune**.
   + Pour **Titre**, tapez **Instance de base de données Neptune.**

   Choisissez **Suivant**.

1. Dans **Nouveau référentiel** :
   + Pour **SPARQL query endpoint URL** (URL de point de terminaison de requête SPARQL), entrez `https://your-neptune-endpoint:port/sparql`.
   + Pour **SPARQL update endpoint URL** (URL de point de terminaison de mise à jour SPARQL), entrez `https://your-neptune-endpoint:port/sparql`.

   Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver l'adresse de votre instance de base de données Neptune. 

   Choisissez **Créer**.

1. Le référentiel **neptune** figure désormais dans la liste des référentiels. Quelques minutes peuvent s'écouler avant que vous ne puissiez utiliser le nouveau référentiel.

1. Dans la colonne **Id** de la table, choisissez le lien **neptune**.

1. Dans le volet de gauche, choisissez **Requête**. 

    
**Note**  
Si les éléments de menu situés sous **Explore** sont désactivés, vous devrez peut-être vous reconnecter au serveur RDF4 J et choisir à nouveau le référentiel **Neptune**.  
Pour ce faire, vous pouvez utiliser les liens **[modifier]** dans le coin supérieur droit.

1. Dans le champ de requête, tapez la requête SPARQL suivante, puis choisissez **Exécuter**.

    

   ```
   select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

    

L'exemple précédent renvoie jusqu'à 10 des triples (subject-predicate-object) du graphe en utilisant la `?s ?p ?o` requête avec une limite de 10. 

# Utilisation de Java pour se connecter à une instance de base de données Neptune
<a name="access-graph-sparql-java"></a>

Cette section vous accompagne lors de l'exécution d'un exemple Java complet qui se connecte à une l'instance de base de données Amazon Neptune et exécute une requête SPARQL.

Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

**Pour se connecter à Neptune à l'aide de Java**

1. Installez Apache Maven sur votre instance EC2. Si vous utilisez Amazon Linux 2023 (de préférence), utilisez :

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

   Si vous utilisez Amazon Linux 2, téléchargez le dernier fichier binaire [sur 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. Cet exemple a été testé avec Java 8 uniquement. Entrez ce qui suit pour installer Java 8 sur votre instance EC2 :

   ```
   sudo yum install java-1.8.0-devel
   ```

1. Entrez la commande suivante pour définir Java 8 en tant qu'exécution par défaut sur votre instance EC2 :

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

   Lorsque vous y êtes invité, saisissez le nombre pour Java 8.

1. Entrez la commande suivante pour définir Java 8 en tant que compilateur par défaut de votre instance EC2 : 

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

   Lorsque vous y êtes invité, saisissez le nombre pour Java 8.

1. Dans un nouveau répertoire , créez un fichier `pom.xml`, puis ouvrez-le dans un éditeur de texte.

1. Copiez ce qui suit dans le fichier `pom.xml` et enregistrez-le (vous pouvez normalement remplacer les numéros de version par la dernière version stable) :

   ```
   <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>
   ```
**Note**  
Si vous modifiez un projet Maven existant, la dépendance obligatoire est mise en évidence dans le code précédent.

1. Pour créer des sous-répertoires pour l'exemple de code source (`src/main/java/com/amazonaws/`), saisissez ce qui suit sur la ligne de commande :

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

1. Dans le répertoire `src/main/java/com/amazonaws/`, créez un fichier `App.java`, puis ouvrez-le dans un éditeur de texte.

1. Copiez ce qui suit dans le fichier `App.java`. Remplacez *your-neptune-endpoint* par l'adresse de votre instance de base de données Neptune.
**Note**  
Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver le nom d'hôte de votre instance de base de données Neptune. 

   ```
   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. Compilez et exécutez l'exemple à l'aide de la commande Maven suivante :

   ```
   mvn compile exec:java
   ```

L'exemple précédent renvoie jusqu'à 10 des triples (subject-predicate-object) du graphe en utilisant la `?s ?p ?o` requête avec une limite de 10. Pour interroger autre chose, remplacez la requête par une autre requête SPARQL.

L'itération des résultats dans l'exemple imprime la valeur de chaque variable renvoyée. L'objet `Value` est convertie en une `String`, puis imprimé. Si vous modifiez la partie `SELECT` de la requête, vous devez modifier le code.

# API HTTP SPARQL
<a name="sparql-api-reference"></a>

Les requêtes HTTP SPARQL sont acceptées au point de terminaison suivant : `https://your-neptune-endpoint:port/sparql`

Pour plus d'informations sur la connexion à Amazon Neptune avec SPARQL, consultez [Accès au graphe Neptune avec SPARQL](access-graph-sparql.md).

Pour plus d'informations sur le langage de requête et le protocole SPARQL, consultez les spécifications [SPARQL 1.1 Protocol](https://www.w3.org/TR/sparql11-protocol/#protocol) et [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

Les rubriques suivantes fournissent des informations sur les formats de sérialisation RDF SPARQL et la façon d'utiliser l'API HTTP SPARQL avec Neptune.

**Contents**
+ [Utilisation du point de terminaison HTTP REST pour se connecter à une instance de base de données Neptune](access-graph-sparql-http-rest.md)
+ [En-têtes de suivi HTTP facultatifs pour les réponses SPARQL en plusieurs parties](access-graph-sparql-http-trailing-headers.md)
+ [Types de médias RDF utilisés par SPARQL dans Neptune](sparql-media-type-support.md)
  + [Formats de sérialisation RDF utilisés par Neptune SPARQL](sparql-media-type-support.md#sparql-serialization-formats)
  + [Formats de sérialisation des résultats SPARQL utilisés par Neptune SPARQL](sparql-media-type-support.md#sparql-serialization-formats-neptune-output)
  + [Types de supports que Neptune peut utiliser pour importer des données RDF](sparql-media-type-support.md#sparql-serialization-formats-input)
  + [Types de supports que Neptune peut utiliser pour exporter les résultats de requêtes](sparql-media-type-support.md#sparql-serialization-formats-output)
+ [Utilisation de SPARQL UPDATE LOAD pour importer des données dans Neptune](sparql-api-reference-update-load.md)
+ [Utilisation de SPARQL UPDATE UNLOAD pour supprimer des données de Neptune](sparql-api-reference-unload.md)

# Utilisation du point de terminaison HTTP REST pour se connecter à une instance de base de données Neptune
<a name="access-graph-sparql-http-rest"></a>

**Note**  
Neptune ne prend actuellement pas en charge le HTTP/2 pour les requêtes d'API REST. Les clients doivent utiliser HTTP/1.1 lorsqu'ils se connectent aux points de terminaison.

Les instructions suivantes vous guident pour la connexion au point de terminaison SPARQL à l'aide de la commande **curl**, avec une connexions via HTTPS et en utilisant la syntaxe HTTP. Vous devez suivre ces instructions à partir d'une instance Amazon EC2 dans le même cloud privé virtuel (VPC) (VPC) que l'instance de base de données Neptune.

Le point de terminaison HTTP pour les requêtes SPARQL dans une instance de base de données Neptune est : `https://your-neptune-endpoint:port/sparql`.

**Note**  
Consultez la section [Connexion aux points de terminaison Amazon Neptune](feature-overview-endpoints.md) pour découvrir comment trouver le nom d'hôte de votre instance de base de données Neptune.

Amazon Neptune fournit un point de terminaison HTTP pour les requêtes SPARQL. L'interface REST est compatible avec SPARQL version 1.1.

**REQUÊTE avec HTTP POST**  
L'exemple suivant utilise **curl** pour soumettre un **`QUERY`** SPARQL via HTTP **POST**.

```
curl -X POST --data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' https://your-neptune-endpoint:port/sparql
```

L'exemple précédent renvoie jusqu'à 10 des triples (subject-predicate-object) du graphe en utilisant la `?s ?p ?o` requête avec une limite de 10. Pour interroger autre chose, remplacez la requête par une autre requête SPARQL.

**Note**  
Le type de support MIME par défaut d'une réponse est `application/sparql-results+json` pour les requêtes `SELECT` et `ASK`.  
Le type MIME par défaut d'une réponse est `application/n-quads` pour les requêtes `CONSTRUCT` et `DESCRIBE`.  
Pour obtenir la liste des types de médias utilisés par Neptune pour la sérialisation, consultez [Formats de sérialisation RDF utilisés par Neptune SPARQL](sparql-media-type-support.md#sparql-serialization-formats).

**MISE À JOUR à l'aide de HTTP POST**  
L'exemple suivant utilise **curl** pour soumettre un **`UPDATE`** SPARQL via HTTP **POST**.

```
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
```

L'exemple précédent insère le triplet suivant dans le graphe SPARQL par défaut : `<https://test.com/s> <https://test.com/p> <https://test.com/o>`

# En-têtes de suivi HTTP facultatifs pour les réponses SPARQL en plusieurs parties
<a name="access-graph-sparql-http-trailing-headers"></a>

La réponse HTTP aux requêtes et aux mises à jour SPARQL est souvent renvoyée en plusieurs parties ou fragments. Il peut être difficile de diagnostiquer un échec qui survient après qu'une requête ou une mise à jour commence à envoyer ces fragments, d'autant plus que le premier arrive avec le code de statut HTTP `200`.

À moins que vous ne demandiez explicitement des en-têtes de suivi, Neptune ne signale un tel échec qu'en ajoutant un message d'erreur dans le corps du message, qui est généralement corrompu.

Pour faciliter la détection et le diagnostic de ce type de problème, vous pouvez inclure un en-tête de suivi à encodage de transfert (TE), `te: trailers`, dans votre demande (voir, par exemple, la [page MDN sur les en-têtes de requête TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)). De cette manière, Neptune inclura deux nouveaux champs d'en-tête dans les en-têtes de suivi des fragments de réponse :
+ `X-Neptune-Status` : contient le code de réponse suivi d'un nom court. Par exemple, en cas de réussite, l'en-tête final serait : `X-Neptune-Status: 200 OK`. En cas d'échec, le code de réponse est un [code d'erreur du moteur Neptune](errors-engine-codes.md), tel que `X-Neptune-Status: 500 TimeLimitExceededException`.
+ `X-Neptune-Detail` : est vide pour les demandes qui ont abouti. En cas d'erreur, il contient le message d'erreur JSON. Étant donné que seuls les caractères ASCII sont autorisés dans les valeurs d'en-tête HTTP, la chaîne JSON est encodée en URL. Le message d'erreur est également toujours ajouté au corps du message de réponse.

# Types de médias RDF utilisés par SPARQL dans Neptune
<a name="sparql-media-type-support"></a>

Les données RDF (Resource Description Framework) peuvent être sérialisées de nombreuses façons différentes, la plupart pouvant être consommées ou générées par SPARQL :

## Formats de sérialisation RDF utilisés par Neptune SPARQL
<a name="sparql-serialization-formats"></a>
+ **RDF/XML** : sérialisation XML de RDF, définie dans [Syntaxe XML pour RDF 1.1](https://www.w3.org/TR/rdf-syntax-grammar/). Type de support : `application/rdf+xml`. Extension de fichier type : `.rdf`.
+ **N-Triples** : format de type ligne et texte simple pour l'encodage d'un graphe RDF, défini dans [N-Triples pour RDF 1.1](https://www.w3.org/TR/n-triples/). Type de support : `application/n-triples`, `text/turtle` ou `text/plain`. Extension de fichier type : `.nt`.
+ **N-Quads** : format de type ligne et texte simple pour l'encodage d'un graphe RDF, défini dans [N-Quads pour RDF 1.1](https://www.w3.org/TR/n-quads/). Il s'agit d'une extension des N-Triples. Type de support : `application/n-quads` ou `text/x-nquads` en cas d'encodage avec US-ASCII sur 7 bits. Extension de fichier type : `.nq`.
+ **Turtle** : syntaxe textuelle pour RDF définie dans [Turtle pour RDF 1.1](https://www.w3.org/TR/turtle/) qui permet à un graphe RDF d'être complètement écrit dans un format de texte naturel et compact, avec des abréviations pour les types de données et modèles d'utilisation courants. Turtle fournit des niveaux de compatibilité avec le format N-Triples ainsi que la syntaxe de modèle de triplet de SPARQL. Type de support : `text/turtle`Extension de fichier type  : `.ttl`.
+ **TriG** : syntaxe textuelle pour RDF définie dans [TriG pour RDF 1.1](https://www.w3.org/TR/trig/) qui permet à un graphe RDF d'être complètement écrit dans un format de texte naturel et compact, avec des abréviations pour les types de données et modèles d'utilisation courants. TriG est une extension du format Turtle. Type de support : `application/trig`. Extension de fichier type : `.trig`.
+ **N3 (Notation3)** : langage de logique et assertion défini dans [Notation3 (N3) : une syntaxe RDF lisible](https://www.w3.org/TeamSubmission/n3/). N3 étend le modèle de données RDF en ajoutant des formulae (littéraux qui sont eux-mêmes des graphes), des variables, une implication logique et des prédicats fonctionnels, et qui fournit une autre syntaxe textuelle possible à RDF/XML. Type de support : `text/n3`. Extension de fichier type : `.n3`.
+ **JSON-LD** : format de messagerie et de sérialisation de données défini dans [JSON-LD 1.0](https://www.w3.org/TR/json-ld/). Type de support : `application/ld+json`. Extension de fichier type : `.jsonld`.
+ **TriX** : sérialisation de RDF en XML, définie dans [TriX : triplets RDF en XML](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html). Type de support : `application/trix`. Extension de fichier type : `.trix`.
+ **Résultats JSON SPARQL** : sérialisation de RDF avec le [format JSON des résultats de requêtes SPARQL 1.1](https://www.w3.org/TR/sparql11-results-json). Type de support : `application/sparql-results+json`. Extension de fichier type : `.srj`.
+ **RDF4Format binaire J — Format** binaire pour le codage des données RDF, documenté dans le format [RDF4J Binary RDF](https://rdf4j.org/documentation/reference/rdf4j-binary). Type de support : `application/x-binary-rdf`.

## Formats de sérialisation des résultats SPARQL utilisés par Neptune SPARQL
<a name="sparql-serialization-formats-neptune-output"></a>
+ **Résultats XML SPARQL** : format XML pour la liaison de variables et les formats de résultats booléens fournis par le langage de requête SPARQL, défini dans [Format XML des résultats de requêtes SPARQL (deuxième édition)](https://www.w3.org/TR/rdf-sparql-XMLres/). Type de support : `application/sparql-results+xml`. Extension de fichier type : `.srx`.
+ **Résultats CSV et TSV SPARQL** : utilisation de valeurs séparées par des virgules ou par des tabulations pour exprimer les résultats de requêtes SPARQL des requêtes `SELECT`, définie dans [Formats CSV et TSV des résultats de requêtes SPARQL 1.1](https://www.w3.org/TR/sparql11-results-csv-tsv/). Type de support : `text/csv` pour les valeurs séparées par des virgules et `text/tab-separated-values` pour les valeurs séparées par des tabulations. Extensions de fichiers types : `.csv` pour les valeurs séparées par des virgules et `.tsv` pour les valeurs séparées par des tabulations.
+ **Tableau des résultats binaires** : format binaire pour l'encodage de la sortie des requêtes SPARQL. Type de support : `application/x-binary-rdf-results-table`.
+ **Résultats JSON SPARQL** : sérialisation de RDF avec le [format JSON des résultats de requêtes SPARQL 1.1](https://www.w3.org/TR/sparql11-results-json/). Type de support : `application/sparql-results+json`.

## Types de supports que Neptune peut utiliser pour importer des données RDF
<a name="sparql-serialization-formats-input"></a>

**Types de supports pris en charge par le [chargeur en bloc Neptune](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/)

**Types de supports que SPARQL UPDATE LOAD peut importer**
+ [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/)

## Types de supports que Neptune peut utiliser pour exporter les résultats de requêtes
<a name="sparql-serialization-formats-output"></a>

Pour spécifier le format de sortie pour une réponse de requête SPARQL, envoyez un en-tête `"Accept: media-type"` avec la demande de requête. Par exemple :

```
curl -H "Accept: application/nquads" ...
```

**Types de supports RDF que SPARQL SELECT peut générer à partir de Neptune**
+ [Résultats JSON SPARQL](https://www.w3.org/TR/sparql11-results-json) (Ceci est la valeur par défaut)
+ [Résultats XML SPARQL](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **Tableau de résultats binaires** (type de support : `application/x-binary-rdf-results-table`)
+ [Valeurs séparées par des virgules (CSV)](https://www.w3.org/TR/sparql11-results-csv-tsv/)
+ [TSV (valeurs séparées par des tabulations)](https://www.w3.org/TR/sparql11-results-csv-tsv/)

**Types de supports RDF que SPARQL ASK peut générer à partir de Neptune**
+ [Résultats JSON SPARQL](https://www.w3.org/TR/sparql11-results-json) (Ceci est la valeur par défaut)
+ [Résultats XML SPARQL](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **Valeur booléenne** (type de support : `text/boolean`, ce qui signifie « vrai » ou « faux »)

**Types de supports RDF que SPARQL CONSTRUCT peut générer à partir de Neptune**
+ [N-Quads](https://www.w3.org/TR/n-quads/) (Ceci est la valeur par défaut)
+ [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/)
+ [Résultats JSON SPARQL](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4Format RDF binaire J](https://rdf4j.org/documentation/reference/rdf4j-binary)

**Types de supports RDF que SPARQL DESCRIBE peut générer à partir de Neptune**
+ [N-Quads](https://www.w3.org/TR/n-quads/) (Ceci est la valeur par défaut)
+ [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/)
+ [Résultats JSON SPARQL](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4Format RDF binaire J](https://rdf4j.org/documentation/reference/rdf4j-binary)

# Utilisation de SPARQL UPDATE LOAD pour importer des données dans Neptune
<a name="sparql-api-reference-update-load"></a>

La syntaxe de la commande SPARQL UPDATE LOAD est spécifiée dans la [recommandation de mise à jour 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`** : (*facultatif*) fait en sorte que l'opération renvoie une réussite même en cas d'erreur lors du traitement.

  Cela peut être utile lorsqu'une seule transaction contient plusieurs déclarations, comme `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"`, et si vous souhaitez qu'elle soit exécutée même si certaines données distantes n'ont pas pu être traitées.
+ *URL of data to be loaded*— (*Obligatoire*) Spécifie un fichier de données distant contenant les données à charger dans un graphique.

  Le fichier distant doit avoir l'une des extensions suivantes :
  + `.nt`pour NTriples.
  + `.nq`pour NQuads.
  + `.trig` pour Trig.
  + `.rdf` pour RDF/XML.
  + `.ttl` pour Turtle.
  + `.n3` pour N3.
  + `.jsonld` pour JSON-LD.
+ **`INTO GRAPH`***(named graph into which to load the data)*— (*Facultatif*) Spécifie le graphique dans lequel les données doivent être chargées.

  Neptune associe chaque triplet à un graphe nommé. Vous pouvez spécifier le graphe nommé par défaut à l'aide de l'URI de remplacement, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`, comme suit :

  ```
  INTO GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

**Note**  
Lorsque vous devez charger un grand nombre de données, nous vous recommandons d'utiliser le chargeur en bloc Neptune au lieu d'UPDATE LOAD. Pour plus d'informations sur le chargeur en bloc, consultez [Utilisation du chargeur en vrac Amazon Neptune pour ingérer des données](bulk-load.md).

Vous pouvez utiliser `SPARQL UPDATE LOAD` pour charger des données directement à partir d'Amazon S3 ou de fichiers obtenus à partir d'un serveur web auto-hébergé. Les ressources à charger doivent se trouver dans la même région que le serveur Neptune, et le point de terminaison pour les ressources doit être ajouté à la liste blanche dans le VPC. Pour en savoir plus sur la création d'un point de terminaison Amazon S3, consultez [Création d'un point de terminaison de VPC Amazon S3](bulk-load-data.md#bulk-load-prereqs-s3).

Tout `SPARQL UPDATE LOAD` URIs doit commencer par`https://`. Cela inclut Amazon S3 URLs.

Contrairement au chargeur en bloc Neptune, un appel à `SPARQL UPDATE LOAD` est entièrement transactionnel.

**Chargement des fichiers directement depuis Amazon S3 dans Neptune avec SPARQL UPDATE LOAD**

Étant donné que Neptune ne vous permet pas de transmettre un rôle IAM à Amazon S3 lors de l'utilisation de SPARQL UPDATE LOAD, le compartiment Amazon S3 en question doit être public ou vous devez utiliser une [URL Amazon S3 présignée](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) dans la requête LOAD.

Pour générer une URL pré-signée pour un fichier Amazon S3, vous pouvez utiliser une AWS CLI commande comme celle-ci :

```
aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to load)
```

Vous pouvez ensuite utiliser l'URL pré-signée qui en résulte dans la commande `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)'
```

Pour plus d'informations, consultez [Authentification des demandes : utilisation des paramètres de requête](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html). La [documentation Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html) montre comment utiliser un script Python pour générer une URL présignée.

De plus, le type de contenu des fichiers à charger doit être défini correctement.

1. Définissez le type de contenu des fichiers lorsque vous les chargez dans Amazon S3 à l'aide du paramètre `-metadata`, comme suit :

   ```
   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. Vérifiez que les informations relatives au type de support sont réellement présentes. Exécuter :

   ```
   curl -v bucket-name/folder-name
   ```

   La sortie de cette commande doit indiquer les informations relatives au type de support que vous définissez lors du chargement des fichiers.

1. Ensuite, vous pouvez utiliser la commande `SPARQL UPDATE LOAD` pour importer ces fichiers dans Neptune :

   ```
   curl https://your-neptune-endpoint:port/sparql \
     -d "update=LOAD <https://s3.amazonaws.com/bucket-name/my-rdf-input/test.rdf>"
   ```

Les étapes ci-dessus ne fonctionnent que pour un compartiment Amazon S3 public ou pour un compartiment auquel vous accédez à l'aide d'une [URL Amazon S3 présignée](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) dans la requête LOAD.

 Vous pouvez également configurer un serveur proxy web pour le charger à partir d'un compartiment Amazon S3 privé, comme indiqué ci-dessous :

**Utilisation d'un serveur web pour charger des fichiers dans Neptune avec SPARQL UPDATE LOAD**

1. Installez un serveur web sur un ordinateur exécuté au sein du VPC qui héberge Neptune et les fichiers à charger. Par exemple, à l'aide d'Amazon Linux, vous pouvez installer Apache comme suit :

   ```
   sudo yum install httpd mod_ssl
   sudo /usr/sbin/apachectl start
   ```

1. Définissez le(s) type(s) MIME du contenu de fichiers RDF que vous allez charger. SPARQL utilise l'en-tête `Content-type` envoyé par le serveur web pour déterminer le format d'entrée du contenu et, par conséquent, vous devez définir les types MIME correspondants pour le serveur web.

   Par exemple, supposons que vous utilisiez les extensions de fichiers suivantes pour identifier les formats de fichiers :
   + `.nt`pour NTriples.
   + `.nq`pour NQuads.
   + `.trig` pour Trig.
   + `.rdf` pour RDF/XML.
   + `.ttl` pour Turtle.
   + `.n3` pour N3.
   + `.jsonld` pour JSON-LD.

   Si vous utilisez Apache 2 en tant que serveur web, vous devez modifier le fichier `/etc/mime.types` et ajouter les types suivants :

   ```
    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. Vérifiez que le mappage de type MIME fonctionne. Une fois que votre serveur web est opérationnel avec l'hébergement des fichiers RDF dans le(s) format(s) de votre choix, vous pouvez tester la configuration en envoyant une demande au serveur web à partir de votre hôte local.

   Par exemple, vous pouvez envoyer une requête comme celle-ci :

   ```
   curl -v http://localhost:80/test.rdf
   ```

   Ensuite, dans la sortie détaillée à partir de `curl`, vous devriez voir une ligne telle que :

   ```
   Content-Type: application/rdf+xml
   ```

   Ceci indique que le mappage du type de contenu a été défini avec succès.

1. Vous êtes maintenant prêt à charger les données à l'aide de la commande SPARQL UPDATE :

   ```
   curl https://your-neptune-endpoint:port/sparql \
       -d "update=LOAD <http://web_server_private_ip:80/test.rdf>"
   ```

**Note**  
L'utilisation de `SPARQL UPDATE LOAD` peut déclencher un délai d'expiration sur le serveur web lorsque le fichier source en cours de chargement est volumineux. Neptune traite les données de fichier au fur et à mesure de leur diffusion et, pour un fichier volumineux, cela peut prendre plus de temps que le délai d'expiration configuré sur le serveur. Cela peut provoquer la fermeture de la connexion par le serveur, ce qui peut entraîner le message d'erreur suivant lorsque Neptune rencontre une fin de fichier (EOF) inattendue dans le flux :  

```
{
  "detailedMessage":"Invalid syntax in the specified file",
  "code":"InvalidParameterException"
}
```
Si vous recevez ce message et que vous ne pensez pas que votre fichier source contienne une syntaxe non valide, essayez d'augmenter les paramètres de délai d'expiration sur le serveur web. Vous pouvez également diagnostiquer le problème en activant les journaux de débogage sur le serveur et en recherchant les délais d'expiration.

# Utilisation de SPARQL UPDATE UNLOAD pour supprimer des données de Neptune
<a name="sparql-api-reference-unload"></a>

Neptune fournit également une opération SPARQL personnalisée, `UNLOAD`, pour supprimer les données spécifiées dans une source distante. `UNLOAD` peut être considéré comme une contrepartie à l'opération `LOAD`. Sa syntaxe est la suivante :

```
UNLOAD SILENT (URL of the remote data to be unloaded) FROM GRAPH (named graph from which to remove the data)
```
+ **`SILENT`** : (*facultatif*) fait en sorte que l'opération renvoie une réussite même en cas d'erreur lors du traitement des données.

  Cela peut être utile lorsqu'une seule transaction contient plusieurs déclarations, comme `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"`, et si vous souhaitez qu'elle soit exécutée même si certaines données distantes n'ont pas pu être traitées.
+ *URL of the remote data to be unloaded*— (*Obligatoire*) Spécifie un fichier de données distant contenant les données à décharger d'un graphique.

  Le fichier distant doit avoir l'une des extensions suivantes (ce sont les mêmes formats que ceux pris en charge par UPDATE-LOAD) :
  + `.nt`pour NTriples.
  + `.nq`pour NQuads.
  + `.trig` pour Trig.
  + `.rdf` pour RDF/XML.
  + `.ttl` pour Turtle.
  + `.n3` pour N3.
  + `.jsonld` pour JSON-LD.

  Toutes les données contenues dans ce fichier seront supprimées de votre cluster de bases de données par l'opération `UNLOAD`.

  Toute authentification Amazon S3 doit être incluse dans l'URL pour que les données soient déchargées. Vous pouvez présigner un fichier Amazon S3, puis utiliser l'URL qui en résulte pour y accéder en toute sécurité. Par exemple :

  ```
  aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to unload)
  ```

  Ensuite :

  ```
  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)'
  ```

  Pour plus d'informations, consultez [Authentification des demandes : utilisation des paramètres de requête](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html).
+ **`FROM GRAPH `***(named graph from which to remove the data)*— (*Facultatif*) Spécifie le graphe nommé à partir duquel les données distantes doivent être déchargées.

  Neptune associe chaque triplet à un graphe nommé. Vous pouvez spécifier le graphe nommé par défaut à l'aide de l'URI de remplacement, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`, comme suit :

  ```
  FROM GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

De la même manière que `LOAD` correspond à `INSERT DATA { (inline data) }`, `UNLOAD` correspond à `DELETE DATA { (inline data) }`. Comme `DELETE DATA`, `UNLOAD` ne fonctionne pas sur les données contenant des nœuds vides.

Par exemple, si un serveur web local gère un fichier nommé `data.nt` contenant les deux triplets suivants :

```
<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> .
```

La commande `UNLOAD` suivante supprime ces deux triplets du graphe nommé, `<http://example.org/graph1>` :

```
UNLOAD <http://localhost:80/data.nt> FROM GRAPH <http://example.org/graph1>
```

L'effet serait le même que si vous utilisiez la commande `DELETE DATA` suivante :

```
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> .
  }
}
```

**Exceptions générées par la commande `UNLOAD`**
+ **`InvalidParameterException`** : présence de nœuds vides dans les données. *État HTTP* : demande 400 incorrecte.

  *Message* : ` Blank nodes are not allowed for UNLOAD`

   
+ **`InvalidParameterException`** : syntaxe des données incorrecte. *État HTTP* : demande 400 incorrecte.

  *Message* : `Invalid syntax in the specified file.`

   
+ **`UnloadUrlAccessDeniedException `** : accès refusé. *État HTTP* : demande 400 incorrecte.

  *Message* : `Update failure: Endpoint (Neptune endpoint) reported access denied error. Please verify access.`

   
+ **`BadRequestException `** : les données distantes ne peuvent pas être récupérées. *État HTTP* : demande 400 incorrecte.

  *Message* : *(dépend de la réponse HTTP).*

# Indicateurs de requête SPARQL
<a name="sparql-query-hints"></a>

Vous pouvez utiliser des indicateurs de requête afin de spécifier des stratégies d'optimisation et d'évaluation pour une requête SPARQL particulière dans Amazon Neptune. 

Les indicateurs de requête sont exprimés à l'aide de modèles de triplet supplémentaires qui sont intégrés à la requête SPARQL avec les éléments suivants :

```
scope hint value
```
+ *portée* : détermine la partie de la requête à laquelle l'indicateur de requête s'applique, comme un certain groupe dans la requête ou la requête complète.
+ *hint* : identifie le type d'indicateur à appliquer.
+ *value* : détermine le comportement de l'aspect du système pris en compte.

Les indicateurs et portées de requête sont exposés sous la forme de termes prédéfinis dans l'espace de noms Amazon Neptune `http://aws.amazon.com/neptune/vocab/v01/QueryHints#`. Les exemples de cette section décrivent l'espace de noms sous la forme d'un préfixe `hint` qui est défini et inclus dans la requête :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```

Par exemple, le code suivant montre comment inclure un indicateur `joinOrder` dans une requête `SELECT` :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ... {
 hint:Query hint:joinOrder "Ordered" .
 ...
}
```

La requête précédente demande au moteur Neptune d'évaluer les jointures dans la requête dans l'ordre *donné* et de désactiver toute réorganisation automatique.

Tenez compte des éléments suivants lorsque vous utilisez des indicateurs de requête :
+ Vous pouvez combiner différents indicateurs de requête dans une seule requête. Par exemple, vous pouvez utiliser l'indicateur de requête `bottomUp` afin d'annoter une sous-requête pour une évaluation ascendante et un indicateur de requête `joinOrder` pour corriger l'ordre des jointures à l'intérieur de la sous-requête.
+ Vous pouvez utiliser le même indicateur de requête plusieurs fois, dans différentes portées qui ne se chevauchent pas.
+ Les indicateurs de requête sont des suggestions. Même si le moteur de requête vise généralement à prendre en compte des indicateurs de requête donnés, il peut également les ignorer.
+ Les indicateurs de requête préservent la sémantique. L'ajout d'un indicateur de requête ne modifie pas la sortie de la requête (sauf pour l'ordre des résultats potentiels quand aucune garantie d'ordre n'est fournie, en d'autres termes, lorsque l'ordre des résultats n'est pas appliqué à l'aide d'ORDER BY). 

Les sections suivantes fournissent plus d'informations sur les indicateurs de requête disponibles et leur utilisation dans Neptune.

**Topics**
+ [Portée des indicateurs de requêtes SPARQL dans Neptune](#sparql-query-hints-scope)
+ [Indicateur de requête `joinOrder` SPARQL](sparql-query-hints-joinOrder.md)
+ [Indicateur de requête `evaluationStrategy` SPARQL](sparql-query-hints-evaluationStrategy.md)
+ [Indicateur de requête `queryTimeout` SPARQL](sparql-query-hints-queryTimeout.md)
+ [Indicateur de requête `rangeSafe` SPARQL](sparql-query-hints-rangeSafe.md)
+ [Indicateur de requête `queryId` SPARQL](sparql-query-hints-queryId.md)
+ [Indicateur de requête `useDFE` SPARQL](sparql-query-hints-useDFE.md)
+ [Indicateurs de requête SPARQL utilisés avec DESCRIBE](sparql-query-hints-for-describe.md)

## Portée des indicateurs de requêtes SPARQL dans Neptune
<a name="sparql-query-hints-scope"></a>

Le tableau suivant montre les portées disponibles, les indicateurs associés et des descriptions pour les indicateurs de requête SPARQL dans Amazon Neptune. Le préfixe `hint` de ces entrées représente l'espace de noms Neptune des indicateurs :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```


| Scope | Indicateurs pris en charge | Description | 
| --- | --- | --- | 
| hint:Query | [joinOrder](sparql-query-hints-joinOrder.md) | L'indicateur de requête s'applique à toute la requête. | 
| hint:Query | [queryTimeout](sparql-query-hints-queryTimeout.md) | La valeur de délai d’attente s'applique à l'ensemble de la requête. | 
| hint:Query | [rangeSafe](sparql-query-hints-rangeSafe.md) | La promotion de type est désactivée pour l'ensemble de la requête. | 
| hint:Query | [queryId](sparql-query-hints-queryId.md) | La valeur d'ID de requête s'applique à l'ensemble de la requête. | 
| hint:Query | [useDFE](sparql-query-hints-useDFE.md) | L'utilisation du DFE est activée (ou désactivée) pour l'ensemble de la requête. | 
| hint:Group | [joinOrder](sparql-query-hints-joinOrder.md) | L'indicateur de requête s'applique aux éléments de niveau supérieur du groupe spécifié, mais pas aux éléments imbriqués (comme les sous-requêtes) ou aux éléments parents. | 
| hint:SubQuery | [evaluationStrategy](sparql-query-hints-evaluationStrategy.md) | L'indicateur est spécifié et appliqué à une sous-requête SELECT imbriquée. La sous-requête est évaluée de façon indépendante, sans tenir compte des solutions calculées avant la sous-requête. | 

# Indicateur de requête `joinOrder` SPARQL
<a name="sparql-query-hints-joinOrder"></a>

Lorsque vous soumettez une requête SPARQL, le moteur de requête Amazon Neptune étudie sa structure. Il réorganise les parties de la requête et tente de réduire au maximum la quantité de travail nécessaire pour l'évaluation et le temps de réponse de la requête.

Par exemple, une séquence de modèles de triplet connectés n'est généralement pas évaluée dans l'ordre donné. Elle est réorganisée à l'aide d'heuristique et de statistiques telles que la sélectivité des différents modèles et la façon dont ils sont connectés via des variables partagées. De plus, si votre requête contient des modèles plus complexes tels que des sous-requêtes ou des blocs OPTIONNEL ou MINUS complexes FILTERs, le moteur de requêtes Neptune les réorganise dans la mesure du possible, dans le but d'obtenir un ordre d'évaluation efficace.

Pour les requêtes plus complexes, l'ordre dans lequel Neptune choisit d'évaluer la requête peut ne pas toujours être optimal. Par exemple, Neptune peut manquer des caractéristiques spécifiques aux données d'instance (par exemple, l'exécution de nœuds Power dans le graphe) qui émergent au cours de l'évaluation de la requête.

Si vous connaissez les caractéristiques exactes des données et que vous souhaitez imposer manuellement l'ordre de l'exécution de la requête, utilisez l'indicateur de requête Neptune `joinOrder` pour demander que la requête soit évaluée dans l'ordre donné.

## Syntaxe des indicateurs `joinOrder` SPARQL
<a name="sparql-query-hints-joinOrder-syntax"></a>

L'indicateur de requête `joinOrder` est spécifié en tant que modèle de triplet inclus dans une requête SPARQL.

Pour plus de clarté, la syntaxe suivante utilise un préfixe `hint` défini et inclus dans la requête pour spécifier l’espace de noms d'indicateur de requête Neptune :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
scope hint:joinOrder "Ordered" .
```

**Portées disponibles**
+ `hint:Query`
+ `hint:Group`

Pour plus d'informations sur les portées d'indicateur de requête, consultez [Portée des indicateurs de requêtes SPARQL dans Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Exemple d'indicateur `joinOrder` SPARQL
<a name="sparql-query-hints-joinOrder-example"></a>

Cette section montre une requête écrite avec et sans l'indicateur de requête `joinOrder`, ainsi que les optimisations associées.

Pour cet exemple, supposons que l'ensemble de données contient les éléments suivants :
+ Une personne unique nommée `John` qui `:likes` 1 000 personnes, y compris `Jane`.
+ Une personne unique nommée `Jane` qui `:likes` 10 personnes, y compris `John`.

**Aucun indicateur de requête**  
La requête SPARQL suivante extrait toutes les paires de personnes nommées `John` et `Jane` qui sont amies à partir d'un ensemble de données de réseau social :

```
PREFIX : <https://example.com/>
SELECT ?john ?jane {
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

Le moteur de requête Neptune peut évaluer les déclarations dans un ordre différent de celui qui est écrit. Par exemple, il peut choisir d'évaluer dans l'ordre suivant :

1. Trouver toutes les personnes nommées `John`.

1. Trouver toutes les personnes connectées à `John` par une arête `:likes`.

1. Filtrer cet ensemble par les personnes nommées `Jane`.

1. Filtrer cet ensemble par les personnes connectées à `John` par une arête `:likes`.

Selon l'ensemble de données, l'évaluation dans cette commande se traduit par 1 000 entités extraites lors de la deuxième étape. La troisième étape affine l'extraction à un nœud unique, `Jane`. L'étape finale détermine ensuite que `Jane` `:likes` également le nœud `John`.

**Indicateur de requête**  
Il serait préférable de démarrer avec le nœud `Jane`, car Jane n'a que 10 arêtes `:likes` sortantes. Cela réduit la quantité de travail pendant l'évaluation de la requête en évitant l'extraction des 1 000 entités au cours de la deuxième étape.

L'exemple suivant utilise l'indicateur de requête **joinOrder** afin de s'assurer que le nœud `Jane` et ses arêtes sortantes sont traités en premier en désactivant toute la réorganisation automatique des jointures pour la requête :

```
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 .
}
```

Un scénario réel applicable peut être une application de réseau social où les utilisateurs du réseau sont classés soit comme des influenceurs avec de nombreuses connexions, soit comme des utilisateurs normaux avec peu de connexions. Dans un tel scénario, vous pouvez vous assurer que l'utilisateur normal (`Jane`) est traité avant l'influenceur (`John`) dans une requête similaire à l'exemple précédent.

**Indicateur de requête et réorganisation**  
Vous pouvez encore améliorer cet exemple. Si vous savez que l'attribut `:name` est unique à un seul nœud, vous pouvez accélérer la requête en réorganisant et en utilisant l'indicateur de requête `joinOrder`. Cette étape permet de s'assurer que les nœuds uniques sont extraits en premier.

```
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 .
}
```

Dans ce cas, vous pouvez réduire la requête suivante aux actions uniques suivantes dans chaque étape :

1. Rechercher le seul nœud de personne avec l'attribut `:name` `Jane`.

1. Rechercher le seul nœud de personne avec l'attribut `:name` `John`.

1. Vérifier que le premier nœud est connecté au deuxième nœud avec une arête `:likes`.

1. Vérifier que le deuxième nœud est connecté au premier nœud avec une arête `:likes`.



**Important**  
Si vous ne choisissez pas l'ordre approprié, l'indicateur de requête `joinOrder` peut entraîner des baisses significatives de performance. Par exemple, l'exemple précédent serait inefficace si les attributs `:name` n'étaient pas uniques. Si les 100 nœuds étaient nommés `Jane` et si tous les 1 000 nœuds étaient nommés `John`, la requête auraient à vérifier 1 000 \$1 100 (100 000) paires pour les arêtes `:likes`.

# Indicateur de requête `evaluationStrategy` SPARQL
<a name="sparql-query-hints-evaluationStrategy"></a>

L'indicateur de requête `evaluationStrategy` indique au moteur de requête Amazon Neptune que le fragment de la requête annotée doit être évalué de bas en haut en tant qu'unité indépendante. Cela signifie qu'aucune des solutions des étapes d'évaluation précédentes n'est utilisée pour calculer le fragment de requête. Le fragment de requête est évalué en tant qu'unité autonome, et ses solutions produites sont jointes au reste de la requête une fois que celle-ci est calculée.

L'utilisation de l'indicateur de requête `evaluationStrategy` implique un plan de requête bloquant (non en pipeline), ce qui signifie que les solutions du fragment annoté avec l'indicateur de requête sont matérialisées et mises en tampon dans la mémoire principale. L'utilisation de l'indicateur de requête peut se traduire par une augmentation importante de la quantité de mémoire principale requise pour évaluer la requête, surtout si le fragment de requête annoté calcule un grand nombre de résultats.

## Syntaxe des indicateurs `evaluationStrategy` SPARQL
<a name="sparql-query-hints-evaluationStrategy-syntax"></a>

L'indicateur de requête `evaluationStrategy` est spécifié en tant que modèle de triplet inclus dans une requête SPARQL.

Pour plus de clarté, la syntaxe suivante utilise un préfixe `hint` défini et inclus dans la requête pour spécifier l’espace de noms d'indicateur de requête Neptune :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
hint:SubQuery hint:evaluationStrategy "BottomUp" .
```

**Portées disponibles**
+ `hint:SubQuery`

**Note**  
Cet indicateur de requête est pris en charge uniquement dans les sous-requêtes imbriquées.

Pour plus d'informations sur les portées d'indicateur de requête, consultez [Portée des indicateurs de requêtes SPARQL dans Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Exemple d'indicateur `evaluationStrategy` SPARQL
<a name="sparql-query-hints-evaluationStrategy-example"></a>



Cette section montre une requête écrite avec et sans l'indicateur de requête `evaluationStrategy`, ainsi que les optimisations associées.

Pour cet exemple, supposons que l'ensemble de données a les caractéristiques suivantes :
+ Il contient de 1 000 arêtes étiquetées `:connectedTo`.
+ Chaque nœud `component` est connecté en moyenne à 100 autres nœuds `component`.
+ Le nombre typique de connexions cycliques à quatre tronçons entre les nœuds est de 100 environ.

Comme exemple typique, l'indicateur `evaluationStrategy` peut s'avérer utile pour optimiser des modèles de requêtes qui contiennent des cycles.

**Aucun indicateur de requête**  
La requête SPARQL suivante extrait tous les nœuds `component` qui sont connectés cycliquement les uns aux autres via quatre tronçons :

```
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 .
}
```

L'approche du moteur de requête Neptune consiste à évaluer cette requête à l'aide des étapes suivantes :
+ Extraire la totalité des 1 000 arêtes `connectedTo` dans le graphe.
+ Multiplier par 100 (le nombre d'arêtes `connectedTo` sortantes de component2).

  Résultats intermédiaires : 100 000 nœuds.
+ Multiplier par 100 (le nombre d'arêtes `connectedTo` sortantes de component3).

  Résultats intermédiaires : 10 000 000 nœuds.
+ Analyser les 10 000 000 nœuds pour la fermeture du cycle.

Cela se traduit par un plan de requête de streaming ayan une quantité constante de mémoire principale.

**Indicateur de requête et sous-requêtes**  
Il se peut que vous souhaitiez faire une compromis sur l'espace mémoire principale pour accélérer le calcul. En réécrivant la requête à l'aide d'un indicateur de requête `evaluationStrategy`, vous pouvez forcer le moteur à calculer une jointure entre deux sous-ensembles matérialisés plus petits.

```
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 .
    }
  }
}
```

Au lieu d'évaluer les modèles de triplet dans l'ordre tout en utilisant de manière itérative les résultats des modèles de triplet précédents comme entrée pour les modèles suivantes, avec l'indicateur `evaluationStrategy`, les deux sous-requêtes sont évaluées de manière indépendante. Les deux sous-requêtes produisent 100 000 nœuds pour les résultats intermédiaires, qui sont ensuite joints pour former la sortie finale. 

En particulier, lorsque vous exécutez Neptune sur des types d'instances de plus grande taille, stocker temporairement ces deux sous-ensembles de 100 000 nœuds en mémoire principale augmente l'utilisation de la mémoire tout en accélérant l'évaluation de manière significative.

# Indicateur de requête `queryTimeout` SPARQL
<a name="sparql-query-hints-queryTimeout"></a>

L'indicateur de requête `queryTimeout` spécifie un délai d'expiration qui est inférieur à la valeur `neptune_query_timeout` définie dans le groupe de paramètres de base de données.

Si la requête se termine en raison de cet indicateur, une exception `TimeLimitExceededException` est déclenchée avec le message `Operation terminated (deadline exceeded)`.

## Syntaxe des indicateurs `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 .
 ...
}
```

La valeur de délai d'attente est exprimée en millisecondes.

La valeur de délai d'attente doit être inférieure à la valeur `neptune_query_timeout` définie dans le groupe de paramètres de base de données. Sinon, une exception `MalformedQueryException` est déclenchée avec le message `Malformed query: Query hint 'queryTimeout' must be less than neptune_query_timeout DB Parameter Group`.

L'indicateur de requête `queryTimeout` doit être spécifié dans la clause `WHERE` de la requête principale ou dans la clause `WHERE` de l'une des sous-requêtes, comme dans l'exemple ci-dessous.

Il ne doit être défini qu'une seule fois dans toutes les sections queries/subqueries et mises à jour de SPARQL (telles que INSERT et DELETE). Sinon, une exception `MalformedQueryException` est déclenchée avec le message `Malformed query: Query hint 'queryTimeout' must be set only once`.

**Portées disponibles**

L'indicateur `queryTimeout` peut être appliqué aux requêtes et mises à jour SPARQL.
+ Dans une requête SPARQL, il peut figurer dans la clause WHERE de la requête principale ou d'une sous-requête.
+ Dans une mise à jour SPARQL, il peut être défini dans la clause INSERT, DELETE ou WHERE. S'il existe plusieurs clauses de mise à jour, il ne peut être défini que dans l'une d'elles.

Pour plus d'informations sur les portées d'indicateur de requête, consultez [Portée des indicateurs de requêtes SPARQL dans Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Exemple d'indicateur `queryTimeout` SPARQL
<a name="sparql-query-hints-queryTimeout-example"></a>

Voici un exemple d'utilisation de `hint:queryTimeout` dans la clause `WHERE` principale d’une requête `UPDATE` :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
INSERT {
    ?s ?p ?o
} WHERE {
    hint:Query hint:queryTimeout 100 .
    ?s ?p ?o .
}
```

Ici, le `hint:queryTimeout` est dans la clause `WHERE` d'une sous-requête :

```
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 .
      }
   }
}
```

# Indicateur de requête `rangeSafe` SPARQL
<a name="sparql-query-hints-rangeSafe"></a>

Utilisez cet indicateur de requête pour désactiver la promotion de type pour une requête SPARQL.

Lorsque vous soumettez une requête SPARQL qui filtre une plage ou une valeur numérique avec `FILTER`, le moteur de requêtes Neptune doit normalement utiliser la promotion de type lorsqu'il exécute la requête. Autrement dit, il doit examiner les valeurs de tous les types susceptibles de contenir la valeur sur laquelle porte le filtre.

Par exemple, si vous filtrez les valeurs égales à 55, le moteur doit rechercher les entiers égaux à 55, les entiers longs égaux à 55L, les nombres flottants égaux à 55,0, etc. Chaque promotion de type implique une recherche supplémentaire au niveau du stockage, ce qui peut entraîner un délai étonnamment long pour terminer une requête apparemment simple.

Souvent, la promotion de type n'est pas nécessaire, car vous savez déjà que vous n'avez besoin de trouver que les valeurs d'un type spécifique. Dans ce cas, vous pouvez accélérer considérablement les requêtes en utilisant l'indicateur de requête `rangeSafe` afin de désactiver la promotion de type.

## Syntaxe des indicateurs `rangeSafe` SPARQL
<a name="sparql-query-hints-rangeSafe-syntax"></a>

L'indicateur de requête `rangeSafe` utilise la valeur `true` pour désactiver la promotion de type. Il accepte également la valeur `false` (valeur par défaut).

**Exemple.** L'exemple suivant montre comment désactiver la promotion de type lors du filtrage d'une valeur entière `o` supérieure à 1 :

```
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>)
```

# Indicateur de requête `queryId` SPARQL
<a name="sparql-query-hints-queryId"></a>

Utilisez cet indicateur de requête pour attribuer votre propre valeur queryId à une requête SPARQL.

Exemple :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * WHERE {
  hint:Query hint:queryId "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
  {?s ?p ?o}}
```

La valeur que vous attribuez doit être unique pour toutes les requêtes de la base de données Neptune.

# Indicateur de requête `useDFE` SPARQL
<a name="sparql-query-hints-useDFE"></a>

Utilisez cet indicateur de requête afin d'activer l'utilisation du DFE pour exécuter la requête. Par défaut, Neptune n'utilise pas le DFE sans que cet indicateur de requête ne soit défini sur `true`, car le paramètre d'instance [neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) est défini par défaut sur `viaQueryHint`. Si vous définissez ce paramètre d'instance sur `enabled`, le moteur DFE est utilisé pour toutes les requêtes, à l'exception de celles dont l'indicateur de requête `useDFE` est défini sur `false`.

Exemple d'activation de l'utilisation du DFE pour une requête :

```
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 .
}
```

# Indicateurs de requête SPARQL utilisés avec DESCRIBE
<a name="sparql-query-hints-for-describe"></a>

Une requête SPARQL `DESCRIBE` fournit un mécanisme flexible permettant de demander des descriptions de ressources. Cependant, les spécifications SPARQL ne définissent pas la sémantique précise de `DESCRIBE`.

À partir de la [version 1.2.0.2 du moteur](engine-releases-1.2.0.2.md), Neptune prend en charge plusieurs modes et algorithmes `DESCRIBE` adaptés à différentes situations.

Cet exemple de jeu de données permet d'illustrer les différents modes :

```
@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 .
```

Les exemples ci-dessous supposent qu'une description de la ressource `:JaneDoe` est demandée à l'aide d'une requête SPARQL comme celle-ci :

```
DESCRIBE <https://example.com/JaneDoe>
```

## Indicateur de requête `describeMode` SPARQL
<a name="sparql-query-hints-describeMode"></a>

L'indicateur de requête `hint:describeMode` SPARQL est utilisé pour sélectionner l'un des modes `DESCRIBE` SPARQL suivants pris en charge par Neptune :

### Mode `ForwardOneStep` DESCRIBE
<a name="sparql-query-hints-describeMode-ForwardOneStep"></a>

Vous invoquez le mode `ForwardOneStep` avec l'indicateur de requête `describeMode` comme suit :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "ForwardOneStep"
}
```

Le mode `ForwardOneStep` renvoie uniquement les attributs et les liens de transfert de la ressource à décrire. Dans le cas de cet exemple, cela signifie qu'il renvoie les triplets dont la ressource à décrire, `:JaneDoe`, est le sujet :

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b301990159 .
```

Notez que la requête DESCRIBE peut renvoyer des triplets avec des nœuds vides, tels que`_:b301990159`, qui sont différents à IDs chaque fois, par rapport au jeu de données en entrée.

### Mode `SymmetricOneStep` DESCRIBE
<a name="sparql-query-hints-describeMode-SymmetricOneStep"></a>

`SymmetricOneStep` est le mode DESCRIBE par défaut si vous ne fournissez aucun indicateur de requête. Vous pouvez également l'invoquer explicitement avec l'indicateur de requête `describeMode` comme ceci :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SymmetricOneStep"
}
```

Sous la sémantique `SymmetricOneStep`, `DESCRIBE` renvoie les attributs, les liens de transfert et les liens inverses de la ressource à décrire :

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b318767375 .

_:b318767631 rdf:subject :JaneDoe .

:RichardRoe :knows :JaneDoe .

:ref_s2 rdf:subject :JaneDoe .
```

### Mode DESCRIBE `CBD` (Concise Bounded Description)
<a name="sparql-query-hints-describeMode-CBD"></a>

Le mode `CBD` (Concise Bounded Description) est invoqué à l'aide de l'indicateur de requête `describeMode` suivant :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "CBD"
}
```

Sous la sémantique `CBD`, `DESCRIBE` renvoie la description CBD (telle que [définie par le W3C](http://www.w3.org/Submission/CBD)) de la ressource à décrire :

```
: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 .
```

La description CBD d'une ressource RDF (c'est-à-dire un nœud dans un graphe RDF) est le plus petit sous-graphe pouvant être autonome centré sur ce nœud. En pratique, cela signifie que si vous considérez ce graphe comme un arbre, avec le nœud désigné comme racine, il n'y a pas de nœuds vides comme feuilles de cet arbre. Comme les nœuds vides ne peuvent pas être traités de manière externe ni utilisés dans les requêtes ultérieures, il ne suffit pas de parcourir le graphe pour trouver le ou les prochains sauts individuels à partir du nœud actuel. Vous devez également aller assez loin pour trouver ce qui pourra être utilisé dans les requêtes ultérieures (à savoir autre chose qu'un nœud vide).

#### Calcul de la valeur CBD
<a name="sparql-query-hints-describeMode-CBD-computing"></a>

Avec un nœud particulier (le nœud ou la racine de départ) dans le graphe RDF source, la valeur CBD de ce nœud est calculée comme suit :

1. Incluez dans le sous-graphe toutes les déclarations du graphe source dont le *sujet* de la déclaration est le nœud de départ.

1. De manière récursive, pour toutes les déclarations du sous-graphe contenant jusqu'à présent un *objet* de nœud vide, incluez dans le sous-graphe toutes les déclarations du graphe source dont le *sujet* de la déclaration correspond à ce nœud vide, et qui ne sont pas déjà incluses dans le sous-graphe.

1. De manière récursive, pour toutes les déclarations incluses dans le sous-graphe jusqu'à présent, pour toutes les réifications de ces déclarations dans le graphe source, incluez la valeur CBD en commençant par le nœud `rdf:Statement` de chaque réification.

Il en résulte un sous-graphe où les nœuds de l'*objet* sont soit des références IRI ou des littéraux, soit des nœuds vides ne faisant l'*objet* d'aucune déclaration dans le graphe. Notez que le CBD ne peut pas être calculé à l'aide d'une seule requête SPARQL SELECT ou CONSTRUCT.

### Mode DESCRIBE `SCBD` (Symmetric Concise Bounded Description)
<a name="sparql-query-hints-describeMode-SCBD"></a>

Le mode `SCBD` (Symetric Concise Bounded Description) est invoqué à l'aide de l'indicateur de requête `describeMode` suivant :

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SCBD"
}
```

Sous la sémantique `SCBD`, `DESCRIBE` renvoie la description SCBD (telle que définie par le W3C dans [Description des jeux de données liés avec le vocabulaire 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 .
```

L'avantage des valeurs CBD et SCBD par rapport aux modes `ForwardOneStep` et `SymmetricOneStep` est que les nœuds vides sont toujours étendus pour inclure leur représentation. Cet avantage est de taille, car vous ne pouvez pas interroger un nœud vide à l'aide de SPARQL. En outre, les modes CBD et SCBD prennent également en compte les réifications.

Notez que l'indicateur de requête `describeMode` peut également faire partie d'une clause `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>
}
```

## Indicateur de requête `describeIterationLimit` SPARQL
<a name="sparql-query-hints-describeIterationLimit"></a>

L'indicateur de requête `hint:describeIterationLimit` SPARQL fournit une contrainte **facultative** sur le nombre maximum d'extensions itératives à effectuer pour les algorithmes itératifs DESCRIBE tels que CBD et SCBD.

DÉCRIVEZ les limites ANDed ensemble. Par conséquent, si la limite d'itération et la limite de déclarations sont spécifiées, elles doivent toutes deux être respectées avant que la requête DESCRIBE ne soit interrompue.

La valeur par défaut est 5. Vous pouvez la définir sur ZÉRO (0) pour ne pas spécifier de limite du nombre d'extensions itératives.

## Indicateur de requête `describeStatementLimit` SPARQL
<a name="sparql-query-hints-describeStatementLimit"></a>

L'indicateur de requête SPARQL `hint:describeStatementLimit` fournit une contrainte **facultative** sur le nombre maximum de déclarations pouvant être présentes dans une réponse à une requête DESCRIBE. Il n'est appliqué qu'aux algorithmes itératifs DESCRIBE tels que CBD et SCBD.

DÉCRIVEZ les limites ANDed ensemble. Par conséquent, si la limite d'itération et la limite de déclarations sont spécifiées, elles doivent toutes deux être respectées avant que la requête DESCRIBE ne soit interrompue.

La valeur par défaut est 5 000. Vous pouvez la définir sur ZÉRO (0) pour ne pas limiter le nombre de déclarations renvoyées.

# Comportement de SPARQL DESCRIBE par rapport au graphe par défaut
<a name="sparql-default-describe"></a>

Le type de requête SPARQL [https://www.w3.org/TR/sparql11-query/#describe](https://www.w3.org/TR/sparql11-query/#describe) vous permet de récupérer des informations sur les ressources sans connaître la structure des données et sans avoir à composer de requête. La manière dont ces informations sont assemblées dépend de l'implémentation SPARQL. Neptune fournit [plusieurs indicateurs de requête](sparql-query-hints-for-describe.md) qui invoquent différents modes et algorithmes à utiliser par `DESCRIBE`.

Dans l'implémentation de Neptune, quel que soit le mode, `DESCRIBE` utilise uniquement les données présentes dans le [graphe par défaut SPARQL](feature-sparql-compliance.md#sparql-default-graph). Cela est cohérent avec la façon dont SPARQL traite les jeux de données (voir [Spécification des jeux de données RDF](https://www.w3.org/TR/sparql11-query/#specifyingDataset) dans la spécification SPARQL).

Dans Neptune, le graphe par défaut contient tous les triplets uniques issus de l'union de tous les graphes nommés de la base de données, sauf si des graphes nommés particuliers sont spécifiés à l'aide de clauses. `FROM` and/or `FROM NAMED` Toutes les données RDF de Neptune sont stockées dans un graphe nommé. Si un triplet est inséré sans contexte de graphe nommé, Neptune le stocke dans un graphe nommé désigné `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`.

Lorsqu'un ou plusieurs graphes nommés sont spécifiés à l'aide de la clause `FROM`, le graphe par défaut est l'union de tous les triplets uniques de ces graphes nommés. S'il n'y a aucune clause `FROM` et qu'il existe une ou plusieurs clauses `FROM NAMED`, le graphe par défaut est vide.

## Exemples SPARQL `DESCRIBE`
<a name="sparql-default-describe-examples"></a>

Prenons les données suivantes :

```
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" .
```

Pour cette requête :

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s
FROM ex:g1
FROM NAMED ex:g2
WHERE {
  GRAPH ex:g2 { ?s ?p "b" . }
}
```

Neptune renvoie :

```
ex:s ex:p1 "a" .
ex:s ex:p2 "c" .
```

Ici, le modèle de graphe `GRAPH ex:g2 { ?s ?p "b" }` est d'abord évalué, ce qui entraîne des liaisons pour `?s`, puis la partie `DESCRIBE` est évaluée par rapport au graphe par défaut, qui n'est plus qu'`ex:g1`.

Toutefois, pour cette requête :

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
FROM NAMED ex:g1 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

Neptune ne renverrait rien, car lorsqu'une clause `FROM NAMED` est présente sans aucune clause `FROM`, le graphe par défaut est vide.

Dans la requête suivante, `DESCRIBE` est utilisé en l'absence de clause `FROM` ou `FROM NAMED` :

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

Dans ce cas, le graphe par défaut est composé de tous les triplets uniques issus de l'union de tous les graphes nommés de la base de données (officiellement, la fusion RDF). Neptune renverrait donc :

```
ex:s ex:p1 "a" . 
ex:s ex:p2 "c" . 
ex:s ex:p3 "b" .
ex:s ex:p3 "d" .
```

# API de statut des requêtes SPARQL
<a name="sparql-api-status"></a>

Pour obtenir le statut des requêtes SPARQL, envoyez une demande HTTP `GET` ou `POST` pour effectuer une requête au point de terminaison `https://your-neptune-endpoint:port/sparql/status`. 

## Paramètres des demandes de statut des requêtes SPARQL
<a name="sparql-api-status-get-request"></a>

**queryId (facultatif)**  
ID d'une requête SPARQL en cours d'exécution. Affiche uniquement le statut de la requête indiquée.

## Syntaxe des réponses de statut des requêtes 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"
      }
    ]
}
```

## Valeurs des réponses de statut des requêtes SPARQL
<a name="sparql-api-status-get-response-values"></a>

**acceptedQueryCount**  
Nombre de requêtes acceptées depuis le dernier redémarrage du moteur Neptune.

**runningQueryCount**  
Nombre de requêtes SPARQL en cours d'exécution.

**queries**  
Liste des requêtes SPARQL actuelles.

**queryId**  
GUID de la requête. Neptune attribue automatiquement cette valeur d'ID à chaque requête, mais vous pouvez également attribuer votre propre ID (voir [Injection d'un ID personnalisé dans une requête Neptune Gremlin ou SPARQL](features-query-id.md)). 

**queryEvalStats**  
Statistiques pour cette requête.

**subqueries**  
Nombre de sous-requêtes de cette requête.

**elapsed**  
Nombre de microsecondes d'exécution de la requête jusqu'ici.

**cancelled**  
True indique que la requête a été annulée.

**queryString**  
Requête soumise.

## Exemple de statut des requêtes SPARQL
<a name="sparql-api-status-get-example"></a>

Voici un exemple de commande de demande du statut utilisant `curl` et la demande HTTP `GET`.

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

Cette sortie affiche une seule requête en cours d'exécution.

```
{
    "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}"
        }
    ]
}
```

# Annulation de requêtes SPARQL
<a name="sparql-api-status-cancel"></a>

Pour obtenir le statut des requêtes SPARQL, envoyez une demande HTTP `GET` ou `POST` pour effectuer une requête au point de terminaison `https://your-neptune-endpoint:port/sparql/status`.

## Paramètres des demandes d'annulation des requêtes SPARQL
<a name="sparql-api-status-cancel-request"></a>

**cancelQuery**  
(Obligatoire) Indique à la commande d'état d'annuler une requête. Ce paramètre n'est pas défini sur une valeur.

**queryId**  
(Obligatoire) ID de la requête SPARQL en cours d'exécution à annuler.

**silent**  
(Facultatif) Si `silent=true`, la requête en cours d'exécution est annulée et le code de réponse HTTP est 200. Si `silent` n'est pas présent ou si `silent=false`, la requête est annulée avec un code d'état HTTP 500.

## Exemple d'annulation de requêtes SPARQL
<a name="sparql-api-status-cancel-example"></a>

**Exemple 1 : Annulation avec `silent=false`**  
Voici un exemple de commande d'état utilisant `curl` pour annuler une requête avec le paramètre `silent` défini sur `false` :

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

Sauf si la requête a déjà commencé à diffuser des résultats, la requête annulée renvoie alors un code HTTP 500 avec une réponse comme celle-ci :

```
{
  "code": "CancelledByUserException",
  "requestId": "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47",
  "detailedMessage": "Operation terminated (cancelled by user)"
}
```

Si la requête a déjà renvoyé un code HTTP 200 (OK) et a commencé à diffuser des résultats avant d'être annulée, les informations d'exception de délai d'attente sont envoyées au flux de sortie normal.

**Exemple 2 : Annulation avec `silent=true`**  
Voici un exemple de la même commande d'état que ci-dessus, mais avec le paramètre `silent` défini sur `true` :

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

Cette commande renvoie la même réponse que lorsque `silent=false`, mais la requête annulée renvoie désormais un code HTTP 200 avec une réponse similaire à celle-ci :

```
{
  "head" : {
    "vars" : [ "s", "p", "o" ]
  },
  "results" : {
    "bindings" : [ ]
  }
}
```

# Utilisation du protocole HTTP SPARQL 1.1 Graph Store (GSP) dans Amazon Neptune
<a name="sparql-graph-store-protocol"></a>

Dans la recommandation du [protocole HTTP SPARQL 1.1 Graph Store](https://www.w3.org/TR/sparql11-http-rdf-update/), le W3C a défini un protocole HTTP pour gérer les graphes RDF. Il définit les opérations permettant de supprimer, de créer et de remplacer le contenu d'un graphe RDF ainsi que d'ajouter des instructions RDF au contenu existant.

Le protocole Graph Store (GSP) fournit un moyen pratique de manipuler l'intégralité du graphe sans avoir à écrire de requêtes SPARQL complexes.

Neptune prend pleinement en charge ce protocole.

Le point de terminaison du protocole Graph Store (GSP) est le suivant :

```
https://your-neptune-cluster:port/sparql/gsp/
```

Pour accéder au graphe par défaut avec le protocole GPS, utilisez :

```
https://your-neptune-cluster:port/sparql/gsp/?default
```

Pour accéder à un graphe nommé avec le protocole GPS, utilisez :

```
https://your-neptune-cluster:port/sparql/gsp/?graph=named-graph-URI
```

## Détails particuliers de la mise en œuvre Neptune du protocole GSP
<a name="sparql-graph-store-protocol-special"></a>

Neptune met pleinement en œuvre la [recommandation du W3C](https://www.w3.org/TR/sparql11-http-rdf-update/) qui définit le protocole GPS. Cependant, il existe quelques situations que cette spécification ne couvre pas.

L'un d'entre elles est le cas où une demande `PUT` ou `POST` spécifie dans le corps de la demande un ou plusieurs graphes nommés qui diffèrent du graphe spécifié par l'URL de la demande. Cela ne peut se produire que lorsque le format RDF du corps de la requête prend en charge les graphes nommés, par exemple en utilisant `Content-Type: application/n-quads` ou `Content-Type: application/trig`.

Dans ce cas, Neptune ajoute ou met à jour tous les graphes nommés présents dans le corps, ainsi que le graphe nommé spécifié dans l'URL.

Supposons, par exemple, qu'en partant d'une base de données vide, vous envoyiez une demande `PUT` pour effectuer l'upsert de votes dans trois graphes. L'un, nommé`urn:votes`, contient tous les votes pour toutes les années électorales. Les deux autres, nommés `urn:votes:2005` et`urn:votes:2019`, contiennent les votes relatifs à des années électorales spécifiques. La demande et sa charge utile sont comme suit :

```
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>
```

Une fois la demande exécutée, les données de la base de données se présentent comme suit :

```
<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>
```

Une autre situation ambiguë est celle où plusieurs graphes sont spécifiés dans l'URL de la demande elle-même, en utilisant `PUT`, `POST`, `GET` ou `DELETE`. Par exemple :

```
POST "http://your-Neptune-cluster:port/sparql/gsp/?graph=urn:votes:2005&graph=urn:votes:2019"
```

Ou:

```
GET "http://your-Neptune-cluster:port/sparql/gsp/?default&graph=urn:votes:2019"
```

Dans ce cas, Neptune renvoie un code HTTP 400 avec un message indiquant qu'un seul graphe peut être spécifié dans l'URL de la demande.

# Analyse de l'exécution des requêtes Neptune à l'aide de la fonctionnalité `explain` SPARQL
<a name="sparql-explain"></a>

Amazon Neptune a ajouté une fonctionnalité SPARQL nommée *explain*. Cette fonctionnalité est un outil en libre-service qui vous aide à comprendre l'approche d'exécution adoptée par le moteur Neptune. Vous l'appelez en ajoutant un paramètre `explain` à un appel HTTP qui soumet une requête SPARQL.

La fonction `explain` fournit des informations sur la structure logique des plans d'exécution de requête. Vous pouvez utiliser ces informations pour identifier les goulots d'étranglement d'évaluation et d'exécution potentiels. Vous pouvez ensuite utiliser des [indicateurs de requête](sparql-query-hints.md) pour améliorer vos plans d'exécution de requêtes.

**Topics**
+ [Fonctionnement du moteur de requête SPARQL dans Neptune](sparql-explain-engine.md)
+ [Comment utiliser la fonction SPARQL `explain` pour analyser l'exécution des requêtes](sparql-explain-using.md)
+ [Exemples d'invocation de la fonctionnalité SPARQL `explain` dans Neptune](sparql-explain-examples.md)
+ [Opérateurs Neptune SPARQL `explain`](sparql-explain-operators.md)
+ [Limites de SPARQL `explain` dans Neptune](sparql-explain-limitations.md)

# Fonctionnement du moteur de requête SPARQL dans Neptune
<a name="sparql-explain-engine"></a>

Pour utiliser les informations fournies par la fonctionnalité SPARQL `explain`, vous devez comprendre certains points spécifiques à la façon dont le moteur de requête SPARQL Amazon Neptune fonctionne.

Le moteur convertit chaque requête SPARQL en un pipeline d'opérateurs. À partir du premier opérateur, des solutions intermédiaires appelées *listes de liaisons* circulent dans ce pipeline d'opérateurs. Vous pouvez vous représenter une liste de liaisons sous la forme d'une table dans laquelle les en-têtes sont un sous-ensemble des variables utilisées dans la requête. Chaque ligne de la table représente un résultat, jusqu'au point d'évaluation.

Supposons que deux préfixes d'espace de noms ont été définis pour nos données :

```
  @prefix ex:   <http://example.com> .
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
```

L'exemple suivant est un exemple de liste de liaisons simple dans ce contexte :

```
  ?person       | ?firstName
  ------------------------------------------------------
  ex:JaneDoe    | "Jane"
  ex:JohnDoe    | "John"
  ex:RichardRoe | "Richard"
```

Pour chacune des trois personnes, la liste lie la variable `?person` à un identifiant de la personne, et la variable `?firstName` à son prénom.

En règle générale, les variables peuvent rester non liées si, par exemple, il existe une sélection `OPTIONAL` d'une variable dans une requête pour laquelle aucune valeur n'est présente dans les données.

L'opérateur `PipelineJoin` est un exemple d'opérateur de moteur de requête Neptune présent dans la sortie de la fonctionnalité `explain`. Il prend en tant qu'entrée un ensemble de liaisons entrantes de l'opérateur précédent et le joint selon un modèle de triplet, par exemple `(?person, foaf:lastName, ?lastName)`. Cette opération utilise les liaisons pour la variable `?person` dans ses flux d'entrée, les substitue dans le modèle de triplet et recherche des triplets à partir de la base de données.

Lorsqu'il est exécuté dans le contexte des liaisons entrantes de la table précédente, l'opérateur `PipelineJoin` évalue trois recherches, à savoir les éléments suivants :

```
  (ex:JaneDoe,    foaf:lastName, ?lastName)
  (ex:JohnDoe,    foaf:lastName, ?lastName)
  (ex:RichardRoe, foaf:lastName, ?lastName)
```

Cette approche est appelée évaluation *as-bound*. Les solutions de ce processus d'évaluation sont jointes à nouveau sur les solutions entrantes, en remplissant le `?lastName` détecté dans les solutions entrantes. En supposant que vous trouviez un nom de famille pour les trois personnes, l'opérateur produirait une liste de liaisons sortantes qui ressemblerait à ceci :

```
  ?person       | ?firstName | ?lastName
  ---------------------------------------
  ex:JaneDoe    | "Jane"     | "Doe"
  ex:JohnDoe    | "John"     | "Doe"
  ex:RichardRoe | "Richard"  | "Roe"
```

Cette liste de liaisons sortantes tient lieu d'entrée pour l'opérateur suivant dans le pipeline. À la fin, la sortie du dernier opérateur du pipeline définit le résultat de la requête.

Les pipelines d'opérateurs sont souvent linéaires, dans la mesure où chaque opérateur émet des solutions pour un seul opérateur connecté. Toutefois, dans certains cas, ils peuvent avoir des structures plus complexes. Par exemple, un opérateur `UNION` dans une requête SPARQL est mappé à une opération `Copy`. Cette opération duplique les liaisons et transmet la copie dans deux sous-plans, l'un pour le côté gauche et l'autre pour le côté droit de l'opérateur `UNION`.

Pour plus d'informations sur les opérateurs, consultez [Opérateurs Neptune SPARQL `explain`](sparql-explain-operators.md).

# Comment utiliser la fonction SPARQL `explain` pour analyser l'exécution des requêtes
<a name="sparql-explain-using"></a>

La fonctionnalité `explain` SPARQL est un outil en libre-service dans Amazon Neptune qui vous aide à comprendre l'approche d'exécution adoptée par le moteur Neptune. Pour appeler `explain`, vous transmettez un paramètre à une demande HTTP ou HTTPS dans le formulaire `explain=mode`.

Sa valeur de mode peut prendre l'une des valeurs suivantes : `static`, `dynamic` ou `details`.
+ En mode *statique*, `explain` affiche uniquement la structure statique du plan de requête.
+ En mode *dynamique*, `explain` inclut également les aspects dynamiques du plan de requête. Ces aspects peuvent inclure le nombre de liaisons intermédiaires transitant via les opérateurs et le ratio de liaisons sortantes par rapport aux liaisons entrantes, ainsi que le temps total pris par les opérateurs.
+ En mode *détails*, `explain` imprime les informations affichées en mode `dynamic`, ainsi que des détails supplémentaires tels que la chaîne de requête SPARQL réelle et le nombre de plages estimé pour le modèle sous-jacent d'un opérateur de jointure.

Neptune prend en charge l'utilisation de la fonctionnalité `explain` avec les trois protocoles d'accès aux requêtes SPARQL répertoriés dans la spécification [W3C SPARQL 1.1 Protocol](https://www.w3.org/TR/sparql11-protocol/#query-operation), à savoir :

1. HTTP GET

1. HTTP POST à l'aide de paramètres encodés en URL

1. HTTP POST à l'aide de paramètres de texte

Pour plus d'informations sur le moteur de requête SPARQL, consultez [Fonctionnement du moteur de requête SPARQL dans Neptune](sparql-explain-engine.md).

Pour plus d'informations sur le type de résultat généré par l'appel de la fonction `explain` SPARQL, consultez [Exemples d'invocation de la fonctionnalité SPARQL `explain` dans Neptune](sparql-explain-examples.md).

# Exemples d'invocation de la fonctionnalité SPARQL `explain` dans Neptune
<a name="sparql-explain-examples"></a>

Les exemples de cette section montrent les différents types de sortie que vous pouvez produire en invoquant la fonctionnalité SPARQL `explain` pour analyser l'exécution des requêtes dans Amazon Neptune.

**Topics**
+ [Présentation de la sortie de la fonction Explain](#sparql-explain-example-output)
+ [Exemple de sortie de mode détaillé](#sparql-explain-example-details)
+ [Exemple de sortie de mode statique](#sparql-explain-example-static)
+ [Différentes façons d'encoder des paramètres](#sparql-explain-example-parameters)
+ [Types de sortie autres que Text/Plain](#sparql-explain-output-options)
+ [Exemple de sortie SPARQL `explain` lorsque le DFE est activé](#sparql-explain-output-dfe)

## Présentation de la sortie de la fonction Explain
<a name="sparql-explain-example-output"></a>

Dans cet exemple, Jane Doe connaît deux personnes, à savoir John Doe et 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" .
.
```

Pour déterminer les prénoms de toutes les personnes que Jane Doe connaît, vous pouvez écrire la requête suivante :

```
 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"
```

Cette requête simple renvoie le résultat suivant :

```
firstName
John
Richard
```

Ensuite, modifiez la commande `curl` pour appeler `explain` en ajoutant `-d "explain=dynamic"` et en utilisant le type de sortie par défaut au lieu de `text/csv` :

```
 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"
```

La requête renvoie maintenant la sortie dans un format ASCII bien formé (type de contenu HTTP `text/plain`), ce qui est le type de sortie par défaut :

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ 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         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

Pour plus d'informations sur les opérations de la colonne `Name` et leurs arguments, consultez [Opérateurs explain](sparql-explain-operators.md).

La section suivante décrit la sortie ligne par ligne :

1. La première étape de la requête principale utilise toujours l'opérateur `SolutionInjection` pour injecter une solution. La solution est ensuite étendue au résultat final via le processus d'évaluation.

   Dans ce cas, la solution soit-disant universelle `{ }` est injectée. En présence de clauses `VALUES` ou `BIND`, cette étape peut également injecter des liaisons de variable plus complexes pour commencer.

   La colonne `Units Out` indique que cette solution unique découle de l'opérateur. La colonne `Out #1` spécifie l'opérateur dans lequel cet opérateur envoie le résultat. Dans cet exemple, tous les opérateurs sont connectés à l'opérateur qui suit dans la table.

1. La deuxième étape est un opérateur `PipelineJoin`. Il reçoit en tant qu'entrée la solution unique universelle (complètement sans contrainte) produite par l'opérateur précédent (`Units In := 1`). Il la joint selon le modèle de tuple défini par son argument `pattern`. Cela correspond à une recherche simple pour le modèle. Dans ce cas, le modèle de triplet est défini comme suit :

   ```
   distinct( ex:JaneDoe, foaf:knows, ?person )
   ```

   L'argument `joinType := join` indique qu'il s'agit d'une jointure normale (les autres types sont notamment les jointures `optional`, `existence check`, etc.).

   L'argument `distinct := true` indique que vous extrayez uniquement les correspondances distinctes de la base de données (aucun doublon) et que vous liez les correspondances distinctes à la variable `joinProjectionVars := ?person`, dédupliquée.

   La valeur 2 de la colonne `Units Out` indique que deux solutions sont produites en sortie. Plus précisément, il s'agit des liaisons pour la variable `?person`, reflétant les deux personnes pour lesquelles les données montrent que Jane Doe les connaît :

   ```
    ?person
    -------------
    ex:JohnDoe
    ex:RichardRoe
   ```

1. Les deux solutions de l'étape 2 sans transmises en tant qu'entrée (`Units In := 2`) dans le deuxième opérateur `PipelineJoin`. Cet opérateur joint les deux solutions précédentes avec le modèle de triplet suivant :

   ```
   distinct(?person, foaf:firstName, ?firstName)
   ```

   Il est connu que la variable `?person` est liée à `ex:JohnDoe` ou `ex:RichardRoe` par la solution entrante de l'opérateur. Compte tenu de cela, l'opérateur `PipelineJoin` extrait les prénoms, John et Richard. Les deux solutions sortants (Units Out : = 2) se présentent alors comme suit :

   ```
    ?person       | ?firstName
    ---------------------------
    ex:JohnDoe    | John
    ex:RichardRoe | Richard
   ```

1. L'opérateur de projection suivante prend en tant qu'entrée les deux solutions de l'étape 3 (`Units In := 2`) et effectue une projection sur la variable `?firstName`. Cela élimine toutes les autres liaisons de variable dans les mappages et transmet les deux liaisons (`Units Out := 2`) :

   ```
    ?firstName
    ----------
    John
    Richard
   ```

1. Pour améliorer les performances, Neptune fonctionne dans la mesure du possible sur des identifiants internes qu'il attribue à des termes tels que URIs et à des littéraux de chaîne, plutôt que sur les chaînes elles-mêmes. L'opérateur final, `TermResolution`, effectue à nouveau un mappage de ces identifiants internes aux chaînes de terme correspondantes.

   Dans une évaluation de requête classique (autre que la fonction Explain), le résultat calculé par le dernier opérateur est ensuite sérialisé dans le format de sérialisation demandé et envoyé vers le client.

## Exemple de sortie de mode détaillé
<a name="sparql-explain-example-details"></a>

Supposons que vous exécutez la même requête que la précédente en mode *détaillé* au lieu du mode *dynamique* :

```
 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"
```

Comme le montre cet exemple, la sortie est la même avec quelques détails supplémentaires comme la chaîne de requête en haut de la sortie et le nombre `patternEstimate` pour l'opérateur `PipelineJoin` :

```
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         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

## Exemple de sortie de mode statique
<a name="sparql-explain-example-static"></a>

Supposons que vous exécutiez la même requête que la requête précédente en mode *statique* (mode par défaut) au lieu du mode *détaillé* :

```
 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"
```

Comme illustré dans cet exemple, la sortie est la même, si ce n'est que les trois dernières colonnes sont omises :

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╗
║ 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 ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╝
```

## Différentes façons d'encoder des paramètres
<a name="sparql-explain-example-parameters"></a>

Les exemples de requête suivants illustrent deux façons différentes d'encoder des paramètres lors d'un appel de la fonction `explain` SPARQL.

**Utilisation de l'encodage par URL** : cet exemple utilise l'encodage de paramètres par URL et spécifie une sortie *dynamique* :

```
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"
```

**Spécification directe des paramètres** : cette approche est identique à la requête précédente, sauf que les paramètres sont transmis via POST directement :

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic"
```

## Types de sortie autres que Text/Plain
<a name="sparql-explain-output-options"></a>

Les exemples précédents utilisent le type de sortie `text/plain` par défaut. Neptune peut également mettre en forme la sortie SPARQL `explain` dans deux autres formats de type MIME, à savoir `text/csv` et `text/html`. Vous les appelez en définissant l'en-tête HTTP `Accept`, ce que vous pouvez faire à l'aide de l'indicateur `-H` dans `curl`, comme suit :

```
  -H "Accept: output type"
```

Voici quelques exemples :

**Sortie `text/csv`**  
Cette requête appelle une sortie de type CSV MIME en spécifiant `-H "Accept: text/csv"` :

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic" \
   -H "Accept: text/csv"
```

Le format CSV, qui est utile pour l'importation dans une feuille de calcul ou une base de données, sépare les champs de chaque ligne `explain` par des points-virgules (`;`), comme suit :

```
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
```

 

**Sortie `text/html`**  
Si vous spécifiez `-H "Accept: text/html"`, `explain` génère une table 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>
```

Le HTML affiche dans un navigateur une sortie similaire à ce qui suit :

![\[Exemple de sortie HTML de la fonction Explain SPARQL.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/sparql-explain-dynamic-html-output.png)


## Exemple de sortie SPARQL `explain` lorsque le DFE est activé
<a name="sparql-explain-output-dfe"></a>

Voici un exemple de sortie SPARQL `explain` lorsque le moteur de requête alternatif Neptune DFE est activé :

```
╔════╤════════╤════════╤═══════════════════╤═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ 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        ║
╚════╧════════╧════════╧═══════════════════╧═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Opérateurs Neptune SPARQL `explain`
<a name="sparql-explain-operators"></a>

Les sections suivantes décrivent les opérateurs et les paramètres de la fonctionnalité SPARQL `explain` actuellement disponibles dans Amazon Neptune.

**Important**  
La fonction `explain` SPARQL est encore en cours d'affinement. Les opérateurs et paramètres documentés ici sont susceptibles de changer dans de futures versions.

**Topics**
+ [Opérateur `Aggregation`](#sparql-explain-operator-aggregation)
+ [Opérateur `ConditionalRouting`](#sparql-explain-operator-conditional-routing)
+ [Opérateur `Copy`](#sparql-explain-operator-copy)
+ [Opérateur `DFENode`](#sparql-explain-operator-dfenode)
+ [Opérateur `Distinct`](#sparql-explain-operator-distinct)
+ [Opérateur `Federation`](#sparql-explain-operator-federation)
+ [Opérateur `Filter`](#sparql-explain-operator-filter)
+ [Opérateur `HashIndexBuild`](#sparql-explain-operator-hash-index-build)
+ [Opérateur `HashIndexJoin`](#sparql-explain-operator-hash-index-join)
+ [Opérateur `MergeJoin`](#sparql-explain-operator-merge-join)
+ [Opérateur `NamedSubquery`](#sparql-explain-operator-named-subquery)
+ [Opérateur `PipelineJoin`](#sparql-explain-operator-pipeline-join)
+ [Opérateur `PipelineCountJoin`](#sparql-explain-operator-pipeline-count-join)
+ [Opérateur `PipelinedHashIndexJoin`](#sparql-explain-operator-pipeline-hash-index-join)
+ [Opérateur `Projection`](#sparql-explain-operator-projection)
+ [Opérateur `PropertyPath`](#sparql-explain-operator-property-path)
+ [Opérateur `TermResolution`](#sparql-explain-operator-term-resolution)
+ [Opérateur `Slice`](#sparql-explain-operator-slice)
+ [Opérateur `SolutionInjection`](#sparql-explain-operator-solution-injection)
+ [Opérateur `Sort`](#sparql-explain-operator-sort)
+ [Opérateur `VariableAlignment`](#sparql-explain-operator-variable-alignment)

## Opérateur `Aggregation`
<a name="sparql-explain-operator-aggregation"></a>

Effectue une ou plusieurs agrégations, en implémentant la sémantique des opérateurs d'agrégation SPARQL tels que `count`, `max`, `min`, `sum`, etc.

`Aggregation` est fourni avec un regroupement facultatif à l'aide de clauses `groupBy` et de contraintes `having` facultatives.

**Arguments**
+ `groupBy` : (*facultatif*) fournit une clause `groupBy` qui spécifie la séquence d'expressions selon laquelle les solutions entrantes sont regroupées.
+ `aggregates` : (*obligatoire*) spécifie une liste ordonnée d'expressions d'agrégation.
+ `having` : (*facultatif*) ajoute des contraintes pour filtrer des groupes comme impliqué par la clause `having` dans la requête SPARQL.

## Opérateur `ConditionalRouting`
<a name="sparql-explain-operator-conditional-routing"></a>

Achemine des solutions entrants en fonction d'une condition. Les solutions qui remplissent les conditions sont acheminées vers l'ID d'opérateur référencé par `Out #1`, tandis que les solutions qui ne les remplissent pas sont acheminées vers l'opérateur référencé par `Out #2`.

**Arguments**
+ `condition` : (*obligatoire*) condition de routage.

## Opérateur `Copy`
<a name="sparql-explain-operator-copy"></a>

Délègue le flux de solution comme spécifié par le mode indiqué.

**Modes**
+ `forward` : transmet les solutions à l'opérateur en aval identifié par `Out #1`. 
+ `duplicate` : duplique les solutions et les transmet à chacun des deux opérateurs identifiées par `Out #1` et `Out #2`.

`Copy` ne comporte aucun argument.

## Opérateur `DFENode`
<a name="sparql-explain-operator-dfenode"></a>

Cet opérateur est une abstraction du plan exécuté par le moteur de requête alternatif DFE. Le plan DFE détaillé est décrit dans les arguments de cet opérateur. L'argument est actuellement surchargé pour contenir les statistiques d'exécution détaillées du plan DFE. Il contient le temps consacré aux différentes étapes de l'exécution des requêtes par le DFE.

L'arbre syntaxique abstrait optimisé (AST) logique pour le plan de requêtes DFE est imprimé avec des informations sur les types d'opérateurs pris en compte lors de la planification et les coûts les plus et les moins favorables associés à l'exécution des opérateurs. L'arbre AST comprend actuellement les types de nœuds suivants :
+ `DFEJoinGroupNode` : représente une jointure d'un ou de plusieurs éléments `DFEPatternNodes`.
+ `DFEPatternNode` : encapsule un modèle sous-jacent à l'aide duquel les tuples correspondants sont projetés hors de la base de données sous-jacente.

La sous-section, `Statistics & Operator histogram`, contient des détails sur le temps d'exécution du plan `DataflowOp` et sur la répartition du temps CPU utilisé par chaque opérateur. En dessous se trouve un tableau qui affiche les statistiques d'exécution détaillées du plan exécuté par le DFE.

**Note**  
Comme le DFE est une fonctionnalité expérimentale publiée en mode laboratoire, le format exact de sa sortie `explain` peut changer.

## Opérateur `Distinct`
<a name="sparql-explain-operator-distinct"></a>

Calcule la projection distincte sur un sous-ensemble des variables, en éliminant les doublons. Par conséquent, le nombre de solutions en entrée est supérieur ou égal au nombre de solutions en sortie.

**Arguments**
+ `vars` : (*obligatoire*) variables auxquelles appliquer la projection `Distinct`.

## Opérateur `Federation`
<a name="sparql-explain-operator-federation"></a>

Transmet une requête spécifique à un point de terminaison SPARQL distant spécifique.

**Arguments**
+ `SERVICE` : (*obligatoire*) URL du point de terminaison dans la déclaration SPARQL `endpoint`. Il peut s'agir d'une chaîne constante, ou, si le point de terminaison de la requête est déterminé en fonction d'une variable au sein de la même requête, il peut s'agir du nom de la variable.
+ `query` : (*obligatoire*) chaîne de requête reconstruite à envoyer au point de terminaison distant. Le moteur ajoute des préfixes par défaut à cette requête, même lorsque le client n'en spécifie aucun.
+ `silent` : (*obligatoire*) valeur booléenne qui indique si le mot-clé `SILENT` apparaît après le mot-clé. `SILENT` indique au moteur de ne pas faire échouer l'ensemble de la requête, même si la partie `SERVICE` distante échoue.

## Opérateur `Filter`
<a name="sparql-explain-operator-filter"></a>

Filtre les solutions entrantes. Seules les solutions qui remplissent la condition de filtre sont transmises à l'opérateur en amont. Toutes les autres sont supprimées.

**Arguments**
+ `condition` : (*obligatoire*) condition de filtre.

## Opérateur `HashIndexBuild`
<a name="sparql-explain-operator-hash-index-build"></a>

Prend une liste de liaisons et les place dans un index de hachage dont le nom est défini par l'argument `solutionSet`. En général, les opérateurs suivants effectuent des jointures en fonction de cette solution, en y faisant référence par ce nom.

**Arguments**
+ `solutionSet` : (*obligatoire*) nom de l'ensemble de solutions de l'index de hachage.
+ `sourceType` : (*obligatoire*) type de la source à partir de laquelle les liaisons à stocker dans l'index de hachage sont obtenues :
  + `pipeline` : place les solutions entrantes de l'opérateur en aval dans le pipeline des opérateurs dans l'index de hachage.
  + `binding set` : place l'ensemble de liaisons fixes spécifié par l'argument `sourceBindingSet` dans l'index de hachage.
+ `sourceBindingSet` : (*facultatif*) si la valeur de l'argument `sourceType` est `binding set`, cet argument spécifie l'ensemble de liaisons statiques à placer dans l'index de hachage.

## Opérateur `HashIndexJoin`
<a name="sparql-explain-operator-hash-index-join"></a>

Joint les solutions entrantes par rapport à l'ensemble de solutions de l'index de hachage, identifié par l'argument `solutionSet`.

**Arguments**
+ `solutionSet` : (*obligatoire*) nom de l'ensemble de solutions sur lequel effectuer la jointure. Il doit s'agir d'un index de hachage qui a été créé dans une étape précédente à l'aide de l'opérateur `HashIndexBuild`.
+ `joinType` : (*obligatoire*) type de jointure à effectuer :
  + `join` : jointure normale, nécessitant une correspondance exacte entre toutes les variables partagées.
  + `optional` : jointure `OPTIONAL` qui utilise la sémantique de l'opérateur `optional` SPARQL.
  + `minus` : une opération `MINUS` conserve un mappage pour lequel aucun partenaire de jointure n'existe, à l'aide de la sémantique de l'opérateur `minus` SPARQL.
  + `existence check` : vérifie s'il existe ou non un partenaire de jointure et lie la variable `existenceCheckResultVar` au résultat de cette vérification.
+ `constraints` : (*facultatif*) des contraintes de jointure supplémentaires sont prises en compte lors de la jointure. Les jointures qui ne remplissent pas ces contraintes sont rejetées.
+ `existenceCheckResultVar` : (*facultatif*) utilisé uniquement pour les jointures où `joinType` est égal à `existence check` (voir l'argument `joinType` ci-dessus).

## Opérateur `MergeJoin`
<a name="sparql-explain-operator-merge-join"></a>

Jointure par fusion sur plusieurs ensembles de solutions, identifiés par l'argument `solutionSets`.

**Arguments**
+ `solutionSets` : (*obligatoire*) ensembles de solutions à joindre.

## Opérateur `NamedSubquery`
<a name="sparql-explain-operator-named-subquery"></a>

Déclenche l'évaluation de la sous-requête identifiée par l'argument `subQuery` et place le résultat dans l'ensemble de solutions spécifié par l'argument `solutionSet`. Les solutions entrantes pour l'opérateur sont transmises à la sous-requête, puis à l'opérateur suivant.

**Arguments**
+ `subQuery` : (*obligatoire*) nom de la sous-requête à évaluer. La sous-requête est affichée explicitement dans la sortie.
+ `solutionSet` : (*obligatoire*) nom de l'ensemble de solutions dans lequel vous souhaitez stocker le résultat de la sous-requête.

## Opérateur `PipelineJoin`
<a name="sparql-explain-operator-pipeline-join"></a>

Reçoit en tant qu'entrée la sortie de l'opérateur précédent et la joint en fonction du modèle de tuple défini par l'argument `pattern`.

**Arguments**
+ `pattern`— (*Obligatoire*) Le modèle, qui prend la forme d'un tuple subject-predicate-object, et éventuellement d'un tuple -graph, qui sous-tend la jointure. Si `distinct` est spécifié pour le modèle, la jointure extrait uniquement les solutions distinctes des variables de projection spécifiées par l'argument `projectionVars`, et non toutes les solutions qui correspondent.
+ `inlineFilters` : (*facultatif*) ensemble de filtres à appliquer aux variables dans le modèle. Le modèle est évalué conjointement avec ces filtres.
+ `joinType` : (*obligatoire*) type de jointure à effectuer :
  + `join` : jointure normale, nécessitant une correspondance exacte entre toutes les variables partagées.
  + `optional` : jointure `OPTIONAL` qui utilise la sémantique de l'opérateur `optional` SPARQL.
  + `minus` : une opération `MINUS` conserve un mappage pour lequel aucun partenaire de jointure n'existe, à l'aide de la sémantique de l'opérateur `minus` SPARQL.
  + `existence check` : vérifie s'il existe ou non un partenaire de jointure et lie la variable `existenceCheckResultVar` au résultat de cette vérification.
+ `constraints` : (*facultatif*) des contraintes de jointure supplémentaires sont prises en compte lors de la jointure. Les jointures qui ne remplissent pas ces contraintes sont rejetées.
+ `projectionVars` : (*facultatif*) variables de la projection. Utilisé en combiné avec `distinct := true` pour appliquer l'extraction de projections distinctes sur un ensemble de variables spécifié.
+ `cutoffLimit` : (*facultatif*) limite de coupure pour le nombre de partenaires de jointure extraits. Même s'il n'existe pas de limite par défaut, vous pouvez définir cet argument sur 1 lorsque vous effectuez des jointures pour implémenter des clauses `FILTER (NOT) EXISTS`, où il suffit de prouver ou de réfuter qu'il existe une jointure partenaire.

## Opérateur `PipelineCountJoin`
<a name="sparql-explain-operator-pipeline-count-join"></a>

Variante de `PipelineJoin`. Au lieu d'effectuer une jointure, compte uniquement les partenaires de jointure correspondants et lie le comptage à la variable spécifiée par l'argument `countVar`.

**Arguments**
+ `countVar` : (*obligatoire*) variable à laquelle le résultat du décompte, à savoir le nombre de partenaires de jointure, doit être limitée.
+ `pattern`— (*Obligatoire*) Le modèle, qui prend la forme d'un tuple subject-predicate-object, et éventuellement d'un tuple -graph, qui sous-tend la jointure. Si `distinct` est spécifié pour le modèle, la jointure extrait uniquement les solutions distinctes des variables de projection spécifiées par l'argument `projectionVars`, et non toutes les solutions qui correspondent.
+ `inlineFilters` : (*facultatif*) ensemble de filtres à appliquer aux variables dans le modèle. Le modèle est évalué conjointement avec ces filtres.
+ `joinType` : (*obligatoire*) type de jointure à effectuer :
  + `join` : jointure normale, nécessitant une correspondance exacte entre toutes les variables partagées.
  + `optional` : jointure `OPTIONAL` qui utilise la sémantique de l'opérateur `optional` SPARQL.
  + `minus` : une opération `MINUS` conserve un mappage pour lequel aucun partenaire de jointure n'existe, à l'aide de la sémantique de l'opérateur `minus` SPARQL.
  + `existence check` : vérifie s'il existe ou non un partenaire de jointure et lie la variable `existenceCheckResultVar` au résultat de cette vérification.
+ `constraints` : (*facultatif*) des contraintes de jointure supplémentaires sont prises en compte lors de la jointure. Les jointures qui ne remplissent pas ces contraintes sont rejetées.
+ `projectionVars` : (*facultatif*) variables de la projection. Utilisé en combiné avec `distinct := true` pour appliquer l'extraction de projections distinctes sur un ensemble de variables spécifié.
+ `cutoffLimit` : (*facultatif*) limite de coupure pour le nombre de partenaires de jointure extraits. Même s'il n'existe pas de limite par défaut, vous pouvez définir cet argument sur 1 lorsque vous effectuez des jointures pour implémenter des clauses `FILTER (NOT) EXISTS`, où il suffit de prouver ou de réfuter qu'il existe une jointure partenaire.

## Opérateur `PipelinedHashIndexJoin`
<a name="sparql-explain-operator-pipeline-hash-index-join"></a>

Il s'agit d'un index de hachage de all-in-one construction et d'un opérateur de jointure. Il utilise une liste de liaisons, les regroupe dans un index de hachage, puis joint les solutions entrantes à l'index de hachage.

**Arguments**
+ `sourceType` : (*obligatoire*) type de la source à partir de laquelle les liaisons à stocker dans l'index de hachage sont obtenues :
  + `pipeline` : incite `PipelinedHashIndexJoin` à placer les solutions entrantes de l'opérateur en aval dans le pipeline des opérateurs dans l'index de hachage.
  + `binding set` : incite `PipelinedHashIndexJoin` à place l'ensemble de liaisons fixes spécifié par l'argument `sourceBindingSet` dans l'index de hachage.
+ `sourceSubQuery ` : (*facultatif*) si la valeur de l'argument `sourceType` est `pipeline`, cet argument indique la sous-requête qui est évaluée et insérée dans l'index de hachage.
+ `sourceBindingSet ` : (*facultatif*) si la valeur de l'argument `sourceType` est `binding set`, cet argument spécifie l'ensemble de liaisons statiques à placer dans l'index de hachage.
+ `joinType` : (*obligatoire*) type de jointure à effectuer :
  + `join` : jointure normale, nécessitant une correspondance exacte entre toutes les variables partagées.
  + `optional` : jointure `OPTIONAL` qui utilise la sémantique de l'opérateur `optional` SPARQL.
  + `minus` : une opération `MINUS` conserve un mappage pour lequel aucun partenaire de jointure n'existe, à l'aide de la sémantique de l'opérateur `minus` SPARQL.
  + `existence check` : vérifie s'il existe ou non un partenaire de jointure et lie la variable `existenceCheckResultVar` au résultat de cette vérification.
+ `existenceCheckResultVar` : (*facultatif*) utilisé uniquement pour les jointures où `joinType` est égal à `existence check` (voir l'argument joinType ci-dessus).

## Opérateur `Projection`
<a name="sparql-explain-operator-projection"></a>

Effectue une projection sur un sous-ensemble des variables. Le nombre de solutions en entrée est égal au nombre de solutions en sortie, mais la forme de la solution diffère selon le paramètre de mode.

**Modes**
+ `retain` : ne conserve dans les solutions que les variables qui sont spécifiées par l'argument `vars`.
+ `drop` : abandonne toutes les variables qui sont spécifiées par l'argument `vars`.

**Arguments**
+ `vars` : (*obligatoire*) variables à conserver ou à abandonner, en fonction du paramètre de mode.

## Opérateur `PropertyPath`
<a name="sparql-explain-operator-property-path"></a>

Active les chemins de propriétés récursifs tels que `+` ou `*`. Neptune met en œuvre une approche d'itération à point fixe basée sur un modèle spécifié par l'argument `iterationTemplate`. Les variables de gauche ou de droite connues sont liées dans le modèle pour chaque itération de type point fixe, jusqu'à ce qu'aucune autre nouvelle solution ne puisse être trouvée.

**Arguments**
+ `iterationTemplate` : (*obligatoire*) nom du modèle de sous-requête utilisé pour implémenter l'itération de type point fixe.
+ `leftTerm` : (*obligatoire*) terme (variable ou constante) à gauche du chemin de propriété.
+ `rightTerm` : (*obligatoire*) terme (variable ou constante) à droite du chemin de propriété.
+ `lowerBound` : (*obligatoire*) limite inférieure pour une itération de type point fixe (`0` pour les requêtes `*` ou `1` pour les requêtes `+`).

## Opérateur `TermResolution`
<a name="sparql-explain-operator-term-resolution"></a>

Reconvertit des valeurs d'identifiant de chaîne interne en leurs chaînes externes correspondantes, ou convertit des chaînes externes en valeurs d'identifiant de chaîne interne, en fonction du mode.

**Modes**
+ `value2id`— Associe des termes tels que les littéraux URIs aux valeurs d'identification internes correspondantes (encodage en valeurs internes).
+ `id2value`— Associe les valeurs d'identification internes aux termes correspondants tels que les littéraux et URIs (décodage des valeurs internes).

**Arguments**
+ `vars`— (*Obligatoire*) Spécifie les variables dont les chaînes ou chaînes internes IDs doivent être mappées.

## Opérateur `Slice`
<a name="sparql-explain-operator-slice"></a>

Implémente une tranche sur le flux de solution entrant, à l'aide de la sémantique des clauses `LIMIT` et `OFFSET` SPARQL.

**Arguments**
+ `limit` : (*facultatif*) limite applicable aux solutions à transmettre.
+ `offset` : (*facultatif*) décalage par rapport auquel les solutions sont évaluées pour la transmission.

## Opérateur `SolutionInjection`
<a name="sparql-explain-operator-solution-injection"></a>

Ne reçoit aucune entrée. Injecte statiquement des solutions dans le plan de requête et les enregistre dans l'argument `solutions`.

Les plans de requête commencent toujours par cette injection statique. Si des solutions statiques à injecter peuvent être dérivées de la requête proprement dite en combinant différentes sources de liaisons statiques (par exemple, à partir de clauses `VALUES` ou `BIND`), l'opérateur `SolutionInjection` injecte ces solutions statiques dérivées. Dans le cas le plus simple, elles reflètent des liaisons qui sont impliquées par une clause `VALUES` externe.

Si aucune solution statique ne peut être dérivée à partir de la requête, `SolutionInjection` injecte la solution soit-disant universelle vide qui est étendue et multipliée tout au long du processus d'évaluation de requête.

**Arguments**
+ `solutions` : (*obligatoire*) séquence de solutions injectées par l'opérateur.

## Opérateur `Sort`
<a name="sparql-explain-operator-sort"></a>

Trie l'ensemble de solutions à l'aide des conditions de tri spécifiées.

**Arguments**
+ `sortOrder` : (*obligatoire*) liste ordonnée de variables, chacune contenant un élément `ASC` (croissant) ou `DESC` (décroissant), utilisées de manière séquentielle pour trier l'ensemble de solutions.

## Opérateur `VariableAlignment`
<a name="sparql-explain-operator-variable-alignment"></a>

Inspecte les solutions une par une, en alignant chacune d'entre elles sur deux variables : une variable `sourceVar` spécifiée et une variable `targetVar` spécifiée.

Si `sourceVar` et `targetVar` dans une solution ont la même valeur, les variables sont considérées comme étant alignées et la solution est transmise avec les variables `sourceVar` redondantes sont projetées.

Si les variables sont liées à des valeurs différentes, la solution est filtrée entièrement.

**Arguments**
+ `sourceVar` : (*obligatoire*) variable source à comparer à la variable cible. Si l'alignement réussit dans une solution, ce qui signifie que les deux variables ont la même valeur, la variable source est projetée.
+ `targetVar` : (*obligatoire*) variable cible à laquelle la variable source est comparée. Elle est conservée même lorsque l'alignement réussit.

# Limites de SPARQL `explain` dans Neptune
<a name="sparql-explain-limitations"></a>

La version de la fonction SPARQL `explain` dans Neptune présente les limites suivantes.

**Neptune ne prend actuellement en charge Explain que dans les requêtes SELECT SPARQL**  
Pour plus d'informations sur le processus d'évaluation pour d'autres formes de requêtes, comme les requêtes `ASK`, `CONSTRUCT`, `DESCRIBE` et `SPARQL UPDATE`, vous pouvez transformer ces requêtes en une requête SELECT. Utilisez ensuite `explain` pour inspecter la requête SELECT correspondante.

Par exemple, pour obtenir des informations `explain` sur une requête `ASK WHERE {...}`, exécutez la requête `SELECT WHERE {...} LIMIT 1` correspondante avec `explain`.

De même, pour une requête `CONSTRUCT {...} WHERE {...}`, supprimez la partie `CONSTRUCT {...}` et exécutez une requête `SELECT` avec `explain` sur la deuxième clause `WHERE {...}`. L'évaluation de la deuxième clause `WHERE` révèle généralement les principales difficultés du traitement de la requête `CONSTRUCT`, car les solutions découlant de la deuxième clause `WHERE` dans le modèle `CONSTRUCT` ne nécessitent généralement qu'une substitution simple.

**Les opérateurs de la fonction Explain peuvent changer dans des versions futures**  
Les opérateurs de la fonction `explain` SPARQL et leurs paramètres sont susceptibles d'être modifiés dans des versions futures.

**La sortie de la fonction Explain peut changer dans des versions futures**  
Par exemple, des en-têtes de colonne peuvent être modifiés et d'autres colonnes peuvent être ajoutées aux tables.

# Requêtes fédérées SPARQL dans Neptune à l'aide de l'extension `SERVICE`
<a name="sparql-service"></a>

Amazon Neptune prend entièrement en charge l'extension de requête fédérée SPARQL qui utilise le mot-clé `SERVICE`. (Pour plus d'informations, consultez [Requête fédérée SPARQL 1.1](https://www.w3.org/TR/sparql11-federated-query/).)

Le mot-clé `SERVICE` indique au moteur de requête SPARQL qu'il doit exécuter une partie de la requête sur un point de terminaison SPARQL distant et composer le résultat de la requête finale. Seules les opérations `READ` sont possibles. Les opérations `WRITE` et `DELETE` ne sont pas prises en charge. Neptune ne peut exécuter des requêtes fédérées que sur des points de terminaison SPARQL accessibles au sein de son cloud privé virtuel (VPC). Toutefois, vous pouvez également utiliser un proxy inverse dans le VPC pour rendre une source de données externe accessible au sein du VPC.

**Note**  
Lorsque SPARQL `SERVICE` est utilisé pour fédérer une requête à deux clusters Neptune ou plus dans le même VPC, les groupes de sécurité doivent être configurés pour autoriser tous ces clusters Neptune à communiquer entre eux.

**Important**  
La fonction SPARQL 1.1 Federation effectue des demandes de service en votre nom lorsqu'elle transmet des requêtes et des paramètres à des points de terminaison SPARQL externes. Il vous incombe de vérifier que les points de terminaison SPARQL externes répondent aux exigences de sécurité et de gestion des données de votre application.

## Exemple de requête fédérée Neptune
<a name="sparql-service-example-1"></a>

L'exemple simple suivant montre le fonctionnement des requêtes fédérées SPARQL.

Supposons qu'un client envoie la requête suivante à *Neptune-1* à l'adresse `http://neptune-1:8182/sparql`.

```
SELECT * WHERE {
   ?person rdf:type foaf:Person .
   SERVICE <http://neptune-2:8182/sparql> {
       ?person foaf:knows ?friend .
    }
}
```

1. *Neptune-1* évalue le premier modèle de requête (*Q-1*) qui est `?person rdf:type foaf:Person`, utilise les résultats pour résoudre `?person` dans *Q-2* (`?person foaf:knows ?friend`) et transmet le modèle obtenu à *Neptune-2* à l'adresse `http://neptune-2:8182/sparql`.

1. *Neptune-2* évalue *Q-2* et renvoie les résultats à *Neptune-1*.

1. *Neptune-1* joint les solutions pour les deux modèles et renvoie les résultats au client.

Ce flux est illustré dans le diagramme suivant.

![\[Diagramme de flux illustrant les modèles de requêtes fédérées SPARQL évalués et les réponses renvoyées au client.\]](http://docs.aws.amazon.com/fr_fr/neptune/latest/userguide/images/federated.png)


**Note**  
« Par défaut, l'optimiseur détermine à quel moment de l'exécution de la requête la déclaration `SERVICE` est exécutée. Vous pouvez annuler ce placement à l'aide de l'indicateur de requête [joinOrder](sparql-query-hints-joinOrder.md).

## Contrôle d'accès pour les requêtes fédérées dans Neptune
<a name="sparql-service-auth"></a>

Neptune utilise Gestion des identités et des accès AWS (IAM) pour l'authentification et l'autorisation. Le contrôle d'accès d'une requête fédérée peut impliquer plusieurs instances de base de données Neptune. Ces instances peuvent avoir des exigences différentes pour le contrôle d'accès. Dans certaines circonstances, cela peut limiter votre capacité à effectuer une requête fédérée.

Prenons l'exemple simple présenté dans la section précédente. *Neptune-1* appelle *Neptune-2* avec les mêmes informations d'identification avec lesquelles il a été appelé.
+ Si *Neptune-1* a besoin d'une authentification et d'une autorisation IAM, mais que ce n'est pas le cas pour *Neptune-2*, vous avez simplement besoin des autorisations IAM appropriées pour *Neptune-1* pour pouvoir effectuer la requête fédérée.
+ Si *Neptune-1* et *Neptune-2* ont tous les deux besoin d'une authentification et d'une autorisation IAM, vous devez attacher les autorisations IAM pour que les deux bases de données puissent effectuer la requête fédérée. Les deux clusters doivent également se trouver dans le même AWS compte et dans la même région. Les architectures de requêtes fédérées and/or entre régions et comptes ne sont actuellement pas prises en charge.
+ Toutefois, si IAM n'est pas activé sur *Neptune-1*, mais qu'il l'est pour *Neptune-2*, vous ne pouvez pas effectuer de requête fédérée. Cela s'explique par le fait que *Neptune-1* ne peut pas récupérer vos informations d'identification IAM et les transmettre à *Neptune-2* pour autoriser la deuxième partie de la requête.