

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Reescritura de consultas de Cypher para ejecutarlas en openCypher en Neptune
<a name="migration-opencypher-rewrites"></a>

El lenguaje de openCypher es un lenguaje de consulta declarativo para gráficos de propiedades que desarrolló originalmente Neo4j y que pasó a ser de código abierto en 2015. Además, contribuyó al [proyecto openCypher](https://www.opencypher.org/) en virtud de una licencia de código abierto Apache 2. En AWS, creemos que el código abierto es bueno para todos y estamos comprometidos a llevar el valor del código abierto a nuestros clientes y la excelencia operativa de AWS las comunidades de código abierto.

OpenCypher La sintaxis está documentada en la [versión 9 de Cypher Query Language Reference](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).

Dado que openCypher incluye un subconjunto de la sintaxis y las características del lenguaje de consultas de Cypher, algunos escenarios de migración requieren reescribir las consultas en formatos compatibles con openCypher o examinar métodos alternativos para lograr la funcionalidad deseada.

En esta sección se incluyen recomendaciones para tratar las diferencias más comunes, pero no es en absoluto exhaustiva. Debe probar minuciosamente cualquier aplicación que utilice estas reescrituras para asegurarse de que los resultados son los previstos.

## Reescritura de funciones de predicado `None`, `All` y `Any`
<a name="migration-opencypher-rewrites-none-all-any"></a>

Estas funciones no forman parte de la especificación de openCypher. Se pueden lograr resultados comparables en openCypher con Comprensión de listas.

Por ejemplo, busque todas las rutas que van del nodo `Start` al nodo `End`, pero no se permite que ningún recorrido atraviese un nodo con una propiedad de clase de `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 opción Comprensión de listas puede lograr los siguientes resultados:

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

## Reescritura de la función `reduce()` de Cypher en openCypher
<a name="migration-opencypher-rewrites-reduce"></a>

La función `reduce()` no forma parte de la especificación de openCypher. Suele utilizarse para crear una agregación de datos a partir de elementos de una lista. En muchos casos, puede utilizar una combinación de Comprensión de listas y la cláusula `UNWIND` para obtener resultados similares.

Por ejemplo, la siguiente consulta de Cypher busca todos los aeropuertos en las rutas que tengan de una a tres paradas entre Anchorage (ANC) y Austin (AUS) y devuelve la distancia total de cada ruta:

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

Puede escribir la misma consulta en openCypher para Neptune, como, por ejemplo:

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

## Reescritura de la cláusula FOREACH de Cypher en openCypher
<a name="migration-opencypher-rewrites-foreach"></a>

La cláusula FOREACH no forma parte de la especificación de openCypher. Suele utilizarse para actualizar los datos en mitad de una consulta, a menudo a partir de agregaciones o elementos de una ruta.

Como ejemplo de ruta, busque todos los aeropuertos de una ruta con no más de dos paradas entre Anchorage (ANC) y Austin (AUS) y establezca una propiedad de visitado en cada una de ellos:

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

Otro ejemplo:

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

## Reescritura de los procedimientos de APOC de Neo4j en Neptune
<a name="migration-opencypher-rewrites-apoc"></a>

Los ejemplos siguientes utilizan openCypher para reemplazar algunos de los [procedimientos de APOC](https://neo4j.com/blog/intro-user-defined-procedures-apoc/) más utilizados. Estos ejemplos son solo de referencia y están destinados a proporcionar algunas sugerencias sobre cómo gestionar situaciones comunes. En la práctica, cada aplicación es diferente y tendrá que idear sus propias estrategias para proporcionar toda la funcionalidad que necesite.

### Reescritura de los procedimientos de `apoc.export`
<a name="migration-opencypher-rewrites-apoc-export"></a>

Neptune ofrece una variedad de opciones para exportaciones completas basadas en consultas y gráficos en varios formatos de salida, como CSV y JSON, mediante la utilidad [neptune-export](https://github.com/aws/neptune-export) (consulte [Exportación de datos desde un clúster de base de datos de Neptune](neptune-data-export.md)).

### Reescritura de los procedimientos de `apoc.schema`
<a name="migration-opencypher-rewrites-apoc-schema"></a>

Neptune no tiene esquemas, índices ni restricciones definidos de forma explícita, por lo que muchos procedimientos de `apoc.schema` ya no son necesarios. Algunos ejemplos son:
+ `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`

openCypher de Neptune admite la recuperación de valores similares a los de los procedimientos, tal y como se muestra a continuación, pero puede tener problemas de rendimiento en gráficos de mayor tamaño, ya que para ello es necesario escanear una gran parte del gráfico con el fin de obtener la respuesta.

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

### Alternativas a los procedimientos de `apoc.do`
<a name="migration-opencypher-rewrites-apoc-do"></a>

Estos procedimientos se utilizan para proporcionar una ejecución de consultas condicional que sea fácil de implementar con otras cláusulas de openCypher. En Neptune hay al menos dos formas de lograr un comportamiento similar:
+ Una forma es combinar las capacidades de Comprensión de listas de openCypher con la cláusula `UNWIND`.
+ Otra forma es usar los pasos choose() y coalesce() de Gremlin.

A continuación se muestran ejemplos de estos enfoques.

#### Alternativas a 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())
```

#### Alternativas a 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())
```

## Alternativas a las propiedades basadas en listas
<a name="migration-opencypher-rewrites-lists"></a>

Neptune no admite actualmente el almacenamiento de propiedades basadas en listas. Sin embargo, se pueden obtener resultados similares si se almacenan los valores de la lista como una cadena separada por comas y, a continuación, se utilizan las funciones `join()` y `split()` para construir y deconstruir la propiedad de la lista.

Por ejemplo, si quisiéramos guardar una lista de etiquetas como una propiedad, podríamos usar el ejemplo de reescritura, que muestra cómo recuperar una propiedad separada por comas, y luego usar las funciones `split()` y `join()` con Compresión de listas para lograr resultados 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
```

## Reescritura de subconsultas CALL
<a name="migration-opencypher-rewrites-call-subqueries"></a>

 Las subconsultas `CALL` de Neptune no admiten la sintaxis `CALL (friend) { ... }` para importar variables al ámbito de la subconsulta (`friend`, en este ejemplo). Utilice la cláusula `WITH` incluida en la subconsulta para hacer lo mismo, por ejemplo, `CALL { WITH friend ... }`. 

 Las subconsultas `CALL` opcionales no se admiten en este momento. 

## Otras diferencias entre openCypher de Neptune y Cypher
<a name="opencypher-compliance-other-differences"></a>
+ Neptune solo admite conexiones TCP para el protocolo Bolt. WebSocketsno se admiten las conexiones para Bolt.
+ openCypher de Neptune elimina los espacios en blanco tal como los define Unicode en las funciones `trim()`, `ltrim()` y `rtrim()`.
+ En openCypher de Neptune, `tostring(`double`)` no cambia automáticamente a la notación E para valores grandes del doble.