Reescritura de consultas de Cypher para ejecutarlas en openCypher en Neptune - Amazon Neptune

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

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 en virtud de una licencia de código abierto Apache 2. En AWS, creemos que el código abierto es la opción adecuada para todos y estamos comprometidos a llevar el valor del código abierto a nuestros clientes y la excelencia operativa de AWS a las comunidades de código abierto.

La sintaxis de openCypher está documentada en Referencia del lenguaje de consultas (versión 9).

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

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

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

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

Los ejemplos siguientes utilizan openCypher para reemplazar algunos de los procedimientos de 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

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 (consulte Exportación de datos desde un clúster de base de datos de Neptune).

Reescritura de los procedimientos de apoc.schema

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

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

# 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

# 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

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