

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á.

# Práticas recomendadas: aproveitar ao máximo o Neptune
<a name="best-practices"></a>

Veja algumas recomendações gerais para trabalhar com o Amazon Neptune. Use essas informações como referência para localizar rapidamente as recomendações para o uso do Amazon Neptune e maximizar o desempenho.

**Contents**
+ [Diretrizes operacionais básicas do Amazon Neptune](best-practices-general-basic.md)
  + [Práticas recomendadas de segurança para o Amazon Neptune](best-practices-general-security.md)
  + [Evitar classes de instância diferentes em um cluster](best-practices-general-basic.md#best-practices-loader-heterogeneous-instances)
  + [Evitar reinicializações repetidas durante o carregamento em massa](best-practices-general-basic.md#best-practices-loader-repeated-restarts)
  + [Habilitar o Índice OSGP se você tiver um grande número de predicados](best-practices-general-basic.md#best-practices-general-predicates)
  + [Evitar transações de longa execução quando possível](best-practices-general-basic.md#best-practices-general-long-running-transactions)
  + [Práticas recomendadas para o uso de métricas do Neptune](best-practices-general-metrics.md)
  + [Práticas recomendadas para ajustar as consultas do Neptune](best-practices-general-basic.md#best-practices-general-tuning)
  + [Balanceamento de carga entre réplicas de leitura](best-practices-general-basic.md#best-practices-general-loadbalance)
  + [Carregar com maior rapidez usando uma instância temporária maior](best-practices-general-basic.md#best-practices-loader-tempinstance)
  + [Redimensione a instância de gravador realizando o failover para uma réplica de leitura](best-practices-general-basic.md#best-practices-resize-instance)
  + [Tentar fazer upload novamente após um erro de interrupção de tarefa de pré-busca de dados](best-practices-general-basic.md#load-api-reference-status-interrupted)
+ [Práticas recomendadas gerais para usar o Gremlin com o Neptune](best-practices-gremlin.md)
  + [Configuração Heartbeat para Neptune Serverless](best-practices-gremlin-heartbeat-serverless.md)
  + [Estruturar consultas de upsert para aproveitar as vantagens do mecanismo do DFE](best-practices-gremlin.md#best-practices-gremlin-upserts)
  + [Testar o código do Gremlin no contexto em que você o implantará](best-practices-gremlin-console-glv-differences.md)
  + [Criação de gravações eficientes com multi-thread do Gremlin](best-practices-gremlin-multithreaded-writes.md)
  + [Redução de registros com o Creation Time Property](best-practices-gremlin-prune.md)
  + [Ao usar o método `datetime( )` para o Groovy Time Data](best-practices-gremlin-datetime.md)
  + [Uso da data e hora nativas para dados de data GLV](best-practices-gremlin-datetime-glv.md)
+ [Práticas recomendadas para usar o cliente Java do Gremlin com o Neptune](best-practices-gremlin-java-client.md)
  + [Reutilizar o objeto de cliente entre vários threads](best-practices-gremlin-java-reuse.md)
  + [Criar objetos separados do cliente Java do Gremlin para endpoints de leitura e gravação](best-practices-gremlin-java-separate.md)
  + [Adicionar vários endpoints de réplica de leitura a um grupo conexão Java do Gremlin](best-practices-gremlin-java-multiple.md)
  + [Fechar o cliente para evitar o limite de conexões](best-practices-gremlin-java-close-connections.md)
  + [Criar uma conexão após o failover](best-practices-gremlin-java-new-connection.md)
  + [Definir `maxInProcessPerConnection` e `maxSimultaneousUsagePerConnection` como o mesmo valor](best-practices-gremlin-java-maxes.md)
  + [Enviar consultas ao servidor como bytecode em vez de strings](best-practices-gremlin-java-bytecode.md)
  + [Sempre consuma completamente o ResultSet ou Iterator retornado por uma consulta](best-practices-gremlin-java-resultset.md)
  + [Adicionar em massa vértices e bordas em lotes](best-practices-gremlin-java-batch-add.md)
  + [Desativar o armazenamento em cache DNS no Java Virtual Machine](best-practices-gremlin-java-disable-dns-caching.md)
  + [Opcionalmente, definir tempos limite em um nível por consulta](best-practices-gremlin-java-per-query-timeout.md)
  + [Solução de problemas do `java.util.concurrent.TimeoutException`](best-practices-gremlin-java-exceptions-TimeoutException.md)
+ [Práticas recomendadas para o Neptune ao usar openCypher e Bolt](best-practices-opencypher.md)
  + [Criar uma conexão após o failover](best-practices-opencypher.md#best-practices-opencypher-renew-connection)
  + [Tratamento de conexões para aplicações de longa duração](best-practices-opencypher.md#best-practices-opencypher-long-connections)
  + [Manipulação de conexão para AWS Lambda](best-practices-opencypher.md#best-practices-opencypher-lambda-connections)
  + [Preferir direcionar para bordas bidirecionais nas consultas](best-practices-opencypher-directed-edges.md)
  + [O Neptune não é compatível com várias consultas simultâneas em uma transação.](best-practices-opencypher-multiple-queries.md)
  + [Fechar objetos de driver ao concluir](best-practices-opencypher-close-driver.md)
  + [Usar modos de transação explícitos para leitura e gravação](best-practices-opencypher-use-explicit-txs.md)
    + [Transações somente leitura](best-practices-opencypher-use-explicit-txs.md#best-practices-opencypher-read-txs)
    + [Transações de mutação](best-practices-opencypher-use-explicit-txs.md#best-practices-opencypher-mutation-txs)
  + [Lógica de novas tentativas para exceções](best-practices-opencypher-retry-logic.md)
  + [Definir várias propriedades de uma vez usando uma única cláusula SET](best-practices-content-0.md)
    + [Usar a cláusula SET para remover várias propriedades de uma só vez](best-practices-content-0.md#best-practices-content-1)
  + [Usar consultas parametrizadas](best-practices-content-2.md)
  + [Use mapas nivelados em vez de mapas aninhados na cláusula UNWIND](best-practices-content-3.md)
  + [Coloque nós mais restritivos no lado esquerdo em expressões de caminho de comprimento variável (VLP)](best-practices-content-4.md)
  + [Evitar verificações redundantes de rótulos de nó usando nomes de relacionamento granulares](best-practices-content-5.md)
  + [Especificar rótulos de borda sempre que possível](best-practices-content-6.md)
  + [Evitar usar a cláusula WITH quando possível](best-practices-content-7.md)
  + [Colocar filtros restritivos o mais cedo possível na consulta](best-practices-content-8.md)
  + [Verificar explicitamente se as propriedades existem](best-practices-content-9.md)
  + [Não usar o caminho nomeado (a menos que seja necessário)](best-practices-content-10.md)
  + [Evitar COLLECT(DISTINCT())](best-practices-content-11.md)
  + [Optar pela função de propriedades em vez da pesquisa de propriedades individuais ao recuperar todos os valores da propriedade](best-practices-content-12.md)
  + [Executar cálculos estáticos fora da consulta](best-practices-content-13.md)
  + [Agrupar entradas usando UNWIND em vez de declarações individuais](best-practices-content-14.md)
  + [Prefiro usar o personalizado IDs para nó/relacionamento](best-practices-content-15.md)
  + [Evitar fazer cálculos de \$1id na consulta](best-practices-content-16.md)
  + [Atualizar/mesclar vários nós](best-practices-merge-multiple-nodes.md)
+ [Práticas recomendadas para o Neptune ao usar SPARQL](best-practices-sparql.md)
  + [Como consultar todos os gráficos nomeados por padrão](best-practices-sparql-query.md)
  + [Como especificar um nome gráfico para carregamento](best-practices-sparql-graph.md)
  + [Como escolher entre FILTER, FILTER...IN e VALUES em suas consultas](best-practices-sparql-batch.md)

# Diretrizes operacionais básicas do Amazon Neptune
<a name="best-practices-general-basic"></a>

As diretrizes operacionais básicas a seguir devem ser seguidas ao trabalhar com o Neptune.
+ Entenda as instâncias de banco de dados do Neptune para que você possa dimensioná-las adequadamente de acordo com seus requisitos de desempenho e caso de uso. Consulte [Clusters e instâncias de banco de dados do Amazon Neptune](feature-overview-db-clusters.md).
+ Monitore o uso que você faz da CPU e da memória. Isso ajuda você a saber quando migrar para uma classe de instância de banco de dados com maior capacidade de memória ou CPU para alcançar o desempenho necessário nas consultas. Você pode configurar CloudWatch a Amazon para notificá-lo quando os padrões de uso mudarem ou quando você se aproximar da capacidade de sua implantação. Isso pode ajudá-lo a manter o desempenho e a disponibilidade do sistema. Consulte [Monitorar instâncias](feature-overview-db-clusters.md#feature-overview-monitoring-instances) e [Monitorar o Neptune](monitoring.md) para obter mais detalhes.

  Como o Neptune tem seu próprio gerenciador de memória, é normal ver um uso relativamente baixo da memória, mesmo quando o uso da CPU é alto. Encontrar out-of-memory exceções ao executar consultas é o melhor indicador de que você precisa aumentar a memória liberável.
+ Ative os backups automáticos e defina a janela de backup para que ela ocorra em um momento conveniente.
+ Teste o failover da instância do banco de dados para entender quanto tempo o processo leva para seu caso de uso. Isso também ajuda a garantir que o aplicativo que acessa sua instância de banco de dados possa se conectar automaticamente à nova instância de banco de dados após o failover.
+ Se possível, execute o cliente e o cluster Neptune na mesma região e VPC, pois as conexões entre regiões com emparelhamento de VPC podem apresentar atrasos nos tempos de resposta de consulta. Para respostas de consulta em milissegundos de um único dígito, é necessário manter o cliente e o cluster do Neptune na mesma região e VPC.
+ Quando você cria uma instância de réplica de leitura, ela deve ser pelo menos tão grande quanto a instância de gravador principal. Isso ajuda a manter o atraso de replicação sob controle e evita reinicializações de réplicas. Consulte [Evitar classes de instância diferentes em um cluster](#best-practices-loader-heterogeneous-instances). 
+ Antes de realizar a atualização para uma nova versão principal do mecanismo, teste a aplicação nela antes de fazer upgrade. Você pode fazer isso clonando o cluster de banco de dados para que o cluster clone execute a nova versão do mecanismo e, depois, testando a aplicação no clone.
+ Para facilitar os failovers, é ideal que todas as instâncias tenham o mesmo tamanho.

**Topics**
+ [Práticas recomendadas de segurança para o Amazon Neptune](best-practices-general-security.md)
+ [Evitar classes de instância diferentes em um cluster](#best-practices-loader-heterogeneous-instances)
+ [Evitar reinicializações repetidas durante o carregamento em massa](#best-practices-loader-repeated-restarts)
+ [Habilitar o Índice OSGP se você tiver um grande número de predicados](#best-practices-general-predicates)
+ [Evitar transações de longa execução quando possível](#best-practices-general-long-running-transactions)
+ [Práticas recomendadas para o uso de métricas do Neptune](best-practices-general-metrics.md)
+ [Práticas recomendadas para ajustar as consultas do Neptune](#best-practices-general-tuning)
+ [Balanceamento de carga entre réplicas de leitura](#best-practices-general-loadbalance)
+ [Carregar com maior rapidez usando uma instância temporária maior](#best-practices-loader-tempinstance)
+ [Redimensione a instância de gravador realizando o failover para uma réplica de leitura](#best-practices-resize-instance)
+ [Tentar fazer upload novamente após um erro de interrupção de tarefa de pré-busca de dados](#load-api-reference-status-interrupted)

# Práticas recomendadas de segurança para o Amazon Neptune
<a name="best-practices-general-security"></a>

Use contas AWS Identity and Access Management (IAM) para controlar o acesso às ações da API Neptune. Controle ações que criam, modificam ou excluem recursos do Neptune (como instâncias de banco de dados, grupos de segurança, grupos de opções ou grupos de parâmetros) e ações administrativas comuns (como fazer backup e restaurar instâncias de banco de dados).
+ Use credenciais temporárias em vez de persistentes sempre que possível.
+ Atribua uma conta do IAM individual a cada pessoa que gerencia recursos do Amazon Relational Database Service (Amazon RDS). Nunca use usuários raiz AWS da conta para gerenciar os recursos do Neptune. Crie um usuário do IAM para todos os usuários, incluindo você mesmo.
+ Conceda a cada usuário o conjunto mínimo de permissões necessárias para realizar suas funções.
+ Use grupos do IAM para gerenciar efetivamente permissões para vários usuários.
+ Mude suas credenciais do IAM regularmente.

Para obter mais informações sobre o uso do IAM para acessar os recursos do Neptune, consulte [Proteger o banco de dados do Amazon Neptune](security.md). Para obter informações gerais sobre como trabalhar com o IAM, consulte [AWS Identity and Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/Welcome.html) e [IAM Best Practices](https://docs.aws.amazon.com/IAM/latest/UserGuide/IAMBestPractices.html) no *Guia do usuário do IAM*.

## Evitar classes de instância diferentes em um cluster
<a name="best-practices-loader-heterogeneous-instances"></a>

Quando o cluster de banco de dados contém instâncias de classes diferentes, podem ocorrer problemas com o tempo. O problema mais comum é que uma pequena instância de leitor pode entrar em um ciclo de reinicializações repetidas devido ao atraso na replicação. Se um nó de leitor tiver uma configuração de classe de instância de banco de dados mais fraca do que a de uma instância de banco de dados de gravador, o volume de alterações poderá ser muito grande para o leitor se atualizar.

**Importante**  
Para evitar reinicializações repetidas causadas pelo atraso na replicação, configure o cluster de banco de dados para que todas as instâncias tenham a mesma classe (tamanho) de instância.

Você pode ver o atraso entre a instância do gravador (a primária) e os leitores em seu cluster de banco de dados usando a `ClusterReplicaLag` métrica na Amazon CloudWatch. A métrica `VolumeWriteIOPs` também permite detectar picos de atividade de gravação no cluster que podem criar atrasos na replicação.

## Evitar reinicializações repetidas durante o carregamento em massa
<a name="best-practices-loader-repeated-restarts"></a>

Se você tiver um ciclo de reinicializações repetidas de réplica de leitura em virtude do atraso na replicação durante o carregamento em massa, é provável que as réplicas não consigam acompanhar o gravador no cluster de banco de dados.

Escale os leitores para serem maiores do que o gravador ou remova-os temporariamente durante o carregamento em massa e, depois, recrie-os após a conclusão.

## Habilitar o Índice OSGP se você tiver um grande número de predicados
<a name="best-practices-general-predicates"></a>

Se o seu modelo de dados contiver um grande número de predicados distintos (mais de mil na maioria dos casos), o desempenho poderá ser degradado e os custos operacionais mais altos.

Se for esse o caso, você poderá melhorar o desempenho habilitando o [índice OSGP](feature-overview-storage-indexing.md#feature-overview-storage-indexing-osgp). Consulte [O índice OSGP](features-lab-mode.md#features-lab-mode-features-osgp-index).

## Evitar transações de longa execução quando possível
<a name="best-practices-general-long-running-transactions"></a>

Transações de longa execução, somente leitura ou leitura e gravação, podem causar problemas inesperados dos seguintes tipos:

Uma transação de longa execução em uma instância de leitor ou em uma instância de gravador com gravações simultâneas pode ocasionar um grande acúmulo de diferentes versões de dados. Isso pode introduzir latências mais altas para consultas de leitura que filtrem uma grande parte dos resultados.

Em alguns casos, as versões acumuladas ao longo de horas podem fazer com que novas gravações sejam limitadas.

Uma transação de leitura e gravação de longa execução com muitas gravações também poderá causar problemas se a instância for reiniciada. Se uma instância for reiniciada a partir de um evento de manutenção ou de uma falha, todas as gravações não confirmadas serão revertidas. Essas operações de desfazer normalmente são executadas em segundo plano e não impedem que a instância volte a funcionar, mas qualquer nova gravação que entre em conflito com as operações que estão sendo revertidas falhará.

Por exemplo, se a mesma consulta for repetida após a conexão ter sido interrompida na execução anterior, ela poderá falhar quando a instância for reiniciada.

O tempo necessário para as operações de desfazer é proporcional ao tamanho das alterações envolvidas.

# Práticas recomendadas para o uso de métricas do Neptune
<a name="best-practices-general-metrics"></a>

Para identificar problemas de desempenho causados por recursos insuficientes e outros gargalos comuns, é possível monitorar as métricas disponíveis para o cluster de banco de dados do Neptune. 

Monitore as métricas de desempenho regularmente para coletar dados sobre os valores médio, máximo e mínimo de uma série de intervalos de tempo. Isso ajuda a identificar quando o desempenho está degradado. Usando esses dados, você pode definir CloudWatch alarmes da Amazon para limites métricos específicos para ser alertado se eles forem atingidos. 

Quando você configura um novo cluster de banco de dados e a executa com uma carga de trabalho típica, tente captar os valores médio, máximo e mínimo de todas as métricas de desempenho em vários intervalos diferentes (por exemplo, uma hora, 24 horas, uma semana, duas semanas). Isso dá a você uma ideia do que é normal. Isso ajuda a obter comparações para as horas de operação de pico e fora de pico. Você pode usar essas informações para identificar quando o desempenho está ficando abaixo dos níveis padrão e definir alarmes corretamente.

Consulte [Monitorando Neptune usando a Amazon CloudWatch](cloudwatch.md) para obter informações sobre como visualizar métricas do Neptune.

Veja a seguir as métricas mais importantes para começar:
+ **BufferCacheHitRatio**— A porcentagem de solicitações atendidas pelo cache de buffer. As falhas de cache adicionam latência significativa à execução da consulta. Se a taxa de acertos do cache estiver abaixo de 99,9% e a latência for um problema na aplicação, pense em atualizar o tipo de instância para armazenar em cache mais dados na memória.
+ **Utilização da CPU**: porcentagem da capacidade de processamento computacional utilizada. Altos valores de consumo de CPU podem ser adequados, dependendo de seus objetivos de desempenho de consultas.
+ **Memória disponível**: quanta RAM está disponível na instância de banco de dados, em megabytes. O Neptune tem seu próprio gerenciador de memória, então essa métrica pode ser mais baixa do que você espera. Um bom sinal de que você deve considerar atualizar sua classe de instância para uma com mais RAM é se as consultas geralmente out-of-memory geram exceções.

A linha vermelha nas métricas da guia **Monitoring (Monitoramento)** é marcada em 75% para CPU e métricas de memória. Se o consumo de memória da instância cruzar essa linha com frequência, verifique sua carga de trabalho ou considere atualizar sua instância para melhorar o desempenho das consultas.

## Práticas recomendadas para ajustar as consultas do Neptune
<a name="best-practices-general-tuning"></a>

 Uma das melhores maneiras de melhorar o desempenho do Neptune é ajustar as consultas mais utilizadas e que requerem mais recursos para baixar o custo de execução delas. 

Para obter informações sobre como ajustar as consultas do Gremlin, consulte [Dicas de consulta do Gremlin](gremlin-query-hints.md) e [Ajustar consultas do Gremlin](gremlin-traversal-tuning.md). Para obter informações sobre como ajustar consultas do SPARQL, consulte [Dicas de consulta do SPARQL](sparql-query-hints.md).

## Balanceamento de carga entre réplicas de leitura
<a name="best-practices-general-loadbalance"></a>

O roteamento ida e volta do endpoint de leitor funciona alterando o host para o qual a entrada DNS aponta. O cliente deve criar uma nova conexão e resolver o registro DNS para obter uma conexão com uma nova réplica de leitura, porque WebSocket as conexões geralmente são mantidas ativas por longos períodos.

Para obter réplicas de leitura diferentes para solicitações sucessivas, certifique-se de que o cliente resolva a entrada de DNS sempre que se conectar. Isso pode exigir o fechamento da conexão e a reconexão ao endpoint de leitor.

Você também pode balancear a carga de solicitações entre réplicas de leitura conectando-se aos endpoints da instância explicitamente.

## Carregar com maior rapidez usando uma instância temporária maior
<a name="best-practices-loader-tempinstance"></a>

O desempenho do carregamento aumenta com tamanhos de instância maiores. Se não estiver usando um tipo de instância ampla, mas quer aumentar a velocidade de carregamento, você pode usar a instância ampla para carregar e então excluí-la.

**nota**  
O procedimento a seguir é para um novo cluster. Se tiver um cluster existente, você pode adicionar uma nova instância maior e, em seguida, promovê-la para uma instância de Banco de Dados.

**Para carregar dados usando um tamanho de instância maior**

1.  Crie um cluster com uma única instância `r5.12xlarge`. Esta instância é a principal instância de banco de dados.

1. Crie uma ou mais réplicas de leitura do mesmo tamanho (`r5.12xlarge`).

   É possível criar as réplicas de leitura em um tamanho menor, mas se elas não forem grandes o suficiente para acompanhar as gravações feitas pela instância principal, talvez precisem ser reiniciadas com frequência. O tempo de inatividade resultante reduz drasticamente o desempenho.

1. No comando do carregador em massa, inclua `“parallelism” : “OVERSUBSCRIBE”` para indicar ao Neptune que use todos os recursos de CPU disponíveis para carregamento (consulte [Parâmetros de solicitação do carregador do Neptune](load-api-reference-load.md#load-api-reference-load-parameters)). A operação de carregamento prosseguirá o mais rápido possível, I/O o que geralmente requer de 60 a 70% dos recursos da CPU.

1. Carregue os dados usando o carregador do Neptune. O trabalho de carga é executado na instância de banco de dados principal.

1. Depois que os dados terminarem de carregar, certifique-se de reduzir todas as instâncias no cluster para o mesmo tipo de instância a fim de evitar cobranças adicionais e problemas repetidos de reinicialização (consulte [Evitar tamanhos de instância diferentes.](#best-practices-loader-heterogeneous-instances)).

## Redimensione a instância de gravador realizando o failover para uma réplica de leitura
<a name="best-practices-resize-instance"></a>

A melhor maneira de redimensionar uma instância no cluster de banco de dados, incluindo a instância de gravador, é criar ou modificar uma instância de réplica de leitura para que ela tenha o tamanho desejado e, depois, fazer o failover deliberadamente para essa réplica de leitura. O tempo de inatividade observado pela aplicação é apenas o tempo necessário para alterar o endereço IP do gravador, que deve ser de cerca de três a cinco segundos.

A API de gerenciamento do Neptune usada para fazer failover deliberadamente da instância de gravador atual para uma instância de réplica de leitura é [FailoverDBCluster](api-clusters.md#FailoverDBCluster). Se você estiver usando o cliente Java do Gremlin, talvez seja necessário criar um objeto Client após o failover para obter o novo endereço IP, conforme mencionado [aqui](best-practices-gremlin-java-new-connection.md).

Altere todas as instâncias para o mesmo tamanho a fim de evitar um ciclo de reinicializações repetidas, conforme mencionado abaixo.

## Tentar fazer upload novamente após um erro de interrupção de tarefa de pré-busca de dados
<a name="load-api-reference-status-interrupted"></a>

Ocasionalmente, quando você estiver carregando dados no Neptune usando o carregador em massa, poderá ocorrer um status `LOAD_FAILED`, com uma mensagem `PARSING_ERROR` e `Data prefetch task interrupted` relatadas em resposta a uma solicitação de informações detalhadas, como:

```
"errorLogs" : [
  {
    "errorCode" : "PARSING_ERROR",
    "errorMessage" : "Data prefetch task interrupted: Data prefetch task for 11467 failed",
    "fileName" : "s3://amzn-s3-demo-bucket/some-source-file",
    "recordNum" : 0
  }
]
```

Se você encontrar esse erro, basta executar novamente a solicitação de upload em massa.

O erro ocorre quando há uma interrupção temporária que normalmente não foi causada por sua solicitação ou seus dados e, geralmente, ele pode ser resolvido executando a solicitação de upload em massa novamente.

Se você estiver usando as configurações padrão, ou seja, `"mode":"AUTO"` e `"failOnError":"TRUE"`, o carregador ignorará os arquivos que ele já tiver carregado com êxito e retomará o carregamento de arquivos que ainda não tinha carregado quando a interrupção ocorreu.

# Práticas recomendadas gerais para usar o Gremlin com o Neptune
<a name="best-practices-gremlin"></a>

Siga estas recomendações ao usar a linguagem de percurso de grafos Gremlin com o Neptune. Para obter informações sobre como usar o Gremlin com Neptune, consulte [Acessar o grafo do Neptune com o Gremlin](access-graph-gremlin.md).

**Importante**  
Foi feita uma alteração na TinkerPop versão 3.4.11 que melhora a exatidão de como as consultas são processadas, mas, no momento, às vezes pode afetar seriamente o desempenho das consultas.  
Por exemplo, uma consulta desse tipo pode apresentar uma lentidão significativa:  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  out()
```
Os vértices após a etapa limite agora são buscados de uma forma não ideal devido à alteração 3.4.11. TinkerPop Para evitar isso, é possível modificar a consulta adicionando a etapa barrier() a qualquer momento após `order().by()`. Por exemplo:  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  barrier().
  out()
```
TinkerPop [3.4.11 foi habilitado na versão 1.0.5.0 do motor Neptune.](engine-releases-1.0.5.0.md)

**Topics**
+ [Configuração Heartbeat para Neptune Serverless](best-practices-gremlin-heartbeat-serverless.md)
+ [Estruturar consultas de upsert para aproveitar as vantagens do mecanismo do DFE](#best-practices-gremlin-upserts)
+ [Testar o código do Gremlin no contexto em que você o implantará](best-practices-gremlin-console-glv-differences.md)
+ [Criação de gravações eficientes com multi-thread do Gremlin](best-practices-gremlin-multithreaded-writes.md)
+ [Redução de registros com o Creation Time Property](best-practices-gremlin-prune.md)
+ [Ao usar o método `datetime( )` para o Groovy Time Data](best-practices-gremlin-datetime.md)
+ [Uso da data e hora nativas para dados de data GLV](best-practices-gremlin-datetime-glv.md)

# Configuração Heartbeat para Neptune Serverless
<a name="best-practices-gremlin-heartbeat-serverless"></a>

Ao usar WebSocket clientes Gremlin com o Neptune Serverless, você precisa configurar o intervalo de ping do cliente de forma adequada para manter conexões estáveis durante eventos de escalabilidade. O cliente Gremlin usa WebSocket conexões e envia pings periódicos para verificar se a conexão está ativa. O cliente espera uma resposta do servidor dentro do intervalo de ping. Se o servidor não responder, o cliente fechará automaticamente a conexão.

**Para instâncias provisionadas pelo **Neptune**, recomendamos definir o intervalo de ping para 5 segundos.** Para clusters **Neptune Serverless**, recomendamos definir o intervalo de ping para **pelo menos 20** segundos para acomodar possíveis atrasos durante as operações de escalabilidade. Esse parâmetro controla quanto tempo o cliente espera entre as gravações no servidor antes de enviar um ping para verificar se a conexão ainda está ativa.

A configuração desse parâmetro varia de acordo com a implementação do cliente:

**Configuração do cliente Java**

Para o cliente Java TinkerPop Gremlin, configure o `keepAliveInterval` parâmetro:

```
Cluster.Builder builder = Cluster.build()
    .addContactPoint(endpoint)
    .keepAliveInterval(20000); // Configure ping interval in milliseconds
```

Para obter mais detalhes sobre a configuração do driver Java, consulte a [ TinkerPop documentação do Java](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java-configuration).

**Configuração do Go Client**

Para o cliente Gremlin Go, configure o `KeepAliveInterval` parâmetro:

```
rc, err := driver.NewDriverRemoteConnection(endpoint,
    func(settings *driver.DriverRemoteConnectionSettings) {
        settings.TraversalSource = "g"
        settings.AuthInfo = auth
        settings.KeepAliveInterval = 20 * time.Second // Configure ping interval
        ...
    })
```

Para obter mais detalhes sobre a configuração do driver Go, consulte a [ TinkerPop documentação do Go](https://tinkerpop.apache.org/docs/current/reference/#gremlin-go-configuration).

**JavaScriptConfiguração do cliente /Node.js**

Para o cliente Gremlin JavaScript /Node.js, configure o `pingInterval` parâmetro:

```
const gremlin = require('gremlin');
const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;

const connection = new DriverRemoteConnection(endpoint, {
    traversalSource: 'g',
    pingInterval: 20000  // Configure ping interval in milliseconds
});
```

Para obter mais detalhes sobre a configuração do JavaScript driver, consulte a [JavaScript TinkerPop documentação](https://tinkerpop.apache.org/docs/current/reference/#gremlin-javascript-configuration).

**Configuração do cliente Python**

Para o cliente Python Gremlin, o intervalo de ping normalmente é gerenciado na camada de transporte. Consulte a documentação específica de implementação de transporte para ver as opções de configuração:

```
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection

g = traversal().with_remote(
    DriverRemoteConnection('wss://your-neptune-endpoint:your-neptune-port/gremlin','g',
        transport_factory=lambda: AiohttpTransport(read_timeout=60,
                                                    write_timeout=20,
                                                    heartbeat=20, // Configure heartbeat
                                                    call_from_event_loop=True,
                                                    max_content_length=100*1024*1024,
                                                    ssl_options=ssl.create_default_context(Purpose.CLIENT_AUTH))))
```

[Para obter mais detalhes sobre a configuração do driver do Python, consulte a documentação do Python. TinkerPop ](https://tinkerpop.apache.org/docs/current/reference/#gremlin-python-configuration)

Essa configuração garante que seu cliente mantenha a estabilidade da conexão durante os eventos de escalabilidade do Neptune Serverless, evitando fechamentos de conexão desnecessários e melhorando a confiabilidade do aplicativo.

## Estruturar consultas de upsert para aproveitar as vantagens do mecanismo do DFE
<a name="best-practices-gremlin-upserts"></a>

[Criar surtos eficientes com as etapas `mergeV()` e `mergeE()` do Gremlin.](gremlin-efficient-upserts.md) explica como estruturar consultas de upsert para usar o mecanismo do DFE da forma mais eficaz possível.

# Testar o código do Gremlin no contexto em que você o implantará
<a name="best-practices-gremlin-console-glv-differences"></a>

No Gremlin, há várias maneiras de os clientes enviarem consultas ao servidor: usando WebSocket o Bytecode GLV ou por meio do console do Gremlin usando scripts baseados em strings.

É importante reconhecer que a execução da consulta do Gremlin pode ser diferente dependendo de como você envia a consulta. Uma consulta que gere um resultado vazio pode ser tratada como bem-sucedida se enviada no modo Bytecode, mas com falha se enviada no modo script. Por exemplo, se você incluir `next()` em uma consulta no modo script, ela será enviada para `next()` o servidor, mas o uso do cliente geralmente ByteCode processa a consulta por si só. `next()` No primeiro caso, a consulta falhará se nenhum resultado for encontrado, mas no segundo, a consulta será bem-sucedida independentemente de o conjunto de resultados estar vazio ou não.

Se você desenvolver e testar o código em um contexto (por exemplo, o console do Gremlin, que geralmente envia consultas em formato de texto), mas depois implanta o código em um contexto diferente (por exemplo, por meio do driver do Java usando Bytecode), você pode ter problemas com o código apresentando comportamentos diferentes na produção e no ambiente de desenvolvimento.

**Importante**  
Teste o código do Gremlin no contexto do GLV em que ele será implantado, para evitar resultados inesperados.

# Criação de gravações eficientes com multi-thread do Gremlin
<a name="best-practices-gremlin-multithreaded-writes"></a>

Há algumas diretrizes para carregamento de dados com multi-thread para o Neptune usando o Gremlin.

Se possível, atribua a cada thread um conjunto de vértices ou bordas a serem inseridos ou modificados que não colidam. Por exemplo, o thread abrange o intervalo de IDs de 1 a 50.000, o thread 2 abrange o intervalo de IDs de 50.001 a 100.000, etc. Isso reduz a chance de atingir uma `ConcurrentModificationException`. Para melhor segurança, coloque um bloco `try/catch` em torno de todas as gravações. Se ocorrer uma falha em qualquer uma delas, você poderá repeti-las depois de um breve atraso.

O agrupamento de gravações em lotes de 50 a 100 (vértices ou bordas) geralmente funciona bem. Se você tiver uma grande quantidade de propriedades sendo adicionadas para cada vértice, um número mais próximo de 50 do que de 100 poderá ser a melhor opção. Alguma experimentação é útil. Portanto, para gravações em lote, você pode usar algo como o seguinte:

```
g.addV(‘test’).property(id,’1’).as(‘a’).
  addV(‘test’).property(id,’2’).
  addE(‘friend’).to(‘a’).
```

Isso é, então, repetido em cada operação em lote.

O uso de lotes é significativamente mais eficiente do que a adição de um vértice ou borda por Gremlin de ida e volta para o servidor.

Se você estiver usando um cliente de Variante da linguagem Gremlin (GLV), crie um lote de forma programática primeiro criando uma travessia. Em seguida, adicione a ele e, por fim, itere sobre ele; por exemplo:

```
  t.addV(‘test’).property(id,’1’).as(‘a’)
  t.addV(‘test’).property(id,’2’)
  t.addE(‘friend’).to(‘a’)
  t.iterate()
```

É melhor usar o cliente da variante de linguagem do Gremlin, se possível. No entanto, você pode fazer algo parecido com um cliente que envia consultas como strings de texto concatenando as strings para criar um lote.

Se você estiver usando uma das bibliotecas do cliente de Gremlin em vez de HTTP básico para consultas, os threads deverão compartilhar o mesmo cliente, cluster ou grupo de conexões. Pode ser necessário ajustar as configurações para obter o melhor throughput possível, configurações como o tamanho do grupo de conexões e o número de threads de operador que o cliente do Gremlin usa.

# Redução de registros com o Creation Time Property
<a name="best-practices-gremlin-prune"></a>

É possível remover os registros de tabela ao armazenar a hora de criação como uma propriedade em vértices e removê-los periodicamente.

Caso precise armazenar dados para uma vida útil específica e então removê-la do gráfico (tempo de vida do vértice), você pode armazenar uma propriedade time stamp na criação do vértice. Em seguida, você pode periodicamente emitir uma consulta do `drop()` para todos os vértices que foram criados antes de um certo período, por exemplo:

```
g.V().has(“timestamp”, lt(datetime('2018-10-11')))
```

# Ao usar o método `datetime( )` para o Groovy Time Data
<a name="best-practices-gremlin-datetime"></a>

O Neptune oferece o método `datetime` para especificar datas e horas para consultas enviadas na variante Gremlin **Groovy**. Isso inclui o Gremlin Console, strings de texto usando a API REST HTTP, e qualquer outra serialização que usa o Groovy. 

**Importante**  
Isso se aplica *somente* a métodos onde você envia a consulta Gremlin como uma *string de texto*. Se você estiver usando uma Variante da Linguagem Gremlin, deverá usar as classes e funções de data nativa para o idioma. Para obter mais informações, consulte a próxima sessão, [Uso da data e hora nativas para dados de data GLV](best-practices-gremlin-datetime-glv.md).  
Começar com TinkerPop `3.5.2` (introduzido na [versão 1.1.1.0 do motor Neptune](engine-releases-1.1.1.0.md)) `datetime` é parte integrante do. TinkerPop

Você pode usar o método do `datetime` para armazenar e comparar datas:

```
g.V('3').property('date',datetime('2001-02-08'))
```

```
g.V().has('date',gt(datetime('2000-01-01')))
```

# Uso da data e hora nativas para dados de data GLV
<a name="best-practices-gremlin-datetime-glv"></a>

Se estiver usando uma Variante da Linguagem Gremlin (GLV, Gremlin Language Variant), você deve usar as classes e funções de data e hora nativas fornecidas pela linguagem de programação para dados de tempo do Gremlin.

As TinkerPop bibliotecas oficiais são todas bibliotecas Gremlin Language Variant.
+  [Go](https://tinkerpop.apache.org/docs/current/reference/#gremlin-go) 
+  [Java](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java) 
+  [Javascript](https://tinkerpop.apache.org/docs/current/reference/#gremlin-javascript) 
+  [.NET](https://tinkerpop.apache.org/docs/current/reference/#gremlin-dotnet) 
+  [Python](https://tinkerpop.apache.org/docs/current/reference/#gremlin-python) 

**Importante**  
 Esta página se aplica somente às bibliotecas de Variante da Linguagem Gremlin (GLV). Se estiver usando um método para enviar a consulta do Gremlin como sequência de texto, você deve usar a função datetime() do Gremlin. Isso inclui o console do Gremlin, sequências de texto usando a API REST HTTP ou envio direto de sequências de caracteres Gremlin por meio dos drivers. 



**Go**  
 Veja a seguir um exemplo parcial no Go que cria uma propriedade única chamada “date” para o vértice com um ID de “3”. Isso define o valor para ser uma data gerada usando a função Go. time.Now(). 

```
import ( "time" )

g.V('3').property('date', time.Now()).next();
```

Para ver um exemplo completo de conexão com o Neptune usando Go, consulte [Usar um cliente Go para se conectar a uma instância de banco de dados do Neptune](https://docs.aws.amazon.com//neptune/latest/userguide/access-graph-gremlin-go.html).

**Java**  
Veja a seguir um exemplo parcial em Java que cria uma propriedade única chamada '`date`' para o vértice com um ID do '`3`'. Isso define o valor a ser uma data gerada usando o construtor do `Date()` Java.

```
import java.util.date

g.V('3').property('date', new Date()).next();
```

Para ver um exemplo completo de como se conectar ao Neptune usando Java, consulte [Usar o cliente do Java para conectar-se a uma instância de banco de dados do Neptune](access-graph-gremlin-java.md).

**Node.js (JavaScript)**  
A seguir está um exemplo parcial em JavaScript que cria uma única propriedade chamada '`date`' para o vértice com um ID de '`3`'. Isso define o valor a ser uma data gerada usando o construtor do `Date()` Node.js.

```
g.V('3').property('date', new Date()).next()
```

Para ver um exemplo completo de como se conectar ao Neptune usando Node.js, consulte [Usar o Node.js para conectar-se a uma instância de banco de dados do Neptune](access-graph-gremlin-node-js.md).

**.NET (C\$1)**  
Veja a seguir um exemplo parcial em C\$1 que cria uma propriedade única chamada '`date`' para o vértice com um ID do '`3`'. Isso define o valor a ser uma data gerada usando a propriedade do `DateTime.UtcNow` .NET.

```
Using System;

g.V('3').property('date', DateTime.UtcNow).next()
```

Para ver um exemplo completo de como se conectar ao Neptune usando C\$1, consulte [Usar .NET para conectar-se a uma instância de banco de dados do Neptune](access-graph-gremlin-dotnet.md).

**Python**  
Veja a seguir um exemplo parcial em Python que cria uma propriedade única chamada '`date`' para o vértice com um ID do '`3`'. Isso define o valor a ser uma data gerada usando o método do `datetime.now()` Python.

```
import datetime

g.V('3').property('date',datetime.datetime.now()).next()
```

Para ver um exemplo completo de como se conectar ao Neptune usando Python, consulte [Usar o Python para conectar-se a uma instância de banco de dados do Neptune](access-graph-gremlin-python.md).

# Práticas recomendadas para usar o cliente Java do Gremlin com o Neptune
<a name="best-practices-gremlin-java-client"></a>

Siga essas recomendações ao usar o cliente Gremlin Java com o Neptune. Essas melhores práticas ajudam você a otimizar o desempenho, gerenciar conexões de forma eficaz e evitar armadilhas comuns ao trabalhar com o driver Java.

Para obter informações sobre como configurar intervalos de pulsação para o Neptune Serverless, consulte. [Configuração Heartbeat para Neptune Serverless](best-practices-gremlin-heartbeat-serverless.md)

**Topics**
+ [Reutilizar o objeto de cliente entre vários threads](best-practices-gremlin-java-reuse.md)
+ [Criar objetos separados do cliente Java do Gremlin para endpoints de leitura e gravação](best-practices-gremlin-java-separate.md)
+ [Adicionar vários endpoints de réplica de leitura a um grupo conexão Java do Gremlin](best-practices-gremlin-java-multiple.md)
+ [Fechar o cliente para evitar o limite de conexões](best-practices-gremlin-java-close-connections.md)
+ [Criar uma conexão após o failover](best-practices-gremlin-java-new-connection.md)
+ [Definir `maxInProcessPerConnection` e `maxSimultaneousUsagePerConnection` como o mesmo valor](best-practices-gremlin-java-maxes.md)
+ [Enviar consultas ao servidor como bytecode em vez de strings](best-practices-gremlin-java-bytecode.md)
+ [Sempre consuma completamente o ResultSet ou Iterator retornado por uma consulta](best-practices-gremlin-java-resultset.md)
+ [Adicionar em massa vértices e bordas em lotes](best-practices-gremlin-java-batch-add.md)
+ [Desativar o armazenamento em cache DNS no Java Virtual Machine](best-practices-gremlin-java-disable-dns-caching.md)
+ [Opcionalmente, definir tempos limite em um nível por consulta](best-practices-gremlin-java-per-query-timeout.md)
+ [Solução de problemas do `java.util.concurrent.TimeoutException`](best-practices-gremlin-java-exceptions-TimeoutException.md)

# Reutilizar o objeto de cliente entre vários threads
<a name="best-practices-gremlin-java-reuse"></a>

Reutilize o mesmo objeto de cliente (ou `GraphTraversalSource`) em vários threads. Ou seja, crie uma instância compartilhada de uma classe `org.apache.tinkerpop.gremlin.driver.Client` em seu aplicativo, em vez de fazê-lo em cada thread. O objeto `Client` é seguro para threads, e a sobrecarga de inicializá-lo é considerável.

Isso também se aplica a `GraphTraversalSource`, que cria um objeto `Client` internamente. Por exemplo, o código a seguir cria um novo objeto `Client` a ser instanciado:

```
import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal; 

  /////

GraphTraversalSource traversal = traversal()
                                   .withRemote(DriverRemoteConnection.using(cluster));
```

# Criar objetos separados do cliente Java do Gremlin para endpoints de leitura e gravação
<a name="best-practices-gremlin-java-separate"></a>

É possível aumentar o desempenho ao executar somente gravações no endpoint de gravação e leitura em um ou mais endpoints somente leitura.

```
Client readerClient = Cluster.build("https://reader-endpoint")
          ...
          .connect()

Client writerClient = Cluster.build("https://writer-endpoint")
          ...
          .connect()
```

# Adicionar vários endpoints de réplica de leitura a um grupo conexão Java do Gremlin
<a name="best-practices-gremlin-java-multiple"></a>

Ao criar um objeto `Cluster` do Gremlin Java, você pode usar o método `.addContactPoint()` para adicionar várias instâncias de réplica de leitura aos pontos de contato do grupo de conexão.

```
Cluster.Builder readerBuilder = Cluster.build()
          .port(8182)
          .minConnectionPoolSize(…)
          .maxConnectionPoolSize(…)
          ………
          .addContactPoint("reader-endpoint-1")
          .addContactPoint("reader-endpoint-2")
```

# Fechar o cliente para evitar o limite de conexões
<a name="best-practices-gremlin-java-close-connections"></a>

É importante fechar o cliente quando terminar de usá-lo para garantir que as WebSocket conexões sejam fechadas pelo servidor e que todos os recursos associados às conexões sejam liberados. Isso ocorrerá automaticamente se você fechar o cluster usando `Cluster.close( )`, porque `client.close( )` depois será chamado internamente.

Se o cliente não estiver fechado corretamente, o Neptune encerrará todas as conexões WebSocket ociosas após 20 a 25 minutos. No entanto, se você não fechar explicitamente WebSocket as conexões ao terminar de usá-las e o número de conexões ativas atingir o [limite de conexões WebSocket simultâneas](limits.md#limits-websockets), conexões adicionais serão recusadas com um código de `429` erro HTTP. Nesse ponto, você deve reiniciar a instância do Neptune para fechar as conexões.

A orientação de chamar `cluster.close()` não se aplica às funções Java do AWS Lambda . Para obter mais detalhes, consulte [Gerenciar conexões do WebSocket do Gremlin em funções do AWS Lambda](lambda-functions-websocket-connections.md).

# Criar uma conexão após o failover
<a name="best-practices-gremlin-java-new-connection"></a>

No caso de failover, o Gremlin Driver pode continuar a se conectar ao gravador antigo porque o nome do DNS do cluster foi resolvido para um endereço IP. Se isso acontecer, crie um novo objeto `Client` após o failover.

# Definir `maxInProcessPerConnection` e `maxSimultaneousUsagePerConnection` como o mesmo valor
<a name="best-practices-gremlin-java-maxes"></a>

Tanto os parâmetros `maxInProcessPerConnection` quanto os `maxSimultaneousUsagePerConnection` parâmetros estão relacionados ao número máximo de consultas simultâneas que você pode enviar em uma única WebSocket conexão. Internamente, esses parâmetros são correlacionados, e a modificação de um deles sem o outro pode fazer com que um cliente receba um tempo limite ao tentar obter uma conexão do grupo de conexões do cliente.

Recomendamos manter os valores em andamento e de uso simultâneo mínimos padrão e definir `maxInProcessPerConnection` e `maxSimultaneousUsagePerConnection` como o mesmo valor.

O valor para definir esses parâmetros é uma função de complexidade de consulta e o modelo de dados. Um caso de uso em que a consulta retorna uma grande quantidade de dados exigiria mais largura de banda de conexão por consulta e, portanto, deve ter valores inferiores para os parâmetros e um valor mais alto para `maxConnectionPoolSize`.

Por outro lado, em um caso em que a consulta retorna uma menor quantidade de dados, `maxInProcessPerConnection` e `maxSimultaneousUsagePerConnection` devem ser definidos como um valor maior que `maxConnectionPoolSize`.

# Enviar consultas ao servidor como bytecode em vez de strings
<a name="best-practices-gremlin-java-bytecode"></a>

Há vantagens de usar bytecode em vez de string ao enviar consultas:
+ **Obter a sintaxe de consulta inválida com antecedência: ** o uso da variante de bytecode permite detectar sintaxe de consulta inválida na fase de compilação. Se você usar a variação com base em string, só detectará a sintaxe inválida quando a consulta for enviada ao servidor e um erro for gerado.
+ **Evite penalidades de desempenho com base em strings:** [qualquer envio de consulta com base em string, seja usando WebSockets HTTP, resulta em um vértice separado, o que implica que o objeto Vertex consiste no ID, no rótulo e em todas as propriedades associadas ao vértice (consulte Propriedades dos elementos).](http://tinkerpop.apache.org/docs/current/reference/#_properties_of_elements)

  Isso pode ocasionar computação desnecessária no servidor em casos em que as propriedades não são necessárias. Por exemplo, se o cliente estiver interessado em obter o vértice com o ID "hakuna\$11" usando a consulta, `g.V("hakuna#1")`. Se a consulta for enviada como um envio baseado em string, o servidor poderá gastar tempo recuperando o ID, o rótulo e todas as propriedades para esse vértice. Se a consulta for enviada como um envio de bytecode, o servidor apenas gastará tempo recuperando o ID e o rótulo do vértice.

Em outras palavras, em vez de enviar uma consulta da seguinte maneira:

```
  final Cluster cluster = Cluster.build("localhost")
                                 .port(8182)
                                 .maxInProcessPerConnection(32)
                                 .maxSimultaneousUsagePerConnection(32)
                                 .serializer(Serializers.GRAPHBINARY_V1D0)
                                 .create();

  try {
      final Client client = cluster.connect();
      List<Result> results = client.submit("g.V().has('name','pumba').out('friendOf').id()").all().get();
      System.out.println(verticesWithNamePumba);
  } finally {
      cluster.close();
  }
```

Em vez disso, envie a consulta usando bytecode, como:

```
  final Cluster cluster = Cluster.build("localhost")
                                 .port(8182)
                                 .maxInProcessPerConnection(32)
                                 .maxSimultaneousUsagePerConnection(32)
                                 .serializer(Serializers.GRAPHBINARY_V1D0)
                                 .create();

  try {
      final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
      List<Object> verticesWithNamePumba = g.V().has("name", "pumba").out("friendOf").id().toList();
      System.out.println(verticesWithNamePumba);
  } finally {
      cluster.close();
  }
```

# Sempre consuma completamente o ResultSet ou Iterator retornado por uma consulta
<a name="best-practices-gremlin-java-resultset"></a>

O objeto de cliente sempre deve consumir completamente o `ResultSet` (no caso de envio com base em string) ou o iterador retornado por `GraphTraversal`. Se os resultados da consulta não forem completamente consumidos, o servidor os manterá, aguardando o cliente terminar de consumi-los.

Se o seu aplicativo precisar apenas de um conjunto parcial de resultados, use uma etapa `limit(X)` com sua consulta para restringir o número de resultados que o servidor gera.

# Adicionar em massa vértices e bordas em lotes
<a name="best-practices-gremlin-java-batch-add"></a>

Cada consulta ao banco de dados do Neptune é executada no escopo de uma única transação, a menos que você use uma sessão. Isso significa que, se você precisa inserir uma grande quantidade de dados usando consultas do gremlin, agrupá-los em um lote de 50-100 melhora o desempenho reduzindo o número de transações criadas para a carga.

Por exemplo, a inclusão de 5 vértices ao banco de dados teria a seguinte aparência:

```
// Create a GraphTraversalSource for the remote connection
final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
// Add 5 vertices in a single query
g.addV("Person").property(T.id, "P1")
 .addV("Person").property(T.id, "P2")
 .addV("Person").property(T.id, "P3")
 .addV("Person").property(T.id, "P4")
 .addV("Person").property(T.id, "P5").iterate();
```

Da mesma forma, você pode adicionar bordas em lote usando. `addE` Use `V()` para referenciar os vértices existentes como a origem e o destino de cada aresta:

```
// Add edges in a single batched query
g.V("P1").addE("knows").to(V("P2"))
 .V("P2").addE("knows").to(V("P3"))
 .V("P3").addE("knows").to(V("P4"))
 .V("P4").addE("knows").to(V("P5")).iterate();
```

Você também pode combinar a criação de vértices e bordas em um único lote. Use `as()` para rotular vértices recém-criados para que você possa referenciá-los ao adicionar bordas na mesma travessia:

```
// Add vertices and edges together in a single query
g.addV("Person").property(T.id, "P1").as("p1")
 .addV("Person").property(T.id, "P2").as("p2")
 .addV("Person").property(T.id, "P3").as("p3")
 .addE("knows").from("p1").to("p2")
 .addE("knows").from("p2").to("p3").iterate();
```

# Desativar o armazenamento em cache DNS no Java Virtual Machine
<a name="best-practices-gremlin-java-disable-dns-caching"></a>

[Em um ambiente em que você deseja balancear a carga de solicitações em várias réplicas de leitura, você precisa desabilitar o cache de DNS na Java Virtual Machine (JVM) e fornecer o endpoint de leitura do Neptune ao criar o objeto Cluster.](https://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/driver/Cluster.html) Desabilitar o cache DNS do JVM garante que o DNS seja resolvido novamente para cada nova conexão, de maneira que as solicitações sejam distribuídas em todas as réplicas de leitura. É possível fazer isso no código de inicialização da aplicação com a seguinte linha:

```
java.security.Security.setProperty("networkaddress.cache.ttl", "0");
```

No entanto, uma solução mais completa e robusta para balanceamento de carga é fornecida pelo código do cliente [Amazon Gremlin](https://github.com/awslabs/amazon-neptune-tools/tree/master/neptune-gremlin-client) Java on. GitHub O cliente Java do Amazon Gremlin está ciente da topologia do cluster e distribui de forma justa as conexões e solicitações em um conjunto de instâncias no cluster do Neptune. Consulte [esta postagem no blog](https://aws.amazon.com/blogs/database/load-balance-graph-queries-using-the-amazon-neptune-gremlin-client/) para ver um exemplo da função do Lambda em Java que usa esse cliente.

# Opcionalmente, definir tempos limite em um nível por consulta
<a name="best-practices-gremlin-java-per-query-timeout"></a>

O Neptune oferece a capacidade de definir um tempo limite para suas consultas usando a opção de grupo de parâmetros `neptune_query_timeout` (consulte [Parâmetros](parameters.md)). Você também pode substituir o tempo limite global com um código como este:

```
  final Cluster cluster = Cluster.build("localhost")
                                 .port(8182)
                                 .maxInProcessPerConnection(32)
                                 .maxSimultaneousUsagePerConnection(32)
                                 .serializer(Serializers.GRAPHBINARY_V1D0)
                                 .create();

  try {
      final GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
      List<Object> verticesWithNamePumba = g.with(ARGS_EVAL_TIMEOUT, 500L).V().has("name", "pumba").out("friendOf").id().toList();
      System.out.println(verticesWithNamePumba);
  } finally {
      cluster.close();
  }
```

Ou, para envio de consulta baseada em string, o código teria a seguinte aparência:

```
  RequestOptions options = RequestOptions.build().timeout(500).create();
  List<Result> result = client.submit("g.V()", options).all().get();
```

**nota**  
Você poderá gerar custos inesperados se definir um valor de tempo limite de consulta muito alto, especialmente em uma instância sem servidor. Sem uma configuração de tempo limite razoável, a consulta poderá continuar sendo executada por muito mais tempo do que o esperado, gerando custos jamais previstos. Esse é particularmente o caso em uma instância sem servidor cuja escala pode ser aumentada verticalmente para um tipo de instância grande e caro durante a execução da consulta.  
É possível evitar despesas inesperadas desse tipo usando um valor de tempo limite de consulta que acomode o tempo de execução esperado e ocasione apenas um tempo limite de execução excepcionalmente longo.  
 A partir da versão 1.3.2.0 do mecanismo do Neptune, o Neptune oferece suporte a um novo parâmetro neptune\$1lab\$1mode como `StrictTimeoutValidation`. Quando este parâmetro tem um valor de `Enabled`, um valor de tempo limite por consulta especificado como uma opção de solicitação ou uma dica de consulta não pode exceder o valor definido globalmente no grupo de parâmetros. Nesse caso, o Neptune lançará `InvalidParameterException`.   
 Essa configuração pode ser confirmada em uma resposta no endpoint '/status' quando o valor for. `Disabled` Na versão do mecanismo`1.3.2.0`, o valor padrão desse parâmetro é`Disabled`. A partir da versão do motor`1.4.0.0`, o `StrictTimeoutValidation` parâmetro é `Enabled` por padrão.   
 Para obter mais informações sobre como a precedência de tempo limite é determinada quando várias configurações de tempo limite são definidas, consulte a documentação do parâmetro [neptune\$1query\$1timeout](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout). 

# Solução de problemas do `java.util.concurrent.TimeoutException`
<a name="best-practices-gremlin-java-exceptions-TimeoutException"></a>

O cliente Gremlin Java lança um `java.util.concurrent.TimeoutException` quando uma solicitação do Gremlin expira no próprio cliente enquanto espera que um slot em uma das WebSocket conexões fique disponível. Essa duração do tempo limite é controlada pelo parâmetro configurável `maxWaitForConnection` do lado do cliente.

**nota**  
Como as solicitações que atingem o tempo limite no cliente nunca são enviadas ao servidor, elas não são refletidas em nenhuma das métricas capturadas no servidor, como `GremlinRequestsPerSec`.

Esse tipo de tempo limite geralmente é causado de duas maneiras:
+ **Na verdade, o servidor atingiu a capacidade máxima.** Se for esse o caso, a fila no servidor é preenchida, o que você pode detectar monitorando a [MainRequestQueuePendingRequests](cw-metrics.md#cw-metrics-available) CloudWatch métrica. O número de consultas paralelas que o servidor pode processar depende do tamanho da instância.

  Se a métrica `MainRequestQueuePendingRequests` não mostrar um acúmulo de solicitações pendentes no servidor, o servidor poderá lidar com mais solicitações e o tempo limite será causado pelo controle de utilização do lado do cliente.
+ **Controle de utilização de solicitações pelo cliente.** Geralmente, isso pode ser corrigido alterando as configurações do cliente.

  O número máximo de solicitações paralelas que o cliente pode enviar pode ser estimado aproximadamente da seguinte forma:

  ```
  maxParallelQueries = maxConnectionPoolSize * Max( maxSimultaneousUsagePerConnection, maxInProcessPerConnection )
  ```

  Enviar mais do que `maxParallelQueries` ao cliente causa exceções `java.util.concurrent.TimeoutException`. Geralmente, é possível corrigir isso de várias maneiras:
  + *Aumente a duração do tempo limite da conexão.* Se a latência não for essencial para a aplicação, aumente a configuração `maxWaitForConnection` do cliente. O cliente então espera mais antes de atingir o tempo limite o que, por sua vez, pode aumentar a latência.
  + *Aumente o máximo de solicitações por conexão.* Isso permite que mais solicitações sejam enviadas usando a mesma WebSocket conexão. Faça isso aumentando as configurações `maxSimultaneousUsagePerConnection` e `maxInProcessPerConnection` do cliente. Essas configurações geralmente devem ter o mesmo valor. 
  + *Aumente o número de conexões no grupo de conexões.* Faça isso aumentando a configuração `maxConnectionPoolSize` do cliente. O custo é o aumento do consumo de recursos, porque cada conexão usa memória e um descritor de arquivo do sistema operacional e exige um SSL e um handshake durante a inicialização. WebSocket

# Práticas recomendadas para o Neptune ao usar openCypher e Bolt
<a name="best-practices-opencypher"></a>

Siga estas práticas recomendadas ao usar a linguagem de consulta openCypher e o protocolo Bolt com Neptune. Para obter informações sobre como usar o openCypher no Neptune, consulte [Acessar o grafo do Neptune com o openCypher](access-graph-opencypher.md).

**Topics**
+ [Criar uma conexão após o failover](#best-practices-opencypher-renew-connection)
+ [Tratamento de conexões para aplicações de longa duração](#best-practices-opencypher-long-connections)
+ [Manipulação de conexão para AWS Lambda](#best-practices-opencypher-lambda-connections)
+ [Preferir direcionar para bordas bidirecionais nas consultas](best-practices-opencypher-directed-edges.md)
+ [O Neptune não é compatível com várias consultas simultâneas em uma transação.](best-practices-opencypher-multiple-queries.md)
+ [Fechar objetos de driver ao concluir](best-practices-opencypher-close-driver.md)
+ [Usar modos de transação explícitos para leitura e gravação](best-practices-opencypher-use-explicit-txs.md)
+ [Lógica de novas tentativas para exceções](best-practices-opencypher-retry-logic.md)
+ [Definir várias propriedades de uma vez usando uma única cláusula SET](best-practices-content-0.md)
+ [Usar consultas parametrizadas](best-practices-content-2.md)
+ [Use mapas nivelados em vez de mapas aninhados na cláusula UNWIND](best-practices-content-3.md)
+ [Coloque nós mais restritivos no lado esquerdo em expressões de caminho de comprimento variável (VLP)](best-practices-content-4.md)
+ [Evitar verificações redundantes de rótulos de nó usando nomes de relacionamento granulares](best-practices-content-5.md)
+ [Especificar rótulos de borda sempre que possível](best-practices-content-6.md)
+ [Evitar usar a cláusula WITH quando possível](best-practices-content-7.md)
+ [Colocar filtros restritivos o mais cedo possível na consulta](best-practices-content-8.md)
+ [Verificar explicitamente se as propriedades existem](best-practices-content-9.md)
+ [Não usar o caminho nomeado (a menos que seja necessário)](best-practices-content-10.md)
+ [Evitar COLLECT(DISTINCT())](best-practices-content-11.md)
+ [Optar pela função de propriedades em vez da pesquisa de propriedades individuais ao recuperar todos os valores da propriedade](best-practices-content-12.md)
+ [Executar cálculos estáticos fora da consulta](best-practices-content-13.md)
+ [Agrupar entradas usando UNWIND em vez de declarações individuais](best-practices-content-14.md)
+ [Prefiro usar o personalizado IDs para nó/relacionamento](best-practices-content-15.md)
+ [Evitar fazer cálculos de \$1id na consulta](best-practices-content-16.md)
+ [Atualizar/mesclar vários nós](best-practices-merge-multiple-nodes.md)

## Criar uma conexão após o failover
<a name="best-practices-opencypher-renew-connection"></a>

No caso de um failover, o driver do Bolt pode continuar se conectando à instância de gravador antiga e não à nova instância ativa, porque o nome do DNS foi resolvido para um endereço IP específico.

Para evitar isso, feche e reconecte o objeto `Driver` após qualquer failover.

## Tratamento de conexões para aplicações de longa duração
<a name="best-practices-opencypher-long-connections"></a>

Ao criar aplicações de longa duração, como aqueles executados em contêineres ou em instâncias do Amazon EC2, instancie um objeto `Driver` uma vez e, depois, reutilize esse objeto durante toda a vida útil da aplicação. O objeto `Driver` é seguro para threads, e a sobrecarga de inicializá-lo é considerável.

## Manipulação de conexão para AWS Lambda
<a name="best-practices-opencypher-lambda-connections"></a>

Os drivers de parafuso não são recomendados para uso em AWS Lambda funções, devido à sobrecarga de conexão e aos requisitos de gerenciamento. Em vez disso, use o [endpoint HTTPS](access-graph-opencypher-queries.md).

# Preferir direcionar para bordas bidirecionais nas consultas
<a name="best-practices-opencypher-directed-edges"></a>

Quando o Neptune realiza otimizações de consulta, as bordas bidirecionais dificultam a criação de planos de consulta ideais. Planos abaixo do ideal exigem que o mecanismo faça um trabalho desnecessário e ocasionam degradação do desempenho.

Portanto, use bordas direcionadas em vez de bidirecionais sempre que possível. Por exemplo, use:

```
MATCH p=(:airport {code: 'ANC'})-[:route]->(d) RETURN p)
```

em vez de:

```
MATCH p=(:airport {code: 'ANC'})-[:route]-(d) RETURN p)
```

Na verdade, a maioria dos modelos de dados não precisa percorrer bordas nas duas direções, portanto, as consultas podem obter melhorias significativas no desempenho ao passar a usar bordas direcionadas.

Se o modelo de dados exigir percurso por bordas bidirecionais, faça do primeiro nó (lado esquerdo) no padrão `MATCH` o nó com a filtragem mais restritiva.

Veja o exemplo: “Encontre-me em todas as `routes` para e do aeroporto `ANC`”. Escreva essa consulta para começar no aeroporto `ANC`, da seguinte forma:

```
MATCH p=(src:airport {code: 'ANC'})-[:route]-(d) RETURN p
```

O mecanismo pode realizar a quantidade mínima de trabalho para atender à consulta, porque o nó mais restrito é colocado como o primeiro nó (lado esquerdo) no padrão. O mecanismo pode então otimizar a consulta.

Essa é de longe a opção preferencial em comparação a filtrar o aeroporto `ANC` no final do padrão, desta forma:

```
MATCH p=(d)-[:route]-(src:airport {code: 'ANC'}) RETURN p
```

Quando o nó mais restrito não é colocado primeiro no padrão, o mecanismo precisa realizar um trabalho adicional porque não pode otimizar a consulta e precisa realizar pesquisas adicionais para chegar aos resultados.

# O Neptune não é compatível com várias consultas simultâneas em uma transação.
<a name="best-practices-opencypher-multiple-queries"></a>

Embora o próprio driver do Bolt permita consultas simultâneas em uma transação, o Neptune não é compatível com várias consultas em uma transação executada simultaneamente. Em vez disso, o Neptune exige que várias consultas em uma transação sejam executadas sequencialmente e que os resultados de cada consulta sejam completamente consumidos antes que a próxima consulta seja iniciada.

O exemplo abaixo mostra como usar o Bolt para executar várias consultas sequencialmente em uma transação, para que os resultados de cada uma sejam completamente consumidos antes do início da próxima:

```
final String query = "MATCH (n) RETURN n";

try (Driver driver = getDriver(HOST_BOLT, getDefaultConfig())) {
  try (Session session = driver.session(readSessionConfig)) {
    try (Transaction trx = session.beginTransaction()) {
      final Result res_1 = trx.run(query);
      Assert.assertEquals(10000, res_1.list().size());
      final Result res_2 = trx.run(query);
      Assert.assertEquals(10000, res_2.list().size());
    }
  }
}
```

# Fechar objetos de driver ao concluir
<a name="best-practices-opencypher-close-driver"></a>

Feche o cliente quando terminar de usá-lo, para que as conexões do Bolt sejam encerradas pelo servidor e todos os recursos associados à conexão sejam liberados. Isso acontecerá automaticamente se você fechar o driver usando `driver.close()`.

Se o driver não for fechado corretamente, o Neptune encerrará todas as conexões inativas do Bolt após vinte minutos ou após dez dias se você estiver usando a autenticação do IAM.

O Neptune não é compatível mais de mil conexões simultâneas do Bolt. Se você não fechar explicitamente as conexões ao terminar de usá-las e o número de conexões ativas atingir o limite de mil, qualquer nova tentativa de conexão falhará.

# Usar modos de transação explícitos para leitura e gravação
<a name="best-practices-opencypher-use-explicit-txs"></a>

Ao usar transações com o Neptune e o driver do Bolt, é melhor definir explicitamente o modo de acesso para transações de leitura e gravação como as configurações corretas.

## Transações somente leitura
<a name="best-practices-opencypher-read-txs"></a>

Para transações somente leitura, se você não transmitir a configuração apropriada do modo de acesso ao criar a sessão, o nível de isolamento padrão será usado, que é o isolamento da consulta de mutação. Como resultado, para as transações somente leitura, é importante definir o modo de acesso como `read` explicitamente.

**Exemplo de transação de leitura de confirmação automática:**

```
SessionConfig sessionConfig = SessionConfig
  .builder()
  .withFetchSize(1000)
  .withDefaultAccessMode(AccessMode.READ)
  .build();
Session session = driver.session(sessionConfig);
try {
  (Add your application code here)
} catch (final Exception e) {
  throw e;
} finally {
  driver.close()
}
```

**Leia o exemplo de transação:**

```
Driver driver = GraphDatabase.driver(url, auth, config);
SessionConfig sessionConfig = SessionConfig
  .builder()
  .withDefaultAccessMode(AccessMode.READ)
  .build();
driver.session(sessionConfig).readTransaction(
  new TransactionWork<List<String>>() {
    @Override
    public List<String> execute(org.neo4j.driver.Transaction tx) {
      (Add your application code here)
    }
  }
);
```

Nos dois casos, o [isolamento de `SNAPSHOT`](transactions-isolation-levels.md) é obtido usando a [semântica de transação somente leitura do Neptune](transactions-neptune.md#transactions-neptune-read-only).

Como as réplicas de leitura só aceitam consultas somente leitura, qualquer consulta enviada a uma réplica de leitura é executada sob a semântica de isolamento `SNAPSHOT`.

Não há leituras sujas ou não repetíveis para transações somente leitura.

## Transações de mutação
<a name="best-practices-opencypher-mutation-txs"></a>

Para consultas de mutação, há três mecanismos diferentes para criar uma transação de gravação, cada um dos quais é ilustrado abaixo:

**Exemplo de transação de gravação implícita:**

```
Driver driver = GraphDatabase.driver(url, auth, config);
SessionConfig sessionConfig = SessionConfig
  .builder()
  .withDefaultAccessMode(AccessMode.WRITE)
  .build();
driver.session(sessionConfig).writeTransaction(
  new TransactionWork<List<String>>() {
    @Override
    public List<String> execute(org.neo4j.driver.Transaction tx) {
      (Add your application code here)
    }
  }
);
```

**Exemplo de transação de gravação de confirmação automática:**

```
SessionConfig sessionConfig = SessionConfig
  .builder()
  .withFetchSize(1000)
  .withDefaultAccessMode(AccessMode.Write)
  .build();
Session session = driver.session(sessionConfig);
try {
  (Add your application code here)
} catch (final Exception e) {
    throw e;
} finally {
    driver.close()
}
```

**Exemplo de transação de gravação explícita:**

```
Driver driver = GraphDatabase.driver(url, auth, config);
SessionConfig sessionConfig = SessionConfig
  .builder()
  .withFetchSize(1000)
  .withDefaultAccessMode(AccessMode.WRITE)
  .build();
Transaction beginWriteTransaction = driver.session(sessionConfig).beginTransaction();
  (Add your application code here)
beginWriteTransaction.commit();
driver.close();
```

**Níveis de isolamento para transações de gravação**
+ As leituras feitas como parte das consultas de mutação são executadas sob isolamento de transações `READ COMMITTED`.
+ Não há leituras sujas para leituras feitas como parte de consultas de mutação.
+ Registros e intervalos de registros são bloqueados durante a leitura de uma consulta de mutação.
+ Quando um intervalo do índice tiver sido lido por uma transação de mutação, há uma forte garantia de que esse intervalo não será modificado por nenhuma transação simultânea até o final da transação de leitura.

As consultas de mutação não são livres de threads.

Sobre conflitos, consulte [Resolução de conflitos usando tempos limite de espera de bloqueio](transactions-neptune.md#transactions-neptune-conflicts).

Em caso de falha, as consultas de mutação não são repetidas automaticamente.

# Lógica de novas tentativas para exceções
<a name="best-practices-opencypher-retry-logic"></a>

Para todas as exceções que permitem uma nova tentativa, geralmente é melhor usar uma [estratégia de recuo exponencial e repetição](https://docs.aws.amazon.com/general/latest/gr/api-retries.html) que forneça tempos de espera progressivamente maiores entre as novas tentativas, a fim de lidar melhor com problemas transitórios, como erros `ConcurrentModificationException`. Veja um exemplo de padrão de recuo exponencial e repetição:

```
public static void main() {
  try (Driver driver = getDriver(HOST_BOLT, getDefaultConfig())) {
    retriableOperation(driver, "CREATE (n {prop:'1'})")
        .withRetries(5)
        .withExponentialBackoff(true)
        .maxWaitTimeInMilliSec(500)
        .call();
  }
}

protected RetryableWrapper retriableOperation(final Driver driver, final String query){
  return new RetryableWrapper<Void>() {
    @Override
    public Void submit() {
      log.info("Performing graph Operation in a retry manner......");
      try (Session session = driver.session(writeSessionConfig)) {
        try (Transaction trx =  session.beginTransaction()) {
            trx.run(query).consume();
            trx.commit();
        }
      }
      return null;
    }

    @Override
    public boolean isRetryable(Exception e) {
      if (isCME(e)) {
        log.debug("Retrying on exception.... {}", e);
        return true;
      }
      return false;
    }

    private boolean isCME(Exception ex) {
      return ex.getMessage().contains("Operation failed due to conflicting concurrent operations");
    }
  };
}



/**
 * Wrapper which can retry on certain condition. Client can retry operation using this class.
 */
@Log4j2
@Getter
public abstract class RetryableWrapper<T> {

  private long retries = 5;
  private long maxWaitTimeInSec = 1;
  private boolean exponentialBackoff = true;

  /**
   * Override the method with custom implementation, which will be called in retryable block.
   */
  public abstract T submit() throws Exception;

  /**
   * Override with custom logic, on which exception to retry with.
   */
  public abstract boolean isRetryable(final Exception e);

  /**
   * Define the number of retries.
   *
   * @param retries -no of retries.
   */
  public RetryableWrapper<T> withRetries(final long retries) {
    this.retries = retries;
    return this;
  }

  /**
   * Max wait time before making the next call.
   *
   * @param time - max polling interval.
   */
  public RetryableWrapper<T> maxWaitTimeInMilliSec(final long time) {
    this.maxWaitTimeInSec = time;
    return this;
  }

  /**
   * ExponentialBackoff coefficient.
   */
  public RetryableWrapper<T> withExponentialBackoff(final boolean expo) {
    this.exponentialBackoff = expo;
    return this;
  }

  /**
   * Call client method which is wrapped in submit method.
   */
  public T call() throws Exception {
    int count = 0;
    Exception exceptionForMitigationPurpose = null;
    do {
      final long waitTime = exponentialBackoff ? Math.min(getWaitTimeExp(retries), maxWaitTimeInSec) : 0;
      try {
          return submit();
      } catch (Exception e) {
        exceptionForMitigationPurpose = e;
        if (isRetryable(e) && count < retries) {
          Thread.sleep(waitTime);
          log.debug("Retrying on exception attempt - {} on exception cause - {}", count, e.getMessage());
        } else if (!isRetryable(e)) {
          log.error(e.getMessage());
          throw new RuntimeException(e);
        }
      }
    } while (++count < retries);

    throw new IOException(String.format(
          "Retry was unsuccessful.... attempts %d. Hence throwing exception " + "back to the caller...", count),
          exceptionForMitigationPurpose);
  }

  /*
   * Returns the next wait interval, in milliseconds, using an exponential backoff
   * algorithm.
   */
  private long getWaitTimeExp(final long retryCount) {
    if (0 == retryCount) {
      return 0;
    }
    return ((long) Math.pow(2, retryCount) * 100L);
  }
}
```

# Definir várias propriedades de uma vez usando uma única cláusula SET
<a name="best-practices-content-0"></a>

 Em vez de usar várias cláusulas SET para definir propriedades individuais, use um mapa para definir várias propriedades para uma entidade de uma vez. 

 Você pode usar: 

```
MATCH (n:SomeLabel {`~id`: 'id1'})
SET n += {property1 : 'value1',
property2 : 'value2',
property3 : 'value3'}
```

 Em vez de: 

```
MATCH (n:SomeLabel {`~id`: 'id1'})
SET n.property1 = 'value1'
SET n.property2 = 'value2'
SET n.property3 = 'value3'
```

 A cláusula SET aceita uma única propriedade ou um mapa. Ao atualizar várias propriedades em uma única entidade, usar uma única cláusula SET com um mapa permite que as atualizações sejam realizadas em uma única operação em vez de várias operações, que podem ser executadas com mais eficiência. 

## Usar a cláusula SET para remover várias propriedades de uma só vez
<a name="best-practices-content-1"></a>

 Ao usar a linguagem openCypher, REMOVE é usado para remover propriedades de uma entidade. No Neptune, cada propriedade removida requer uma operação separada, adicionando latência de consulta. Em vez disso, você pode usar SET com um mapa para definir todos os valores das propriedades como `null`, o que em Neptune é o equivalente a remover propriedades. O Neptune terá um desempenho aprimorado quando for necessário remover várias propriedades em uma única entidade. 

Use:

```
WITH {prop1: null, prop2: null, prop3: null} as propertiesToRemove 
MATCH (n) 
SET n += propertiesToRemove
```

Em vez de:

```
MATCH (n) 
REMOVE n.prop1, n.prop2, n.prop3
```

# Usar consultas parametrizadas
<a name="best-practices-content-2"></a>

 É recomendável sempre usar consultas parametrizadas ao fazer consultas usando o openCypher. O mecanismo de consulta pode aproveitar consultas parametrizadas repetidas para recursos como cache do plano de consulta, em que a invocação repetida da mesma estrutura parametrizada com parâmetros diferentes pode aproveitar os planos em cache. O plano de consulta gerado para consultas parametrizadas é armazenado em cache e reutilizado somente quando é concluído em 100 ms e os tipos de parâmetros são NUMBER, BOOLEAN ou STRING. 

Use:

```
MATCH (n:foo) WHERE id(n) = $id RETURN n
```

Com parâmetros:

```
parameters={"id": "first"}
parameters={"id": "second"}
parameters={"id": "third"}
```

Em vez de:

```
MATCH (n:foo) WHERE id(n) = "first" RETURN n
MATCH (n:foo) WHERE id(n) = "second" RETURN n
MATCH (n:foo) WHERE id(n) = "third" RETURN n
```

# Use mapas nivelados em vez de mapas aninhados na cláusula UNWIND
<a name="best-practices-content-3"></a>

 Uma estrutura aninhada profunda pode restringir a capacidade do mecanismo de consulta de gerar um plano de consulta ideal. Para aliviar parcialmente esse problema, os seguintes padrões definidos criarão planos ideais para os seguintes cenários: 
+  Cenário 1: UNWIND com uma lista de literais cifrados, que inclui NUMBER, STRING e BOOLEAN. 
+  Cenário 2: UNWIND com uma lista de mapas nivelados, que inclui somente literais cifrados (NUMBER, STRING, BOOLEAN) como valores. 

 Ao escrever uma consulta contendo a cláusula UNWIND, use a recomendação acima para melhorar o desempenho. 

Exemplo do cenário 1:

```
UNWIND $ids as x
MATCH(t:ticket {`~id`: x})
```

Com parâmetros:

```
parameters={
  "ids": [1, 2, 3]
}
```

 Um exemplo do Cenário 2 é gerar uma lista de nós para CREATE ou MERGE. Em vez de emitir várias declarações, use o seguinte padrão para definir as propriedades como um conjunto de mapas nivelados: 

```
UNWIND $props as p
CREATE(t:ticket {title: p.title, severity:p.severity})
```

Com parâmetros:

```
parameters={
  "props": [
    {"title": "food poisoning", "severity": "2"},
    {"title": "Simone is in office", "severity": "3"}
  ]
}
```

Em vez de objetos de nós aninhados, como:

```
UNWIND $nodes as n
CREATE(t:ticket n.properties)
```

Com parâmetros:

```
parameters={
  "nodes": [
    {"id": "ticket1", "properties": {"title": "food poisoning", "severity": "2"}},
    {"id": "ticket2", "properties": {"title": "Simone is in office", "severity": "3"}}
  ]
}
```

# Coloque nós mais restritivos no lado esquerdo em expressões de caminho de comprimento variável (VLP)
<a name="best-practices-content-4"></a>

 Nas consultas de caminho de comprimento variável (VLP), o mecanismo de consulta otimiza a avaliação escolhendo iniciar o percurso do lado esquerdo ou direito da expressão. A decisão é baseada na cardinalidade de padrões no lado esquerdo e direito. A cardinalidade é o número de nós que correspondem ao padrão especificado. 
+  Se o padrão correto tiver uma cardinalidade de um, o lado direito será o ponto de partida. 
+  Se o lado esquerdo e o direito tiverem cardinalidade de um, a expansão é verificada em ambos os lados e começa no lado com a expansão menor. Expansão é o número de bordas de entrada ou saída do nó à esquerda e à direita da expressão VLP. Essa parte da otimização é usada somente se o relacionamento VLP for unidirecional e for fornecido. 
+  Caso contrário, o lado esquerdo será o ponto de partida. 

 Para uma cadeia de expressões VLP, essa otimização só pode ser aplicada à primeira expressão. Os outros VLPs são avaliados começando pelo lado esquerdo. Como exemplo, a cardinalidade de (a), (b) deve ser um e a cardinalidade de (c) maior que um. 
+  `(a)-[*1..]->(c)`: a avaliação começa com (a). 
+  `(c)-[*1..]->(a)`: a avaliação começa com (a). 
+  `(a)-[*1..]-(c)`: a avaliação começa com (a). 
+  `(c)-[*1..]-(a)`: a avaliação começa com (a). 

 Agora, permita que as bordas de entrada de (a) sejam dois, as bordas de saída de (a) três, as formas de entrada de (b) quatro e as bordas de saída de (b), cinco. 
+  `(a)-[*1..]->(b)`: a avaliação começa com (a), pois as bordas de saída de (a) são menores do que as bordas de entrada de (b). 
+  `(a)<-[*1..]-(b)`: a avaliação começa com (a), pois as bordas de entrada de (a) são menores do que as bordas de saída de (b). 

 Como regra geral, coloque o padrão mais restritivo no lado esquerdo de uma expressão VLP. 

# Evitar verificações redundantes de rótulos de nó usando nomes de relacionamento granulares
<a name="best-practices-content-5"></a>

 Ao otimizar o desempenho, usar rótulos de relacionamento exclusivos dos padrões do nó permite a remoção da filtragem de rótulos nos nós. Considere um modelo de grafo em que o relacionamento `likes` é usado somente para definir um relacionamento entre dois nós `person`. Poderíamos escrever a seguinte consulta para encontrar esse padrão: 

```
MATCH (n:person)-[:likes]->(m:person)
RETURN n, m
```

 A verificação do rótulo `person` em n e m é redundante, pois definimos que o relacionamento só apareça quando ambos forem do tipo `person`. Para otimizar o desempenho, podemos escrever a consulta da seguinte forma: 

```
MATCH (n)-[:likes]->(m)
RETURN n, m
```

 Esse padrão também pode ser aplicado quando as propriedades são exclusivas a um rótulo de nó único. Suponha que somente os nós `person` tenham a propriedade `email`, portanto, verificar a correspondência do rótulo do nó `person` é redundante. Escrever a consulta como: 

```
MATCH (n:person)
WHERE n.email = 'xxx@gmail.com'
RETURN n
```

 É menos eficiente do que escrever a consulta como: 

```
MATCH (n)
WHERE n.email = 'xxx@gmail.com'
RETURN n
```

 Adote esse padrão somente quando o desempenho for importante e tiver verificações em seu processo de modelagem para garantir que esses rótulos de borda não sejam reutilizados para padrões envolvendo os rótulos de nó. Se você introduzir posteriormente uma propriedade `email` em outro rótulo de nó, como `company`, os resultados serão diferentes entre essas duas versões da consulta. 

# Especificar rótulos de borda sempre que possível
<a name="best-practices-content-6"></a>

 É recomendável fornecer um rótulo de borda sempre que possível ao especificar uma borda em um padrão. Considere o exemplo de consulta a seguir, usado para vincular todas as pessoas que moram em uma cidade a todas as pessoas que visitaram essa cidade. 

```
MATCH (person)-->(city {country: "US"})-->(anotherPerson)
RETURN person, anotherPerson
```

 Se seu modelo de grafo vincular pessoas a nós que não sejam somente cidades usando vários rótulos de borda, ao não especificar o rótulo final, o Neptune precisará avaliar caminhos adicionais que serão descartados posteriormente. Na consulta acima, como um rótulo de borda não foi fornecido, o mecanismo trabalha mais e depois filtra os valores para obter o resultado correto. Uma versão aprimorada da consulta acima pode ser: 

```
MATCH (person)-[:livesIn]->(city {country: "US"})-[:visitedBy]->(anotherPerson)
RETURN person, anotherPerson
```

 Isso não só ajuda na avaliação, mas permite que o planejador de consultas crie planos melhores. Você pode até mesmo combinar essa prática recomendada com verificações redundantes de rótulos de nós para remover a verificação de rótulos de cidades e escrever a consulta como: 

```
MATCH (person)-[:livesIn]->({country: "US"})-[:visitedBy]->(anotherPerson)
RETURN person, anotherPerson
```

# Evitar usar a cláusula WITH quando possível
<a name="best-practices-content-7"></a>

 A cláusula WITH no openCypher atua como um limite em que tudo antes dela é executado e os valores resultantes são passados para as partes restantes da consulta. A cláusula WITH é necessária quando você precisa de agregação provisória ou deseja limitar o número de resultados, mas, além desses casos, evite o uso dessa cláusula. A orientação geral é remover essas cláusulas WITH simples (sem agregação, ordem ou limite) para permitir que o planejador de consultas trabalhe em toda a consulta para criar um plano globalmente ideal. Por exemplo, suponha que você escreveu uma consulta para retornar todas as pessoas que moram em `India`: 

```
MATCH (person)-[:lives_in]->(city)
WITH person, city
MATCH (city)-[:part_of]->(country {name: 'India'})
RETURN collect(person) AS result
```

 Na versão acima, a cláusula WITH restringe o posicionamento do padrão `(city)-[:part_of]->(country {name: 'India'})` (que é mais restritivo) antes de `(person)-[:lives_in]->(city)`. Isso deixa o plano abaixo do ideal. Uma otimização dessa consulta seria remover a cláusula WITH e permitir que o planejador calculasse o melhor plano. 

```
MATCH (person)-[:lives_in]->(city)
MATCH (city)-[:part_of]->(country {name: 'India'})
RETURN collect(person) AS result
```

# Colocar filtros restritivos o mais cedo possível na consulta
<a name="best-practices-content-8"></a>

 Em todos os cenários, colocar filtros na consulta antecipadamente ajuda a reduzir as soluções intermediárias que um plano de consulta deve considerar. Isso significa que menos memória e menos recursos computacionais são necessários para executar a consulta. 

 O exemplo a seguir ajuda você a entender esses impactos. Suponha que você escreva uma consulta para retornar todas as pessoas que moram em `India`. Uma versão da consulta pode ser: 

```
MATCH (n)-[:lives_in]->(city)-[:part_of]->(country)
WITH country, collect(n.firstName + " "  + n.lastName) AS result
WHERE country.name = 'India'
RETURN result
```

 A versão de consulta acima não é a melhor maneira de alcançar esse caso de uso. O filtro `country.name = 'India'` aparece posteriormente no padrão de consulta. Primeiro, ele coletará todas as pessoas e onde elas moram, as agrupará por país e, em seguida, filtrará somente o grupo para `country.name = India`. O ideal é consultar somente as pessoas que moram em `India` e depois realizar a agregação de coleta. 

```
MATCH (n)-[:lives_in]->(city)-[:part_of]->(country)
WHERE country.name = 'India'
RETURN collect(n.firstName + " "  + n.lastName) AS result
```

 Uma regra geral é colocar um filtro o mais rápido possível após a introdução da variável. 

# Verificar explicitamente se as propriedades existem
<a name="best-practices-content-9"></a>

 Com base na semântica do openCypher, quando uma propriedade é acessada, ela é equivalente a uma junção opcional e deve reter todas as linhas, mesmo que a propriedade não exista. Se você souber, com base em seu esquema de grafos, que uma propriedade específica sempre existirá para essa entidade, verificar explicitamente a existência dessa propriedade permite que o mecanismo de consulta crie planos ideais e melhore o desempenho. 

 Considere um modelo de grafos em que nós do tipo `person` sempre tenham uma propriedade `name`. Em vez de escrever: 

```
MATCH (n:person)
RETURN n.name
```

 Verifique explicitamente a existência da propriedade na consulta com uma verificação IS NOT NULL: 

```
MATCH (n:person)
WHERE n.name IS NOT NULL
RETURN n.name
```

# Não usar o caminho nomeado (a menos que seja necessário)
<a name="best-practices-content-10"></a>

 O caminho nomeado em uma consulta sempre tem um custo adicional, o que pode adicionar penalidades em termos de maior latência e uso de memória. Considere a seguinte consulta: 

```
MATCH p = (n)-[:commentedOn]->(m)
WITH p, m, n, n.score + m.score as total
WHERE total > 100 
MATCH (m)-[:commentedON]->(o)
WITH p, m, n, distinct(o) as o1
RETURN p, m.name, n.name, o1.name
```

 Na consulta acima, supondo que queremos somente saber as propriedades dos nós, o uso do caminho “p” é desnecessário. Ao especificar o caminho nomeado como uma variável, a operação de agregação que usa DISTINCT será cara em termos de tempo e uso de memória. Uma versão otimizada da consulta acima poderia ser: 

```
MATCH (n)-[:commentedOn]->(m)
WITH m, n, n.score + m.score as total
WHERE total > 100 
MATCH (m)-[:commentedON]->(o)
WITH m, n, distinct(o) as o1
RETURN m.name, n.name, o1.name
```

# Evitar COLLECT(DISTINCT())
<a name="best-practices-content-11"></a>

**nota**  
A partir da versão [1.4.7.0](engine-releases-1.4.7.0.md) do motor, essa reescrita recomendada não é mais necessária.

 COLLECT(DISTINCT()) é usada sempre que uma lista deve ser formada contendo valores distintos. COLLECT é uma função de agregação e o agrupamento é feito com base em chaves adicionais projetadas na mesma instrução. Quando “distinct” é usado, a entrada é dividida em vários blocos, e cada pedaço denota um grupo para redução. O desempenho será afetado à medida que o número de grupos aumentar. Em Neptune, é muito mais eficiente executar DISTINCT antes collecting/forming de realmente fazer a lista. Isso permite que o agrupamento seja feito diretamente nas chaves de agrupamento de todo o bloco. 

 Considere a seguinte consulta: 

```
MATCH (n:Person)-[:commented_on]->(p:Post)
WITH n, collect(distinct(p.post_id)) as post_list
RETURN n, post_list
```

 Uma maneira mais ideal de escrever essa consulta é: 

```
MATCH (n:Person)-[:commented_on]->(p:Post)
WITH DISTINCT n, p.post_id as postId
WITH n, collect(postId) as post_list
RETURN n, post_list
```

# Optar pela função de propriedades em vez da pesquisa de propriedades individuais ao recuperar todos os valores da propriedade
<a name="best-practices-content-12"></a>

 A função `properties()` é usada para retornar um mapa contendo todas as propriedades de uma entidade e é muito mais eficiente do que retornar propriedades individualmente. 

 Supondo que seus nós `Person` contenham cinco propriedades (`firstName`, `lastName`, `age`, `dept` e `company`), a seguinte consulta seria preferível: 

```
MATCH (n:Person)
WHERE n.dept = 'AWS'
RETURN properties(n) as personDetails
```

 Em vez de usar: 

```
MATCH (n:Person)
WHERE n.dept = 'AWS'
RETURN n.firstName, n.lastName, n.age, n.dept, n.company
    
=== OR ===
    
MATCH (n:Person)
WHERE n.dept = 'AWS'
RETURN {firstName: n.firstName, lastName: n.lastName, age: n.age, 
department: n.dept, company: n.company} as personDetails
```

# Executar cálculos estáticos fora da consulta
<a name="best-practices-content-13"></a>

 É recomendável resolver cálculos estáticos ( mathematical/string operações simples) no lado do cliente. Considere este exemplo em que você deseja encontrar todas as pessoas um ano mais velhas ou mais novas que o autor: 

```
MATCH (m:Message)-[:HAS_CREATOR]->(p:person)
WHERE p.age <= ($age + 1)
RETURN m
```

 Aqui, `$age` é injetado na consulta por meio de parâmetros e, em seguida, adicionado a um valor fixo. Esse valor é então comparado com `p.age`. Em vez disso, uma abordagem melhor seria fazer a adição no lado do cliente e passar o valor calculado como um parâmetro \$1ageplusone. Isso ajuda o mecanismo de consulta a criar planos otimizados e evita cálculos estáticos para cada linha de entrada. Seguindo essas diretrizes, uma versão mais eficiente da consulta seria: 

```
MATCH (m:Message)-[:HAS_CREATOR]->(p:person)
WHERE p.age <= $ageplusone
RETURN m
```

# Agrupar entradas usando UNWIND em vez de declarações individuais
<a name="best-practices-content-14"></a>

 Sempre que a mesma consulta precisar ser executada para entradas diferentes, em vez de executar uma consulta por entrada, seria muito mais eficiente executar uma consulta para um lote de entradas. 

 Se você quiser mesclar um conjunto de nós, uma opção é executar uma consulta de mesclagem por entrada: 

```
MERGE (n:Person {`~id`: $id})
SET n.name = $name, n.age = $age, n.employer = $employer
```

 Com parâmetros: 

```
params = {id: '1', name: 'john', age: 25, employer: 'Amazon'}
```

 A consulta acima precisa ser executada para cada entrada. Embora essa abordagem funcione, ela pode exigir que muitas consultas sejam executadas para um grande conjunto de entradas. Nesse cenário, o agrupamento em lotes pode ajudar a reduzir o número de consultas executadas no servidor, bem como melhorar o throughput geral. 

 Use o seguinte padrão: 

```
UNWIND $persons as person
MERGE (n:Person {`~id`: person.id})
SET n += person
```

 Com parâmetros: 

```
params = {persons: [{id: '1', name: 'john', age: 25, employer: 'Amazon'}, 
{id: '2', name: 'jack', age: 28, employer: 'Amazon'},
{id: '3', name: 'alice', age: 24, employer: 'Amazon'}...]}
```

 Recomenda-se experimentar com diferentes tamanhos de lote para determinar o que funciona melhor para sua workload. 

# Prefiro usar o personalizado IDs para nó/relacionamento
<a name="best-practices-content-15"></a>

 O Neptune permite que os usuários IDs atribuam explicitamente nós e relacionamentos. O ID deve ser globalmente exclusivo no conjunto de dados e determinístico para ser útil. Um ID determinístico pode ser usado como um mecanismo de pesquisa ou filtragem, assim como propriedades; no entanto, do ponto de vista da execução da consulta, usar um ID é um método muito mais otimizado do que usar propriedades. Há vários benefícios em usar o personalizado IDs - 
+  As propriedades podem ser nulas para uma entidade existente, mas o ID deve existir. Isso permite que o mecanismo de consulta use uma junção otimizada durante a execução. 
+  Quando consultas de mutação simultâneas são executadas, as chances de [exceções de modificação simultânea](https://docs.aws.amazon.com//neptune/latest/userguide/transactions-exceptions.html) (CMEs) são reduzidas significativamente quando usadas para acessar nós, porque menos bloqueios IDs estão ocorrendo IDs do que propriedades devido à sua exclusividade imposta. 
+  O uso IDs evita a chance de criar dados duplicados, pois Neptune impõe exclusividade em propriedades diferentes. IDs 

 O exemplo de consulta a seguir usa um ID personalizado: 

**nota**  
 A propriedade `~id` é usada para especificar o ID, já `id` é armazenada somente como qualquer outra propriedade. 

```
CREATE (n:Person {`~id`: '1', name: 'alice'})
```

 Sem usar um ID personalizado: 

```
CREATE (n:Person {id: '1', name: 'alice'})
```

 Se estiver usando o último mecanismo, não há imposição de exclusividade e você poderá executar a consulta posteriormente: 

```
CREATE (n:Person {id: '1', name: 'john'})
```

 Isso cria um segundo nó com `id=1` chamado `john`. Nesse cenário, agora você teria dois nós com `id=1`, cada um com um nome diferente (alice e john). 

# Evitar fazer cálculos de \$1id na consulta
<a name="best-practices-content-16"></a>

 Ao usar IDs customização nas consultas, sempre realize cálculos estáticos fora das consultas e forneça esses valores nos parâmetros. Quando valores estáticos são fornecidos, o mecanismo é mais capaz de otimizar as pesquisas e evitar a digitalização e a filtragem desses valores. 

 Se você quiser criar bordas entre os nós que existem no banco de dados, uma opção pode ser: 

```
UNWIND $sections as section
MATCH (s:Section {`~id`: 'Sec-' + section.id})
MERGE (s)-[:IS_PART_OF]->(g:Group {`~id`: 'g1'})
```

 Com parâmetros: 

```
parameters={sections: [{id: '1'}, {id: '2'}]}
```

 Na consulta acima, o `id` da seção está sendo computado na consulta. Como o cálculo é dinâmico, o mecanismo não pode embutir identificações estaticamente e acaba escaneando todos os nós da seção. O mecanismo então executa a pós-filtragem dos nós necessários. Isso pode ser caro se houver muitos nós de seção no banco de dados. 

 A melhor maneira de fazer isso é prefixar `Sec-` nos ids que estão sendo passados para o banco de dados: 

```
UNWIND $sections as section
MATCH (s:Section {`~id`: section.id})
MERGE (s)-[:IS_PART_OF]->(g:Group {`~id`: 'g1'})
```

 Com parâmetros: 

```
parameters={sections: [{id: 'Sec-1'}, {id: 'Sec-2'}]}
```

# Atualizar/mesclar vários nós
<a name="best-practices-merge-multiple-nodes"></a>

 Ao executar `MERGE` ou `CREATE` consultar em vários nós, é recomendável usar um `UNWIND` em combinação com uma única MERGE/CREATE cláusula em vez de usar uma MERGE/CREATE cláusula para cada nó. As consultas que usam uma cláusula por nó levam a um plano de execução ineficiente devido à necessidade de otimizar cada linha. Isso faz com que a maior parte do tempo de execução da consulta seja gasto no processamento estático em vez da atualização real. 

 Uma cláusula por nó não é ideal, pois não é escalável com o aumento do número de nós: 

```
MERGE (p1:Person {name: 'NameA'})
ON CREATE SET p1 += {prop1: 'prop1V1', prop2: 'prop2V1'}
MERGE (p2:Person {name: 'NameB'})
ON CREATE SET p2 += {prop1: 'prop1V2', prop2: 'prop2V2'}
MERGE (p3:Person {name: 'NameC'})
ON CREATE SET p3 += {prop1: 'prop1V3', prop2: 'prop1V3'}
```

 Usar um `UNWIND` em conjunto com uma MERGE/CREATE cláusula permite o mesmo comportamento, mas um plano de execução mais otimizado. Com isso em mente, a consulta alterada ficaria assim: 

```
## If not using custom id for nodes/relationship
UNWIND [{name: 'NameA', prop1: 'prop1V1', prop2: 'prop2V1'}, {name: 'NameB', prop1: 'prop1V2', prop2: 'prop2V2'}, {name: 'NameC', prop1: 'prop1V3', prop2: 'prop1V3'}] AS props
MERGE (p:Person {name: props.name})
ON CREATE SET p = props

## If using custom id for nodes/relationship
UNWIND [{`~id`: '1', 'name': 'NameA', 'prop1: 'prop1V1', prop2: 'prop2V1'}, {`~id`: '2', name: 'NameB', prop1: 'prop1V2', prop2: 'prop2V2'}, {`~id`: '3', name: 'NameC', prop1: 'prop1V3', prop2: 'prop1V3'}] AS props
MERGE (p:Person {`~id`: props.id})
ON CREATE SET p = removeKeyFromMap(props, '~id')
```

# Práticas recomendadas para o Neptune ao usar SPARQL
<a name="best-practices-sparql"></a>

Siga estas práticas recomendadas ao usar a linguagem de consulta SPARQL com Neptune. Para obter informações sobre como usar o SPARQL no Neptune, consulte [Acessar o grafo do Neptune com o SPARQL](access-graph-sparql.md).

**Topics**
+ [Como consultar todos os gráficos nomeados por padrão](best-practices-sparql-query.md)
+ [Como especificar um nome gráfico para carregamento](best-practices-sparql-graph.md)
+ [Como escolher entre FILTER, FILTER...IN e VALUES em suas consultas](best-practices-sparql-batch.md)

# Como consultar todos os gráficos nomeados por padrão
<a name="best-practices-sparql-query"></a>

O Amazon Neptune associa cada triplo a um grafo nomeado. O gráfico padrão é definido como a união de todos os gráficos nomeados. 

Se você enviar uma consulta do SPARQL sem especificar explicitamente um gráfico por meio da palavra-chave `GRAPH` ou construções como `FROM NAMED`, o Neptune sempre considerará todos os trios em sua instância de banco de dados. Por exemplo, a seguinte consulta gera todos os triplos de um endpoint do SPARQL no Neptune: 

```
SELECT * WHERE { ?s ?p ?o }
```

Trios que aparecem em mais de um gráfico são retornados somente uma vez.

Para obter informações sobre a especificação de gráfico padrão, consulte a seção [Dataset do RDF](https://www.w3.org/TR/sparql11-query/#rdfDataset) da especificação do SPARQL 1.1 Query Language.

# Como especificar um nome gráfico para carregamento
<a name="best-practices-sparql-graph"></a>

O Amazon Neptune associa cada triplo a um grafo nomeado. Se você não especificar um grafo nomeado ao carregar, inserir ou atualizar triplos, o Neptune usará o grafo nomeado fallback definido pelo URI, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`.

Se você estiver usando o carregador em massa do Neptune, será possível especificar um grafo nomeado para usar todos os triplos (ou quadrantes com a quarta posição em branco) usando o parâmetro `parserConfiguration: namedGraphUri`. Para obter informações sobre a sintaxe do comando `Load` do carregador do Neptune, consulte [Comando do carregador do Neptune](load-api-reference-load.md).

# Como escolher entre FILTER, FILTER...IN e VALUES em suas consultas
<a name="best-practices-sparql-batch"></a>

Existem três maneiras básicas para injetar valores em consultas SPARQL:   `FILTER`,   `FILTER...IN`   e   `VALUES`.

Por exemplo, suponha que você queira pesquisar os amigos de várias pessoas em uma única consulta. Usando `FILTER`, você pode estruturar a consulta da seguinte forma:

```
  PREFIX ex: <https://www.example.com/>
  PREFIX foaf : <http://xmlns.com/foaf/0.1/>

  SELECT ?s ?o
  WHERE {?s foaf:knows ?o. FILTER (?s = ex:person1 || ?s = ex:person2)}
```

Isso retorna todos os triplos no gráfico que têm `?s` vinculado a `ex:person1` ou a `ex:person2` e uma borda de saída chamada `foaf:knows`.

Você também pode criar uma consulta usando `FILTER...IN` que retorna resultados equivalentes:

```
  PREFIX ex: <https://www.example.com/>
  PREFIX foaf : <http://xmlns.com/foaf/0.1/>

  SELECT ?s ?o
  WHERE {?s foaf:knows ?o. FILTER (?s IN (ex:person1, ex:person2))}
```

Você também pode criar uma consulta usando `VALUES` que, nesse caso, também retorna resultados equivalentes:

```
  PREFIX ex: <https://www.example.com/>
  PREFIX foaf : <http://xmlns.com/foaf/0.1/>

  SELECT ?s ?o
  WHERE {?s foaf:knows ?o. VALUES ?s {ex:person1 ex:person2}}
```

Embora em muitos casos essas consultas sejam semanticamente equivalentes, há alguns casos em que as duas variantes `FILTER` diferem da variante `VALUES`:
+ O primeiro caso é quando você injeta valores duplicados, como injetar a mesma pessoa duas vezes. Nesse caso, a consulta `VALUES` inclui as duplicatas no resultado. Você pode eliminar essas duplicações explicitamente adicionando um `DISTINCT` à cláusula `SELECT`. No entanto, pode haver situações em que você realmente quer duplicações nos resultados da consulta de injeção de valor redundante.

  No entanto, as versões `FILTER` e `FILTER...IN` extraem o valor somente uma vez quando o mesmo valor é exibido várias vezes.
+ O segundo caso está relacionado ao fato de que `VALUES` sempre realiza uma correspondência exata, enquanto `FILTER` pode aplicar uma promoção de tipo e fazer correspondência difusa em alguns casos.

  Por exemplo, quando você inclui um literal, como `"2.0"^^xsd:float` na cláusula de valores, uma consulta `VALUES` corresponde exatamente a essa literal, incluindo valor de literal e tipo de dados.

  Por outro lado, `FILTER` produz uma correspondência difusa para esses literais numéricos. As correspondências podem incluir literais com o mesmo valor, mas com diferentes tipos de dados numéricos, como `xsd:double`.
**nota**  
Não há diferença entre o comportamento de `FILTER` e de `VALUES` ao enumerar literais de strings ou URIs.

As diferenças entre `FILTER` e `VALUES` podem afetar a otimização e a estratégia de avaliação de consulta resultante. A não ser que seu caso de uso precise de correspondência difusa, recomendamos usar `VALUES` porque ele evita olhar para casos especiais relacionados a conversão do tipo. Como resultado, `VALUES` muitas vezes produz uma consulta mais eficiente cuja execução é mais rápida e mais econômica.