

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.

# Réécriture des requêtes Cypher pour les exécuter dans openCypher sur Neptune
<a name="migration-opencypher-rewrites"></a>

Le langage 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](https://www.opencypher.org/) sous une licence open source Apache 2. Chez AWS, nous pensons que l'open source est bénéfique pour tout le monde et nous nous engageons à apporter la valeur de l'open source à nos clients et l'excellence opérationnelle AWS aux communautés open source.

OpenCypher la syntaxe est documentée dans le [Cypher Query Language Reference, version 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).

Comme openCypher contient un sous-ensemble de la syntaxe et des fonctionnalités du langage de requête Cypher, certains scénarios de migration nécessitent soit de réécrire les requêtes dans des formulaires compatibles avec openCypher, soit d'examiner d'autres méthodes pour obtenir le fonctionnement souhaité.

Cette section contient des recommandations pour gérer les différences courantes, mais elles ne sont en aucun cas exhaustives. Testez minutieusement toute application utilisant ces réécritures pour vous assurer que les résultats sont conformes à vos attentes.

## Réécriture des fonctions de prédicat `None`, `All` et `Any`
<a name="migration-opencypher-rewrites-none-all-any"></a>

Ces fonctions ne font pas partie de la spécification openCypher. Des résultats comparables peuvent être obtenus dans openCypher à l'aide de la compréhension de liste.

Par exemple, recherchez tous les chemins qui vont d'un nœud `Start` au nœud `End`, mais aucun trajet n'est autorisé à passer par un nœud dont la propriété de classe correspond à `D` :

```
# Neo4J Cypher code
match p=(a:Start)-[:HOP*1..]->(z:End)
where none(node IN nodes(p) where node.class ='D')
return p

# Neptune openCypher code
match p=(a:Start)-[:HOP*1..]->(z:End)
where size([node IN nodes(p) where node.class = 'D']) = 0
return p
```

La compréhension de liste peut obtenir ces résultats comme suit :

```
all  => size(list_comprehension(list)) = size(list)
any  => size(list_comprehension(list)) >= 1
none => size(list_comprehension(list)) = 0
```

## Réécriture de la fonction Cypher `reduce()` en openCypher
<a name="migration-opencypher-rewrites-reduce"></a>

La fonction `reduce()` ne fait pas partie de la spécification openCypher. Elle est souvent utilisée pour créer une agrégation de données à partir d'éléments d'une liste. Dans de nombreux cas, vous pouvez utiliser une combinaison de la compréhension de liste et de la clause `UNWIND` pour obtenir des résultats similaires.

Par exemple, la requête Cypher suivante trouve tous les aéroports situés sur des trajets comportant un à trois arrêts entre Anchorage (ANC) et Austin (AUS), et renvoie la distance totale de chaque trajet :

```
MATCH p=(a:airport {code: 'ANC'})-[r:route*1..3]->(z:airport {code: 'AUS'})
RETURN p, reduce(totalDist=0, r in relationships(p) | totalDist + r.dist) AS totalDist
ORDER BY totalDist LIMIT 5
```

Vous pouvez écrire la même requête en openCypher pour Neptune comme suit :

```
MATCH p=(a:airport {code: 'ANC'})-[r:route*1..3]->(z:airport {code: 'AUS'})
UNWIND [i in relationships(p) | i.dist] AS di
RETURN p, sum(di) AS totalDist
ORDER BY totalDist
LIMIT 5
```

## Réécriture de la clause Cypher FOREACH en openCypher
<a name="migration-opencypher-rewrites-foreach"></a>

La clause FOREACH ne fait pas partie de la spécification openCypher. Elle est souvent utilisée pour mettre à jour les données au milieu d'une requête, souvent à partir d'agrégations ou d'éléments au sein d'un chemin.

À titre d'exemple, recherchez tous les aéroports situés sur un trajet ne comportant pas plus de deux arrêts entre Anchorage (ANC) et Austin (AUS) et définissez la propriété « visited » pour chacun d'eux :

```
# Neo4J Example
MATCH p=(:airport {code: 'ANC'})-[*1..2]->({code: 'AUS'})
FOREACH (n IN nodes(p) | SET n.visited = true)

# Neptune openCypher
MATCH p=(:airport {code: 'ANC'})-[*1..2]->({code: 'AUS'})
WITH nodes(p) as airports
UNWIND airports as a
SET a.visited=true
```

Voici un autre exemple :

```
# Neo4J Example
MATCH p=(start)-[*]->(finish)
WHERE start.name = 'A' AND finish.name = 'D'
FOREACH (n IN nodes(p) | SET n.marked = true)

# Neptune openCypher
MATCH p=(start)-[*]->(finish)
WHERE start.name = 'A' AND finish.name = 'D'
UNWIND nodes(p) AS n
SET n.marked = true
```

## Réécriture des procédures Neo4j APOC dans Neptune
<a name="migration-opencypher-rewrites-apoc"></a>

Les exemples ci-dessous utilisent openCypher pour remplacer certaines des [procédures APOC](https://neo4j.com/blog/intro-user-defined-procedures-apoc/) les plus couramment utilisées. Ces exemples sont fournis à titre de référence uniquement et visent à fournir des suggestions sur la manière de gérer les scénarios courants. Dans la pratique, chaque application est différente. Vous devrez donc élaborer vos propres stratégies pour fournir toutes les fonctionnalités dont vous avez besoin.

### Réécriture des procédures `apoc.export`
<a name="migration-opencypher-rewrites-apoc-export"></a>

Neptune propose un éventail d'options pour les exportations de graphes complets et les exportations basées sur des requêtes dans différents formats de sortie tels que CSV et JSON, à l'aide de l'utilitaire [neptune-export](https://github.com/aws/neptune-export) (voir [Exportation de données depuis un cluster de bases de données Neptune](neptune-data-export.md)).

### Réécriture des procédures `apoc.schema`
<a name="migration-opencypher-rewrites-apoc-schema"></a>

Neptune n'a pas de schéma, d'index ni de contraintes explicitement définis. De nombreuses procédures `apoc.schema` ne sont donc plus nécessaires. Voici quelques exemples :
+ `apoc.schema.assert`
+ `apoc.schema.node.constraintExists`
+ `apoc.schema.node.indexExists`,
+ `apoc.schema.relationship.constraintExists`
+ `apoc.schema.relationship.indexExists`
+ `apoc.schema.nodes`
+ `apoc.schema.relationships`

Neptune openCypher prend en charge la récupération de valeurs similaires à celles des procédures, comme indiqué ci-dessous. Toutefois, il peut rencontrer des problèmes de performances sur les graphes de grande taille, car l'analyse d'une grande partie du graphe est nécessaire pour pouvoir renvoyer la réponse.

```
# openCypher replacement for apoc.schema.properties.distinct
MATCH (n:airport)
RETURN DISTINCT n.runways
```

```
# openCypher replacement for apoc.schema.properties.distinctCount
MATCH (n:airport)
RETURN DISTINCT n.runways, count(n.runways)
```

### Alternatives aux procédures `apoc.do`
<a name="migration-opencypher-rewrites-apoc-do"></a>

Ces procédures sont utilisées pour fournir une exécution de requête conditionnelle facile à implémenter à l'aide d'autres clauses openCypher. Dans Neptune, il existe au moins deux manières d'obtenir un comportement similaire :
+ L'une des solutions consiste à combiner les fonctionnalités de compréhension de liste openCypher avec la clause `UNWIND`.
+ Une autre méthode consiste à utiliser les étapes choose() et coalesce() dans Gremlin.

Des exemples de ces approches sont présentés ci-dessous.

#### Alternatives à apoc.do.when
<a name="migration-opencypher-rewrites-apoc-do-when"></a>

```
# Neo4J Example
MATCH (n:airport {region: 'US-AK'})
CALL apoc.do.when(
 n.runways>=3,
 'SET n.is_large_airport=true RETURN n',
 'SET n.is_large_airport=false RETURN n',
 {n:n}
) YIELD value
WITH collect(value.n) as airports
RETURN size([a in airports where a.is_large_airport]) as large_airport_count,
size([a in airports where NOT a.is_large_airport]) as small_airport_count


# Neptune openCypher
MATCH (n:airport {region: 'US-AK'})
WITH n.region as region, collect(n) as airports
WITH [a IN airports where a.runways >= 3] as large_airports,
[a IN airports where a.runways < 3] as small_airports, airports
UNWIND large_airports as la
SET la.is_large_airport=true
WITH DISTINCT small_airports, airports
UNWIND small_airports as la
    SET la.small_airports=true
WITH DISTINCT airports
RETURN size([a in airports where a.is_large_airport]) as large_airport_count,
size([a in airports where NOT a.is_large_airport]) as small_airport_count

#Neptune Gremlin using choose()
g.V().
  has('airport', 'region', 'US-AK').
  choose(
    values('runways').is(lt(3)),
    property(single, 'is_large_airport', false),
    property(single, 'is_large_airport', true)).
  fold().
  project('large_airport_count', 'small_airport_count').
    by(unfold().has('is_large_airport', true).count()).
    by(unfold().has('is_large_airport', false).count())

 #Neptune Gremlin using coalesce() 
g.V().
  has('airport', 'region', 'US-AK').
  coalesce(
    where(values('runways').is(lt(3))).
    property(single, 'is_large_airport', false),
    property(single, 'is_large_airport', true)).
  fold().
  project('large_airport_count', 'small_airport_count').
    by(unfold().has('is_large_airport', true).count()).
    by(unfold().has('is_large_airport', false).count())
```

#### Alternatives à apoc.do.case
<a name="migration-opencypher-rewrites-apoc-do-case"></a>

```
# Neo4J Example
MATCH (n:airport {region: 'US-AK'})
CALL apoc.case([
 n.runways=1, 'RETURN "Has one runway" as b',
 n.runways=2, 'RETURN "Has two runways" as b'
 ],
 'RETURN "Has more than 2 runways" as b'
) YIELD value 
RETURN {type: value.b,airport: n}

# Neptune openCypher
MATCH (n:airport {region: 'US-AK'})
WITH n.region as region, collect(n) as airports
WITH [a IN airports where a.runways =1] as single_runway,
[a IN airports where a.runways =2] as double_runway,
[a IN airports where a.runways >2] as many_runway
UNWIND single_runway as sr
    WITH {type: "Has one runway",airport: sr} as res, double_runway, many_runway
WITH DISTINCT double_runway as double_runway, collect(res) as res, many_runway
UNWIND double_runway as dr
    WITH {type: "Has two runways",airport: dr} as two_runways, res, many_runway
WITH collect(two_runways)+res as res, many_runway
UNWIND many_runway as mr
    WITH {type: "Has more than 2 runways",airport: mr} as res2, res, many_runway
WITH collect(res2)+res as res
UNWIND res as r
RETURN r

#Neptune Gremlin using choose()
g.V().
  has('airport', 'region', 'US-AK').
  project('type', 'airport').
    by(
      choose(values('runways')).
        option(1, constant("Has one runway")).
        option(2, constant("Has two runways")).
        option(none, constant("Has more than 2 runways"))).
    by(elementMap())

 #Neptune Gremlin using coalesce()
 g.V().
  has('airport', 'region', 'US-AK').
  project('type', 'airport').
    by(
      coalesce(
        has('runways', 1).constant("Has one runway"),
        has('runways', 2).constant("Has two runways"),
        constant("Has more than 2 runways"))).
    by(elementMap())
```

## Alternatives aux propriétés basées sur des listes
<a name="migration-opencypher-rewrites-lists"></a>

Neptune ne prend actuellement pas en charge le stockage des propriétés basées sur des listes. Cependant, des résultats similaires peuvent être obtenus en stockant les valeurs de liste sous forme de chaîne séparée par des virgules, puis en utilisant les fonctions `join()` et `split()` pour construire et déconstruire la propriété de liste.

Par exemple, si nous voulions enregistrer une liste de balises en tant que propriété, nous pourrions utiliser l'exemple de réécriture qui montre comment récupérer une propriété séparée par des virgules, puis utiliser les fonctions `split()` et `join()` avec la compréhension de liste pour obtenir des résultats comparables :

```
# Neo4j Example (In this example, tags is a durable list of string.
MATCH (person:person {name: "TeeMan"})
WITH person, [tag in person.tags WHERE NOT (tag IN ['test1', 'test2', 'test3'])] AS newTags
SET person.tags = newTags
RETURN person

# Neptune openCypher 
MATCH (person:person {name: "TeeMan"})
WITH person, [tag in split(person.tags, ',') WHERE NOT (tag IN ['test1', 'test2', 'test3'])] AS newTags
SET person.tags = join(newTags,',')
RETURN person
```

## Réécriture des sous-requêtes CALL
<a name="migration-opencypher-rewrites-call-subqueries"></a>

 `CALL`Les sous-requêtes Neptune ne prennent pas en charge la syntaxe `CALL (friend) { ... }` permettant d'importer des variables dans le champ d'application de la sous-requête (dans cet `friend` exemple). Veuillez utiliser la `WITH` clause contenue dans la sous-requête pour la même chose, par exemple, `CALL { WITH friend ... }` 

 Les `CALL` sous-requêtes facultatives ne sont pas prises en charge pour le moment. 

## Autres différences entre Neptune openCypher et Cypher
<a name="opencypher-compliance-other-differences"></a>
+ Neptune prend uniquement en charge les connexions TCP pour le protocole Bolt. WebSocketsles connexions pour Bolt ne sont pas prises en charge.
+ Neptune openCypher supprime les espaces tels que définis par Unicode dans les fonctions `trim()`, `ltrim()` et `rtrim()`.
+ Dans Neptune openCypher, `tostring(`double`)` ne passe pas automatiquement en notation E pour les grandes valeurs du double.