

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.

# Accès au graphe Neptune avec openCypher
openCypher

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
Comparaison de Gremlin et openCypher

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
Utilisation d'openCypher

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
Point de terminaison de statut

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
Parameters

**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
Champs de réponse

**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
Exemples de demandes et de réponses
+ **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
Point de terminaison HTTPS

**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
Requêtes de lecture et d'écriture

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
OpenCypher format des résultats

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
En-têtes de suivi HTTP facultatifs

 [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
AWS SDK

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
Exemples

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
Utilisation du protocole Bolt

[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
Exemples Java Bolt

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
Exemple Python Bolt

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
Exemple .NET Bolt

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
Exemple Java Bolt avec authentification IAM

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
Exemple Python Bolt avec authentification IAM

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
Node.js avec authentification IAM

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
Exemple .NET Bolt avec authentification IAM

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
Exemple Go Bolt avec authentification IAM

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
Comportement des connexion Bolt

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
Exemples de requêtes paramétrées

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
Exemple avec le point de terminaison HTTPS

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
Exemples Bolt

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
Modèle de données

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

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
Limitations

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`
Opérateurs DFE

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`
En-têtes de colonnes

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
Exemple de base

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
Exemple : recherche d'une relation

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
Exemple : fonction de valeur

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
Exemple : expression mathématique

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)
Exemple : chemin de longueur variable

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
Transactions

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
Transactions en lecture seule

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
Transactions implicites en lecture seule

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
Transactions de validation automatique en lecture seule

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
Transactions explicites en lecture seule

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
Transactions de mutation

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
Transactions de mutation implicites

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
Transactions de mutation à validation automatique

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
Transactions de mutation explicites

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
Indicateurs de requête

**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
Cache du plan de requêtes

 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


 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
Délai d'expiration de la requête

 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
Restrictions

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
Exceptions

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
Extensions

 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


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
La fonction `join()`

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
La fonction `removeKeyFromMap()`

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
Valeurs d'ID personnalisées

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é
Correction des propriétés `~id` existantes

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


 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


 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


 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


 À l'heure actuelle, les mises à jour au sein d'une `CALL` sous-requête ne sont pas prises en charge. 

## Fonctions Neptune OpenCypher


 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


 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


 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


 `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


 `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


 `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


 Disponible dans Neptune Database 1.4.6.0 et versions ultérieures, et dans Neptune Analytics. 

#### réduire ()


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


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


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


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


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


É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


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


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

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


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 ()
autorisations sur neptune.read ()

## Politiques IAM requises


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


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
Données spatiales

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


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


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


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


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


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
Fonctions spatiales

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


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


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


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


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


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


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


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


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


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


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


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