

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
<a name="migration-opencypher-rewrites"></a>

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](https://www.opencypher.org/) 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 das AWS comunidades de código aberto.

OpenCypher a sintaxe está documentada na [Cypher Query Language Reference, versão 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).

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`
<a name="migration-opencypher-rewrites-none-all-any"></a>

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 name="migration-opencypher-rewrites-reduce"></a>

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 name="migration-opencypher-rewrites-foreach"></a>

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.
<a name="migration-opencypher-rewrites-apoc"></a>

Os exemplos abaixo usam o openCypher para substituir alguns dos [procedimentos APOC](https://neo4j.com/blog/intro-user-defined-procedures-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`
<a name="migration-opencypher-rewrites-apoc-export"></a>

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](https://github.com/aws/neptune-export) (consulte [Exportar dados de um cluster de banco de dados do Neptune](neptune-data-export.md)).

### Procedimentos de reformulação de `apoc.schema`
<a name="migration-opencypher-rewrites-apoc-schema"></a>

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`
<a name="migration-opencypher-rewrites-apoc-do"></a>

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
<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 para 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 às propriedades baseadas em listas
<a name="migration-opencypher-rewrites-lists"></a>

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

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

 As subconsultas `CALL` do Neptune não oferecem suporte à sintaxe `CALL (friend) { ... }` para importar variáveis para o escopo da subconsulta (`friend`, neste exemplo). Use a cláusula `WITH` dentro da subconsulta para o mesmo, por exemplo, `CALL { WITH friend ... }`. 

 Atualmente, não há suporte para subconsultas `CALL` opcionais. 

## Outras diferenças entre o openCypher e o Cypher do Neptune
<a name="opencypher-compliance-other-differences"></a>
+ O Neptune só suporta conexões TCP para o protocolo Bolt. WebSocketsconexões para Bolt não são suportadas.
+ O openCypher do Neptune remove o espaço em branco conforme definido pelo Unicode nas funções `trim()`, `ltrim()` e `rtrim()`.
+ No openCypher do Neptune, `tostring(`duplo`)` não muda automaticamente para a notação E para valores grandes do duplo.