Reformular consultas do Cypher para serem executadas no openCypher no Neptune - Amazon Neptune

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Reformular consultas do Cypher para serem executadas no openCypher no Neptune

O openCypher é uma linguagem de consulta declarativa para grafos de propriedades originalmente desenvolvida pela Neo4j, que passou a ser de código aberto em 2015, e contribuiu para o projeto openCypher sob uma licença de código aberto Apache 2. Na AWS, acreditamos que o código aberto é bom para todos e estamos comprometidos em trazer o valor do código aberto aos nossos clientes e a excelência operacional da AWS para as comunidades de código aberto.

A sintaxe do OpenCypher está documentada na Cypher Query Language Reference, versão 9.

Como o openCypher contém um subconjunto da sintaxe e atributos da linguagem de consulta Cypher, alguns cenários de migração exigem a reformulação de consultas em formas compatíveis com o openCypher ou a análise de métodos alternativos para obter a funcionalidade desejada.

Esta seção contém recomendações para lidar com diferenças comuns, mas elas não são completas. É necessário testar as aplicações usando essas reformulações minuciosamente a fim de garantir que os resultados sejam os esperados.

Reformular funções de predicado None, All e Any

Essas funções não fazem parte da especificação do openCypher. É possível obter resultados comparáveis no openCypher usando a compreensão de lista.

Por exemplo, encontre todos os caminhos que vão do nó Start ao End , mas nenhuma jornada pode passar por um nó com a propriedade de 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

A compreensão de lista pode alcançar esses resultados da seguinte forma:

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

Reformulando a função reduce() do Cypher em openCypher.

A função reduce() não faz parte da especificação do openCypher. Geralmente é usada para criar uma agregação de dados a partir de elementos em uma lista. Em muitos casos, é possível usar uma combinação de compreensão de lista e a cláusula UNWIND para obter resultados semelhantes.

Por exemplo, a consulta do Cypher a seguir encontra todos os aeroportos em caminhos com uma a três paradas entre Anchorage (ANC) e Austin (AUS) e exibe a distância total de cada caminho:

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

Você pode reformular a mesma consulta em openCypher para Neptune da seguinte forma:

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

Reformulando a cláusula FOREACH do Cypher em openCypher.

A cláusula FOREACH não faz parte da especificação do openCypher. Em geral, é usada para atualizar dados no meio de uma consulta, geralmente de agregações ou elementos em um caminho.

Como exemplo de caminho, encontre todos os aeroportos em um caminho com no máximo duas paradas entre Anchorage (ANC) e Austin (AUS) e defina uma propriedade visitada em cada um deles:

# 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

Outro exemplo é:

# 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

Reformulando procedimentos APOC do Neo4j no Neptune.

Os exemplos abaixo usam o openCypher para substituir alguns dos procedimentos APOC mais usados. Esses exemplos são apenas para referência e têm como objetivo fornecer algumas sugestões sobre como lidar com cenários comuns. Na prática, cada aplicação é diferente e você precisará criar suas próprias estratégias para fornecer todas as funcionalidades de que precisa.

Procedimentos de reformulação de apoc.export

O Neptune fornece uma variedade de opções para exportações completas com base em grafos e consultas em vários formatos de saída, como CSV e JSON, usando o utilitário neptune-export (consulte Exportar dados de um cluster de banco de dados do Neptune).

Procedimentos de reformulação de apoc.schema

O Neptune não tem esquemas, índices nem restrições explicitamente definidos, portanto, muitos procedimentos apoc.schema não são mais necessários. Veja estes exemplos:

  • 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

O openCypher no Neptune é compatível com a recuperação de valores semelhantes aos dos procedimentos, conforme mostrado abaixo, mas pode ter problemas de desempenho em grafos maiores, pois isso requer a verificação de uma grande parte do grafo para exibir a resposta.

# 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 aos procedimentos apoc.do

Esses procedimentos são usados para fornecer uma execução condicional de consultas que seja fácil de implementar usando outras cláusulas do openCypher. No Neptune, existem pelo menos duas maneiras de obter um comportamento semelhante:

  • Uma delas é combinar os recursos de compreensão de listas do openCypher com a cláusula UNWIND.

  • Outra forma é usar as etapas choose() e coalesce() no Gremlin.

Exemplos dessas abordagens são mostrados abaixo.

Alternativas para 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 para 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 às propriedades baseadas em listas

No momento, o Neptune não aceita o armazenamento de propriedades baseadas em listas. No entanto, resultados semelhantes podem ser obtidos armazenando os valores da lista como uma string separada por vírgula e, depois, usando as funções join() e split() para construir e desconstruir a propriedade da lista.

Por exemplo, se quisermos salvar uma lista de tags como uma propriedade, poderemos usar o exemplo de reformulação, que mostra como recuperar uma propriedade separada por vírgula e, depois, usar as funções split() e join() com a compreensão de lista para obter resultados comparáveis:

# 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