Riscrittura delle query Cypher da eseguire in openCypher su Neptune - Amazon Neptune

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Riscrittura delle query Cypher da eseguire in openCypher su Neptune

openCypher è un linguaggio di query dichiarativo per grafi di proprietà che è stato sviluppato originariamente da Neo4j, per poi diventare open source nel 2015, e che ha contribuito al progetto openCypher con una licenza open source Apache 2. In AWS, crediamo che l'open source sia un bene per tutti e ci impegniamo a offrirne il valore ai nostri clienti, nonché a fornire l'eccellenza operativa di AWS alle community open source.

La sintassi di openCypher è documentata nel documento Cypher Query Language Reference, versione 9.

Poiché openCypher contiene un sottoinsieme della sintassi e delle caratteristiche del linguaggio di query Cypher, alcuni scenari di migrazione richiedono la riscrittura delle query in moduli compatibili con openCypher oppure la valutazione di metodi alternativi per ottenere la funzionalità desiderata.

Questa sezione contiene alcuni consigli non esaustivi per gestire le differenze più comuni. È necessario testare accuratamente qualsiasi applicazione utilizzando queste riscritture per assicurarsi che i risultati siano quelli previsti.

Riscrittura delle funzioni di predicato None, All e Any

Queste funzioni non fanno parte della specifica openCypher. È possibile ottenere risultati simili in openCypher utilizzando la comprensione di lista.

Ad esempio, trova tutti i percorsi che vanno dal nodo Start al nodo End, ma nessun percorso può attraversare un nodo con una proprietà di classe 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 comprensione di lista consente di ottenere questi risultati come descritto di seguito:

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

Riscrittura della funzione Cypher reduce() in openCypher

La funzione reduce() non fa parte delle specifiche openCypher. Viene spesso utilizzata per creare un'aggregazione di dati a partire da elementi all'interno di un elenco. In molti casi, è possibile utilizzare una combinazione di comprensione di lista e della clausola UNWIND per ottenere risultati simili.

Ad esempio, la seguente query Cypher trova tutti gli aeroporti su rotte che comprendono da uno a tre scali Anchorage (ANC) e Austin (AUS) e restituisce la distanza totale di ciascun percorso:

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

Puoi scrivere la stessa query in openCypher per Neptune come segue:

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

Riscrittura della clausola Cypher FOREACH in openCypher

La clausola FOREACH non fa parte delle specifiche openCypher. Viene spesso utilizzata per aggiornare i dati in mezzo a una query, spesso da aggregazioni o elementi all'interno di un percorso.

Come esempio di percorso, trova tutti gli aeroporti su una rotta con non più di due scali tra Anchorage (ANC) e Austin (AUS) e imposta la proprietà Visited per ciascuno di essi:

# 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

Un altro esempio è:

# 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

Riscrittura delle procedure APOC Neo4j in Neptune

Gli esempi seguenti utilizzano openCypher per sostituire alcune delle procedure APOC usate più comunemente. Questi esempi sono solo di riferimento e hanno lo scopo di fornire alcuni suggerimenti su come gestire scenari comuni. In pratica, ogni applicazione è diversa ed è necessario trovare strategie personalizzate per fornire tutte le funzionalità di cui hai bisogno.

Riscrittura delle procedure apoc.export

Neptune offre un array di opzioni sia per le esportazioni a grafo completo che per quelle basate su query in vari formati di output come CSV e JSON, il tutto mediante l'utilità neptune-export (vedi Esportazione di dati da un cluster database Neptune).

Riscrittura delle procedure apoc.schema

Neptune non ha schemi, indici o vincoli definiti in modo esplicito, perciò molte procedure apoc.schema non sono più necessarie. Alcuni esempi sono:

  • 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 per Neptune supporta il recupero di valori simili a quelli utilizzati dalle procedure, come mostrato di seguito, ma potrebbe riscontrare problemi di prestazioni su grafi più grandi poiché sarebbe necessario scansionare un'ampia porzione del grafo per restituire la risposta.

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

Alternative alle procedure apoc.do

Queste procedure vengono utilizzate per consentire l'esecuzione di query condizionali facili da implementare utilizzando altre clausole openCypher. In Neptune ci sono almeno due modi per ottenere un comportamento simile:

  • Un modo è combinare le funzionalità della comprensione di lista di openCypher con la clausola UNWIND.

  • Un altro modo è usare i passaggi choose() e coalesce() in Gremlin.

Di seguito sono riportati alcuni esempi di questi approcci.

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

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

Alternative alle proprietà basate su elenco

Neptune attualmente non supporta la memorizzazione di proprietà basate su elenco. Tuttavia, è possibile ottenere risultati simili memorizzando i valori dell'elenco come stringa separata da virgole e, successivamente, utilizzando le funzioni join() e split() per costruire e decostruire la proprietà di elenco.

Ad esempio, per salvare un elenco di tag come proprietà, potremmo usare l'esempio di riscrittura che mostra come recuperare una proprietà separata da virgole, quindi utilizzare le funzioni split() e join() con la comprensione di lista per ottenere risultati simili:

# 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