

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

# Esecuzione di query su un grafo Neptune
<a name="access-graph-queries"></a>

Neptune supporta i seguenti linguaggi di query a grafo per accedere a un grafo:
+ [Gremlin](https://tinkerpop.apache.org/gremlin.html), definito da [Apache per la creazione e l'interrogazione di grafici TinkerPop](https://tinkerpop.apache.org/) delle proprietà.

  Una query in Gremlin è un attraversamento composto da passaggi discreti, ognuno dei quali segue un arco fino a un nodo.

  Vedi [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md) per ottenere informazioni sull'uso di Gremlin in Neptune e [Conformità agli standard Gremlin in Amazon Neptune](access-graph-gremlin-differences.md) per trovare dettagli specifici sull'implementazione di Gremlin in Neptune.
+ [openCypher](access-graph-opencypher.md) è un linguaggio di query dichiarativo per grafi di proprietà che è stato sviluppato originariamente da Neo4j, per poi diventare open source nel 2015, e che ha contribuito al progetto [openCypher](http://www.opencypher.org/) con una licenza open source Apache 2. La sintassi è documentata nella [specifica openCypher](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).
+ [SPARQL](https://www.w3.org/TR/sparql11-overview/) è un linguaggio dichiarativo basato sulla corrispondenza di modelli del grafo, per l'esecuzione di query sui dati [RDF](https://www.w3.org/2001/sw/wiki/RDF). È supportato dal [World Wide Web Consortium](https://www.w3.org/).

  Vedi [Accesso al grafo Neptune con SPARQL](access-graph-sparql.md) per ottenere informazioni sull'uso di SPARQL in Neptune e [Conformità agli standard SPARQL in Amazon Neptune](feature-sparql-compliance.md) per trovare dettagli specifici sull'implementazione di SPARQL in Neptune.

**Nota**  
Sia Gremlin che openCypher possono essere usati per eseguire query sui dati dei grafi di proprietà archiviati in Neptune, indipendentemente da come sono stati caricati.

**Topics**
+ [

# Accodamento delle query in Amazon Neptune
](access-graph-queuing.md)
+ [

# Cache del piano di query in Amazon Neptune
](access-graph-qpc.md)
+ [

# Inserimento di un ID personalizzato in una query Neptune Gremlin o SPARQL
](features-query-id.md)
+ [

# Accesso al grafo Neptune con Gremlin
](access-graph-gremlin.md)
+ [

# Accesso al grafo di Neptune con openCypher
](access-graph-opencypher.md)
+ [

# Accesso al grafo Neptune con SPARQL
](access-graph-sparql.md)

# Accodamento delle query in Amazon Neptune
<a name="access-graph-queuing"></a>

Durante lo sviluppo e l'ottimizzazione di applicazioni grafiche, può essere utile conoscere le implicazioni di come le query vengono accodate dal database. In Amazon Neptune, l'accodamento delle query si verifica come segue:
+ Il numero massimo di query che è possibile accodare per istanza, indipendentemente dalla dimensione dell'istanza, è 8.192. Tutte le query superiori a quel numero vengono rifiutate e danno esito negativo con un `ThrottlingException`.
+ Il numero massimo di query che possono essere eseguite contemporaneamente è determinato dal numero di thread di lavoro assegnati, che in genere è impostato sul doppio del numero di core CPU virtuali (v) disponibili. CPUs
+ La latenza delle query include il tempo trascorso da una query nella coda, nonché il round trip della rete e il tempo necessario per l'esecuzione.

## Determinare quante query ci sono nella coda in un dato momento
<a name="access-graph-queuing-count"></a>

La `MainRequestQueuePendingRequests` CloudWatch metrica registra il numero di richieste in attesa nella coda di input con una granularità di cinque minuti (vedi). [Metriche di Neptune CloudWatch](cw-metrics.md)

Per Gremlin, è possibile ottenere un conteggio corrente di query nella coda utilizzando il valore `acceptedQueryCount` restituito da [API di stato delle query Gremlin](gremlin-api-status.md). Si noti, tuttavia, che il valore `acceptedQueryCount` restituito da [API di stato delle query SPARQL](sparql-api-status.md) include tutte le query accettate dall'avvio del server, incluse le query completate.

## Come l'accodamento delle query può influire sui timeout
<a name="access-graph-queuing-timeouts"></a>

Come notato in precedenza, la latenza delle query include il tempo impiegato da una query nella coda e il tempo necessario per l'esecuzione.

Poiché il periodo di timeout di una query viene generalmente misurato a partire da quando entra nella coda, una coda a spostamento lento può mandare molte query in timeout non appena vengono rimosse dalla coda. Questo è ovviamente indesiderabile, quindi è bene evitare di accodare un gran numero di query a meno che non possano essere eseguite rapidamente.

# Cache del piano di query in Amazon Neptune
<a name="access-graph-qpc"></a>

 Quando una query viene inviata a Neptune, la stringa di query viene analizzata, ottimizzata e trasformata in un piano di query, che viene quindi eseguito dal motore. Le applicazioni sono spesso supportate da modelli di query comuni istanziati con valori diversi. La cache del piano di query può ridurre la latenza complessiva memorizzando nella cache i piani di query ed evitando così l'analisi e l'ottimizzazione di tali schemi ripetuti. 

 Query Plan Cache può essere utilizzata per le query, sia quelle non **OpenCypher**parametrizzate che quelle parametrizzate. È abilitato per READ e per HTTP e Bolt. **Non** è supportato per le query di mutazione OC. **Non** è supportato per le query Gremlin o SPARQL. 

## Come forzare l'attivazione o la disabilitazione della cache del piano di query
<a name="access-graph-qpc-enable"></a>

 La cache del piano di query è abilitata di default per le query parametrizzate a bassa latenza. **Un piano per una query con parametri viene memorizzato nella cache solo quando la latenza è inferiore alla soglia di 100 ms.** Questo comportamento può essere sovrascritto per singola query (parametrizzata o meno) dal Query Hint a livello di query. `QUERY:PLANCACHE` Deve essere usato con la clausola. `USING` Il suggerimento di interrogazione accetta `enabled` o `disabled` come valore. 

```
# Forcing plan to be cached or reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
  
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  -d "parameters={\"arg\": 123}"
  
# Forcing plan to be neither cached nor reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

## Come determinare se un piano è memorizzato nella cache o meno
<a name="access-graph-qpc-status"></a>

 Per HTTP READ, se la query è stata inviata e il piano è stato memorizzato nella cache, `explain` mostrerebbe i dettagli relativi alla cache del piano di query. 

```
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1" \
  -d "explain=[static|details]"

Query: <QUERY STRING>
Plan cached by request: <REQUEST ID OF FIRST TIME EXECUTION>
Plan cached at: <TIMESTAMP OF FIRST TIME EXECUTION>
Parameters: <PARAMETERS, IF QUERY IS PARAMETERIZED QUERY>
Plan cache hits: <NUMBER OF CACHE HITS FOR CACHED PLAN>
First query evaluation time: <LATENCY OF FIRST TIME EXECUTION>

The query has been executed based on a cached query plan. Detailed explain with operator runtime statistics can be obtained by running the query with plan cache disabled (using HTTP parameter planCache=disabled).
```

 Quando si utilizza Bolt, la funzione di spiegazione non è supportata. 

## Sfratto
<a name="access-graph-qpc-eviction"></a>

 Un piano di query viene eliminato dal cache time to live (TTL) o quando è stato raggiunto un numero massimo di piani di query memorizzati nella cache. Quando il piano di query viene raggiunto, il TTL viene aggiornato. Le impostazioni predefinite sono: 
+  1000: il numero massimo di piani che possono essere memorizzati nella cache per istanza. 
+  TTL: 300.000 millisecondi o 5 minuti. L'accesso alla cache riavvia il TTL e lo reimposta a 5 minuti. 

## Condizioni che impediscono la memorizzazione del piano nella cache
<a name="access-graph-qpc-conditions"></a>

 La cache del piano di query non verrebbe utilizzata nelle seguenti condizioni: 

1.  Quando viene inviata una query utilizzando il suggerimento `QUERY:PLANCACHE "disabled"` di interrogazione. È possibile eseguire nuovamente la query e rimuoverla `QUERY:PLANCACHE "disabled"` per abilitare la cache del piano di interrogazione. 

1.  Se la query inviata non è un'interrogazione con parametri e non contiene il suggerimento. `QUERY:PLANCACHE "enabled"` 

1.  Se il tempo di valutazione della query è superiore alla soglia di latenza, la query non viene memorizzata nella cache e viene considerata una query di lunga durata che non trarrebbe vantaggio dalla cache del piano di query. 

1.  Se la query contiene uno schema che non restituisce alcun risultato. 
   +  cioè `MATCH (n:nonexistentLabel) return n` quando ci sono zero nodi con l'etichetta specificata. 
   +  cioè `MATCH (n {name: $param}) return n` con `parameters={"param": "abcde"}` quando non ci sono nodi contenenti`name=abcde`. 

1.  Se il parametro di interrogazione è di tipo composito, ad esempio a `list` o a`map`. 

   ```
   curl -k https://<endpoint>:<port>/opencypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": [1, 2, 3]}"
   
   curl -k https://<endpoint>:<port>/opencypher \
     -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
     -d "parameters={\"arg\": {\"a\": 1}}"
   ```

1.  Se il parametro di query è una stringa che non ha fatto parte di un'operazione di caricamento o inserimento di dati. Ad esempio, se `CREATE (n {name: "X"})` viene eseguito per inserire`"X"`, `RETURN "X"` viene memorizzato nella cache, mentre non `RETURN "Y"` verrebbe memorizzato nella cache, poiché `"Y"` non è stato inserito e non esiste nel database. 

# Inserimento di un ID personalizzato in una query Neptune Gremlin o SPARQL
<a name="features-query-id"></a>

Per impostazione predefinita, Neptune assegna un valore `queryId` univoco a ogni query. Puoi utilizzare questo ID per ottenere informazioni su una query in esecuzione (consulta [API di stato delle query Gremlin](gremlin-api-status.md) o [API di stato delle query SPARQL](sparql-api-status.md)) o annullarla (consulta [Annullamento delle query Gremlin](gremlin-api-status-cancel.md) o [Annullamento della query SPARQL](sparql-api-status-cancel.md)).

Neptune consente inoltre di specificare il proprio valore `queryId` per una query Gremlin o SPARQL, nell'intestazione HTTP o per una query SPARQL utilizzando l'hint di query `queryId`. L'assegnazione del proprio `queryID` consente di tenere traccia di una query in modo da ottenere lo stato o annullarla.

## Inserimento di un valore `queryId` personalizzato tramite l'intestazione HTTP
<a name="features-query-id-header"></a>

Per Gremlin e SPARQL, l'intestazione HTTP può essere utilizzata per inserire il proprio valore `queryId` in una query.

**Esempio Gremlin**

```
curl -XPOST https://your-neptune-endpoint:port \
    -d "{\"gremlin\": \
        \"g.V().limit(1).count()\" , \
        \"queryId\":\"4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47\"  }"
```

**Esempio SPARQL**

```
curl https://your-neptune-endpoint:port/sparql \
    -d "query=SELECT * WHERE { ?s ?p ?o } " \
       --data-urlencode \
       "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

## Inserimento di un valore `queryId` personalizzato mediante un hint di query SPARQL
<a name="features-query-id-hint"></a>

Di seguito è riportato un esempio di come utilizzare l'hint di query `queryId` SPARQL per inserire un valore `queryId` personalizzato in una query SPARQL:

```
curl https://your-neptune-endpoint:port/sparql \
    -d "query=PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#> \
       SELECT * WHERE { hint:Query hint:queryId \"4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47\" \
       {?s ?p ?o}}"
```

## Utilizzo del valore `queryId` per controllare lo stato della query
<a name="features-query-id-check-status"></a>

**Esempio Gremlin**

```
curl https://your-neptune-endpoint:port/gremlin/status \
    -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

**Esempio SPARQL**

```
curl https://your-neptune-endpoint:port/sparql/status \
    -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
```

# Accesso al grafo Neptune con Gremlin
<a name="access-graph-gremlin"></a>

Amazon Neptune è compatibile con TinkerPop Apache e Gremlin. Ciò significa che puoi connetterti a un'istanza DB di Neptune e usare il linguaggio di attraversamento Gremlin per interrogare il grafico ([vedi](https://tinkerpop.apache.org/docs/current/reference/#graph) The Graph nella documentazione di Apache). TinkerPop Per le differenze nell'implementazione di Gremlin in Neptune, consulta [Conformità agli standard Gremlin](access-graph-gremlin-differences.md).

 L'*attraversamento* in Gremlin corrisponde a una serie di passaggi concatenati. Inizia in un vertice (o edge). Percorre il grafo seguendo gli edge in uscita di ogni vertice, quindi gli edge in uscita di quei vertici. Nell'attraversamento, ogni passaggio corrisponde a un'operazione. [Per ulteriori informazioni, consulta The Traversal nella documentazione.](https://tinkerpop.apache.org/docs/current/reference/#traversal) TinkerPop 

Versioni diverse del motore Neptune supportano versioni diverse di Gremlin. Controlla la [pagina di rilascio del motore](engine-releases.md) della versione di Neptune in uso per determinare quale versione di Gremlin supporta o consulta la seguente tabella che elenca le versioni più vecchie e più recenti TinkerPop supportate da diverse versioni del motore Neptune:


| Versione del motore Neptune | Versione minima TinkerPop  |  TinkerPop Versione massima | 
| --- | --- | --- | 
| `1.3.2.0 and newer` | `3.7.1` | `3.7.3` | 
| `1.3.1.0` | `3.6.2` | `3.6.5` | 
| `1.3.0.0` | `3.6.2` | `3.6.4` | 
| `1.2.1.0 <= 1.2.1.2` | `3.6.2` | `3.6.2` | 
| `1.1.1.0 <= 1.2.0.2` | `3.5.5` | `3.5.6` | 
| `1.1.0.0 and older` | `(deprecated)` | `(deprecated)` | 

TinkerPop I client sono in genere retrocompatibili all'interno di una serie (ad esempio`3.6.x`, o`3.7.x`) e sebbene possano spesso funzionare oltre tali limiti, la tabella precedente consiglia le combinazioni di versioni da utilizzare per la migliore esperienza e compatibilità possibili. Salvo diversa indicazione, in genere è meglio attenersi a queste linee guida e aggiornare le applicazioni client in modo che corrispondano alla versione in uso TinkerPop .

Quando si aggiornano TinkerPop le versioni, è sempre importante fare riferimento alla [documentazione TinkerPop di aggiornamento](http://tinkerpop.apache.org/docs/current/upgrade/), che aiuterà a identificare le nuove funzionalità da sfruttare, ma anche i problemi di cui potrebbe essere necessario essere consapevoli man mano che ci si avvicina all'aggiornamento. In genere è necessario aspettarsi che le query e le funzionalità esistenti funzionino dopo l'aggiornamento, a meno che non venga indicato qualcosa in particolare come un problema da considerare. Infine, è importante notare che se una versione aggiornata include una nuova funzionalità, potrebbe non essere possibile utilizzarla se proviene da una versione successiva a quella supportata da Neptune.

Per l'accesso a Gremlin esistono varianti di linguaggio e supporto in diversi linguaggi di programmazione. Per ulteriori informazioni, vedete [On Gremlin Language Variants nella documentazione](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants). TinkerPop 

Questa documentazione descrive come accedere a Neptune con le seguenti varianti e linguaggi di programmazione:
+ [Configurazione della console Gremlin per la connessione a un'istanza database Neptune](access-graph-gremlin-console.md)
+ [Utilizzo dell'endpoint HTTPS REST per connettersi a un'istanza database Neptune](access-graph-gremlin-rest.md)
+ [Client Gremlin basati su Java da utilizzare con Amazon Neptune](access-graph-gremlin-client.md)
+ [Utilizzo di Python per connettersi a un'istanza database Neptune](access-graph-gremlin-python.md)
+ [Utilizzo di .NET per connettersi a un'istanza database Neptune](access-graph-gremlin-dotnet.md)
+ [Utilizzo di Node.js per connettersi a un'istanza database Neptune](access-graph-gremlin-node-js.md)
+ [Utilizzo di Go per connettersi a un'istanza database Neptune](access-graph-gremlin-go.md)

Come discusso in precedenza[Crittografia delle connessioni al tuo database Amazon Neptune con SSL/HTTPS](security-ssl.md), è necessario utilizzare Transport Layer Security/Secure Sockets Layer (TLS/SSL) per la connessione a Neptune in tutte le regioni. AWS 

Prima di iniziare, devi disporre di quanto segue:
+ Istanza database Neptune. Per informazioni sulla creazione di un'istanza database Neptune, consulta [Creazione di un cluster Amazon Neptune](get-started-create-cluster.md).
+ Istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

Per ulteriori informazioni sul caricamento di dati in Neptune, incluso i prerequisiti, i formati di caricamento e i parametri di caricamento, vedi [Caricamento di dati in Amazon Neptune](load-data.md).

**Topics**
+ [

# Configurazione della console Gremlin per la connessione a un'istanza database Neptune
](access-graph-gremlin-console.md)
+ [

# Utilizzo dell'endpoint HTTPS REST per connettersi a un'istanza database Neptune
](access-graph-gremlin-rest.md)
+ [

# Client Gremlin basati su Java da utilizzare con Amazon Neptune
](access-graph-gremlin-client.md)
+ [

# Utilizzo di Python per connettersi a un'istanza database Neptune
](access-graph-gremlin-python.md)
+ [

# Utilizzo di .NET per connettersi a un'istanza database Neptune
](access-graph-gremlin-dotnet.md)
+ [

# Utilizzo di Node.js per connettersi a un'istanza database Neptune
](access-graph-gremlin-node-js.md)
+ [

# Utilizzo di Go per connettersi a un'istanza database Neptune
](access-graph-gremlin-go.md)
+ [

# Utilizzo dell' AWS SDK per eseguire le query Gremlin
](access-graph-gremlin-sdk.md)
+ [

# Hint di query Gremlin
](gremlin-query-hints.md)
+ [

# API di stato delle query Gremlin
](gremlin-api-status.md)
+ [

# Annullamento delle query Gremlin
](gremlin-api-status-cancel.md)
+ [

# Supporto delle sessioni basate su script Gremlin
](access-graph-gremlin-sessions.md)
+ [

# Transazioni Gremlin in Neptune
](access-graph-gremlin-transactions.md)
+ [

# Utilizzo dell'API Gremlin con Amazon Neptune
](gremlin-api-reference.md)
+ [

# Memorizzazione nella cache dei risultati delle query con Gremlin in Amazon Neptune
](gremlin-results-cache.md)
+ [

# Creazione di upsert efficienti con i passaggi `mergeV()` e `mergeE()` di Gremlin
](gremlin-efficient-upserts.md)
+ [

# Creazione di upsert Gremlin efficienti con `fold()/coalesce()/unfold()`
](gremlin-efficient-upserts-pre-3.6.md)
+ [

# Analisi dell'esecuzione di query Neptune tramite la funzionalità Gremlin `explain`
](gremlin-explain.md)
+ [

# Utilizzo di Gremlin con il motore di query Neptune DFE
](gremlin-with-dfe.md)

# Configurazione della console Gremlin per la connessione a un'istanza database Neptune
<a name="access-graph-gremlin-console"></a>

La console Gremlin consente di sperimentare TinkerPop grafici e interrogazioni in un ambiente REPL (loop). read-eval-print 

## Installazione della console Gremlin e connessione ad essa nel modo consueto
<a name="access-graph-gremlin-console-usual-connect"></a>

Con la console Gremlin puoi connetterti a un database a grafo remoto. La sezione seguente illustra l'installazione e la configurazione della console Gremlin per connettersi in remoto a un'istanza database Neptune. Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

Per informazioni sulla connessione a Neptune SSL/TLS con (operazione obbligatoria), consulta. [Configurazione SSL/TLS](access-graph-gremlin-java.md#access-graph-gremlin-java-ssl)

**Nota**  
Se nel cluster database Neptune è [abilitata l'autenticazione IAM](iam-auth-enable.md), per installare la console Gremlin seguire le istruzioni riportate in [Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con la console Gremlin](iam-auth-connecting-gremlin-console.md) anziché le istruzioni riportate qui.

**Per installare la console Gremlin e connettersi a Neptune**

1. I binari della console Gremlin richiedono Java 8 o Java 11. Queste istruzioni presuppongono l'uso di Java 11. Puoi installare Java 11 sull'istanza EC2 come segue:
   + Se utilizzi [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2):

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + Se utilizzi [Amazon Linux 2023 (AL2023)](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html):

     ```
     sudo yum install java-11-amazon-corretto-devel
     ```
   + Per altre distribuzioni, usa l'opzione appropriata tra le seguenti:

     ```
     sudo yum install java-11-openjdk-devel
     ```

     oppure:

     ```
     sudo apt-get install openjdk-11-jdk
     ```

1. Per impostare Java 11 come runtime predefinito sull'istanza EC2, digita quanto segue.

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   Quando richiesto, immetti il numero per Java 11.

1. Scarica la versione appropriata della console Gremlin dal sito Web di Apache. Puoi controllare quale versione di [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md) Gremlin è supportata dalla tua versione di Neptune. Ad esempio, se hai bisogno della versione 3.7.2, puoi scaricare la [console Gremlin](https://archive.apache.org/dist/tinkerpop/3.7.2/apache-tinkerpop-gremlin-console-3.7.2-bin.zip) dal sito web di [Apache](https://tinkerpop.apache.org/download.html) Tinkerpop sulla tua istanza EC2 in questo modo:

   ```
   wget https://archive.apache.org/dist/tinkerpop/3.7.2/apache-tinkerpop-gremlin-console-3.7.2-bin.zip
   ```

1. Decomprimi il file zip della console Gremlin.

   ```
   unzip apache-tinkerpop-gremlin-console-3.7.2-bin.zip
   ```

1. Cambiare directory nella directory decompressa.

   ```
   cd apache-tinkerpop-gremlin-console-3.7.2
   ```

1. Nella sottodirectory `conf` della directory estratta, creare un file denominato `neptune-remote.yaml` con il testo seguente. Sostituisci *your-neptune-endpoint* con il nome host o l'indirizzo IP dell'istanza DB di Neptune. Le parentesi quadre (`[ ]`) sono obbligatorie.
**Nota**  
Per informazioni su come trovare il nome host dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

   ```
   hosts: [your-neptune-endpoint]
   port: 8182
   connectionPool: { enableSsl: true }
   serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1,
                 config: { serializeResultToString: true }}
   ```
**Nota**  
 I serializzatori sono stati spostati dal `gremlin-driver` modulo al nuovo `gremlin-util` modulo nella versione 3.7.0. Il pacchetto è cambiato da org.apache.tinkerpop.gremlin.driver.ser a org.apache.tinkerpop.gremlin.util.ser. 

1. In un terminale, vai alla directory della console Gremlin (`apache-tinkerpop-gremlin-console-3.7.2`) e immetti il comando seguente per eseguire la console Gremlin.

   ```
   bin/gremlin.sh
   ```

   Verrà visualizzato l’output seguente:

   ```
            \,,,/
            (o o)
   -----oOOo-(3)-oOOo-----
   plugin activated: tinkerpop.server
   plugin activated: tinkerpop.utilities
   plugin activated: tinkerpop.tinkergraph
   gremlin>
   ```

   Ora ti trovi al prompt `gremlin>`. Immetti i restanti passaggi in questo prompt.

1. Al prompt `gremlin>`, immetti quanto segue per connetterti all'istanza database Neptune.

   ```
   :remote connect tinkerpop.server conf/neptune-remote.yaml
   ```

1. Al prompt `gremlin>`, immetti quanto segue per passare alla modalità remota. In questo modo tutte le query Gremlin vengono inviate alla connessione remota.

   ```
   :remote console
   ```

1. Immetti quanto segue per inviare una query al grafo Gremlin.

   ```
   g.V().limit(1)
   ```

1. Al termine, immetti quanto segue per uscire dalla console di Gremlin.

   ```
   :exit
   ```

**Nota**  
Utilizzare un punto e virgola (`;`) o un carattere nuova riga (`\n`) per separare ogni istruzione.   
Ogni attraversamento che precede l'attraversamento finale deve terminare in `next()` per essere eseguito. Vengono restituiti solo i dati dell'ultimo attraversamento.

Per ulteriori informazioni sull'implementazione di Gremlin in Neptune, consulta [Conformità agli standard Gremlin in Amazon Neptune](access-graph-gremlin-differences.md).

# Un modo alternativo per connettersi alla console Gremlin
<a name="access-graph-gremlin-console-connect"></a>

**Svantaggi dell'approccio di connessione normale**

Il modo più comune per connettersi alla console Gremlin è quello spiegato sopra, utilizzando comandi come questo al prompt `gremlin>`.

```
gremlin> :remote connect tinkerpop.server conf/(file name).yaml
gremlin> :remote console
```

Funziona bene e consente di inviare query a Neptune. Tuttavia, esclude il motore di script Groovy dal ciclo, quindi Neptune tratta tutte le query come puro Gremlin. Ciò significa che i seguenti moduli di query hanno esito negativo:

```
gremlin> 1 + 1
gremlin> x = g.V().count()
```

La cosa più vicina all'utilizzo di una variabile quando si è connessi in questo modo è utilizzare la variabile `result` gestita dalla console e inviare la query utilizzando `:>`, in questo modo:

```
gremlin> :remote console
==>All scripts will now be evaluated locally - type ':remote console' to return to remote mode for Gremlin Server - [krl-1-cluster.cluster-ro-cm9t6tfwbtsr.us-east-1.neptune.amazonaws.com/172.31.19.217:8182]
gremlin> :> g.V().count()
==>4249

gremlin> println(result)
[result{object=4249 class=java.lang.Long}]

gremlin> println(result['object'])
[4249]
```

 

**Un modo diverso di connettersi**

Puoi anche connetterti alla console Gremlin in un modo diverso, che potresti trovare più comodo, come questo:

```
gremlin> g = traversal().withRemote('conf/neptune.properties')
```

In questo caso il formato di `neptune.properties` è il seguente:

```
gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
gremlin.remote.driver.clusterFile=conf/my-cluster.yaml
gremlin.remote.driver.sourceName=g
```

Il file `my-cluster.yaml` sarà simile al seguente:

```
hosts: [my-cluster-abcdefghijk.us-east-1.neptune.amazonaws.com]
port: 8182
serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1,
              config: { serializeResultToString: false } }
connectionPool: { enableSsl: true }
```

**Nota**  
 I serializzatori sono stati spostati dal modulo al nuovo modulo nella versione `gremlin-driver` 3.7.0. `gremlin-util` Il pacchetto è cambiato da org.apache.tinkerpop.gremlin.driver.ser a org.apache.tinkerpop.gremlin.util.ser. 

La configurazione della connessione alla console Gremlin in questo modo consente di effettuare correttamente i seguenti tipi di query:

```
gremlin> 1+1
==>2

gremlin> x=g.V().count().next()
==>4249

gremlin> println("The answer was ${x}")
The answer was 4249
```

Puoi evitare di visualizzare il risultato, in questo modo:

```
gremlin> x=g.V().count().next();[]
gremlin> println(x)
4249
```

Tutti i metodi usuali di esecuzione di query (senza il passaggio terminale) continuano a funzionare. Esempio:

```
gremlin> g.V().count()
==>4249
```

Puoi anche usare il passaggio [https://tinkerpop.apache.org/docs/current/reference/#io-step](https://tinkerpop.apache.org/docs/current/reference/#io-step) per caricare un file con questo tipo di connessione.

## Autenticazione IAM
<a name="access-graph-gremlin-console-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione dalla console Gremlin, consulta. [Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con la console Gremlin](iam-auth-connecting-gremlin-console.md)

# Utilizzo dell'endpoint HTTPS REST per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-rest"></a>

Amazon Neptune fornisce un endpoint HTTPS per le query Gremlin. L'interfaccia REST è compatibile con qualsiasi versione di Gremlin utilizzata dal cluster database (consulta la [pagina di rilascio del motore](engine-releases.md) della versione del motore Neptune che stai utilizzando per determinare quale rilascio di Gremlin supporta).

**Nota**  
Come illustrato in [Crittografia delle connessioni al tuo database Amazon Neptune con SSL/HTTPS](security-ssl.md), Neptune ora richiede la connessione tramite HTTPS anziché HTTP. Inoltre, Neptune attualmente non supporta HTTP/2 per le richieste API REST. I client devono utilizzare HTTP/1.1 per la connessione agli endpoint.

Le istruzioni seguenti mostrano come connettersi a un endpoint di Gremlin utilizzando il comando `curl` e HTTPS. Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

L'endpoint HTTPS per le query Gremlin in un'istanza database Neptune è `https://your-neptune-endpoint:port/gremlin`.

**Nota**  
Per informazioni su come trovare il nome host dell'istanza database Neptune, consulta [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

## Per connettersi a Neptune utilizzando l'endpoint HTTP REST
<a name="access-graph-gremlin-rest-connect"></a>

L'esempio seguente utilizza **curl** per inviare una query Gremlin tramite HTTP **POST**. La query viene inviata in formato JSON nel corpo del post come proprietà `gremlin`.

```
curl -X POST -d '{"gremlin":"g.V().limit(1)"}' https://your-neptune-endpoint:port/gremlin
```

Questo esempio restituisce il primo vertice nel grafo utilizzando l'attraversamento `g.V().limit(1)`. Per eseguire una query su qualcos'altro, sostituirlo con un altro attraversamento Gremlin.

**Importante**  
Per impostazione predefinita, l'endpoint REST restituisce tutti i risultati in un unico insieme di risultati JSON. Se questo insieme di risultati è troppo grande, può verificarsi un'eccezione `OutOfMemoryError` sull'istanza database Neptune.  
È possibile evitare tale problema abilitando le risposte in blocchi (risultati restituiti in una serie di risposte separate). Per informazioni, consulta [Utilizzo di intestazioni HTTP finali opzionali per abilitare le risposte Gremlin in più parti](access-graph-gremlin-rest-trailing-headers.md).

Sebbene le richieste HTTP **POST** siano consigliate per l'invio di query Gremlin, è possibile utilizzare anche le richieste HTTP **GET**:

```
curl -G "https://your-neptune-endpoint:port?gremlin=g.V().count()"
```

**Nota**  
Neptune non supporta la proprietà `bindings`.

# Utilizzo di intestazioni HTTP finali opzionali per abilitare le risposte Gremlin in più parti
<a name="access-graph-gremlin-rest-trailing-headers"></a>

Per impostazione predefinita, la risposta HTTP alle query Gremlin viene restituita in un unico insieme di risultati JSON. Nel caso di un insieme di risultati molto grande, ciò può causare un'eccezione `OutOfMemoryError` sull'istanza database.

Tuttavia, è possibile abilitare le risposte *in blocchi* (risposte restituite in più parti separate). A tale scopo, includere nella richiesta un'intestazione transfer-encoding (TE) trailers (`te: trailers`). Per ulteriori informazioni sulle intestazioni TE, vedi [la pagina MDN sulle intestazioni di richiesta TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE).

Quando una risposta viene restituita in più parti, può essere difficile diagnosticare un problema che si verifica dopo la ricezione della prima parte, poiché la prima parte arriva con il codice di stato HTTP `200` (OK). Un errore successivo di solito si traduce in un corpo del messaggio contenente una risposta danneggiata, al termine della quale Neptune aggiunge un messaggio di errore.

Per facilitare il rilevamento e la diagnosi di questo tipo di errore, Neptune include anche due nuovi campi di intestazione all'interno delle intestazioni finali di ogni blocco di risposta:
+ `X-Neptune-Status`: contiene il codice di risposta seguito da un nome breve. Ad esempio, in caso di esito positivo, l'intestazione finale sarà: `X-Neptune-Status: 200 OK`. In caso di errore, il codice di risposta sarà uno dei [codici di errore del motore Neptune](errors-engine-codes.md), ad esempio `X-Neptune-Status: 500 TimeLimitExceededException`.
+ `X-Neptune-Detail`: è vuoto per le richieste riuscite. In caso di errori, contiene il messaggio di errore JSON. Poiché nei valori di intestazione HTTP sono consentiti solo caratteri ASCII, la stringa JSON è codificata come URL.

**Nota**  
Neptune attualmente non supporta la compressione `gzip` delle risposte in blocchi. Se il client richiede contemporaneamente la codifica e la compressione in blocchi, Neptune salta la compressione.

# Client Gremlin basati su Java da utilizzare con Amazon Neptune
<a name="access-graph-gremlin-client"></a>

[Puoi utilizzare uno dei due client Gremlin open source basati su Java con Amazon Neptune: il client [Apache TinkerPop Java Gremlin o il client Gremlin](https://search.maven.org/artifact/org.apache.tinkerpop/gremlin-driver) per Amazon Neptune.](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client)

## Client Apache Java Gremlin TinkerPop
<a name="access-graph-gremlin-java-driver"></a>

Il [driver gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java) Apache TinkerPop Java è il client Gremlin standard e ufficiale che funziona con qualsiasi database grafico abilitato. TinkerPop Usa questo client quando hai bisogno della massima compatibilità con lo spazio di TinkerPop sviluppo più ampio, quando lavori con più sistemi di database a grafi o quando non hai bisogno della gestione avanzata dei cluster e delle funzionalità di bilanciamento del carico specifiche di Neptune. Questo client è adatto anche per applicazioni semplici che si connettono a una singola istanza di Neptune o quando si preferisce gestire il bilanciamento del carico a livello di infrastruttura anziché all'interno del client.

**Importante**  
La scelta della versione corretta del driver Apache TinkerPop Gremlin è fondamentale per la compatibilità con la versione del motore Neptune in uso. L'utilizzo di una versione incompatibile può causare errori di connessione o comportamenti imprevisti. Per informazioni dettagliate sulla compatibilità delle versioni, vedere. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md)

**Nota**  
La tabella che consente di determinare la TinkerPop versione di Apache corretta da utilizzare con Neptune è stata spostata in. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md) Questa tabella si trovava in precedenza in questa pagina per molti anni e ora è più centralizzata come riferimento per tutti i linguaggi di programmazione che lo supportano. TinkerPop 

## Client Java Gremlin per Amazon Neptune
<a name="access-graph-neptune-gremlin-client"></a>

Il client Gremlin per Amazon Neptune è [un client Gremlin open source basato su Java che funge da sostituto](https://github.com/aws/neptune-gremlin-client) diretto del client Java standard. TinkerPop 

Il client Gremlin di Neptune è ottimizzato per i cluster Neptune. Consente di gestire la distribuzione del traffico su più istanze di un cluster e si adatta alle modifiche della topologia del cluster quando si aggiunge o si rimuove una replica. È anche possibile configurare il client per distribuire le richieste su un sottoinsieme di istanze del cluster, in base al ruolo, al tipo di istanza, alla zona di disponibilità (AZ) o ai tag associati alle istanze.

L'[ultima versione del client Java Gremlin di Neptune](https://search.maven.org/artifact/software.amazon.neptune/gremlin-client) è disponibile su Maven Central.

Per ulteriori informazioni sul client Java Gremlin di Neptune, consulta [questo post del blog](https://aws.amazon.com/blogs/database/load-balance-graph-queries-using-the-amazon-neptune-gremlin-client/). [Per esempi di codice e demo, consulta il progetto del cliente. GitHub ](https://github.com/aws/neptune-gremlin-client)

Quando si sceglie la versione del client Neptune Gremlin, è necessario considerare la versione TinkerPop sottostante in relazione alla versione del motore Neptune. Fai riferimento alla tabella di compatibilità all'indirizzo [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md) per determinare la TinkerPop versione corretta per il tuo motore Neptune, quindi usa la tabella seguente per selezionare la versione del client Neptune Gremlin appropriata:


**Compatibilità della versione del client Neptune Gremlin**  

| Versione client Neptune Gremlin | TinkerPop versione | 
| --- | --- | 
| 3.x | 3.7.x (AWS SDK per Java 2.x/1.x) | 
| 2.1.x | 3.7.x (AWS SDK per Java 1.x) | 
| 2.0.x | 3.6.x | 
| 1.12 | 3.5.x | 

# Utilizzo di un client Java per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-java"></a>

La sezione seguente illustra l'esecuzione di un esempio Java completo che si connette a un'istanza DB di Neptune ed esegue un attraversamento di Gremlin utilizzando il client Apache Gremlin. TinkerPop

Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

**Per connettersi a Neptune tramite Java**

1. Installare Apache Maven sull'istanza EC2. Se usi Amazon Linux 2023 (preferito), usa:

   ```
   sudo dnf update -y
   sudo dnf install maven -y
   ```

   Se usi Amazon Linux 2, scarica il file binario più recente da [https://maven.apache.org/download.cgi:](https://maven.apache.org/download.cgi:)

   ```
   sudo yum remove maven -y
   wget https://dlcdn.apache.org/maven/maven-3/ <version>/binaries/apache-maven-<version>-bin.tar.gz
   sudo tar -xzf apache-maven-<version>-bin.tar.gz -C /opt/
   sudo ln -sf /opt/apache-maven-<version> /opt/maven
   echo 'export MAVEN_HOME=/opt/maven' >> ~/.bashrc
   echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> ~/.bashrc
   source ~/.bashrc
   ```

1. **Installare Java.** Le librerie Gremlin richiedono Java 8 o 11. Puoi installare Java 11 nel modo seguente:
   + Se utilizzi [Amazon Linux 2 (AL2)](https://aws.amazon.com/amazon-linux-2):

     ```
     sudo amazon-linux-extras install java-openjdk11
     ```
   + Se utilizzi [Amazon Linux 2023 (AL2023)](https://docs.aws.amazon.com/linux/al2023/ug/what-is-amazon-linux.html):

     ```
     sudo yum install java-11-amazon-corretto-devel
     ```
   + Per altre distribuzioni, usa l'opzione appropriata tra le seguenti:

     ```
     sudo yum install java-11-openjdk-devel
     ```

     oppure:

     ```
     sudo apt-get install openjdk-11-jdk
     ```

1. **Imposta Java 11 come runtime predefinito sull'istanza EC2:** inserisci quanto segue per impostare Java 8 come runtime predefinito sull'stanza EC2:

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   Quando richiesto, immetti il numero per Java 11.

1. **Crea una nuova directory denominata `gremlinjava`:**

   ```
   mkdir gremlinjava
   cd gremlinjava
   ```

1.  Nella directory `gremlinjava`, creare un file `pom.xml`, quindi aprirlo in un editor di testo:

   ```
   nano pom.xml
   ```

1. Copiare quanto segue nel file `pom.xml` e salvare:

   ```
   <project xmlns="https://maven.apache.org/POM/4.0.0"
            xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
     <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.amazonaws</groupId>
     <artifactId>GremlinExample</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>GremlinExample</name>
     <url>https://maven.apache.org</url>
     <dependencies>
       <dependency>
         <groupId>org.apache.tinkerpop</groupId>
         <artifactId>gremlin-driver</artifactId>
         <version>3.7.2</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-jdk14</artifactId>
         <version>1.7.25</version>
       </dependency>
     </dependencies>
     <build>
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.5.1</version>
           <configuration>
             <source>11</source>
             <target>11</target>
           </configuration>
         </plugin>
           <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>exec-maven-plugin</artifactId>
             <version>1.3</version>
             <configuration>
               <executable>java</executable>
               <arguments>
                 <argument>-classpath</argument>
                 <classpath/>
                 <argument>com.amazonaws.App</argument>
               </arguments>
               <mainClass>com.amazonaws.App</mainClass>
               <complianceLevel>1.11</complianceLevel>
               <killAfter>-1</killAfter>
             </configuration>
           </plugin>
       </plugins>
     </build>
   </project>
   ```
**Nota**  
Se stai modificando un progetto Maven esistente, la dipendenza necessaria è evidenziata nel codice precedente.

1. Creare sottodirectory per il codice sorgente di esempio (`src/main/java/com/amazonaws/`) digitando quanto segue nella riga di comando:

   ```
   mkdir -p src/main/java/com/amazonaws/
   ```

1. Nella directory `src/main/java/com/amazonaws/`, creare un file denominato `App.java`, quindi aprirlo in un editor di testo.

   ```
   nano src/main/java/com/amazonaws/App.java
   ```

1. Copiare quanto segue nel file `App.java`. Sostituisci *your-neptune-endpoint* con l'indirizzo della tua istanza DB Neptune. *Non* includere il prefisso `https://` nel metodo `addContactPoint`.
**Nota**  
Per informazioni su come trovare il nome host dell'istanza database Neptune, consulta [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

   ```
   package com.amazonaws;
   import org.apache.tinkerpop.gremlin.driver.Cluster;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
   import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
   import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection;
   import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
   import org.apache.tinkerpop.gremlin.structure.T;
   
   public class App
   {
     public static void main( String[] args )
     {
       Cluster.Builder builder = Cluster.build();
       builder.addContactPoint("your-neptune-endpoint");
       builder.port(8182);
       builder.enableSsl(true);
   
       Cluster cluster = builder.create();
   
       GraphTraversalSource g = traversal().withRemote(DriverRemoteConnection.using(cluster));
   
       // Add a vertex.
       // Note that a Gremlin terminal step, e.g. iterate(), is required to make a request to the remote server.
       // The full list of Gremlin terminal steps is at https://tinkerpop.apache.org/docs/current/reference/#terminal-steps
       g.addV("Person").property("Name", "Justin").iterate();
   
       // Add a vertex with a user-supplied ID.
       g.addV("Custom Label").property(T.id, "CustomId1").property("name", "Custom id vertex 1").iterate();
       g.addV("Custom Label").property(T.id, "CustomId2").property("name", "Custom id vertex 2").iterate();
   
       g.addE("Edge Label").from(__.V("CustomId1")).to(__.V("CustomId2")).iterate();
   
       // This gets the vertices, only.
       GraphTraversal t = g.V().limit(3).elementMap();
   
       t.forEachRemaining(
         e ->  System.out.println(t.toList())
       );
   
       cluster.close();
     }
   }
   ```

   Per informazioni sulla connessione a Neptune SSL/TLS con (operazione obbligatoria), consulta. [Configurazione SSL/TLS](#access-graph-gremlin-java-ssl)

1. Compilare ed eseguire il campione usando il comando Maven seguente:

   ```
   mvn compile exec:exec
   ```

L'esempio precedente restituisce una mappa della chiave e i valori di ogni proprietà per i primi due vertici nel grafo utilizzando l'attraversamento `g.V().limit(3).elementMap()`. Per eseguire query per qualcos'altro, sostituirla con un altro attraversamento Gremlin con uno dei metodi finali appropriati.

**Nota**  
La parte finale della query Gremlin, `.toList()` è obbligatoria per inviare l'attraversamento al server per la valutazione. Se non includi quel metodo o un altro metodo equivalente, la query non viene inviata all'istanza database Neptune.  
È inoltre necessario aggiungere una chiusura appropriata quando si aggiunge un vertice o un arco, ad esempio quando si utilizza il passaggio `addV( )`.

I metodi riportati sotto inviano la query all'istanza database Neptune:
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

## Configurazione SSL/TLS per il client Java Gremlin
<a name="access-graph-gremlin-java-ssl"></a>

Neptune SSL/TLS deve essere abilitato per impostazione predefinita. In genere, se il driver Java è configurato con `enableSsl(true)`, può connettersi a Neptune senza dover impostare `trustStore()` o `keyStore()` con una copia locale di un certificato.

Tuttavia, se l'istanza con cui ti stai connettendo non dispone di una connessione Internet tramite la quale verificare un certificato pubblico o se il certificato che stai utilizzando non è pubblico, puoi effettuare le seguenti operazioni per configurare una copia locale del certificato:

**Configurazione di una copia locale del certificato per abilitare SSL/TLS**

1. Scarica e installa [keytool](https://docs.oracle.com/javase/9/tools/keytool.htm#JSWOR-GUID-5990A2E4-78E3-47B7-AE75-6D1826259549) da Oracle. Ciò renderà molto più semplice la configurazione dell'archivio chiavi locale.

1. Scarica il certificato CA `SFSRootCAG2.pem` (l'SDK Gremlin Java richiede un certificato per verificare il certificato remoto):

   ```
   wget https://www.amazontrust.com/repository/SFSRootCAG2.pem
   ```

1. Crea un archivio di chiavi in formato JKS o. PKCS12 Questo esempio usa JKS. Rispondi alle domande che seguono al prompt. La password che crei qui sarà necessaria in seguito:

   ```
   keytool -genkey -alias (host name) -keyalg RSA -keystore server.jks
   ```

1. Importa il file `SFSRootCAG2.pem` che hai scaricato nell'archivio chiavi appena creato:

   ```
   keytool -import -keystore server.jks -file .pem
   ```

1. Configura l'oggetto `Cluster` a livello di codice:

   ```
   Cluster cluster = Cluster.build("(your neptune endpoint)")
                            .port(8182)
                            .enableSSL(true)
                            .keyStore(‘server.jks’)
                            .keyStorePassword("(the password from step 2)")
                            .create();
   ```

   Si può fare la stessa cosa in un file di configurazione, come è possibile fare con la console Gremlin:

   ```
   hosts: [(your neptune endpoint)]
   port: 8182
   connectionPool: { enableSsl: true, keyStore: server.jks, keyStorePassword: (the password from step 2) }
   serializer: { className: org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
   ```

## Autenticazione IAM
<a name="access-graph-gremlin-java-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione da un client Java, consulta[Connessione ai database Amazon Neptune tramite IAM con Gremlin Java](iam-auth-connecting-gremlin-java.md).

# Esempio Java di connessione a un'istanza database Neptune con logica di riconnessione
<a name="access-graph-gremlin-java-reconnect-example"></a>

Il seguente esempio Java mostra come connettersi al client Gremlin con la logica di riconnessione per eseguire il ripristino in seguito a una disconnessione imprevista.

Presenta le seguenti dipendenze:

```
<dependency>
    <groupId>org.apache.tinkerpop</groupId>
    <artifactId>gremlin-driver</artifactId>
    <version>${gremlin.version}</version>
</dependency>

<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>amazon-neptune-sigv4-signer</artifactId>
    <version>${sig4.signer.version}</version>
</dependency>

<dependency>
    <groupId>com.evanlennick</groupId>
    <artifactId>retry4j</artifactId>
    <version>0.15.0</version>
</dependency>
```

Ecco il codice di esempio:

**Importante**  
 L'executor `CallExecutor` di Retry4j potrebbe non essere thread-safe. Prendi in considerazione l'idea di fare in modo che ogni thread utilizzi la propria `CallExecutor` istanza o utilizzi una libreria di riprova diversa. 

**Nota**  
 L'esempio seguente è stato aggiornato per includere l'uso di requestInterceptor (). Questo è stato aggiunto nella versione 3.6.6. TinkerPop Prima della TinkerPop versione 3.6.6, l'esempio di codice utilizzava handshakeInterceptor (), che era obsoleto in quella versione. 

```
public static void main(String args[]) {
  boolean useIam = true;

  // Create Gremlin cluster and traversal source
  Cluster.Builder builder = Cluster.build()
         .addContactPoint(System.getenv("neptuneEndpoint"))
         .port(Integer.parseInt(System.getenv("neptunePort")))
         .enableSsl(true)
         .minConnectionPoolSize(1)
         .maxConnectionPoolSize(1)
         .serializer(Serializers.GRAPHBINARY_V1D0)
         .reconnectInterval(2000);

  if (useIam) {
      builder.requestInterceptor( r -> {
         try {
            NeptuneNettyHttpSigV4Signer sigV4Signer =
                        new NeptuneNettyHttpSigV4Signer("(your region)", new DefaultAWSCredentialsProviderChain());
            sigV4Signer.signRequest(r);
         } catch (NeptuneSigV4SignerException e) {
            throw new RuntimeException("Exception occurred while signing the request", e);
         }
         return r;
      });
   }

  Cluster cluster = builder.create();

  GraphTraversalSource g = AnonymousTraversalSource
      .traversal()
      .withRemote(DriverRemoteConnection.using(cluster));

  // Configure retries
  RetryConfig retryConfig = new RetryConfigBuilder()
      .retryOnCustomExceptionLogic(getRetryLogic())
      .withDelayBetweenTries(1000, ChronoUnit.MILLIS)
      .withMaxNumberOfTries(5)
      .withFixedBackoff()
      .build();

  @SuppressWarnings("unchecked")
  CallExecutor<Object> retryExecutor = new CallExecutorBuilder<Object>()
      .config(retryConfig)
      .build();

  // Do lots of queries
  for (int i = 0; i < 100; i++){
    String id = String.valueOf(i);

    @SuppressWarnings("unchecked")
    Callable<Object> query = () -> g.V(id)
        .fold()
        .coalesce(
            unfold(),
            addV("Person").property(T.id, id))
        .id().next();

    // Retry query
    // If there are connection failures, the Java Gremlin client will automatically
    // attempt to reconnect in the background, so all we have to do is wait and retry.
    Status<Object> status = retryExecutor.execute(query);

    System.out.println(status.getResult().toString());
  }

  cluster.close();
}

private static Function<Exception, Boolean> getRetryLogic() {

  return e -> {

    Class<? extends Exception> exceptionClass = e.getClass();

    StringWriter stringWriter = new StringWriter();
    String message = stringWriter.toString();


    if (RemoteConnectionException.class.isAssignableFrom(exceptionClass)){
      System.out.println("Retrying because RemoteConnectionException");
      return true;
    }

    // Check for connection issues
    if (message.contains("Timed out while waiting for an available host") ||
        message.contains("Timed-out") && message.contains("waiting for connection on Host") ||
        message.contains("Connection to server is no longer active") ||
        message.contains("Connection reset by peer") ||
        message.contains("SSLEngine closed already") ||
        message.contains("Pool is shutdown") ||
        message.contains("ExtendedClosedChannelException") ||
        message.contains("Broken pipe") ||
        message.contains(System.getenv("neptuneEndpoint")))
    {
      System.out.println("Retrying because connection issue");
      return true;
    };

    // Concurrent writes can sometimes trigger a ConcurrentModificationException.
    // In these circumstances you may want to backoff and retry.
    if (message.contains("ConcurrentModificationException")) {
      System.out.println("Retrying because ConcurrentModificationException");
      return true;
    }

    // If the primary fails over to a new instance, existing connections to the old primary will
    // throw a ReadOnlyViolationException. You may want to back and retry.
    if (message.contains("ReadOnlyViolationException")) {
      System.out.println("Retrying because ReadOnlyViolationException");
      return true;
    }

    System.out.println("Not a retriable error");
    return false;
  };
}
```

# Utilizzo di Python per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-python"></a>

**Importante**  
La scelta della versione corretta del driver Apache TinkerPop Gremlin è fondamentale per la compatibilità con la versione del motore Neptune in uso. L'utilizzo di una versione incompatibile può causare errori di connessione o comportamenti imprevisti. Per informazioni dettagliate sulla compatibilità delle versioni, vedere. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md)

La sezione seguente illustra come eseguire un esempio Python che si connette a un'istanza database Amazon Neptune ed esegue un attraversamento Gremlin.

Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

Prima di iniziare, esegui queste attività:
+ Scarica e installa Python 3.6 o versione successiva dal [sito Web Python.org](https://www.python.org/downloads/).
+ Verificare di aver installato **pip**. Se non si dispone di **pip** o non si è sicuri, consultare [Do I need to install pip? (Devo installare pip?)](https://pip.pypa.io/en/stable/installing/#do-i-need-to-install-pip) nella documentazione **pip**.
+ Se l'installazione Python non lo comprende già, scaricare `futures` come segue: `pip install futures`



**Per connettersi a Neptune tramite Python**

1. Installare il pacchetto `gremlinpython` immettendo quanto segue:

   ```
   pip install --user gremlinpython
   ```

1. Creare un file denominato `gremlinexample.py`, quindi aprirlo in un editor di testo.

1. Copiare quanto segue nel file `gremlinexample.py`. Sostituisci *your-neptune-endpoint* con l'indirizzo del tuo cluster Neptune DB *your-neptune-port* e con la porta del tuo cluster Neptune DB (impostazione predefinita: 8182). 

   Per informazioni su come trovare l'indirizzo dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

    L'esempio seguente mostra come connettersi con Gremlin Python. 

   ```
   import boto3
   import os
   from botocore.auth import SigV4Auth
   from botocore.awsrequest import AWSRequest
   from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
   from gremlin_python.process.anonymous_traversal import traversal
   
   database_url = "wss://your-neptune-endpoint:your-neptune-port/gremlin"
   
   remoteConn = DriverRemoteConnection(database_url, "g")
   
   g = traversal().withRemote(remoteConn)
   
   print(g.inject(1).toList())
   remoteConn.close()
   ```

1. Immettere il comando seguente per eseguire l'esempio:

   ```
   python gremlinexample.py
   ```

   La query Gremlin alla fine di questo esempio restituisce i vertici (`g.V().limit(2)`) in un elenco. Questo elenco viene quindi stampato con la funzione Python standard `print`.
**Nota**  
La parte finale della query Gremlin, `toList()` è obbligatoria per inviare l'attraversamento al server per la valutazione. Se non includi quel metodo o un altro metodo equivalente, la query non viene inviata all'istanza database Neptune.

   I metodi riportati sotto inviano la query all'istanza database Neptune:
   + `toList()`
   + `toSet()`
   + `next()`
   + `nextTraverser()`
   + `iterate()`

   

   L'esempio precedente restituisce i primi due vertici del grafo utilizzando l'attraversamento `g.V().limit(2).toList()`. Per eseguire query per qualcos'altro, sostituirla con un altro attraversamento Gremlin con uno dei metodi finali appropriati.

## Autenticazione IAM
<a name="access-graph-gremlin-python-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione da un client Python, vedere. [Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con Gremlin Python](gremlin-python-iam-auth.md)

# Utilizzo di .NET per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-dotnet"></a>

**Importante**  
La scelta della versione corretta del driver Apache TinkerPop Gremlin è fondamentale per la compatibilità con la versione del motore Neptune in uso. L'utilizzo di una versione incompatibile può causare errori di connessione o comportamenti imprevisti. Per informazioni dettagliate sulla compatibilità delle versioni, vedere. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md)

La sezione seguente contiene un codice di esempio scritto in C \$1 che si connette a un'istanza database Neptune ed esegue un attraversamento Gremlin.

Le connessioni ad Amazon Neptune devono provenire da un'istanza Amazon EC2 che si trova nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune. Questo codice di esempio è stato testato su un'istanza Amazon EC2 che esegue Ubuntu.

Prima di iniziare, esegui queste attività:
+ Installa .NET sull'istanza Amazon EC2. Per istruzioni su come installare .NET su sistemi operativi multipli, incluso Windows, Linux e macOS, vedere [Get Started with .NET](https://www.microsoft.com/net/learn/get-started/).
+ Installa Gremlin.NET eseguendo `dotnet add package gremlin.net` per il tuo pacchetto. Per ulteriori informazioni, consulta [Gremlin.NET nella documentazione](https://tinkerpop.apache.org/docs/current/reference/#gremlin-DotNet). TinkerPop 



**Per connettersi a Neptune utilizzando Gremlin.NET**

1. Crea un nuovo progetto .NET.

   ```
   dotnet new console -o gremlinExample
   ```

1. Spostare le directory nella nuova directory di progetto.

   ```
   cd gremlinExample
   ```

1. Copiare quanto segue nel file `Program.cs`. Sostituisci *your-neptune-endpoint* con l'indirizzo della tua istanza DB Neptune.

   Per informazioni su come trovare l'indirizzo dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

   ```
   using System;
   using System.Threading.Tasks;
   using System.Collections.Generic;
   using Gremlin.Net;
   using Gremlin.Net.Driver;
   using Gremlin.Net.Driver.Remote;
   using Gremlin.Net.Structure;
   using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;
   namespace gremlinExample
   {
     class Program
     {
       static void Main(string[] args)
       {
         try
         {
           var endpoint = "your-neptune-endpoint";
           // This uses the default Neptune and Gremlin port, 8182
           var gremlinServer = new GremlinServer(endpoint, 8182, enableSsl: true );
           var gremlinClient = new GremlinClient(gremlinServer);
           var remoteConnection = new DriverRemoteConnection(gremlinClient, "g");
           var g = Traversal().WithRemote(remoteConnection);
           g.AddV("Person").Property("Name", "Justin").Iterate();
           g.AddV("Custom Label").Property("name", "Custom id vertex 1").Iterate();
           g.AddV("Custom Label").Property("name", "Custom id vertex 2").Iterate();
           var output = g.V().Limit<Vertex>(3).ToList();
           foreach(var item in output) {
               Console.WriteLine(item);
           }
         }
         catch (Exception e)
         {
             Console.WriteLine("{0}", e);
         }
       }
     }
   }
   ```

1. Immettere il comando seguente per eseguire l'esempio:

   ```
   dotnet run
   ```

   La query Gremlin alla fine di questo esempio restituisce il conteggio di un singolo vertice a scopo di test. Viene quindi stampata sulla console.
**Nota**  
La parte finale della query Gremlin, `Next()` è obbligatoria per inviare l'attraversamento al server per la valutazione. Se non includi quel metodo o un altro metodo equivalente, la query non viene inviata all'istanza database Neptune.

   I metodi riportati sotto inviano la query all'istanza database Neptune:
   + `ToList()`
   + `ToSet()`
   + `Next()`
   + `NextTraverser()`
   + `Iterate()`

   Utilizza `Next()` se hai bisogno che i risultati della query vengano serializzati e restituiti oppure `Iterate()` in caso contrario.

   L'esempio precedente restituisce un elenco utilizzando l'attraversamento `g.V().Limit(3).ToList()`. Per eseguire query per qualcos'altro, sostituirla con un altro attraversamento Gremlin con uno dei metodi finali appropriati.

## Autenticazione IAM
<a name="access-graph-gremlin-dotnet-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione da un client.NET, consulta[Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con Gremlin.NET](gremlin-dotnet-iam-auth.md).

# Utilizzo di Node.js per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-node-js"></a>

**Importante**  
La scelta della versione corretta del driver Apache TinkerPop Gremlin è fondamentale per la compatibilità con la versione del motore Neptune in uso. L'utilizzo di una versione incompatibile può causare errori di connessione o comportamenti imprevisti. Per informazioni dettagliate sulla compatibilità delle versioni, vedere. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md)

La sezione seguente illustra come eseguire un esempio Node.js che si connette a un'istanza database Amazon Neptune ed esegue un attraversamento Gremlin.

Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

Prima di iniziare, esegui queste attività:
+ Verificare che Node.js versione 8.11 o successiva sia installato. In caso contrario, scaricare e installare Node.js dal [sito Web Nodejs.org](https://nodejs.org).

**Per connettersi a Neptune tramite Node.js**

1. Installare il pacchetto `gremlin-javascript` immettendo quanto segue:

   ```
   npm install gremlin
   ```

1. Creare un file denominato `gremlinexample.js` e aprirlo in un editor di testo.

1. Copiare quanto segue nel file `gremlinexample.js`. Sostituisci *your-neptune-endpoint* con l'indirizzo della tua istanza DB Neptune.

   Per informazioni su come trovare l'indirizzo dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

   ```
   const gremlin = require('gremlin');
   const DriverRemoteConnection = gremlin.driver.DriverRemoteConnection;
   const Graph = gremlin.structure.Graph;
   
   dc = new DriverRemoteConnection('wss://your-neptune-endpoint:8182/gremlin',{});
   
   const graph = new Graph();
   const g = graph.traversal().withRemote(dc);
   
   g.V().limit(1).count().next().
       then(data => {
           console.log(data);
           dc.close();
       }).catch(error => {
           console.log('ERROR', error);
           dc.close();
       });
   ```

1. Immettere il comando seguente per eseguire l'esempio:

   ```
   node gremlinexample.js
   ```

L'esempio precedente restituisce il conteggio di un singolo vertice nel grafo utilizzando l'attraversamento `g.V().limit(1).count().next()`. Per eseguire query per qualcos'altro, sostituirla con un altro attraversamento Gremlin con uno dei metodi finali appropriati.

**Nota**  
La parte finale della query Gremlin, `next()` è obbligatoria per inviare l'attraversamento al server per la valutazione. Se non includi quel metodo o un altro metodo equivalente, la query non viene inviata all'istanza database Neptune.

I metodi riportati sotto inviano la query all'istanza database Neptune:
+ `toList()`
+ `toSet()`
+ `next()`
+ `nextTraverser()`
+ `iterate()`

Utilizza `next()` se hai bisogno che i risultati della query vengano serializzati e restituiti oppure `iterate()` in caso contrario.

**Importante**  
Questo è un esempio Node.js standalone. Se hai intenzione di eseguire codice come questo in una AWS Lambda funzione, consulta [Esempi di funzione Lambda](lambda-functions-examples.md) per i dettagli sull'utilizzo JavaScript efficiente in una funzione Neptune Lambda.

## Autenticazione IAM
<a name="access-graph-gremlin-nodejs-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione da un JavaScript client, consulta[Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con Gremlin JavaScript](gremlin-javascript-iam-auth.md).

# Utilizzo di Go per connettersi a un'istanza database Neptune
<a name="access-graph-gremlin-go"></a>

**Importante**  
La scelta della versione corretta del driver Apache TinkerPop Gremlin è fondamentale per la compatibilità con la versione del motore Neptune in uso. L'utilizzo di una versione incompatibile può causare errori di connessione o comportamenti imprevisti. Per informazioni dettagliate sulla compatibilità delle versioni, vedere. [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md)

**Nota**  
Le versioni di gremlingo 3.5.x sono retrocompatibili con le versioni TinkerPop 3.4.x purché si utilizzino solo le funzionalità 3.4.x nelle query Gremlin che scrivi.

La sezione seguente illustra come eseguire un esempio Go che si connette a un'istanza database Amazon Neptune ed esegue un attraversamento Gremlin.

Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

Prima di iniziare, esegui queste attività:
+ Scarica e installa Go 1.17 o versioni successive dal sito Web [go.dev](https://go.dev/dl/).

**Per connettersi a Neptune tramite Go**

1. Partendo da una directory vuota, inizializza un nuovo modulo Go:

   ```
   go mod init example.com/gremlinExample
   ```

1. Aggiungi gremlin-go come dipendenza del nuovo modulo:

   ```
   go get github.com/apache/tinkerpop/gremlin-go/v3/driver
   ```

1. Crea un file denominato `gremlinExample.go`, quindi aprilo in un editor di testo.

1. Copia quanto segue nel file `gremlinExample.go`, sostituendo *`(your neptune endpoint)`* con l'indirizzo della tua istanza database Neptune:

   ```
   package main
   
   import (
     "fmt"
     gremlingo "github.com/apache/tinkerpop/gremlin-go/v3/driver"
   )
   
   func main() {
     // Creating the connection to the server.
     driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("wss://(your neptune endpoint):8182/gremlin",
       func(settings *gremlingo.DriverRemoteConnectionSettings) {
         settings.TraversalSource = "g"
       })
     if err != nil {
       fmt.Println(err)
       return
     }
     // Cleanup
     defer driverRemoteConnection.Close()
   
     // Creating graph traversal
     g := gremlingo.Traversal_().WithRemote(driverRemoteConnection)
   
     // Perform traversal
     results, err := g.V().Limit(2).ToList()
     if err != nil {
       fmt.Println(err)
       return
     }
     // Print results
     for _, r := range results {
       fmt.Println(r.GetString())
     }
   }
   ```
**Nota**  
Il formato del certificato TLS Neptune non è attualmente supportato su Go 1.18\$1 con macOS e potrebbe restituire un errore 509 quando si tenta di avviare una connessione. Per i test locali, questo può essere ignorato aggiungendo "crypto/tls" alle importazioni e modificando le impostazioni `DriverRemoteConnection` come segue:  

   ```
   // Creating the connection to the server.
   driverRemoteConnection, err := gremlingo.NewDriverRemoteConnection("wss://your-neptune-endpoint:8182/gremlin",
     func(settings *gremlingo.DriverRemoteConnectionSettings) {
         settings.TraversalSource = "g"
         settings.TlsConfig = &tls.Config{InsecureSkipVerify: true}
     })
   ```

1. Immettere il comando seguente per eseguire l'esempio:

   ```
   go run gremlinExample.go
   ```

La query Gremlin alla fine di questo esempio restituisce i vertici `(g.V().Limit(2))` in una sezione. Questa sezione viene quindi ripetuta e stampata con la funzione standard `fmt.Println`.

**Nota**  
La parte finale della query Gremlin, `ToList()` è obbligatoria per inviare l'attraversamento al server per la valutazione. Se non includi quel metodo o un altro metodo equivalente, la query non viene inviata all'istanza database Neptune.

I metodi riportati sotto inviano la query all'istanza database Neptune:
+ `ToList()`
+ `ToSet()`
+ `Next()`
+ `GetResultSet()`
+ `Iterate()`

L'esempio precedente restituisce i primi due vertici del grafo utilizzando l'attraversamento `g.V().Limit(2).ToList()`. Per eseguire query per qualcos'altro, sostituirla con un altro attraversamento Gremlin con uno dei metodi finali appropriati.

## Autenticazione IAM
<a name="access-graph-gremlin-go-iam"></a>

Neptune [supporta l'autenticazione IAM](iam-auth-enable.md) per controllare l'accesso al cluster DB. Se hai abilitato l'autenticazione IAM, devi utilizzare la firma Signature Version 4 per autenticare le tue richieste. Per istruzioni dettagliate ed esempi di codice per la connessione da un client Go, consulta[Connessione ai database Amazon Neptune utilizzando l'autenticazione IAM con Gremlin Go](gremlin-go-iam-auth.md).

# Utilizzo dell' AWS SDK per eseguire le query Gremlin
<a name="access-graph-gremlin-sdk"></a>

Con l' AWS SDK, puoi eseguire query Gremlin sul tuo grafico di Neptune utilizzando un linguaggio di programmazione a tua scelta. L'SDK dell'API dati Neptune (`neptunedata`nome del servizio) fornisce l'azione per inviare [ExecuteGremlinQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteGremlinQuery.html)le query Gremlin.

È necessario eseguire questi esempi da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) del cluster Neptune DB o da una posizione che dispone di connettività di rete all'endpoint del cluster.

Di seguito sono disponibili collegamenti diretti alla documentazione di riferimento dell'API per il `neptunedata` servizio in ogni lingua SDK:


| Linguaggio di programmazione | Riferimento all'API neptunedata | 
| --- | --- | 
| C\$1\$1 | [https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html](https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html) | 
| Go | [https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/](https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/) | 
| Java | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html) | 
| JavaScript | [https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/) | 
| Kotlin | [https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html](https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html) | 
| .NET | [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html) | 
| PHP | [https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html](https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html) | 
| Python | [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html) | 
| Ruby | [https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html) | 
| Rust | [https://crates.io/crates/aws-sdk-neptunedata](https://crates.io/crates/aws-sdk-neptunedata) | 
| CLI | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

## Esempi di Gremlin AWS SDK
<a name="access-graph-gremlin-sdk-examples"></a>

Gli esempi seguenti mostrano come configurare un `neptunedata` client, eseguire una query Gremlin e stampare i risultati. Sostituisci *YOUR\$1NEPTUNE\$1HOST* e *YOUR\$1NEPTUNE\$1PORT* con l'endpoint e la porta del tuo cluster Neptune DB.

**Timeout lato client e nuovo tentativo di configurazione**  
*Il timeout del client SDK controlla per quanto tempo il client attende una risposta.* Non controlla per quanto tempo viene eseguita la query sul server. Se il client scade prima del termine del server, la query può continuare a essere eseguita su Neptune mentre il client non ha modo di recuperare i risultati.  
[Ti consigliamo di impostare il timeout di lettura lato client su `0` (nessun timeout) o su un valore che sia almeno qualche secondo più lungo rispetto all'impostazione neptune\$1query\$1timeout lato server sul tuo cluster Neptune DB.](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) Ciò consente a Neptune di controllare il timeout delle query.  
Consigliamo inoltre di impostare il numero massimo di tentativi su `1` (nessun tentativo). Se l'SDK riprova a eseguire una query ancora in esecuzione sul server, le operazioni possono essere duplicate. Ciò è particolarmente importante per le query di mutazione, in cui un nuovo tentativo potrebbe causare scritture duplicate non intenzionali.

------
#### [ Python ]

1. Segui le istruzioni di [installazione per installare Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html).

1. Crea un file denominato `gremlinExample.py` e incolla il seguente codice:

   ```
   import boto3
   import json
   from botocore.config import Config
   
   # Disable the client-side read timeout and retries so that
   # Neptune's server-side neptune_query_timeout controls query duration.
   client = boto3.client(
       'neptunedata',
       endpoint_url=f'https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT',
       config=Config(read_timeout=None, retries={'total_max_attempts': 1})
   )
   
   # Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   response = client.execute_gremlin_query(
       gremlinQuery='g.V().limit(1)',
       serializer='application/vnd.gremlin-v3.0+json;types=false'
   )
   
   print(json.dumps(response['result'], indent=2))
   ```

1. Esegui l'esempio: `python gremlinExample.py`

------
#### [ Java ]

1. Segui le [istruzioni di installazione](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) per configurare l' AWS SDK for Java.

1. Utilizzate il codice seguente per configurare`NeptunedataClient`, eseguire una query Gremlin e stampare il risultato:

   ```
   import java.net.URI;
   import java.time.Duration;
   import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
   import software.amazon.awssdk.core.retry.RetryPolicy;
   import software.amazon.awssdk.services.neptunedata.NeptunedataClient;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteGremlinQueryRequest;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteGremlinQueryResponse;
   
   // Disable the client-side timeout and retries so that
   // Neptune's server-side neptune_query_timeout controls query duration.
   NeptunedataClient client = NeptunedataClient.builder()
       .endpointOverride(URI.create("https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT"))
       .overrideConfiguration(ClientOverrideConfiguration.builder()
           .apiCallTimeout(Duration.ZERO)
           .retryPolicy(RetryPolicy.none())
           .build())
       .build();
   
   // Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   ExecuteGremlinQueryRequest request = ExecuteGremlinQueryRequest.builder()
       .gremlinQuery("g.V().limit(1)")
       .serializer("application/vnd.gremlin-v3.0+json;types=false")
       .build();
   
   ExecuteGremlinQueryResponse response = client.executeGremlinQuery(request);
   
   System.out.println(response.result().toString());
   ```

------
#### [ JavaScript ]

1. Segui le [istruzioni di installazione](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) per configurare l' AWS SDK per. JavaScript Installa il pacchetto client neptunedata:. `npm install @aws-sdk/client-neptunedata`

1. Crea un file denominato `gremlinExample.js` e incolla il seguente codice:

   ```
   import { NeptunedataClient, ExecuteGremlinQueryCommand } from "@aws-sdk/client-neptunedata";
   import { NodeHttpHandler } from "@smithy/node-http-handler";
   
   const config = {
       endpoint: "https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT",
       // Disable the client-side request timeout so that
       // Neptune's server-side neptune_query_timeout controls query duration.
       requestHandler: new NodeHttpHandler({
           requestTimeout: 0
       }),
       maxAttempts: 1
   };
   
   const client = new NeptunedataClient(config);
   
   // Use the untyped GraphSON v3 serializer for a cleaner JSON response.
   const input = {
       gremlinQuery: "g.V().limit(1)",
       serializer: "application/vnd.gremlin-v3.0+json;types=false"
   };
   
   const command = new ExecuteGremlinQueryCommand(input);
   const response = await client.send(command);
   
   console.log(JSON.stringify(response, null, 2));
   ```

1. Esegui l'esempio: `node gremlinExample.js`

------

# Hint di query Gremlin
<a name="gremlin-query-hints"></a>

Puoi usare gli hint di query per specificare le strategie di ottimizzazione e valutazione per una particolare query Gremlin in Amazon Neptune. 

Gli hint di query vengono specificati aggiungendo un passaggio `withSideEffect` alla query con la seguente sintassi.

```
g.withSideEffect(hint, value)
```
+ *hint*: identifica il tipo di hint da applicare.
+ *value*: determina il comportamento dell'aspetto del sistema in esame.

Ad esempio, di seguito è indicato come includere un hint `repeatMode` in un attraversamento Gremlin.

**Nota**  
Tutti gli hint di query Gremlin sono preceduti da `Neptune#`.

```
g.withSideEffect('Neptune#repeatMode', 'DFS').V("3").repeat(out()).times(10).limit(1).path()
```

La query precedente indica al motore Neptune di attraversare il grafo *Depth First* (`DFS`) anziché il grafo Neptune predefinito, *Breadth First* (`BFS`).

Nelle seguenti sezioni sono fornite ulteriori informazioni sugli hint di query disponibili e sul relativo utilizzo.

**Topics**
+ [

# Hint di query Gremlin repeatMode
](gremlin-query-hints-repeatMode.md)
+ [

# Hint di query Gremlin noReordering
](gremlin-query-hints-noReordering.md)
+ [

# Hint di query Gremlin typePromotion
](gremlin-query-hints-typePromotion.md)
+ [

# Hint di query Gremlin useDFE
](gremlin-query-hints-useDFE.md)
+ [

# Hint di query Gremlin per l'utilizzo della cache dei risultati
](gremlin-query-hints-results-cache.md)

# Hint di query Gremlin repeatMode
<a name="gremlin-query-hints-repeatMode"></a>

L'hint di query Neptune `repeatMode` specifica come il motore Neptune valuta il passaggio `repeat()` in un attraversamento Gremlin: breadth first, depth first o chunked depth first.

La modalità di valutazione del passaggio `repeat()` è importante quando si usa per trovare o seguire un percorso, anziché ripetere un passaggio per un numero limitato di volte.

## Sintassi
<a name="gremlin-query-hints-repeatMode-syntax"></a>

L'hint di query `repeatMode` si specifica aggiungendo un passaggio `withSideEffect` alla query.

```
g.withSideEffect('Neptune#repeatMode', 'mode').gremlin-traversal
```

**Nota**  
Tutti gli hint di query Gremlin sono preceduti da `Neptune#`.

**Modalità disponibili**
+ `BFS`

  Breadth-First Search

  Modalità di esecuzione predefinita del passaggio `repeat()`. In tal modo si ottengono tutti i nodi di pari livello prima di procedere lungo il percorso.

  Questa versione richiede molta memoria e le frontiere possono diventare molto grandi. Esiste un rischio elevato che la query esaurisca la memoria e venga annullata dal motore Neptune. Questo caso si applica più strettamente ad altre implementazioni Gremlin.
+ `DFS`

  Depth-First Search

  Segue ogni percorso alla profondità massima prima di passare alla soluzione successiva.

  Questa soluzione utilizza meno memoria. Può fornire prestazioni migliori in situazioni quali la ricerca di un singolo percorso partendo da un hop multiplo.
+ `CHUNKED_DFS`

  Chunked Depth-First Search

  Un approccio ibrido che esplora il grafo depth-first in blocchi di 1.000 nodi, invece di 1 nodo (`DFS`) o tutti i nodi (`BFS)`.

  Il motore Neptune ottiene fino a 1.000 nodi a ogni livello prima di avanzare nel percorso.

  Questo è un approccio equilibrato tra velocità e utilizzo della memoria. 

  È utile anche se vuoi usare `BFS`, ma la query sta usando troppa memoria.



## Esempio
<a name="gremlin-query-hints-repeatMode-example"></a>

La sezione seguente descrive l'effetto della modalità di ripetizione su un attraversamento Gremlin.

In Neptune la modalità predefinita per il passaggio `repeat()` è eseguire una strategia di esecuzione breadth-first (`BFS`) per tutti gli attraversamenti. 

Nella maggior parte dei casi, l' TinkerGraph implementazione utilizza la stessa strategia di esecuzione, ma in alcuni casi altera l'esecuzione di un attraversamento. 

Ad esempio, l' TinkerGraph implementazione modifica la seguente query.

```
g.V("3").repeat(out()).times(10).limit(1).path()
```

Il passaggio `repeat()` in questo attraversamento sarà "svolto" nell’attraversamento seguente, che risulta in una strategia depth-first (`DFS`).

```
g.V(<id>).out().out().out().out().out().out().out().out().out().out().limit(1).path()
```

**Importante**  
Il motore di query Neptune non esegue l'operazione automaticamente.

Breadth-first (`BFS`) è la strategia di esecuzione predefinita ed è simile nella maggior parte dei casi. TinkerGraph Tuttavia, vi sono alcuni casi in cui sono preferibili delle strategie depth-first (`DFS`).

 

**BFS (impostazione predefinita)**  
Breadth-first (BFS) è la strategia di esecuzione predefinita per l'operatore `repeat()`.

```
g.V("3").repeat(out()).times(10).limit(1).path()
```

Il motore Neptune esplora le prime frontiere a nove hop prima di trovare una soluzione a dieci hop. Questa soluzione è efficace in molti casi, come per una query del percorso più breve.

Tuttavia, per l'esempio precedente l'attraversamento sarebbe molto più veloce usando la modalità depth-first (`DFS`) per l'operatore `repeat()`.

**DFS**  
La seguente query utilizza la modalità depth-first (`DFS`) per l'operatore `repeat()`.

```
g.withSideEffect("Neptune#repeatMode", "DFS").V("3").repeat(out()).times(10).limit(1)
```

Ogni singola soluzione viene seguita fino alla profondità massima prima di esplorare la soluzione successiva. 

# Hint di query Gremlin noReordering
<a name="gremlin-query-hints-noReordering"></a>

Quando invii un attraversamento Gremlin, il motore di query Neptune esamina la struttura dell'attraversamento e riordina le parti della query, tentando di ridurre al minimo la quantità di lavoro richiesta per la valutazione e il tempo di risposta della query. Ad esempio, un attraversamento con più vincoli, come più passaggi `has()`, in genere non viene valutato nell'ordine specificato. Viene invece riordinato dopo che la query viene controllata con analisi statica.

Il motore di query Neptune tenta di identificare quale vincolo è più selettivo e lo esegue per primo. Questa soluzione spesso produce prestazioni migliori, ma l'ordine in cui Neptune sceglie di valutare la query potrebbe non essere sempre ottimale.

Se conosci le caratteristiche esatte dei dati e desideri indicare manualmente l'ordine di esecuzione della query, puoi utilizzare l'hint di query Neptune `noReordering` per specificare che l'attraversamento deve essere valutato nell'ordine specificato.

## Sintassi
<a name="gremlin-query-hints-noReordering-syntax"></a>

L'hint di query `noReordering` si specifica aggiungendo un passaggio `withSideEffect` alla query.

```
g.withSideEffect('Neptune#noReordering', true or false).gremlin-traversal
```

**Nota**  
Tutti gli hint di query Gremlin sono preceduti da `Neptune#`.

**Valori disponibili**
+ `true`
+ `false`

# Hint di query Gremlin typePromotion
<a name="gremlin-query-hints-typePromotion"></a>

Quando invii un attraversamento Gremlin che filtra in base a un valore o intervallo numerico, il motore di query Neptune deve normalmente utilizzare la promozione dei tipi quando esegue la query. Ciò significa che deve esaminare i valori di ogni tipo che potrebbe contenere il valore in base al quale stai filtrando.

Ad esempio, se filtri per valori pari a 55, il motore deve cercare numeri interi pari a 55, numeri interi long pari a 55L, numeri a virgola mobile pari a 55.0 e così via. Ogni promozione di tipo richiede una ricerca aggiuntiva nell'archiviazione, che può far sì che una query apparentemente semplice richieda un tempo inaspettatamente lungo per essere completata.

Supponiamo che tu stia cercando tutti i vertici con una proprietà relativa all'età del cliente maggiore di 5:

```
g.V().has('customerAge', gt(5))
```

Per eseguire tale attraversamento in modo completo, Neptune deve espandere la query per esaminare ogni tipo numerico a cui potrebbe essere promosso il valore per cui stai eseguendo la query. In questo caso, il filtro `gt` deve essere applicato a qualsiasi numero intero superiore a 5, a qualsiasi numero long superiore a 5L, a qualsiasi numero a virgola mobile superiore a 5.0 e a qualsiasi valore double superiore a 5.0. Poiché ognuna di queste promozioni di tipo richiede una ricerca aggiuntiva nell'archiviazione, quando esegui [API Gremlin `profile`](gremlin-profile-api.md) per questa query vedrai più filtri per ogni filtro numerico e il completamento richiederà molto più tempo di quanto potresti aspettarti.

Spesso la promozione dei tipi non è necessaria perché si sa in anticipo che è necessario trovare solo valori di un tipo specifico. In questo caso, puoi velocizzare notevolmente le query utilizzando l'hint di query `typePromotion` per disattivare la promozione dei tipi.

## Sintassi
<a name="gremlin-query-hints-typePromotion-syntax"></a>

L'hint di query `typePromotion` si specifica aggiungendo un passaggio `withSideEffect` alla query.

```
g.withSideEffect('Neptune#typePromotion', true or false).gremlin-traversal
```

**Nota**  
Tutti gli hint di query Gremlin sono preceduti da `Neptune#`.

**Valori disponibili**
+ `true`
+ `false`

Per disattivare la promozione dei tipi per la query precedente, puoi usare:

```
g.withSideEffect('Neptune#typePromotion', false).V().has('customerAge', gt(5))
```

# Hint di query Gremlin useDFE
<a name="gremlin-query-hints-useDFE"></a>

Utilizzare questo hint di query per abilitare l'uso del motore DFE per l'esecuzione della query. Per impostazione predefinita, Neptune non utilizza il motore DFE senza che questo hint di query sia impostato su `true`, poiché il parametro di istanza [neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) è impostato su `viaQueryHint`. Se imposti il parametro di istanza su `enabled`, il motore DFE viene utilizzato per tutte le query ad eccezione di quelle con l'hint di query `useDFE` impostato su `false`.

Esempio di abilitazione del motore DFE per una query:

```
g.withSideEffect('Neptune#useDFE', true).V().out()
```

# Hint di query Gremlin per l'utilizzo della cache dei risultati
<a name="gremlin-query-hints-results-cache"></a>

I seguenti hint di query possono essere utilizzati quando è abilitata la [cache dei risultati delle query](gremlin-results-cache.md).

## Hint di query Gremlin `enableResultCache`
<a name="gremlin-query-hints-results-cache-enableResultCache"></a>

L'hint di query `enableResultCache` con valore `true` fa sì che i risultati della query vengano restituiti dalla cache se sono già stati memorizzati nella cache. In caso contrario, restituisce i nuovi risultati e li memorizza nella cache fino a quando non vengono cancellati dalla cache. Esempio:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Successivamente, è possibile accedere ai risultati memorizzati nella cache eseguendo di nuovo esattamente la stessa query.

Se il valore di questo hint di query è `false` o se non è presente, i risultati della query non vengono memorizzati nella cache. Tuttavia, impostando il valore su `false` non si cancellano i risultati esistenti memorizzati nella cache. Per cancellare i risultati memorizzati nella cache, usare l'hint `invalidateResultCache` o `invalidateResultCachekey`.

## Hint di query Gremlin `enableResultCacheWithTTL`
<a name="gremlin-query-hints-results-cache-enableResultCacheWithTTL"></a>

L'hint di query `enableResultCacheWithTTL` restituisce anche i risultati memorizzati nella cache, se presenti, senza influire sul TTL dei risultati già presenti nella cache. Se attualmente non sono presenti risultati nella cache, la query restituisce nuovi risultati e li memorizza nella cache per il time to live (TTL) specificato dall'hint di query `enableResultCacheWithTTL`. Il time to live è specificato in secondi. Ad esempio, la seguente query specifica un time to live di sessanta secondi:

```
g.with('Neptune#enableResultCacheWithTTL', 60)
 .V().has('genre','drama').in('likes')
```

Prima che siano trascorsi 60 secondi time-to-live, puoi usare la stessa query (qui`g.V().has('genre','drama').in('likes')`) con il suggerimento `enableResultCache` o la `enableResultCacheWithTTL` query per accedere ai risultati memorizzati nella cache.

**Nota**  
Il time to live specificato con `enableResultCacheWithTTL` non influisce sui risultati che sono già stati memorizzati nella cache.  
Se i risultati sono stati precedentemente memorizzati nella cache utilizzando `enableResultCache`, la cache deve essere cancellata in modo esplicito prima che `enableResultCacheWithTTL` generi nuovi risultati e li memorizzi nella cache per il TTL specificato.
Se i risultati sono stati precedentemente memorizzati nella cache utilizzando `enableResultCachewithTTL`, il TTL precedente deve scadere prima che `enableResultCacheWithTTL` generi nuovi risultati e li memorizzi nella cache per il TTL specificato.

Una volta trascorso il time to live, i risultati della query memorizzati nella cache vengono cancellati e un'istanza successiva della stessa query restituisce nuovi risultati. Se `enableResultCacheWithTTL` è associato alla query successiva, i nuovi risultati vengono memorizzati nella cache con il TTL specificato.

## Hint di query Gremlin `invalidateResultCacheKey`
<a name="gremlin-query-hints-results-cache-invalidateResultCacheKey"></a>

L'hint di query `invalidateResultCacheKey` può accettare il valore `true` o `false`. Il valore `true` fa sì che i risultati memorizzati nella cache per la query a cui `invalidateResultCacheKey` è associato vengano cancellati. Ad esempio, l'esempio seguente fa sì che i risultati memorizzati nella cache per la chiave di query `g.V().has('genre','drama').in('likes')` vengano cancellati:

```
g.with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

La query di esempio precedente non fa sì che i nuovi risultati vengano memorizzati nella cache. È possibile includere `enableResultCache` (o `enableResultCacheWithTTL`) nella stessa query se si desidera memorizzare nella cache i nuovi risultati dopo aver cancellato quelli esistenti:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

## Hint di query Gremlin `invalidateResultCache`
<a name="gremlin-query-hints-results-cache-invalidateResultCache"></a>

L'hint di query `invalidateResultCache` può accettare il valore `true` o `false`. Il valore `true` fa sì che tutti i risultati nella cache dei risultati vengano cancellati. Esempio:

```
g.with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

La query di esempio precedente non fa sì che i relativi risultati vengano memorizzati nella cache. È possibile includere `enableResultCache` (o `enableResultCacheWithTTL`) nella stessa query se si desidera memorizzare nella cache i nuovi risultati dopo aver cancellato completamente la cache esistente:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

## Hint di query Gremlin `numResultsCached`
<a name="gremlin-query-hints-results-cache-numResultsCached"></a>

L'hint di query `numResultsCached` può essere utilizzato solo con le query che contengono `iterate()` e specifica il numero massimo di risultati da memorizzare nella cache per la query a cui è associato. Si not che i risultati memorizzati nella cache quando è presente `numResultsCached` non vengono restituiti, ma solo memorizzati nella cache.

Ad esempio, la seguente query specifica che devono essere memorizzati nella cache fino a 100 risultati, ma nessuno di questi risultati memorizzati nella cache viene restituito:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#numResultsCached', 100)
 .V().has('genre','drama').in('likes').iterate()
```

È quindi possibile utilizzare una query come la seguente per recuperare un intervallo di risultati memorizzati nella cache (in questo caso i primi dieci):

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#numResultsCached', 100)
 .V().has('genre','drama').in('likes').range(0, 10)
```

## Hint di query Gremlin `noCacheExceptions`
<a name="gremlin-query-hints-results-cache-noCacheExceptions"></a>

L'hint di query `noCacheExceptions` può accettare il valore `true` o `false`. Il valore `true` causa l'eliminazione di tutte le eccezioni relative alla cache dei risultati. Esempio:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#noCacheExceptions', true)
 .V().has('genre','drama').in('likes')
```

In particolare, elimina l'eccezione `QueryLimitExceededException`, che viene generato se i risultati di una query sono troppo grandi per essere inseriti nella cache dei risultati.

# API di stato delle query Gremlin
<a name="gremlin-api-status"></a>

Per ottenere lo stato delle query Gremlin, utilizza l'operazione HTTP `GET` o `POST` per effettuare una richiesta all'endpoint `https://your-neptune-endpoint:port/gremlin/status`. 

## Parametri della richiesta di stato delle query Gremlin
<a name="gremlin-api-status-get-request"></a>
+ **queryId** (*opzionale*): ID di una query Gremlin in esecuzione. Viene mostrato solo lo stato della query specificata.
+ **includeWaiting** (*opzionale*): restituisce lo stato di tutte le query in attesa.

  Normalmente, nella risposta sono incluse solo le query in esecuzione, ma quando viene specificato il parametro `includeWaiting`, viene restituito anche lo stato di tutte le query in attesa.

## Sintassi della risposta di stato delle query Gremlin
<a name="gremlin-api-status-get-response-syntax"></a>

```
{
  "acceptedQueryCount": integer,
  "runningQueryCount": integer,
  "queries": [
    {
      "queryId":"guid",
      "queryEvalStats":
        {
          "waited": integer,
          "elapsed": integer,
          "cancelled": boolean
        },
      "queryString": "string"
    }
  ]
}
```

## Valori della risposta di stato delle query Gremlin
<a name="gremlin-api-status-get-response-values"></a>
+ **acceptedQueryCount**— Il numero di interrogazioni che sono state accettate ma non ancora completate, incluse le interrogazioni in coda.
+ **runningQueryCount**— Il numero di interrogazioni Gremlin attualmente in esecuzione.
+ **queries**: elenco delle query Gremlin correnti.
+ **queryId**: ID GUID della query. Neptune assegna automaticamente questo valore ID a ogni query oppure è possibile assegnare un ID personalizzato (consulta [Inserimento di un ID personalizzato in una query Neptune Gremlin o SPARQL](features-query-id.md)).
+ **queryEvalStats**— Statistiche per questa interrogazione.
+ **subqueries**: numero di sottoquery in questa query.
+ **elapsed**: numero di millisecondi in cui la query è stata eseguita finora.
+ **cancelled**: il valore True indica che la query è stata annullata.
+ **queryString**: la query inviata. Questa è troncata a 1024 caratteri nel caso in cui sia più lunga.
+ **waited**: indica il tempo di attesa della query, in millisecondi.

## Esempio di stato di una query Gremlin
<a name="gremlin-api-status-get-example"></a>

Di seguito è riportato un esempio del comando di stato che utilizza `curl` e l'operazione HTTP `GET`.

```
curl https://your-neptune-endpoint:port/gremlin/status
```

Questo output mostra una sola query in esecuzione.

```
{
  "acceptedQueryCount":9,
  "runningQueryCount":1,
  "queries": [
    {
      "queryId":"fb34cd3e-f37c-4d12-9cf2-03bb741bf54f",
      "queryEvalStats":
        {
          "waited": 0,
          "elapsed": 23,
          "cancelled": false
        },
      "queryString": "g.V().out().count()"
    }
  ]
}
```

# Annullamento delle query Gremlin
<a name="gremlin-api-status-cancel"></a>

Per ottenere lo stato delle query Gremlin, utilizza l'operazione HTTP `GET` o `POST` per effettuare una richiesta all'endpoint `https://your-neptune-endpoint:port/gremlin/status`.

## Parametri della richiesta di annullamento delle query Gremlin
<a name="gremlin-api-status-cancel-request"></a>
+ **cancelQuery**: obbligatorio per l'annullamento. Il parametro non dispone di un valore corrispondente.
+ **queryId**: ID della query Gremlin in esecuzione da annullare.

## Esempio di annullamento di una query Gremlin
<a name="gremlin-api-status-cancel-example"></a>

Di seguito è riportato un esempio del comando `curl` per annullare una query.

```
curl https://your-neptune-endpoint:port/gremlin/status \
  --data-urlencode "cancelQuery" \
  --data-urlencode "queryId=fb34cd3e-f37c-4d12-9cf2-03bb741bf54f"
```

L'avvenuto annullamento restituisce il codice HTTP `200` impostato su OK.

# Supporto delle sessioni basate su script Gremlin
<a name="access-graph-gremlin-sessions"></a>

È possibile utilizzare le sessioni Gremlin con transazioni implicite in Amazon Neptune. Per informazioni sulle sessioni Gremlin, vedere [Considering Sessions nella documentazione](http://tinkerpop.apache.org/docs/current/reference/#sessions) di TinkerPop Apache. Le sezioni seguenti descrivono come utilizzare le sessioni Gremlin con Java.

**Importante**  
Attualmente il periodo di tempo massimo in cui Neptune può mantenere aperta una sessione basata su script è pari a 10 minuti. Se non si chiude una sessione prima di questo tempo, la sessione scade e tutto il contenuto viene sottoposto a rollback.

**Topics**
+ [

## Sessioni Gremlin sulla console Gremlin
](#access-graph-gremlin-sessions-console)
+ [

## Sessioni Gremlin nella variante del linguaggio Gremlin
](#access-graph-gremlin-sessions-glv)

## Sessioni Gremlin sulla console Gremlin
<a name="access-graph-gremlin-sessions-console"></a>

Se crei una connessione remota sulla console Gremlin senza il parametro `session`, la connessione remota viene creata in modalità *senza sessioni* . In questa modalità, ogni richiesta inviata al server viene considerata come una transazione completa in sé e nessuno stato viene salvato tra le richieste. Se una richiesta ha esito negativo, viene eseguito il rollback solo di quella richiesta.

Se si crea una connessione remota che *utilizza* il parametro `session`, si crea una sessione basata su script che dura finché non si chiude la connessione remota. Ogni sessione è identificata da un UUID univoco che la console genera e restituisce.

Di seguito è riportato un esempio di una chiamata della console che crea una sessione. Dopo aver inviato le query, un'altra chiamata chiude la sessione ed esegue il commit delle query.

**Nota**  
Il client Gremlin deve essere sempre chiuso per rilasciare le risorse lato server.

```
gremlin> :remote connect tinkerpop.server conf/neptune-remote.yaml session
  . . .
  . . .
gremlin> :remote close
```

Per ulteriori informazioni ed esempi, vedete [Sessions nella documentazione](http://tinkerpop.apache.org/docs/current/reference/#console-sessions). TinkerPop 

Tutte le query eseguite durante una sessione formano una singola transazione di cui non viene eseguito il commit finché tutte le query non vanno a buon fine e la connessione remota non viene chiusa. Se una query non riesce o se non si chiude la connessione entro la durata massima della sessione supportata da Neptune, non viene eseguito il commit della transazione di sessione e viene eseguito il rollback di tutte le query in essa contenute

## Sessioni Gremlin nella variante del linguaggio Gremlin
<a name="access-graph-gremlin-sessions-glv"></a>

Nel Gremlin Language Variant, è necessario creare un oggetto `SessionedClient` per inviare più query in una singola transazione, come descritto nell'esempio seguente.

```
try {                              // line 1
  Cluster cluster = Cluster.open();                    // line 2
  Client client = cluster.connect("sessionName");      // line 3
   ...
   ...
} finally {
  // Always close. If there are no errors, the transaction is committed; otherwise, it's rolled back.
  client.close();
}
```

La riga 3 nell'esempio precedente crea l'oggetto `SessionedClient` in base alle opzioni di configurazione impostate per il cluster in questione. La *sessionName* stringa che passi al metodo connect diventa il nome univoco della sessione. Per evitare collisioni, utilizzare un UUID per il nome.

Il client avvia una transazione di sessione quando viene inizializzato. Il commit di tutte le query che esegui durante il modulo di sessione viene eseguito solo quando chiami `client.close( )`. Ancora una volta, se una singola query non riesce o se non si chiude la connessione entro la durata massima supportata da Neptune, la transazione della sessione non riesce e viene eseguito il rollback di tutte le query in essa contenute.

**Nota**  
Il client Gremlin deve essere sempre chiuso per rilasciare le risorse lato server.

```
GraphTraversalSource g = traversal().withRemote(conn);

Transaction tx = g.tx();

// Spawn a GraphTraversalSource from the Transaction.
// Traversals spawned from gtx are executed within a single transaction.
GraphTraversalSource gtx = tx.begin();
try {
  gtx.addV('person').iterate();
  gtx.addV('software').iterate();

  tx.commit();
} finally {
    if (tx.isOpen()) {
        tx.rollback();
    }
}
```

# Transazioni Gremlin in Neptune
<a name="access-graph-gremlin-transactions"></a>

Esistono diversi contesti in cui vengono eseguite le [transazioni](transactions.md) Gremlin. Quando si lavora con Gremlin è importante comprendere il contesto in cui si lavora e quali sono le relative implicazioni:
+ **`Script-based`**: le richieste vengono effettuate utilizzando stringhe Gremlin basate su testo, come queste:
  + Utilizzando il driver Java e `Client.submit(string)`.
  + Utilizzando la console Gremlin e `:remote connect`.
  + Utilizzando l'API HTTP.
+ **`Bytecode-based`**: le richieste vengono effettuate utilizzando il bytecode Gremlin serializzato tipico delle [varianti del linguaggio Gremlin](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants) (GLV).

  Ad esempio, utilizzando il driver Java, `g = traversal().withRemote(...)`.

Per entrambi i contesti sopra descritti, esiste il contesto aggiuntivo della richiesta inviata come senza sessione o come associata a una sessione.

**Nota**  
 Le transazioni Gremlin devono sempre essere sottoposte a commit o rollback, in modo che le risorse lato server possano essere rilasciate. In caso di errore durante la transazione, è importante ripetere l'intera transazione e non solo la richiesta specifica non riuscita. 

## Richieste senza sessione
<a name="access-graph-gremlin-transactions-sessionless"></a>

 Quando è senza sessione, una richiesta equivale a una singola transazione.

Per gli script, l'implicazione è che una o più istruzioni Gremlin inviate in una singola richiesta verranno sottoposte a commit o rollback come singola transazione. Esempio:

```
Cluster cluster = Cluster.open();
Client client = cluster.connect(); // sessionless
// 3 vertex additions in one request/transaction:
client.submit("g.addV();g.addV();g.addV()").all().get();
```

Per il bytecode, viene effettuata una richiesta senza sessione per ogni attraversamento generato ed eseguito da `g`:

```
GraphTraversalSource g = traversal().withRemote(...);

// 3 vertex additions in three individual requests/transactions:
g.addV().iterate();
g.addV().iterate();
g.addV().iterate();

// 3 vertex additions in one single request/transaction:
g.addV().addV().addV().iterate();
```

## Richieste associate a una sessione
<a name="access-graph-gremlin-transactions-session-bound"></a>

Se associate a una sessione, è possibile applicare più richieste nel contesto di una singola transazione.

Per gli script, l'implicazione è che non è necessario concatenare tutte le operazioni del grafo in un unico valore di stringa incorporato:

```
Cluster cluster = Cluster.open();
Client client = cluster.connect(sessionName); // session
try {
    // 3 vertex additions in one request/transaction:
    client.submit("g.addV();g.addV();g.addV()").all().get();
} finally {
    client.close();
}

try {
    // 3 vertex additions in three requests, but one transaction:
    client.submit("g.addV()").all().get(); // starts a new transaction with the same sessionName
    client.submit("g.addV()").all().get();
    client.submit("g.addV()").all().get();
} finally {
    client.close();
}
```

Per quanto riguarda il bytecode, in seguito TinkerPop `3.5.x`, la transazione può essere controllata in modo esplicito e la sessione gestita in modo trasparente. Le varianti del linguaggio Gremlin (GLV) supportano la sintassi `tx()` di Gremlin per eseguire le operazioni di `commit()` o `rollback()` su una transazione come segue:

```
GraphTraversalSource g = traversal().withRemote(conn);

Transaction tx = g.tx();

// Spawn a GraphTraversalSource from the Transaction.
// Traversals spawned from gtx are executed within a single transaction.
GraphTraversalSource gtx = tx.begin();
try {
    gtx.addV('person').iterate();
    gtx.addV('software').iterate();

    tx.commit();
} finally {
    if (tx.isOpen()) {
        tx.rollback();
    }
}
```

Sebbene l'esempio precedente sia scritto in Java, è possibile utilizzare questa sintassi `tx()` anche in Python, Javascript e .NET.

**avvertimento**  
Le query di sola lettura senza sessione vengono eseguite con isolamento [SNAPSHOT](transactions-isolation-levels.md), mentre le query di sola lettura eseguite all'interno di una transazione esplicita vengono eseguite con isolamento [SERIALIZABLE](transactions-isolation-levels.md). Le query di sola lettura eseguite con isolamento `SERIALIZABLE` comportano un sovraccarico maggiore e possono bloccarsi o essere bloccate da scritture simultanee, a differenza di quelle eseguite con isolamento `SNAPSHOT`.

# Utilizzo dell'API Gremlin con Amazon Neptune
<a name="gremlin-api-reference"></a>

**Nota**  
Amazon Neptune non supporta la proprietà `bindings`.

Tutte le richieste HTTPS Gremlin utilizzano un singolo endpoint: `https://your-neptune-endpoint:port/gremlin`. Tutte le connessioni Neptune devono utilizzare HTTPS.

È possibile collegare la console Gremlin a un grafico di Neptune direttamente tramite. WebSockets

Per ulteriori informazioni sulla connessione all'endpoint di Gremlin, consulta [Accesso al grafo Neptune con Gremlin](access-graph-gremlin.md).

L'implementazione di Gremlin in Amazon Neptune prevede dettagli specifici e differenze da prendere in considerazione. Per ulteriori informazioni, consulta [Conformità agli standard Gremlin in Amazon Neptune](access-graph-gremlin-differences.md).

[Per informazioni sul linguaggio Gremlin e sui suoi attraversamenti, consulta The Traversal nella documentazione di Apache.](https://tinkerpop.apache.org/docs/current/reference/#traversal) TinkerPop 

# Memorizzazione nella cache dei risultati delle query con Gremlin in Amazon Neptune
<a name="gremlin-results-cache"></a>

Amazon Neptune supporta una cache dei risultati per le query Gremlin.

È possibile abilitare la cache dei risultati delle query e quindi utilizzare un hint di query per memorizzare nella cache i risultati di una query di sola lettura Gremlin.

Qualsiasi riesecuzione della query recupera quindi i risultati memorizzati nella cache con bassa latenza e senza I/O costi, purché siano ancora nella cache. Funziona per le query inviate sia su un endpoint HTTP che tramite Websocket, sia come codice byte che sotto forma di stringa.

**Nota**  
Le query inviate all'endpoint del profilo non vengono memorizzate nella cache anche quando la cache delle query è abilitata.

È possibile controllare il comportamento della cache dei risultati delle query di Neptune in diversi modi. Esempio:
+ È possibile ottenere risultati memorizzati nella cache paginati, in blocchi.
+ È possibile specificare il time-to-live (TTL) per le query specificate.
+ È possibile cancellare la cache per query specifiche.
+ È possibile cancellare l'intera cache.
+ È possibile impostare la possibilità di ricevere una notifica se i risultati superano la dimensione della cache.

La cache viene gestita utilizzando una politica least-recently-used (LRU), il che significa che una volta che lo spazio assegnato alla cache è pieno, i least-recently-used risultati vengono rimossi per liberare spazio quando i nuovi risultati vengono memorizzati nella cache.

**Importante**  
La cache dei risultati delle query non è disponibile per i tipi di istanza `t3.medium` o `t4.medium`.

## Abilitazione della cache dei risultati delle query in Neptune
<a name="gremlin-results-cache-enabling"></a>

 La cache dei risultati delle query può essere abilitata in tutte le istanze di un cluster o per istanza. Per abilitare la cache dei risultati su tutte le istanze di un cluster, imposta il `neptune_result_cache` parametro in quella del cluster su. `cluster-parameter-group` `1` Per abilitarla su un'istanza specifica, imposta il `neptune_result_cache` parametro nell'istanza `instance-parameter-group` su`1`. L'impostazione del gruppo di parametri del cluster sostituirà il valore del gruppo di parametri di istanza. 

 È necessario un riavvio su tutte le istanze interessate per applicare le impostazioni dei parametri della cache dei risultati. Sebbene sia possibile abilitare la cache dei risultati in tutte le istanze di un cluster tramite la`cluster-parameter-group`, ogni istanza mantiene la propria cache. La funzionalità di cache dei risultati delle query non è una cache a livello di cluster. 

Una volta abilitata la cache dei risultati, Neptune riserva una parte della memoria corrente per memorizzare nella cache i risultati delle query. Più grande è il tipo di istanza utilizzato e maggiore è la memoria disponibile, maggiore sarà la quantità di memoria che Neptune riserverà per la cache.

Se la memoria cache dei risultati si riempie, Neptune least-recently-used elimina automaticamente i risultati (LRU) memorizzati nella cache per far posto a quelli nuovi.

È possibile verificare lo stato corrente della cache dei risultati utilizzando il comando [Stato dell'istanza](access-graph-status.md).

## Utilizzo degli hint per memorizzare nella cache i risultati delle query
<a name="gremlin-results-cache-using"></a>

Una volta abilitata la cache dei risultati delle query, è possibile utilizzare gli hint di query per controllare la memorizzazione nella cache delle query. Tutti gli esempi seguenti si applicano allo stesso attraversamento della query, vale a dire:

```
g.V().has('genre','drama').in('likes')
```

### Uso di `enableResultCache`
<a name="using-enableResultCache"></a>

Con la cache dei risultati delle query abilitata, è possibile memorizzare nella cache i risultati di una query Gremlin utilizzando l'hint di query `enableResultCache`, come segue:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Neptune restituisce quindi i risultati della query e li memorizza nella cache. Successivamente, è possibile accedere ai risultati memorizzati nella cache eseguendo di nuovo esattamente la stessa query:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

La chiave della cache che identifica i risultati memorizzati nella cache è la stringa di query stessa, vale a dire:

```
g.V().has('genre','drama').in('likes')
```

### Uso di `enableResultCacheWithTTL`
<a name="using-enableResultCacheWithTTL"></a>

È possibile specificare per quanto tempo i risultati delle query devono essere memorizzati nella cache utilizzando l'hint di query `enableResultCacheWithTTL`. Ad esempio, la seguente query specifica che i risultati della query devono scadere dopo 120 secondi:

```
g.with('Neptune#enableResultCacheWithTTL', 120)
 .V().has('genre','drama').in('likes')
```

Anche in questo caso, la chiave della cache che identifica i risultati memorizzati nella cache è la stringa di query di base:

```
g.V().has('genre','drama').in('likes')
```

E anche in questo caso, è possibile accedere ai risultati memorizzati nella cache usando tale stringa di query con l'hint di query `enableResultCache`:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Se sono trascorsi 120 o più secondi da quando i risultati sono stati memorizzati nella cache, quella query restituirà nuovi risultati e li memorizzerà nella cache, senza alcun risultato. time-to-live

È inoltre possibile accedere ai risultati memorizzati nella cache inviando nuovamente la stessa query con l'hint di query `enableResultCacheWithTTL`. Esempio:

```
g.with('Neptune#enableResultCacheWithTTL', 140)
 .V().has('genre','drama').in('likes')
```

Finché non sono trascorsi 120 secondi (ovvero il TTL attualmente in vigore), questa nuova query che utilizza l'hint di query `enableResultCacheWithTTL` restituisce i risultati memorizzati nella cache. Dopo 120 secondi, restituirà nuovi risultati e li memorizzerà nella cache per 140 secondi. time-to-live

**Nota**  
Se i risultati di una chiave di query sono già memorizzati nella cache, la stessa chiave di query con `enableResultCacheWithTTL` non genera nuovi risultati e non ha alcun effetto sui time-to-live risultati attualmente memorizzati nella cache.  
Se i risultati sono stati precedentemente memorizzati nella cache utilizzando `enableResultCache`, la cache deve essere cancellata prima che `enableResultCacheWithTTL` generi nuovi risultati e li memorizzi nella cache per il TTL specificato.
Se i risultati sono stati precedentemente memorizzati nella cache utilizzando `enableResultCachewithTTL`, il TTL precedente deve scadere prima che `enableResultCacheWithTTL` generi nuovi risultati e li memorizzi nella cache per il TTL specificato.

### Uso di `invalidateResultCacheKey`
<a name="using-invalidateResultCacheKey"></a>

È possibile utilizzare l'hint di query `invalidateResultCacheKey` per cancellare i risultati memorizzati nella cache per una determinata query. Esempio:

```
g.with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

Questa query cancella la cache per la chiave di query, `g.V().has('genre','drama').in('likes')`, e restituisce nuovi risultati per la query.

È inoltre possibile combinare `invalidateResultCacheKey` con `enableResultCache` o `enableResultCacheWithTTL`. Ad esempio, la seguente query cancella i risultati correnti memorizzati nella cache, memorizza nella cache i nuovi risultati e li restituisce:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCacheKey', true)
 .V().has('genre','drama').in('likes')
```

### Uso di `invalidateResultCache`
<a name="using-invalidateResultCache"></a>

È possibile utilizzare l'hint di query `invalidateResultCache` per cancellare tutti i risultati memorizzati nella cache dei risultati della query. Esempio:

```
g.with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

Questa query cancella l'intera cache dei risultati e restituisce nuovi risultati per la query.

È inoltre possibile combinare `invalidateResultCache` con `enableResultCache` o `enableResultCacheWithTTL`. Ad esempio, la seguente query cancella l'intera cache dei risultati, memorizza nella cache i nuovi risultati per questa query e li restituisce:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#invalidateResultCache', true)
 .V().has('genre','drama').in('likes')
```

## Paginazione dei risultati delle query memorizzati nella cache
<a name="gremlin-results-cache-paginating"></a>

Supponiamo di aver già memorizzato nella cache un gran numero di risultati come questo:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes')
```

Supponiamo ora di inviare la seguente query di intervallo:

```
g.with('Neptune#enableResultCache', true)
 .V().has('genre','drama').in('likes').range(0,10)
```

Neptune cerca innanzitutto la chiave completa della cache, vale a dire `g.V().has('genre','drama').in('likes').range(0,10)`. Se tale chiave non esiste, Neptune cerca se esiste una chiave per la stringa di query senza l'intervallo (vale a dire `g.V().has('genre','drama').in('likes')`). Quando trova la chiave, Neptune recupera i primi dieci risultati dalla relativa cache, come specificato dall'intervallo.

**Nota**  
Se si usa l'hint di query `invalidateResultCacheKey` con una query che ha un intervallo alla fine, Neptune cancella la cache per una query senza l'intervallo se non trova una corrispondenza esatta per la query con l'intervallo.

### Uso di `numResultsCached` con `.iterate()`
<a name="gremlin-results-cache-paginating-numResultsCached"></a>

Utilizzando l'hint di query `numResultsCached`, è possibile popolare la cache dei risultati senza restituire tutti i risultati memorizzati nella cache, il che può essere utile quando si preferisce paginare un numero elevato di risultati.

L'hint di query `numResultsCached` funziona solo con le query che terminano con `iterate()`.

Ad esempio, se si desidera memorizzare nella cache i primi 50 risultati della query di esempio:

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

In questo caso la chiave di query nella cache è: `g.with("Neptune#numResultsCached", 50).V().has('genre','drama').in('likes')`. Ora è possibile recuperare i primi dieci risultati memorizzati nella cache con questa query:

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(0, 10)
```

Inoltre, è possibile recuperare i dieci risultati successivi dalla query nel modo seguente:

```
g.with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').range(10, 20)
```

Non dimenticare di includere l'hint `numResultsCached`. È una parte essenziale della chiave di query e deve quindi essere presente per poter accedere ai risultati memorizzati nella cache.

**Alcune cose da tenere a mente quando si utilizza `numResultsCached`:**
+ **Il numero fornito con `numResultsCached` viene applicato alla fine della query.**   Ciò significa, ad esempio, che la seguente query memorizza effettivamente nella cache i risultati nell'intervallo `(1000, 1500)`:

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```
+ **Il numero fornito con `numResultsCached` specifica il numero massimo di risultati da memorizzare nella cache.**   Ciò significa, ad esempio, che la seguente query memorizza effettivamente nella cache i risultati nell'intervallo `(1000, 2000)`:

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 100000)
   .V().range(1000, 2000).iterate()
  ```
+ **I risultati memorizzati nella cache delle query che terminano con `.range().iterate()` hanno un proprio intervallo.**   Ad esempio, supponiamo di memorizzare nella cache i risultati utilizzando una query come questa:

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).iterate()
  ```

  Per recuperare i primi 100 risultati dalla cache, scrivere una query come questa:

  ```
  g.with("Neptune#enableResultCache", true)
   .with("Neptune#numResultsCached", 500)
   .V().range(1000, 2000).range(0, 100)
  ```

  Questi cento risultati saranno equivalenti ai risultati della query di base nell'intervallo `(1000, 1100)`.

## Chiavi della cache delle query utilizzate per individuare i risultati memorizzati nella cache
<a name="gremlin-results-cache-query-keys"></a>

Dopo che i risultati di una query sono stati memorizzati nella cache, le query successive con la stessa *chiave di cache delle query* recuperano i risultati dalla cache anziché generarne di nuovi. La chiave di cache di una query viene valutata come segue:

1. Tutti gli hint di query relativi alla cache vengono ignorati, ad eccezione di `numResultsCached`.

1. Il passaggio finale `iterate()` viene ignorato.

1. Il resto della query viene ordinato in base alla rappresentazione del codice byte.

La stringa risultante viene confrontata con un indice dei risultati della query già presenti nella cache per determinare se esiste un riscontro nella cache per la query.

Ad esempio, prendiamo questa query:

```
g.withSideEffect('Neptune#typePromotion', false).with("Neptune#enableResultCache", true)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes').iterate()
```

Verrà memorizzata come versione in codice byte di questa:

```
g.withSideEffect('Neptune#typePromotion', false)
 .with("Neptune#numResultsCached", 50)
 .V().has('genre','drama').in('likes')
```

## Eccezioni relative alla cache dei risultati
<a name="gremlin-results-cache-exceptions"></a>

Se i risultati di una query che si sta cercando di memorizzare nella cache sono troppo grandi per essere contenuti nella memoria cache anche dopo aver rimosso tutto ciò che era precedentemente memorizzato nella cache, Neptune genera un errore `QueryLimitExceededException`. Non viene restituito alcun risultato e l'eccezione genera il seguente messaggio di errore:

```
The result size is larger than the allocated cache,
      please refer to results cache best practices for options to rerun the query.
```

È possibile eliminare questo messaggio utilizzando l'hint di query `noCacheExceptions`, come segue:

```
g.with('Neptune#enableResultCache', true)
 .with('Neptune#noCacheExceptions', true)
 .V().has('genre','drama').in('likes')
```

# Creazione di upsert efficienti con i passaggi `mergeV()` e `mergeE()` di Gremlin
<a name="gremlin-efficient-upserts"></a>

Un upsert (o inserimento condizionale) riutilizza un vertice o uno arco se già esiste oppure lo crea se non esiste. Upsert efficienti possono fare una differenza significativa nelle prestazioni delle query Gremlin.

Gli upsert consentono di scrivere operazioni di inserimento idempotenti: indipendentemente dal numero di volte in cui si esegue un'operazione di questo tipo, il risultato complessivo è lo stesso. Ciò è utile in scenari di scrittura altamente simultanei in cui modifiche simultanee alla stessa parte del grafo possono forzare il rollback di una o più transazioni con un'eccezione `ConcurrentModificationException`, rendendo quindi necessari nuovi tentativi.

Ad esempio, la seguente query esegue l'upsert di un vertice utilizzando l'oggetto `Map` fornito per cercare prima un vertice con `T.id` di `"v-1"`. Se il vertice viene trovato, viene restituito. Se non viene trovato, viene creato un vertice con tale valore `id` e tale proprietà tramite la clausola `onCreate`.

```
g.mergeV([(id):'v-1']).
  option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org'])
```

## Upsert in batch per migliorare la velocità di trasmissione effettiva
<a name="gremlin-upserts-batching"></a>

Per scenari di scrittura con velocità di trasmissione effettiva elevata, è possibile concatenare i passaggi `mergeV()` e `mergeE()` per eseguire l'upsert di vertici e archi in batch. Il batching riduce il sovraccarico transazionale dell'upsert di un gran numero di vertici e archi. È quindi possibile migliorare ulteriormente la velocità di trasmissione effettiva eseguendo l'upsert di richieste batch in parallelo utilizzando più client.

Come regola generale, è consigliabile eseguire l'upsert di circa 200 record per richiesta batch. Un record è una singola etichetta o proprietà di un vertice o un arco. Un vertice con una singola etichetta e 4 proprietà, ad esempio, crea 5 record. Un arco con un'etichetta e una singola proprietà crea 2 record. Se si vuole eseguire l'upsert di batch di vertici, ciascuno con una singola etichetta e 4 proprietà, è necessario iniziare con una dimensione di batch di 40, perché `200 / (1 + 4) = 40`.

È possibile sperimentare con la dimensione del batch. 200 record per batch sono un buon punto di partenza, ma la dimensione ideale del batch può essere maggiore o minore a seconda del carico di lavoro. Tenere presente, tuttavia, che Neptune può limitare il numero complessivo di passaggi Gremlin per richiesta. Questo limite non è documentato, ma per sicurezza, cercare di assicurarsi che le richieste non contengano più di 1.500 passaggi Gremlin. Neptune può rifiutare richieste batch di grandi dimensioni con più di 1.500 passaggi.

Per aumentare la velocità di trasmissione effettiva, è possibile eseguire l'upsert di batch in parallelo utilizzando più client (vedi [Creazione di scritture multithread Gremlin efficienti](best-practices-gremlin-multithreaded-writes.md)). Il numero di client deve essere uguale al numero di thread di lavoro sull'istanza di Neptune writer, che in genere è 2 volte il numero di CPUs v sul server. Ad esempio, un'`r5.8xlarge`istanza ha 32 thread v CPUs e 64 thread di lavoro. Per scenari di scrittura con velocità di trasmissione effettiva elevata che utilizzano un'istanza `r5.8xlarge`, è necessario utilizzare 64 client che scrivono upsert in batch su Neptune in parallelo.

Ogni client deve inviare una richiesta batch e attendere il completamento della richiesta prima di inviarne un'altra. Sebbene più client vengano eseguiti in parallelo, ogni singolo client invia le richieste in modo seriale. Ciò garantisce che il server riceva un flusso costante di richieste che occupano tutti i thread di lavoro senza sovraccaricare la coda delle richieste lato server (vedi [Dimensionamento delle istanze database in un cluster database Neptune](feature-overview-db-clusters.md#feature-overview-sizing-instances)).

## Cercare di evitare passaggi che generano più traverser
<a name="gremlin-upserts-single-traverser"></a>

Quando viene eseguito un passaggio Gremlin, accetta un traverser in entrata ed emette uno o più traverser in uscita. Il numero di traverser emessi da un passaggio determina il numero di volte in cui viene eseguito il passaggio successivo.

In genere, quando si eseguono operazioni in batch, si desidera che ogni operazione, ad esempio l'upsert del vertice A, venga eseguita una sola volta, in modo che la sequenza di operazioni sia la seguente: upsert del vertice A, quindi upsert del vertice B, quindi upsert del vertice C e così via. Finché un passaggio crea o modifica un solo elemento, emette un solo traverser e i passaggi che rappresentano l'operazione successiva vengono eseguiti una sola volta. Se, invece, un'operazione crea o modifica più di un elemento, emette più traverser, che a loro volta fanno sì che i passaggi successivi vengano eseguiti più volte, una volta per ogni traverser emesso. Ciò può comportare l'esecuzione di operazioni aggiuntive non necessarie nel database e, in alcuni casi, la creazione di vertici, archi o valori di proprietà aggiuntivi indesiderati.

Un esempio di come le cose possano andare male è con una query come `g.V().addV()`. Questa semplice query aggiunge un vertice per ogni vertice trovato nel grafo, perché `V()` emette un traverser per ogni vertice del grafo e ognuno di questi traverser attiva una chiamata a `addV()`.

Consulta [Combinazione di upsert e inserimenti](#gremlin-upserts-and-inserts) per informazioni su come gestire le operazioni che possono emettere più traverser.

## Upsert dei vertici
<a name="gremlin-upserts-vertices"></a>

Il passaggio `mergeV()` è progettato specificamente per l'upsert dei vertici. Accetta come argomento un oggetto `Map` che rappresenta gli elementi di cui trovare una corrispondenza con i vertici esistenti nel grafo e, se non viene trovato un elemento, usa tale oggetto `Map` per creare un nuovo vertice. Il passaggio consente anche di modificare il comportamento in caso di creazione o corrispondenza, in cui è possibile applicare il modulatore `option()` con i token `Merge.onCreate` e `Merge.onMatch` per controllare i rispettivi comportamenti. Consulta la [documentazione TinkerPop di riferimento](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step) per ulteriori informazioni su come utilizzare questo passaggio.

È possibile utilizzare un ID vertice per determinare se esiste un vertice specifico. Questo è l'approccio preferito, perché Neptune ottimizza gli upsert per casi d'uso altamente simultanei. IDs Ad esempio, la seguente query crea un vertice con un determinato ID vertice se non esiste già o lo riutilizza se esiste:

```
g.mergeV([(T.id): 'v-1']).
    option(onCreate, [(T.label): 'PERSON', email: 'person-1@example.org', age: 21]).
    option(onMatch, [age: 22]).
  id()
```

Tenere presente che questa query termina con un passaggio `id()` Sebbene non sia strettamente necessario ai fini dell'upsert del vertice, un passaggio `id()` alla fine di una query di upsert assicura che il server non serializzi tutte le proprietà del vertice sul client, riducendo il costo di blocco della query.

In alternativa, è possibile utilizzare una proprietà del vertice per identificare un vertice:

```
g.mergeV([email: 'person-1@example.org']).
    option(onCreate, [(T.label): 'PERSON', age: 21]).
    option(onMatch, [age: 22]).
  id()
```

Se possibile, utilizzate i vertici forniti dall'utente IDs per creare vertici e utilizzateli per determinare se esiste un vertice durante un'operazione IDs di ribaltamento. Ciò consente a Neptune di ottimizzare gli upsert. Un upsert basato su ID può essere significativamente più efficiente di un upsert basato su proprietà quando le modifiche simultanee sono frequenti.

### Concatenamento degli upsert dei vertici
<a name="gremlin-upserts-vertices-chaining"></a>

È possibile concatenare gli upsert dei vertici per inserirli in un batch:

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .id()
```

In alternativa, è possibile anche utilizzare questa sintassi `mergeV()`:

```
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']).
  mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']).
  mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org'])
```

Tuttavia, poiché questo tipo di query include elementi nei criteri di ricerca che sono superflui rispetto alla ricerca di base con `id`, non è efficiente quanto la query precedente.

## Upsert degli archi
<a name="gremlin-upserts-edges"></a>

Il passaggio `mergeE()` è progettato specificamente per l'upsert degli archi. Accetta come argomento un oggetto `Map` che rappresenta gli elementi di cui trovare una corrispondenza con gli archi esistenti nel grafo e, se non viene trovato un elemento, usa tale oggetto `Map` per creare un nuovo arco. Il passaggio consente anche di modificare il comportamento in caso di creazione o corrispondenza, in cui è possibile applicare il modulatore `option()` con i token `Merge.onCreate` e `Merge.onMatch` per controllare i rispettivi comportamenti. Consultate la [documentazione TinkerPop di riferimento](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step) per ulteriori informazioni su come utilizzare questo passaggio.

È possibile utilizzare il bordo IDs per ribaltare gli spigoli nello stesso modo in cui si ribaltano i vertici utilizzando un vertice personalizzato. IDs Anche in questo caso, si tratta dell'approccio preferito perché consente a Neptune di ottimizzare la query. Ad esempio, la seguente query crea un arco in base al relativo ID arco se non esiste già oppure lo riutilizza se esiste. La query utilizza anche i `Direction.to` vertici IDs del `Direction.from` e se deve creare un nuovo spigolo:

```
g.mergeE([(T.id): 'e-1']).
    option(onCreate, [(from): 'v-1', (to): 'v-2', weight: 1.0]).
    option(onMatch, [weight: 0.5]).
  id()
```

Tenere presente che questa query termina con un passaggio `id()` Sebbene non sia strettamente necessario ai fini dell'upsert dell'arco, l'aggiunta di un passaggio `id()` alla fine di una query di upsert assicura che il server non serializzi tutte le proprietà dell'arco sul client, riducendo il costo di blocco della query.

Molte applicazioni utilizzano vertici personalizzati IDs, ma lasciano che Neptune generi l'edge. IDs Se non conosci l'ID di un bordo, ma conosci il `to` vertice `from` and IDs, puoi usare questo tipo di query per capovolgere un bordo:

```
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  id()
```

Tutti i vertici a cui fa riferimento `mergeE()` devono esistere affinché il passaggio crei l'arco.

### Concatenamento degli upsert degli archi
<a name="gremlin-upserts-edges-chaining"></a>

Come per gli upsert dei vertici, è semplice concatenare i passaggi `mergeE()` per le richieste batch:

```
g.mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']).
  mergeE([(from): 'v-3', (to): 'v-4', (T.label): 'KNOWS']).
  id()
```

## Combinazione di upsert di vertici e archi
<a name="gremlin-upserts-vertexes-and-edges"></a>

A volte si può desiderare di eseguire l'upsert sia dei vertici che degli archi che li collegano. È possibile combinare gli esempi batch illustrati qui. L'esempio seguente esegue l'upsert di 3 vertici e 2 archi:

```
g.mergeV([(id):'v-1']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']).
  mergeV([(id):'v-2']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']).
  mergeV([(id):'v-3']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']).
  mergeE([(from): 'v-1', (to): 'v-2', (T.label): 'KNOWS']).
  mergeE([(from): 'v-2', (to): 'v-3', (T.label): 'KNOWS']).
 id()
```

## Combinazione di upsert e inserimenti
<a name="gremlin-upserts-and-inserts"></a>

A volte si può desiderare di eseguire l'upsert sia dei vertici che degli archi che li collegano. È possibile combinare gli esempi batch illustrati qui. L'esempio seguente esegue l'upsert di 3 vertici e 2 archi:

Gli upsert in genere procedono un elemento alla volta. Se ci si attiene ai modelli di upsert qui presentati, ogni operazione di upsert emette un singolo traverser, che fa sì che l'operazione successiva venga eseguita una sola volta.

Tuttavia, a volte si può voler combinare gli upsert con gli inserimenti. Questo può essere il caso, ad esempio, se si usano gli archi per rappresentare istanze di azioni o eventi. Una richiesta potrebbe utilizzare gli upsert per assicurarsi che esistano tutti i vertici necessari e quindi utilizzare gli inserimenti per aggiungere gli archi. Con richieste di questo tipo, occorre prestare attenzione al numero potenziale di traverser emessi da ciascuna operazione.

Considerare l'esempio seguente, che combina upsert e inserimenti per aggiungere archi che rappresentano gli eventi nel grafo:

```
// Fully optimized, but inserts too many edges
g.mergeV([(id):'v-1']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-1@example.org']).
  mergeV([(id):'v-2']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-2@example.org']).
  mergeV([(id):'v-3']).
    option(onCreate, [(label): 'PERSON', 'email': 'person-3@example.org']).
  mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']).
  V('p-1', 'p-2').
  addE('FOLLOWED').to(V('p-1')).
  V('p-1', 'p-2', 'p-3').
  addE('VISITED').to(V('c-1')).
  id()
```

La query deve inserire 5 archi: 2 archi FOLLOWED e 3 archi VISITED. Tuttavia, la query così com'è scritta inserisce 8 archi: 2 FOLLOWED e 6 VISITED. Il motivo di ciò è che l'operazione che inserisce i 2 archi FOLLOWED emette 2 traverser, facendo sì che la successiva operazione di inserimento, che inserisce 3 archi, venga eseguita due volte.

La soluzione consiste nell'aggiungere un passaggio `fold()` dopo ogni operazione che può potenzialmente emettere più di un traverser:

```
g.mergeV([(T.id): 'v-1', (T.label): 'PERSON', email: 'person-1@example.org']).
  mergeV([(T.id): 'v-2', (T.label): 'PERSON', email: 'person-2@example.org']).
  mergeV([(T.id): 'v-3', (T.label): 'PERSON', email: 'person-3@example.org']).
  mergeV([(T.id): 'c-1', (T.label): 'CITY', name: 'city-1']).
  V('p-1', 'p-2').
  addE('FOLLOWED').
    to(V('p-1')).
  fold().
  V('p-1', 'p-2', 'p-3').
  addE('VISITED').
    to(V('c-1')).
  id()
```

In questo caso è stato inserito un passaggio `fold()` dopo l'operazione che inserisce gli archi FOLLOWED. In questo modo si ottiene un singolo traverser, che fa sì che l'operazione successiva venga eseguita una sola volta.

Lo svantaggio di questo approccio è che la query ora non è completamente ottimizzata, perché `fold()` non è ottimizzato. Anche l'operazione di inserimento che segue `fold()` ora non sarà ottimizzata.

Se è necessario usare `fold()` per ridurre il numero di traverser per i passaggi successivi, provare a ordinare le operazioni in modo che quelle meno costose occupino la parte non ottimizzata della query.

## Impostazione della cardinalità
<a name="gremlin-upserts-setting-cardinality"></a>

 La cardinalità predefinita per le proprietà dei vertici in Neptune è impostata, il che significa che quando si usa mergeV () ai valori forniti nella mappa verrà assegnata a tutti quella cardinalità. Per utilizzare una singola cardinalità, è necessario utilizzarla in modo esplicito. A partire dalla TinkerPop versione 3.7.0, è disponibile una nuova sintassi che consente di fornire la cardinalità come parte della mappa, come mostrato nell'esempio seguente: 

```
g.mergeV([(T.id): '1234']).
  option(onMatch, ['age': single(20), 'name': single('alice'), 'city': set('miami')])
```

 In alternativa, è possibile impostare la cardinalità come impostazione predefinita nel modo seguente: `option` 

```
// age and name are set to single cardinality by default
g.mergeV([(T.id): '1234']).
  option(onMatch, ['age': 22, 'name': 'alice', 'city': set('boston')], single)
```

 Nelle versioni `mergeV()` precedenti alla 3.7.0 sono disponibili meno opzioni per impostare la cardinalità. L'approccio generale consiste nel tornare alla `property()` fase seguente: 

```
g.mergeV([(T.id): '1234']). 
  option(onMatch, sideEffect(property(single,'age', 20).
  property(set,'city','miami')).constant([:]))
```

**Nota**  
 Questo approccio funziona solo `mergeV()` quando viene utilizzato con una fase iniziale. Non sareste quindi in grado di concatenarvi `mergeV()` all'interno di un singolo attraversamento, poiché il primo passaggio `mergeV()` successivo al passaggio iniziale che utilizza questa sintassi produrrà un errore nel caso in cui l'attraversatore in entrata sia un elemento grafico. In questo caso, è consigliabile suddividere le `mergeV()` chiamate in più richieste, ognuna delle quali può essere un passaggio iniziale. 

# Creazione di upsert Gremlin efficienti con `fold()/coalesce()/unfold()`
<a name="gremlin-efficient-upserts-pre-3.6"></a>

Un upsert (o inserimento condizionale) riutilizza un vertice o uno arco se già esiste oppure lo crea se non esiste. Upsert efficienti possono fare una differenza significativa nelle prestazioni delle query Gremlin.

Questa pagina mostra come utilizzare il modello Gremlin `fold()/coalesce()/unfold()` per creare upsert efficienti. Tuttavia, con il rilascio della TinkerPop versione 3.6.x introdotta in Neptune nella versione [1.2.1.0](engine-releases-1.2.1.0.md) del motore, nella maggior parte dei casi sono preferibili le nuove `mergeV()` fasi. `mergeE()` Il modello `fold()/coalesce()/unfold()` qui descritto può essere ancora utile in alcune situazioni complesse, ma in generale, se possibile, utilizzare `mergeV()` e `mergeE()`, come descritto in [Creazione di upsert efficienti con i passaggi `mergeV()` e `mergeE()` di Gremlin](gremlin-efficient-upserts.md).

Gli upsert consentono di scrivere operazioni di inserimento idempotenti: indipendentemente dal numero di volte in cui si esegue un'operazione di questo tipo, il risultato complessivo è lo stesso. Ciò è utile in scenari di scrittura altamente simultanei in cui modifiche simultanee alla stessa parte del grafo possono forzare il rollback di una o più transazioni con un'eccezione `ConcurrentModificationException`, rendendo quindi necessari un nuovo tentativo.

Ad esempio, la seguente query esegue l'upsert di un vertice cercando prima il vertice specificato nel set di dati e quindi raggruppando i risultati in un elenco. Nel primo attraversamento fornito al passaggio `coalesce()`, la query espande quindi questo elenco. Se l'elenco espanso non è vuoto, i risultati vengono emessi da `coalesce()`. Se, tuttavia, `unfold()` restituisce una raccolta vuota perché il vertice attualmente non esiste, `coalesce()` passa a valutare il secondo attraversamento che gli è stato fornito e in questo secondo attraversamento la query crea il vertice mancante.

```
g.V('v-1').fold()
          .coalesce(
             unfold(),
             addV('Person').property(id, 'v-1')
                           .property('email', 'person-1@example.org')
           )
```

## Utilizzo di una forma ottimizzata di `coalesce()` per gli upsert
<a name="gremlin-upserts-pre-3.6-coalesce"></a>

Neptune può ottimizzare l'idioma `fold().coalesce(unfold(), ...)` per apportare aggiornamenti con velocità di trasmissione effettiva elevata, ma questa ottimizzazione funziona solo se entrambe le parti di `coalesce()` restituiscono un vertice o un arco e nient'altro. Se si tenta di restituire qualcosa di diverso, ad esempio una proprietà, da qualsiasi parte di `coalesce()`, l'ottimizzazione di Neptune non si verifica. La query può avere esito positivo, ma non avrà le stesse prestazioni di una versione ottimizzata, in particolare su set di dati di grandi dimensioni.

Poiché le query upsert non ottimizzate aumentano i tempi di esecuzione e riducono la velocità di trasmissione effettiva, vale la pena utilizzare l'endpoint Gremlin `explain` per determinare se una query upsert è completamente ottimizzata. Quando si esaminano i piani `explain`, cercare le righe che iniziano con `+ not converted into Neptune steps` e `WARNING: >>`. Esempio:

```
+ not converted into Neptune steps: [FoldStep, CoalesceStep([[UnfoldStep], [AddEdgeSte...
WARNING: >> FoldStep << is not supported natively yet
```

Questi avvisi consentono di identificare le parti di una query che ne impediscono l'ottimizzazione completa.

A volte non è possibile ottimizzare completamente una query. In queste situazioni è consigliabile provare a inserire i passaggi che non possono essere ottimizzati alla fine della query, in modo da consentire al motore di ottimizzare il maggior numero possibile di passaggi. Questa tecnica viene utilizzata in alcuni esempi di upsert in batch, in cui tutti gli upsert ottimizzati per un insieme di vertici o archi vengono eseguiti prima di applicare eventuali modifiche aggiuntive, potenzialmente non ottimizzate, agli stessi vertici o archi.

## Upsert in batch per migliorare la velocità di trasmissione effettiva
<a name="gremlin-upserts-pre-3.6-batching"></a>

Per scenari di scrittura con velocità di trasmissione effettiva elevata, è possibile concatenare i passaggi per eseguire l'upsert di vertici e archi in batch. Il batching riduce il sovraccarico transazionale dell'upsert di un gran numero di vertici e archi. È quindi possibile migliorare ulteriormente la velocità di trasmissione effettiva eseguendo l'upsert di richieste batch in parallelo utilizzando più client.

Come regola generale, è consigliabile eseguire l'upsert di circa 200 record per richiesta batch. Un record è una singola etichetta o proprietà di un vertice o un arco. Un vertice con una singola etichetta e 4 proprietà, ad esempio, crea 5 record. Un arco con un'etichetta e una singola proprietà crea 2 record. Se si vuole eseguire l'upsert di batch di vertici, ciascuno con una singola etichetta e 4 proprietà, è necessario iniziare con una dimensione di batch di 40, perché `200 / (1 + 4) = 40`.

È possibile sperimentare con la dimensione del batch. 200 record per batch sono un buon punto di partenza, ma la dimensione ideale del batch può essere maggiore o minore a seconda del carico di lavoro. Tenere presente, tuttavia, che Neptune può limitare il numero complessivo di passaggi Gremlin per richiesta. Questo limite non è documentato, ma per sicurezza, cercare di assicurarsi che le richieste non contengano più di 1.500 passaggi Gremlin. Neptune può rifiutare richieste batch di grandi dimensioni con più di 1.500 passaggi.

Per aumentare la velocità di trasmissione effettiva, è possibile eseguire l'upsert di batch in parallelo utilizzando più client (vedi [Creazione di scritture multithread Gremlin efficienti](best-practices-gremlin-multithreaded-writes.md)). Il numero di client deve essere uguale al numero di thread di lavoro sull'istanza di Neptune writer, che in genere è 2 volte il numero di CPUs v sul server. Ad esempio, un'`r5.8xlarge`istanza ha 32 thread v CPUs e 64 thread di lavoro. Per scenari di scrittura con velocità di trasmissione effettiva elevata che utilizzano un'istanza `r5.8xlarge`, è necessario utilizzare 64 client che scrivono upsert in batch su Neptune in parallelo.

Ogni client deve inviare una richiesta batch e attendere il completamento della richiesta prima di inviarne un'altra. Sebbene più client vengano eseguiti in parallelo, ogni singolo client invia le richieste in modo seriale. Ciò garantisce che il server riceva un flusso costante di richieste che occupano tutti i thread di lavoro senza sovraccaricare la coda delle richieste lato server (vedi [Dimensionamento delle istanze database in un cluster database Neptune](feature-overview-db-clusters.md#feature-overview-sizing-instances)).

## Cercare di evitare passaggi che generano più traverser
<a name="gremlin-upserts-pre-3.6-single-traverser"></a>

Quando viene eseguito un passaggio Gremlin, accetta un traverser in entrata ed emette uno o più traverser in uscita. Il numero di traverser emessi da un passaggio determina il numero di volte in cui viene eseguito il passaggio successivo.

In genere, quando si eseguono operazioni in batch, si desidera che ogni operazione, ad esempio l'upsert del vertice A, venga eseguita una sola volta, in modo che la sequenza di operazioni sia la seguente: upsert del vertice A, quindi upsert del vertice B, quindi upsert del vertice C e così via. Finché un passaggio crea o modifica un solo elemento, emette un solo traverser e i passaggi che rappresentano l'operazione successiva vengono eseguiti una sola volta. Se, invece, un'operazione crea o modifica più di un elemento, emette più traverser, che a loro volta fanno sì che i passaggi successivi vengano eseguiti più volte, una volta per ogni traverser emesso. Ciò può comportare l'esecuzione di operazioni aggiuntive non necessarie nel database e, in alcuni casi, la creazione di vertici, archi o valori di proprietà aggiuntivi indesiderati.

Un esempio di come le cose possano andare male è con una query come `g.V().addV()`. Questa semplice query aggiunge un vertice per ogni vertice trovato nel grafo, perché `V()` emette un traverser per ogni vertice del grafo e ognuno di questi traverser attiva una chiamata a `addV()`.

Consulta [Combinazione di upsert e inserimenti](#gremlin-upserts-pre-3.6-and-inserts) per informazioni su come gestire le operazioni che possono emettere più traverser.

## Upsert dei vertici
<a name="gremlin-upserts-pre-3.6-vertices"></a>

È possibile utilizzare un ID vertice per determinare se esiste un vertice corrispondente. Questo è l'approccio preferito, perché Neptune ottimizza gli upsert per casi d'uso altamente simultanei. IDs Ad esempio, la seguente query crea un vertice con un determinato ID vertice se non esiste già o lo riutilizza se esiste:

```
g.V('v-1')
 .fold()
  .coalesce(unfold(),
            addV('Person').property(id, 'v-1')
                          .property('email', 'person-1@example.org'))
  .id()
```

Tenere presente che questa query termina con un passaggio `id()` Sebbene non sia strettamente necessario ai fini dell'upsert del vertice, l'aggiunta di un passaggio `id()` alla fine di una query di upsert assicura che il server non serializzi tutte le proprietà del vertice sul client, riducendo il costo di blocco della query.

In alternativa, è possibile utilizzare una proprietà del vertice per determinare se il vertice esiste:

```
g.V()
 .hasLabel('Person')
 .has('email', 'person-1@example.org')
 .fold()
 .coalesce(unfold(),
           addV('Person').property('email', 'person-1@example.org'))
 .id()
```

Se possibile, utilizzate i vertici forniti dall'utente IDs per creare vertici e utilizzateli per determinare se esiste un vertice durante un'operazione IDs di ribaltamento. Ciò consente a Neptune di ottimizzare i turbamenti intorno al. IDs Un upsert basato su ID può essere significativamente più efficiente di un upsert basato su proprietà in scenari di modifica altamente simultanei.

### Concatenamento degli upsert dei vertici
<a name="gremlin-upserts-pre-3.6-vertices-chaining"></a>

È possibile concatenare gli upsert dei vertici per inserirli in un batch:

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .id()
```

## Upsert degli archi
<a name="gremlin-upserts-pre-3.6-edges"></a>

È possibile utilizzare il bordo IDs per ribaltare i bordi nello stesso modo in cui si ribaltano i vertici utilizzando un vertice personalizzato. IDs Anche in questo caso, si tratta dell'approccio preferito perché consente a Neptune di ottimizzare la query. Ad esempio, la seguente query crea un arco in base al relativo ID arco se non esiste già oppure lo riutilizza se esiste. L'interrogazione utilizza anche i `to` vertici IDs del `from` e se deve creare un nuovo spigolo.

```
g.E('e-1')
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2'))
                        .property(id, 'e-1'))
 .id()
```

Molte applicazioni utilizzano vertici personalizzati IDs, ma lasciano che Neptune generi l'edge. IDs Se non conosci l'ID di un bordo, ma conosci il `to` vertice `from` and IDs, puoi usare questa formulazione per capovolgere un bordo:

```
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2')))
 .id()
```

Notare che il passaggio del vertice nella clausola `where()` deve essere `inV()` (o `outV()` se è stato usato `inE()` per trovare l'arco), non `otherV()`. Non utilizzare `otherV()` in questo caso, altrimenti la query non verrà ottimizzata e le prestazioni ne risentiranno. Ad esempio, Neptune non ottimizzerà la seguente query:

```
// Unoptimized upsert, because of otherV()
g.V('v-1')
 .outE('KNOWS')
 .where(otherV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           addE('KNOWS').from(V('v-1'))
                        .to(V('v-2')))
 .id()
```

Se non conosci lo spigolo o il vertice in primo piano, puoi IDs capovolgerlo usando le proprietà del vertice:

```
g.V()
 .hasLabel('Person')
 .has('name', 'person-1')
 .outE('LIVES_IN')
 .where(inV().hasLabel('City').has('name', 'city-1'))
 .fold()
 .coalesce(unfold(),
           addE('LIVES_IN').from(V().hasLabel('Person')
                                    .has('name', 'person-1'))
                           .to(V().hasLabel('City')
                                  .has('name', 'city-1')))
 .id()
```

Come per i ribaltamenti dei vertici, è preferibile utilizzare i ribaltamenti degli spigoli basati su ID utilizzando un ID del bordo o `from` un `to` vertice IDs, piuttosto che gli upsert basati sulle proprietà, in modo che Neptune possa ottimizzare completamente l'upsert.

### Verifica dell'esistenza dei vertici `from` e `to`
<a name="gremlin-upserts-pre-3.6-edges-checking"></a>

Notare la costruzione dei passaggi che creano un nuovo arco: `addE().from().to()`. Questa costruzione assicura che la query verifichi l'esistenza sia del vertice `from` che del vertice `to`. Se uno dei due non esiste, la query restituisce un errore come segue:

```
{
  "detailedMessage": "Encountered a traverser that does not map to a value for child...
  "code": "IllegalArgumentException",
  "requestId": "..."
}
```

Se è possibile che il vertice `from` o il vertice `to` non esista, è consigliabile provare a eseguirne l'upsert prima di eseguire l'upsert dell'arco tra di loro. Per informazioni, consulta [Combinazione di upsert di vertici e archi](#gremlin-upserts-pre-3.6-vertexes-and-edges).

Esiste una costruzione alternativa per la creazione di un arco che non è consigliabile usare: `V().addE().to()`. Aggiunge uno arco solo se esiste il vertice `from`. Se il vertice `to` non esiste, la query genera un errore, come descritto in precedenza, ma se il vertice `from` non esiste, l'inserimento di un arco non riesce ma non viene generato alcun errore. Ad esempio, il seguente upsert viene completato senza eseguire l'upsert di un arco se il vertice `from` non esiste:

```
// Will not insert edge if from vertex does not exist
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2')))
 .id()
```

### Concatenamento degli upsert degli archi
<a name="gremlin-upserts-pre-3.6-edges-chaining"></a>

Se desiderate concatenare gli upsert degli spigoli per creare una richiesta batch, dovete iniziare ogni upsert con una ricerca dei vertici, anche se conoscete già lo spigolo. IDs

Se conosci già gli IDs spigoli che vuoi ribaltare e i vertici e, puoi usare questa IDs formulazione`from`: `to`

```
g.V('v-1')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2'))
                   .property(id, 'e-1'))
 .V('v-3')
 .outE('KNOWS')
 .hasId('e-2').fold()
 .coalesce(unfold(),
           V('v-3').addE('KNOWS')
                   .to(V('v-4'))
                   .property(id, 'e-2'))
 .V('v-5')
 .outE('KNOWS')
 .hasId('e-3')
 .fold()
 .coalesce(unfold(),
           V('v-5').addE('KNOWS')
                   .to(V('v-6'))
                   .property(id, 'e-3'))
 .id()
```

Forse lo scenario di ribaltamento degli spigoli in batch più comune è che si conosce il `to` vertice `from` and IDs, ma non si conoscono gli spigoli che si desidera IDs ribaltare. In tal caso, utilizzare la seguente formulazione:

```
g.V('v-1')
 .outE('KNOWS')
 .where(inV().hasId('v-2'))
 .fold()
 .coalesce(unfold(),
           V('v-1').addE('KNOWS')
                   .to(V('v-2')))

 .V('v-3')
 .outE('KNOWS')
 .where(inV().hasId('v-4'))
 .fold()
 .coalesce(unfold(),
           V('v-3').addE('KNOWS')
                   .to(V('v-4')))
 .V('v-5')
 .outE('KNOWS')
 .where(inV().hasId('v-6'))
 .fold()
 .coalesce(unfold(),
           V('v-5').addE('KNOWS').to(V('v-6')))
 .id()
```

Se IDs conoscete gli spigoli che volete ribaltare, ma non conoscete i IDs `to` vertici `from` e (questo è insolito), potete usare questa formulazione:

```
g.V()
 .hasLabel('Person')
 .has('email', 'person-1@example.org')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-1@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-2@example.org'))
                     .property(id, 'e-1'))
 .V()
 .hasLabel('Person')
 .has('email', 'person-3@example.org')
 .outE('KNOWS')
 .hasId('e-2')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-3@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-4@example.org'))
              .property(id, 'e-2'))
 .V()
 .hasLabel('Person')
 .has('email', 'person-5@example.org')
 .outE('KNOWS')
 .hasId('e-1')
 .fold()
 .coalesce(unfold(),
           V().hasLabel('Person')
              .has('email', 'person-5@example.org')
              .addE('KNOWS')
              .to(V().hasLabel('Person')
                     .has('email', 'person-6@example.org'))
                     .property(id, 'e-3'))
 .id()
```

## Combinazione di upsert di vertici e archi
<a name="gremlin-upserts-pre-3.6-vertexes-and-edges"></a>

A volte si può desiderare di eseguire l'upsert sia dei vertici che degli archi che li collegano. È possibile combinare gli esempi batch illustrati qui. L'esempio seguente esegue l'upsert di 3 vertici e 2 archi:

```
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2')
                         .property('name', 'person-2@example.org'))
 .V('c-1')
 .fold()
 .coalesce(unfold(),
           addV('City').property(id, 'c-1')
                       .property('name', 'city-1'))
 .V('p-1')
 .outE('LIVES_IN')
 .where(inV().hasId('c-1'))
 .fold()
 .coalesce(unfold(),
           V('p-1').addE('LIVES_IN')
                   .to(V('c-1')))
 .V('p-2')
 .outE('LIVES_IN')
 .where(inV().hasId('c-1'))
 .fold()
 .coalesce(unfold(),
           V('p-2').addE('LIVES_IN')
                   .to(V('c-1')))
 .id()
```

## Combinazione di upsert e inserimenti
<a name="gremlin-upserts-pre-3.6-and-inserts"></a>

A volte si può desiderare di eseguire l'upsert sia dei vertici che degli archi che li collegano. È possibile combinare gli esempi batch illustrati qui. L'esempio seguente esegue l'upsert di 3 vertici e 2 archi:

Gli upsert in genere procedono un elemento alla volta. Se ci si attiene ai modelli di upsert qui presentati, ogni operazione di upsert emette un singolo traverser, che fa sì che l'operazione successiva venga eseguita una sola volta.

Tuttavia, a volte si può voler combinare gli upsert con gli inserimenti. Questo può essere il caso, ad esempio, se si usano gli archi per rappresentare istanze di azioni o eventi. Una richiesta potrebbe utilizzare gli upsert per assicurarsi che esistano tutti i vertici necessari e quindi utilizzare gli inserimenti per aggiungere gli archi. Con richieste di questo tipo, occorre prestare attenzione al numero potenziale di traverser emessi da ciascuna operazione.

Considerare l'esempio seguente, che combina upsert e inserimenti per aggiungere archi che rappresentano gli eventi nel grafo:

```
// Fully optimized, but inserts too many edges
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2')
                         .property('name', 'person-2@example.org'))
 .V('p-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-3')
                         .property('name', 'person-3@example.org'))
 .V('c-1')
 .fold()
 .coalesce(unfold(),
           addV('City').property(id, 'c-1')
                       .property('name', 'city-1'))
 .V('p-1', 'p-2')
 .addE('FOLLOWED')
 .to(V('p-1'))
 .V('p-1', 'p-2', 'p-3')
 .addE('VISITED')
 .to(V('c-1'))
 .id()
```

La query deve inserire 5 archi: 2 archi FOLLOWED e 3 archi VISITED. Tuttavia, la query così com'è scritta inserisce 8 archi: 2 FOLLOWED e 6 VISITED. Il motivo di ciò è che l'operazione che inserisce i 2 archi FOLLOWED emette 2 traverser, facendo sì che la successiva operazione di inserimento, che inserisce 3 archi, venga eseguita due volte.

La soluzione consiste nell'aggiungere un passaggio `fold()` dopo ogni operazione che può potenzialmente emettere più di un traverser:

```
g.V('p-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-1')
                         .property('email', 'person-1@example.org'))
 .V('p-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-2').
                         .property('name', 'person-2@example.org'))
 .V('p-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'p-3').
                         .property('name', 'person-3@example.org'))
 .V('c-1')
 .fold().
 .coalesce(unfold(),
            addV('City').property(id, 'c-1').
                        .property('name', 'city-1'))
 .V('p-1', 'p-2')
 .addE('FOLLOWED')
 .to(V('p-1'))
 .fold()
 .V('p-1', 'p-2', 'p-3')
 .addE('VISITED')
 .to(V('c-1')).
 .id()
```

In questo caso è stato inserito un passaggio `fold()` dopo l'operazione che inserisce gli archi FOLLOWED. In questo modo si ottiene un singolo traverser, che fa sì che l'operazione successiva venga eseguita una sola volta.

Lo svantaggio di questo approccio è che la query ora non è completamente ottimizzata, perché `fold()` non è ottimizzato. L'operazione di inserimento che segue `fold()` ora non sarà ottimizzata.

Se è necessario usare `fold()` per ridurre il numero di traverser per i passaggi successivi, provare a ordinare le operazioni in modo che quelle meno costose occupino la parte non ottimizzata della query.

## Upsert che modificano vertici e archi esistenti
<a name="gremlin-upserts-pre-3.6-that-modify"></a>

A volte si desidera creare un vertice o un arco se non esiste e quindi aggiungere o aggiornare una proprietà, indipendentemente dal fatto che si tratti di un vertice o di un arco nuovo o esistente.

Per aggiungere o modificare una proprietà, utilizzare il passaggio `property()`. Utilizzare questo passaggio all'esterno del passaggio `coalesce()`. Se si prova a modificare la proprietà di un vertice o di un arco esistente all'interno del passaggio `coalesce()`, la query potrebbe non essere ottimizzata dal motore di query Neptune.

La seguente query aggiunge o aggiorna la proprietà counter su ogni vertice di cui è stato eseguito l'upsert. Ogni passaggio `property()` ha una cardinalità singola per garantire che i nuovi valori sostituiscano quelli esistenti, anziché essere aggiunti a un insieme di valori esistenti.

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .property(single, 'counter', 1)
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .property(single, 'counter', 2)
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .property(single, 'counter', 3)
 .id()
```

Se si dispone di un valore di proprietà, ad esempio il valore di timestamp `lastUpdated`, che si applica a tutti gli elementi di cui è stato eseguito l'upsert, è possibile aggiungerlo o aggiornarlo alla fine della query:

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org'))
 .V('v-2').
 .fold().
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org'))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org'))
 .V('v-1', 'v-2', 'v-3')
 .property(single, 'lastUpdated', datetime('2020-02-08'))
 .id()
```

Se esistono condizioni aggiuntive che determinano se un vertice o un arco debba essere ulteriormente modificato, è possibile utilizzare un passaggio `has()` per filtrare gli elementi a cui verrà applicata una modifica. L'esempio seguente utilizza un passaggio `has()` per filtrare i vertici di cui è stato eseguito l'upsert in base al valore della relativa proprietà `version`. La query quindi aggiorna a 3 il valore `version` di qualsiasi vertice il cui valore `version` sia inferiore a 3:

```
g.V('v-1')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-1')
                         .property('email', 'person-1@example.org')
                         .property('version', 3))
 .V('v-2')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-2')
                         .property('email', 'person-2@example.org')
                         .property('version', 3))
 .V('v-3')
 .fold()
 .coalesce(unfold(),
           addV('Person').property(id, 'v-3')
                         .property('email', 'person-3@example.org')
                         .property('version', 3))
 .V('v-1', 'v-2', 'v-3')
 .has('version', lt(3))
 .property(single, 'version', 3)
 .id()
```

# Analisi dell'esecuzione di query Neptune tramite la funzionalità Gremlin `explain`
<a name="gremlin-explain"></a>

Amazon Neptune ha aggiunto una funzionalità Gremlin denominata *explain*. Questa funzionalità è uno strumento self-service che consente di comprendere l'approccio di esecuzione adottato dal motore Neptune. È possibile richiamarla aggiungendo un parametro `explain` a una chiamata HTTP che invia una query Gremlin.

La funzione `explain` fornisce informazioni sulla struttura logica dei piani di esecuzione di query. Puoi utilizzare queste informazioni per identificare potenziali problemi di valutazione ed esecuzione, oltre che per ottimizzare la query, come spiegato in [Ottimizzazione di query Gremlin](gremlin-traversal-tuning.md). Puoi quindi utilizzare gli [hint di query](gremlin-query-hints.md) per migliorare i piani di esecuzione delle query.

**Topics**
+ [

# Introduzione al funzionamento delle query Gremlin in Neptune
](gremlin-explain-background.md)
+ [

# Utilizzo dell'API Gremlin `explain` in Neptune
](gremlin-explain-api.md)
+ [

# API Gremlin `profile` in Neptune
](gremlin-profile-api.md)
+ [

# Ottimizzazione delle query Gremlin con `explain` e `profile`
](gremlin-traversal-tuning.md)
+ [

# Supporto nativo dei passaggi Gremlin in Amazon Neptune
](gremlin-step-support.md)

# Introduzione al funzionamento delle query Gremlin in Neptune
<a name="gremlin-explain-background"></a>

Per sfruttare appieno i report `explain` e `profile` di Gremlin in Amazon Neptune, è utile comprendere alcune informazioni generali sulle query Gremlin.

**Topics**
+ [

# Dichiarazioni Gremlin in Neptune
](gremlin-explain-background-statements.md)
+ [

# Come Neptune elabora le query Gremlin mediante gli indici di dichiarazione
](gremlin-explain-background-indexing-examples.md)
+ [

# Come vengono elaborate le query Gremlin in Neptune
](gremlin-explain-background-querying.md)

# Dichiarazioni Gremlin in Neptune
<a name="gremlin-explain-background-statements"></a>

I dati del grafo delle proprietà in Amazon Neptune sono costituiti da dichiarazioni a quattro posizioni (quadruple). Ognuna di queste dichiarazioni rappresenta una singola unità atomica dei dati del grafo di proprietà. Per ulteriori informazioni, consulta [Modello di dati a grafo di Neptune](feature-overview-data-model.md). Analogamente al modello di dati Resource Description Framework (RDF), queste quattro posizioni sono le seguenti:
+ `subject (S)`
+ `predicate (P)`
+ `object (O)`
+ `graph (G)`

Ogni dichiarazione è un'asserzione su una o più risorse. Ad esempio, una dichiarazione può asserire l'esistenza di una relazione tra due risorse o può collegare una proprietà (coppia chiave-valore) ad alcune risorse.

Il predicato può essere considerato come il verbo della dichiarazione, che descrive il tipo di relazione o la proprietà. L'oggetto è la destinazione della relazione o il valore della proprietà. La posizione del grafo è opzionale e può essere utilizzata in diversi modi. Per i dati del grafo delle proprietà (PG) Neptune, questa è inutilizzata (grafico null) o è utilizzata per rappresentare l'identificatore di un arco. Un set di dichiarazioni con identificatori di risorsa condivisi crea un grafo.

Esistono tre classi di dichiarazioni nel modello di dati del grafo delle proprietà Neptune:

**Topics**
+ [Dichiarazioni dell'etichetta del vertice](#gremlin-explain-background-vertex-labels)
+ [Dichiarazioni di edge](#gremlin-explain-background-edge-statements)
+ [Dichiarazioni di proprietà](#gremlin-explain-background-property-statements)

## Dichiarazioni dell'etichetta del vertice Gremlin
<a name="gremlin-explain-background-vertex-labels"></a>

Le dichiarazioni dell'etichetta del vertice in Neptune hanno due scopi:
+ Tracciare le etichette per un vertice.
+ La presenza di almeno una di queste dichiarazioni implica di per sé l'esistenza di un determinato vertice nel grafo.

Il soggetto di queste dichiarazioni è un identificatore del vertice e l'oggetto è un'etichetta, entrambi specificati dall'utente. È possibile utilizzare uno predicato fisso speciale per queste dichiarazioni, visualizzato come `<~label>` e un identificatore del grafo predefinito (il grafo null), visualizzato come `<~>`.

Considera, ad esempio, l'attraversamento `addV` seguente:

```
g.addV("Person").property(id, "v1")
```

Questo attraversamento determina l'aggiunta della seguente dichiarazione al grafo.

```
StatementEvent[Added(<v1> <~label> <Person> <~>) .]
```

## Dichiarazioni di edge Gremlin
<a name="gremlin-explain-background-edge-statements"></a>

Una dichiarazione di arco Gremlin implica di per sé l'esistenza di un arco tra due vertici in un grafo in Neptune. Il soggetto (S) di una dichiarazione di edge è il vertice `from` di origine. Il predicato (P) è un'etichetta di edge fornita dall'utente. L'oggetto (O) è il vertice `to` di destinazione. Il grafico (G) è un identificatore di edge fornito dall'utente.

Considera, ad esempio, l'attraversamento `addE` seguente:

```
g.addE("knows").from(V("v1")).to(V("v2")).property(id, "e1")
```

L'attraversamento comporta l'aggiunta della seguente dichiarazione al grafico.

```
StatementEvent[Added(<v1> <knows> <v2> <e1>) .]
```

## Dichiarazioni di proprietà Gremlin
<a name="gremlin-explain-background-property-statements"></a>

Una dichiarazione di proprietà Gremlin in Neptune afferma un singolo valore di proprietà per un vertice o un arco. Il soggetto è un identificatore di vertice o edge fornito dall'utente. Il predicato è il nome della proprietà (chiave) e l'oggetto è il singolo valore della proprietà. Il grafo (G) è di nuovo l'identificatore del grafo predefinito, il grafo null, visualizzato come `<~>`.

Considerate il seguente esempio di proprietà vertex.

```
g.V("v1").property("name", "John")
```

Questa dichiarazione genera quanto segue.

```
StatementEvent[Added(<v1> <name> "John" <~>) .]
```

Le istruzioni di proprietà differiscono dalle altre in quanto il relativo oggetto è un valore primitivo (`string`, `date`, `byte`, `short`, `int`, `long`, `float` o `double`). Il loro oggetto non è un identificatore di risorsa che può essere utilizzato come il soggetto di un'altra asserzione.

Per le proprietà multiple, ogni singolo valore di proprietà nel set riceve la propria dichiarazione.

```
g.V("v1").property(set, "phone", "956-424-2563").property(set, "phone", "956-354-3692 (tel:9563543692)")
```

I risultati sono illustrati di seguito.

```
StatementEvent[Added(<v1> <phone> "956-424-2563" <~>) .]
StatementEvent[Added(<v1> <phone> "956-354-3692" <~>) .]
```

Le proprietà degli spigoli vengono gestite in modo simile alle proprietà dei vertici, ma utilizzano l'identificatore del bordo nella posizione (S). Ad esempio, l'aggiunta di una proprietà a un bordo:

```
g.E("e1").property("weight", 0.8)
```

Ciò comporta l'aggiunta della seguente istruzione al grafico.

```
StatementEvent[Added(<e1> <weight> 0.8 <~>) .]
```

# Come Neptune elabora le query Gremlin mediante gli indici di dichiarazione
<a name="gremlin-explain-background-indexing-examples"></a>

L'accesso alle dichiarazioni in Amazon Neptune avviene tramite tre indici di dichiarazioni, come descritto in [In che modo le dichiarazioni vengono indicizzate in Neptune](feature-overview-storage-indexing.md). Neptune estrae un *modello* di dichiarazione da una query Gremlin in cui alcune posizioni sono note mentre le altre vengono individuate tramite la ricerca nell'indice.

Neptune presuppone che le dimensioni dello schema del grafo delle proprietà non siano grandi. Ciò significa che il numero di etichette degli archi e di nomi di proprietà distinti è piuttosto basso, determinando un basso numero totale di predicati distinti. Neptune tiene traccia dei predicati distinti in un indice separato. Utilizza questa cache di predicati per eseguire una scansione dell'unione di `{ all P x POGS }` anziché utilizzare un indice OSPG. La possibilità di evitare un indice OSPG di attraversamento inverso permette di risparmiare spazio di storage e throughput del caricamento.

L'API Neptune Explain/Profile Gremlin ti consente di ottenere il conteggio dei predicati nel tuo grafico. È possibile quindi determinare se l'applicazione invalida il presupposto di Neptune che le dimensioni dello schema del grafo delle proprietà siano ridotte.

I seguenti esempi illustrano come Neptune utilizza gli indici per elaborare le query Gremlin.

**Domanda: quali sono le etichette dei vertici `v1`?**

```
  Gremlin code:      g.V('v1').label()
  Pattern:           (<v1>, <~label>, ?, ?)
  Known positions:   SP
  Lookup positions:  OG
  Index:             SPOG
  Key range:         <v1>:<~label>:*
```

**Domanda: quali sono gli edge "noti" dei vertici `v1`?**

```
  Gremlin code:      g.V('v1').out('knows')
  Pattern:           (<v1>, <knows>, ?, ?)
  Known positions:   SP
  Lookup positions:  OG
  Index:             SPOG
  Key range:         <v1>:<knows>:*
```

**Domanda: quali vertici hanno un'etichetta di vertice `Person`?**

```
  Gremlin code:      g.V().hasLabel('Person')
  Pattern:           (?, <~label>, <Person>, <~>)
  Known positions:   POG
  Lookup positions:  S
  Index:             POGS
  Key range:         <~label>:<Person>:<~>:*
```

**Domanda: Quali sono i from/to vertici di un determinato spigolo? `e1`**

```
  Gremlin code:      g.E('e1').bothV()
  Pattern:           (?, ?, ?, <e1>)
  Known positions:   G
  Lookup positions:  SPO
  Index:             GPSO
  Key range:         <e1>:*
```

Un indice di dichiarazione **non** presente in Neptune è un indice OSPG di attraversamento inverso. Questo indice può essere utilizzato per raccogliere tutti gli edge in entrata in tutte le etichette edge, come nell'esempio seguente.

**Domanda: quali sono i vertici `v1` adiacenti in entrata?**

```
  Gremlin code:      g.V('v1').in()
  Pattern:           (?, ?, <v1>, ?)
  Known positions:   O
  Lookup positions:  SPG
  Index:             OSGP  // <-- Index does not exist
```

# Come vengono elaborate le query Gremlin in Neptune
<a name="gremlin-explain-background-querying"></a>

In Amazon Neptune, attraversamenti più complessi possono essere rappresentati da una serie di modelli che creano una relazione basata sulla definizione di variabili denominate che possono essere condivise tra modelli per creare join. Questo viene mostrato nell’esempio seguente.

**Domanda: cos'è il quartiere a due hop del vertice `v1`?**

```
  Gremlin code:      g.V(‘v1’).out('knows').out('knows').path()
  Pattern:           (?1=<v1>, <knows>, ?2, ?) X Pattern(?2, <knows>, ?3, ?)

  The pattern produces a three-column relation (?1, ?2, ?3) like this:
                     ?1     ?2     ?3
                     ================
                     v1     v2     v3
                     v1     v2     v4
                     v1     v5     v6
```

Condividendo la variabile `?2` tra i due modelli (nella posizione O del primo modello e nella posizione S del secondo modello), si crea un join dai primi quartieri hop ai secondi quartieri hop. Ogni soluzione Neptune ha associazioni per le tre variabili denominate, che possono essere utilizzate per ricreare [TinkerPopun](http://tinkerpop.apache.org/docs/current/reference/#_the_traverser) Traverser (comprese le informazioni sul percorso).

```
```

[http://tinkerpop.apache.org/docs/current/reference/#traversal](http://tinkerpop.apache.org/docs/current/reference/#traversal) Questi passaggi, che fanno parte del [ TinkerPop progetto open source Apache](http://tinkerpop.apache.org/), sono sia gli operatori logici che fisici che compongono un attraversamento Gremlin nell'implementazione di riferimento. Entrambi vengono utilizzati per rappresentare il modello della query. Si tratta di operatori eseguibili che possono generare soluzioni in base alla semantica dell'operatore che rappresentano. Ad esempio, `.V()` è sia rappresentato che eseguito da. TinkerPop [GraphStep](http://tinkerpop.apache.org/docs/current/reference/#graph-step)

Poiché questi off-the-shelf TinkerPop passaggi sono eseguibili, un TinkerPop Traversal di questo tipo può eseguire qualsiasi interrogazione Gremlin e produrre la risposta corretta. Tuttavia, se eseguiti su un grafico di grandi dimensioni, TinkerPop i passaggi a volte possono essere molto inefficienti e lenti. Anziché usarle, Neptune cerca di convertire l'attraversamento in un formato dichiarativo composto da gruppi di modelli, come descritto in precedenza.

Neptune non supporta attualmente tutti gli operatori Gremlin (passaggi) nel motore di query nativo. Pertanto, tenta di comprimere il maggior numero di fasi possibili in una singola `NeptuneGraphQueryStep`, che contiene il piano di query logico dichiarativo per tutte le fasi che sono state convertite. Idealmente, tutte le fasi vengono convertite. Ma quando viene rilevato un passaggio che non può essere convertito, Neptune interrompe l'esecuzione nativa e rinvia tutta l'esecuzione delle query da quel momento in avanti ai passaggi. TinkerPop Non tenta di intrufolarsi nell'esecuzione nativa.

Dopo che i passaggi vengono tradotte in un piano di query logico, Neptune esegue una serie di ottimizzatori di query che riscrivono il piano di query in base all'analisi statica e alle cardinalità stimate. Questi ottimizzatori eseguono operazioni come riordinare operatori in base a conteggi di intervalli, eliminare operatori superflui o ridondanti, riordinare i filtri, eseguire il push di operatori in gruppi diversi e così via.

Dopo aver prodotto un piano di query ottimizzato, Neptune crea una pipeline di operatori fisici che eseguono il lavoro di esecuzione della query. Ciò include la lettura dei dati dagli indici di dichiarazione, l'esecuzione di join di vari tipi, il filtraggio, l'ordinamento e così via. La pipeline produce un flusso di soluzioni che viene poi riconvertito in un flusso di oggetti Traverser. TinkerPop

## Serializzazione dei risultati delle query
<a name="gremlin-explain-background-querying-serialization"></a>

Amazon Neptune attualmente si affida ai serializzatori TinkerPop dei messaggi di risposta per convertire i risultati delle query TinkerPop (Traversers) in dati serializzati da inviare via cavo al client. Questi formati di serializzazione tendono a essere piuttosto dettagliati.

Ad esempio, per serializzare il risultato di una query del vertice quale `g.V().limit(1)`, il motore di query Neptune deve eseguire una singola ricerca per produrre il risultato della query. Tuttavia, il serializzatore `GraphSON` eseguirà un numero elevato di ricerche aggiuntive per creare un pacchetto del vertice nel formato di serializzazione. Deve eseguire una ricerca per ottenere l'etichetta, una per ottenere le chiavi di proprietà e una ricerca per chiave di proprietà per il vertice per ottenere tutti i valori per ogni chiave.

Alcuni dei formati di serializzazione sono più efficienti, ma tutti richiedono ricerche aggiuntive. Inoltre, i TinkerPop serializzatori non cercano di evitare ricerche duplicate, spesso con il risultato che molte ricerche vengono ripetute inutilmente.

Questo rende molto importante scrivere le query in modo da richiedere specificamente solo le informazioni necessarie. Ad esempio, `g.V().limit(1).id()` restituisce solo l'ID del vertice ed elimina tutte le ricerche di serializzatore aggiuntive. [API Gremlin `profile` in Neptune](gremlin-profile-api.md) consente di vedere quante chiamate di ricerca vengono effettuate durante l'esecuzione della query e durante la serializzazione.

# Utilizzo dell'API Gremlin `explain` in Neptune
<a name="gremlin-explain-api"></a>

L'API `explain` di Gremlin in Amazon Neptune restituisce il piano di query che verrebbe eseguito se fosse stata eseguita una determinata query. Poiché l'API non esegue effettivamente la query, il piano viene restituito quasi istantaneamente.

Si differenzia dal passaggio TinkerPop .explain () per poter riportare informazioni specifiche per il motore Neptune.

## Informazioni contenute in un report Gremlin `explain`
<a name="gremlin-explain-api-results"></a>

Il report `explain` contiene le seguenti informazioni:
+ La stringa di query che è stata richiesta.
+ **L'attraversamento originale.** Questo è l'oggetto TinkerPop Traversal prodotto analizzando la stringa di query in passaggi. TinkerPop È equivalente alla query originale prodotta eseguendo la query `.explain()` su. TinkerPop TinkerGraph
+ **L'attraversamento convertito.** Questo è il Neptune Traversal prodotto convertendo il Traversal nella rappresentazione del piano di interrogazione TinkerPop logica di Neptune. In molti casi l'intero TinkerPop attraversamento viene convertito in due passaggi di Neptune: uno che esegue l'intera query () `NeptuneGraphQueryStep` e uno che converte l'output del motore di query Neptune in Traversers (). TinkerPop `NeptuneTraverserConverterStep`
+ **L'attraversamento ottimizzato.** Questa è la versione ottimizzata del piano di query Neptune dopo che è stato eseguito tramite una serie di ottimizzatori di riduzione del lavoro statici che riscrivono la query in base all'analisi statica e alle cardinalità stimate. Questi ottimizzatori eseguono operazioni come riordinare operatori in base a conteggi di intervalli, eliminare operatori superflui o ridondanti, riordinare i filtri, eseguire il push di operatori in gruppi diversi e così via.
+ **Il conteggio di predicati.** A causa della strategia di indicizzazione Neptune descritta in precedenza, avere un numero elevato di predicati diversi può causare problemi di prestazioni. Ciò vale soprattutto per query che utilizzano operatori di attraversamento inverso senza etichetta edge (`.in` o `.both`). Se vengono utilizzati tali operatori e il conteggio di predicati è sufficientemente elevato, il report `explain` visualizza un messaggio di avviso.
+ **Informazioni su DFE.** Quando il motore alternativo DFE è abilitato, nell'attraversamento ottimizzato possono apparire i seguenti componenti di attraversamento:
  + **`DFEStep`**: passaggio DFE ottimizzato per Neptune nell'attraversamento che contiene un oggetto `DFENode` figlio. `DFEStep` rappresenta la parte del piano di query che viene eseguita nel motore DFE.
  + **`DFENode`**: contiene la rappresentazione intermedia come uno o più oggetti `DFEJoinGroupNodes` figlio.
  + **`DFEJoinGroupNode`**: rappresenta l'unione di uno o più elementi `DFENode` o `DFEJoinGroupNode`.
  + **`NeptuneInterleavingStep`**: passaggio DFE ottimizzato per Neptune nell'attraversamento che contiene un oggetto `DFEStep` figlio.

    Contiene anche un elemento `stepInfo` che contiene informazioni sull'attraversamento, come l'elemento di frontiera, gli elementi di percorso utilizzati e così via. Queste informazioni vengono utilizzate per elaborare l'oggetto `DFEStep` figlio.

  Un modo semplice per scoprire se la query viene valutata dal motore DFE consiste nel verificare se l'output `explain` contiene un oggetto `DFEStep`. Qualsiasi parte dell'attraversamento che non fa parte di non verrà eseguita da DFE e `DFEStep` verrà eseguita dal motore. TinkerPop 

  Vedi [Esempio con DFE abilitato](#gremlin-explain-dfe) per un report di esempio.

## Sintassi di Gremlin `explain`
<a name="gremlin-explain-api-syntax"></a>

La sintassi dell'API `explain` è identica a quella dell'API HTTP per la query, tranne per il fatto che utilizza `/gremlin/explain` come endpoint anziché `/gremlin`, come nell'esempio seguente.

```
curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().limit(1)"}'
```

La query precedente produrrebbe il seguente output.

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().limit(1)

Original Traversal
==================
[GraphStep(vertex,[]), RangeGlobalStep(0,1)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
        }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY}
        }, finishers=[limit(1)], annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 18
```

## TinkerPop Passi non convertiti
<a name="gremlin-explain-unconverted-steps"></a>

Idealmente, tutte le TinkerPop fasi di un attraversamento hanno una copertura dell'operatore Neptune nativa. In caso contrario, Neptune ricorre all'esecuzione a fasi per eventuali lacune TinkerPop nella copertura degli operatori. Se un attraversamento utilizza un passaggio per il quale Neptune non dispone ancora di copertura nativa, il report `explain` visualizza un avviso che mostra dove si è verificata la lacuna.

Quando viene rilevato un passaggio senza un corrispondente operatore Neptune nativo, l'intero attraversamento da quel punto in poi viene eseguito TinkerPop utilizzando i passaggi, anche se i passaggi successivi hanno operatori Neptune nativi.

L'eccezione a questo è quando viene richiamata la ricerca full-text Neptune. NeptuneSearchStep Implementa passaggi senza equivalenti nativi come passaggi di ricerca a testo completo.

## Esempio di output di `explain` in cui tutti i passaggi di una query dispongono di equivalenti nativi
<a name="gremlin-explain-all-steps-converted"></a>

Di seguito è riportato un esempio di report di `explain` per una query in cui tutti i passaggi dispongono di equivalenti nativi:

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().out()

Original Traversal
==================
[GraphStep(vertex,[]), VertexStep(OUT,vertex)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, ?5, ?3, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep], maxVarId=7}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 18
```

## Esempio in cui alcune fasi in una query non dispongono di equivalenti nativi
<a name="gremlin-explain-not-all-steps-converted"></a>

Neptune gestisce `GraphStep` e `VertexStep` in modo nativo, ma se si introduce `FoldStep` e `UnfoldStep`, l'output risultante di `explain` è diverso:

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============
g.V().fold().unfold().out()

Original Traversal
==================
[GraphStep(vertex,[]), FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
        }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep
]
+ not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .], {estimatedCardinality=INFINITY}
        }, annotations={path=[Vertex(?1):GraphStep], maxVarId=3}
    },
    NeptuneTraverserConverterStep,
    NeptuneMemoryTrackerStep
]
+ not converted into Neptune steps: [FoldStep, UnfoldStep, VertexStep(OUT,vertex)]

WARNING: >> FoldStep << is not supported natively yet
```

In questo caso, `FoldStep` interrompe l'esecuzione nativa. Tuttavia, anche la `VertexStep` successiva non viene più gestita in modo nativo perché viene visualizzato a valle delle fasi `Fold/Unfold`.

Per migliorare le prestazioni e ridurre i costi, è importante provare a formulare trasversali in modo che la massima quantità di lavoro possibile venga eseguita nativamente all'interno del motore di query Neptune, anziché implementazioni graduali. TinkerPop 

## Esempio di una query che utilizza Neptune full-text-search
<a name="gremlin-explain-full-text-search-steps"></a>

La query seguente utilizza la ricerca full-text Neptune:

```
g.withSideEffect("Neptune#fts.endpoint", "some_endpoint")
  .V()
  .tail(100)
  .has("Neptune#fts mark*")
  -------
  .has("name", "Neptune#fts mark*")
  .has("Person", "name", "Neptune#fts mark*")
```

La parte `.has("name", "Neptune#fts mark*")` limita la ricerca ai vertici con `name`, mentre `.has("Person", "name", "Neptune#fts mark*")` limita la ricerca ai vertici con `name` e all'etichetta `Person`. Ciò ha come risultato il seguente attraversamento nel report di `explain`:

```
Final Traversal
[NeptuneGraphQueryStep(Vertex) {
    JoinGroupNode {
        PatternNode[(?1, termid(1,URI), ?2, termid(0,URI)) . project distinct ?1 .], {estimatedCardinality=INFINITY}
    }, annotations={path=[Vertex(?1):GraphStep], maxVarId=4}
}, NeptuneTraverserConverterStep, NeptuneTailGlobalStep(10), NeptuneTinkerpopTraverserConverterStep, NeptuneSearchStep {
    JoinGroupNode {
        SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint}
    }
    JoinGroupNode {
        SearchNode[(idVar=?3, query=mark*, field=name) . project ask .], {endpoint=some_endpoint}
    }
}]
```

## Esempio di utilizzo di `explain` quando il motore DFE è abilitato
<a name="gremlin-explain-dfe"></a>

Di seguito è riportato un esempio di un report di `explain` quando il motore di query alternativo DFE è abilitato:

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().as("a").out().has("name", "josh").out().in().where(eq("a"))


Original Traversal
==================
[GraphStep(vertex,[])@[a], VertexStep(OUT,vertex), HasStep([name.eq(josh)]), VertexStep(OUT,vertex), VertexStep(IN,vertex), WherePredicateStep(eq(a))]

Converted Traversal
===================
Neptune steps:
[
    DFEStep(Vertex) {
      DFENode {
        DFEJoinGroupNode[ children={
          DFEPatternNode[(?1, <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>, ?2, <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>) . project DISTINCT[?1] {rangeCountEstimate=unknown}],
          DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}]
        }, {rangeCountEstimate=unknown}
        ]
      } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep]
    } ,
    NeptuneTraverserConverterDFEStep
]
+ not converted into Neptune steps: HasStep([name.eq(josh)]),
Neptune steps:
[
    NeptuneInterleavingStep {
      StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms],
      DFEStep(Vertex) {
        DFENode {
          DFEJoinGroupNode[ children={
            DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}],
            DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph> . ), {rangeCountEstimate=unknown}]
          }, {rangeCountEstimate=unknown}
          ]
        } [Vertex(?9):VertexStep, Vertex(?12):VertexStep]
      } 
    }
]
+ not converted into Neptune steps: WherePredicateStep(eq(a)),
Neptune steps:
[
    DFECleanupStep
]


Optimized Traversal
===================
Neptune steps:
[
    DFEStep(Vertex) {
      DFENode {
        DFEJoinGroupNode[ children={
          DFEPatternNode[(?1, ?3, ?4, ?5) . project ALL[?1, ?4] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}]
        }, {rangeCountEstimate=unknown}
        ]
      } [Vertex(?1):GraphStep@[a], Vertex(?4):VertexStep]
    } ,
    NeptuneTraverserConverterDFEStep
]
+ not converted into Neptune steps: NeptuneHasStep([name.eq(josh)]),
Neptune steps:
[
    NeptuneMemoryTrackerStep,
    NeptuneInterleavingStep {
      StepInfo[joinVars=[?7, ?1], frontierElement=Vertex(?7):HasStep, pathElements={a=(last,Vertex(?1):GraphStep@[a])}, listPathElement={}, indexTime=0ms],
      DFEStep(Vertex) {
        DFENode {
          DFEJoinGroupNode[ children={
            DFEPatternNode[(?7, ?8, ?9, ?10) . project ALL[?7, ?9] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}],
            DFEPatternNode[(?12, ?11, ?9, ?13) . project ALL[?9, ?12] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807}]
          }, {rangeCountEstimate=unknown}
          ]
        } [Vertex(?9):VertexStep, Vertex(?12):VertexStep]
      } 
    }
]
+ not converted into Neptune steps: WherePredicateStep(eq(a)),
Neptune steps:
[
    DFECleanupStep
]


WARNING: >> [NeptuneHasStep([name.eq(josh)]), WherePredicateStep(eq(a))] << (or one of the children for each step) is not supported natively yet

Predicates
==========
# of predicates: 8
```

Per una descrizione delle sezioni specifiche del motore DFE nel report, vedi [Informazioni in `explain`](#gremlin-explain-api-results).

# API Gremlin `profile` in Neptune
<a name="gremlin-profile-api"></a>

L'API `profile` di Gremlin in Neptune esegue un attraversamento Gremlin specificato, raccoglie varie metriche relative all'esecuzione e produce un report di profile come output.

Si differenzia dal passaggio TinkerPop .profile () per poter riportare informazioni specifiche per il motore Neptune.

Il report del profilo include le seguenti informazioni relative al piano di query:
+ La pipeline dell'operatore fisico
+ Le operazioni di indice per l'esecuzione e la serializzazione di query
+ Le dimensioni del risultato

L'API `profile` utilizza una versione estesa della sintassi API HTTP per le query, con `/gremlin/profile` come endpoint anziché `/gremlin`.

## Parametri specifici di `profile` di Gremlin in Neptune
<a name="gremlin-profile-api-parameters"></a>
+ **profile.results**: `boolean`, valori consentiti: `TRUE` e `FALSE`, valore predefinito: `TRUE`.

  Se true, i risultati della query vengono raccolti e visualizzati come parte del report di `profile`. Se false, viene visualizzato solo il conteggio dei risultati.
+ **profile.chop**: `int`, valore predefinito: 250.

  Se diverso da zero, la stringa dei risultati viene troncata a tale numero di caratteri. Ciò non impedisce l'acquisizione di tutti i risultati. Limita semplicemente le dimensioni della stringa nel report del profilo. Se impostato su zero, la stringa contiene tutti i risultati.
+ **profile.serializer**: `string`, valore predefinito: `<null>`.

  Se diverso da null, i risultati raccolti vengono restituiti in un messaggio di risposta serializzato nel formato specificato da questo parametro. Il numero di operazioni di indice necessarie per produrre tale messaggio di risposta viene segnalato insieme alle dimensioni in byte da inviare al client.

  I valori consentiti sono `<null>` o uno qualsiasi dei valori enumerativi «Serializers» del TinkerPop driver o del tipo MIME validi.

  ```
  "application/json" or "GRAPHSON"
  "application/vnd.gremlin-v1.0+json" or "GRAPHSON_V1"
  "application/vnd.gremlin-v1.0+json;types=false" or "GRAPHSON_V1_UNTYPED"
  "application/vnd.gremlin-v2.0+json" or "GRAPHSON_V2"
  "application/vnd.gremlin-v2.0+json;types=false" or "GRAPHSON_V2_UNTYPED"
  "application/vnd.gremlin-v3.0+json" or "GRAPHSON_V3"
  "application/vnd.gremlin-v3.0+json;types=false" or "GRAPHSON_V3_UNTYPED"
  "application/vnd.graphbinary-v1.0" or "GRAPHBINARY_V1"
  ```
+ **profile.indexOps**: `boolean`, valori consentiti: `TRUE` e `FALSE`, valore predefinito: `FALSE`.

  Se true, mostra un report dettagliato di tutte le operazioni sugli indici eseguite durante l'esecuzione e la serializzazione delle query. Avviso: questo report può essere dettagliato.



## Output di esempio di `profile` di Gremlin in Neptune
<a name="gremlin-profile-sample-output"></a>

Di seguito è riportata una query `profile` di esempio.

```
curl -k -X POST https://your-neptune-endpoint:port/gremlin/profile \
     -d '{"gremlin":"g.V().hasLabel(\"airport\").has(\"code\", \"AUS\").emit().repeat(in().simplePath()).times(2).limit(100)", "profile.serializer":"application/vnd.gremlin-v3.0+json"}'
```

Questa query genera il seguente report `profile` quando eseguita sul grafo di esempio air-routes da post del blog, [Let Me Graph That For You - Part 1 - Air Routes](https://aws.amazon.com/blogs/database/let-me-graph-that-for-you-part-1-air-routes/).

```
*******************************************************
                Neptune Gremlin Profile
*******************************************************

Query String
==================
g.V().hasLabel("airport").has("code", "AUS").emit().repeat(in().simplePath()).times(2).limit(100)

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([~label.eq(airport), code.eq(AUS)]), RepeatStep(emit(true),[VertexStep(IN,vertex), PathFilterStep(simple), RepeatEndStep],until(loops(2))), RangeGlobalStep(0,100)]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(Vertex) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "AUS", ?) . project ?1 .], {estimatedCardinality=1, indexTime=84, hashJoin=true, joinTime=3, actualTotalOutput=1}
            PatternNode[(?1, <~label>, ?2=<airport>, <~>) . project ask .], {estimatedCardinality=3374, indexTime=29, hashJoin=true, joinTime=0, actualTotalOutput=61}
            RepeatNode {
                Repeat {
                    PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0, joinTime=3}
                }
                Emit {
                    Filter(true)
                }
                LoopsCondition {
                    LoopsFilter([?1, ?3],eq(2))
                }
            }, annotations={repeatMode=BFS, emitFirst=true, untilFirst=false, leftVar=?1, rightVar=?3}
        }, finishers=[limit(100)], annotations={path=[Vertex(?1):GraphStep, Repeat[Vertex(?3):VertexStep]], joinStats=true, optimizationTime=495, maxVarId=7, executionTime=323}
    },
    NeptuneTraverserConverterStep
]

Physical Pipeline
=================
NeptuneGraphQueryStep
    |-- StartOp
    |-- JoinGroupOp
        |-- SpoolerOp(100)
        |-- DynamicJoinOp(PatternNode[(?1, <code>, "AUS", ?) . project ?1 .], {estimatedCardinality=1, indexTime=84, hashJoin=true})
        |-- SpoolerOp(100)
        |-- DynamicJoinOp(PatternNode[(?1, <~label>, ?2=<airport>, <~>) . project ask .], {estimatedCardinality=3374, indexTime=29, hashJoin=true})
        |-- RepeatOp
            |-- <upstream input> (Iteration 0) [visited=1, output=1 (until=0, emit=1), next=1]
            |-- BindingSetQueue (Iteration 1) [visited=61, output=61 (until=0, emit=61), next=61]
                |-- SpoolerOp(100)
                |-- DynamicJoinOp(PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0})
            |-- BindingSetQueue (Iteration 2) [visited=38, output=38 (until=38, emit=0), next=0]
                |-- SpoolerOp(100)
                |-- DynamicJoinOp(PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . SimplePathFilter(?1, ?3)) .], {hashJoin=true, estimatedCardinality=50148, indexTime=0})
        |-- LimitOp(100)

Runtime (ms)
============
Query Execution:  392.686
Serialization:   2636.380

Traversal Metrics
=================
Step                                                               Count  Traversers       Time (ms)    % Dur
-------------------------------------------------------------------------------------------------------------
NeptuneGraphQueryStep(Vertex)                                        100         100         314.162    82.78
NeptuneTraverserConverterStep                                        100         100          65.333    17.22
                                            >TOTAL                     -           -         379.495        -

Repeat Metrics
==============
Iteration  Visited   Output    Until     Emit     Next
------------------------------------------------------
        0        1        1        0        1        1
        1       61       61        0       61       61
        2       38       38       38        0        0
------------------------------------------------------
               100      100       38       62       62

Predicates
==========
# of predicates: 16

WARNING: reverse traversal with no edge label(s) - .in() / .both() may impact query performance

Results
=======
Count: 100
Output: [v[3], v[3600], v[3614], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[47], v[49], v[136], v[13], v[15], v[16], v[17], v[18], v[389], v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[416], v[29], v[30], v[430], v[31], v[9...
Response serializer: GRYO_V3D0
Response size (bytes): 23566

Index Operations
================
Query execution:
    # of statement index ops: 3
    # of unique statement index ops: 3
    Duplication ratio: 1.0
    # of terms materialized: 0
Serialization:
    # of statement index ops: 200
    # of unique statement index ops: 140
    Duplication ratio: 1.43
    # of terms materialized: 393
```

Oltre ai piani di query restituiti da una chiamata a Neptune `explain`, i risultati di `profile` includono le statistiche di runtime relative all'esecuzione della query. Ogni operazione join è contrassegnata con il tempo richiesto per eseguire il join e il numero effettivo di soluzioni trasferite.

L'output `profile` include il tempo richiesto durante la fase di esecuzione della query principale, nonché la fase di serializzazione se l'opzione `profile.serializer` è stata specificata.

Nella parte inferiore dell'output `profile` è inclusa anche l'analisi dettagliata delle operazioni sugli indici eseguite durante ogni fase.

Notare che esecuzioni consecutive della stessa query possono mostrare risultati diversi in termini di tempo di esecuzione e operazioni sugli indici a causa del caching.

Per le query che utilizzano la fase `repeat()`, è disponibile un'analisi dettagliata della frontiera per ogni iterazione se la fase `repeat()` è stata trasferita come parte di una `NeptuneGraphQueryStep`.

## Differenze nei report di `profile` quando è abilitato il motore DFE
<a name="gremlin-profile-dfe-output"></a>

Quando il motore di query alternativo Neptune DFE è abilitato, l'output di `profile` è leggermente diverso:

**Attraversamento ottimizzato:** questa sezione è simile a quella dell'output di `explain` ma contiene informazioni aggiuntive. Include il tipo di operatori DFE che sono stati considerati nella pianificazione e le stime dei costi associati nel caso peggiore e nel caso migliore.

**Pipeline fisica:** questa sezione raccoglie gli operatori utilizzati per eseguire la query. Gli elementi `DFESubQuery` astraggono il piano fisico utilizzato dal motore DFE per eseguire la parte del piano di cui è responsabile. Gli elementi `DFESubQuery` sono illustrati nella sezione seguente in cui sono elencate le statistiche del motore DFE.

**DFEQueryStatistiche del motore:** questa sezione viene visualizzata solo quando almeno una parte della query viene eseguita da DFE. Descrive varie statistiche di runtime specifiche di DFE e contiene una suddivisione dettagliata del tempo impiegato nelle varie parti dell'esecuzione della query, da parte di `DFESubQuery`.

Le sottoquery annidate in diversi elementi `DFESubQuery` sono semplificate in questa sezione e gli identificatori univoci sono contrassegnati da un'intestazione che inizia con `subQuery=`.

**Metriche di attraversamento:** questa sezione mostra le metriche di attraversamento a livello di passaggio e, quando il motore DFE esegue tutta o parte della query, visualizza le metriche per `DFEStep` e/o `NeptuneInterleavingStep`. Per informazioni, consulta [Ottimizzazione delle query Gremlin con `explain` e `profile`](gremlin-traversal-tuning.md).

**Nota**  
DFE è una funzionalità sperimentale rilasciata in modalità di laboratorio, quindi il formato esatto dell'output di `profile` è ancora soggetto a modifiche.

## Output di `profile` di esempio quando il motore Neptune Dataflow (DFE) è abilitato
<a name="gremlin-profile-sample-dfe-output"></a>

Quando il motore DFE viene utilizzato per eseguire le query Gremlin, l'output di [API Gremlin `profile`](#gremlin-profile-api) è formattato come mostrato nell'esempio seguente.

Query:

```
curl https://your-neptune-endpoint:port/gremlin/profile \
  -d "{\"gremlin\": \"g.withSideEffect('Neptune#useDFE', true).V().has('code', 'ATL').out()\"}"
```

```
*******************************************************
                    Neptune Gremlin Profile
    *******************************************************

    Query String
    ==================
    g.withSideEffect('Neptune#useDFE', true).V().has('code', 'ATL').out()

    Original Traversal
    ==================
    [GraphStep(vertex,[]), HasStep([code.eq(ATL)]), VertexStep(OUT,vertex)]

    Optimized Traversal
    ===================
    Neptune steps:
    [
        DFEStep(Vertex) {
          DFENode {
            DFEJoinGroupNode[null](
              children=[
                DFEPatternNode((?1, vp://code[419430926], ?4, defaultGraph[526]) . project DISTINCT[?1] objectFilters=(in(ATL[452987149]) . ), {rangeCountEstimate=1},
                  opInfo=(type=PipelineJoin, cost=(exp=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=0.00),wc=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=0.00)),
                    disc=(type=PipelineScan, cost=(exp=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=34.00),wc=(in=1.00,out=1.00,io=0.00,comp=0.00,mem=34.00))))),
                DFEPatternNode((?1, ?5, ?6, ?7) . project ALL[?1, ?6] graphFilters=(!= defaultGraph[526] . ), {rangeCountEstimate=9223372036854775807})],
              opInfo=[
                OperatorInfoWithAlternative[
                  rec=(type=PipelineJoin, cost=(exp=(in=1.00,out=27.76,io=0.00,comp=0.00,mem=0.00),wc=(in=1.00,out=27.76,io=0.00,comp=0.00,mem=0.00)),
                    disc=(type=PipelineScan, cost=(exp=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00),wc=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00)))),
                  alt=(type=PipelineScan, cost=(exp=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00),wc=(in=1.00,out=27.76,io=Infinity,comp=0.00,mem=295147905179352830000.00)))]])
          } [Vertex(?1):GraphStep, Vertex(?6):VertexStep]
        } ,
        NeptuneTraverserConverterDFEStep,
        DFECleanupStep
    ]


    Physical Pipeline
    =================
    DFEStep
        |-- DFESubQuery1

    DFEQueryEngine Statistics
    =================
    DFESubQuery1
    ╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤════════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio  │ Time (ms) ║
    ╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪════════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFESolutionInjection  │ solutions=[]                                                                                                 │ -    │ 0        │ 1         │ 0.00   │ 0.01      ║
    ║    │        │        │                       │ outSchema=[]                                                                                                 │      │          │           │        │           ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_1 │ -    │ 1        │ 1         │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 2  │ 3      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_2 │ -    │ 1        │ 242       │ 242.00 │ 0.02      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 3  │ 4      │ -      │ DFEMergeChunks        │ -                                                                                                            │ -    │ 242      │ 242       │ 1.00   │ 0.01      ║
    ╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 4  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 242      │ 0         │ 0.00   │ 0.01      ║
    ╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧════════╧═══════════╝


    subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_1
    ╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                   │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
    ╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFEPipelineScan      │ pattern=Node(?1) with property 'code' as ?4 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.22      ║
    ║    │        │        │                      │ inlineFilters=[(?4 IN ["ATL"])]                             │      │          │           │       │           ║
    ║    │        │        │                      │ patternEstimate=1                                           │      │          │           │       │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 1  │ 2      │ -      │ DFEMergeChunks       │ -                                                           │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 2  │ 4      │ -      │ DFERelationalJoin    │ joinVars=[]                                                 │ -    │ 2        │ 1         │ 0.50  │ 0.09      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 3  │ 2      │ -      │ DFESolutionInjection │ solutions=[]                                                │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
    ║    │        │        │                      │ outSchema=[]                                                │      │          │           │       │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
    ║ 4  │ -      │ -      │ DFEDrain             │ -                                                           │ -    │ 1        │ 0         │ 0.00  │ 0.01      ║
    ╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


    subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#089f43e3-4d71-4259-8d19-254ff63cee04/graph_2
    ╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════╤══════╤══════════╤═══════════╤════════╤═══════════╗
    ║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                           │ Mode │ Units In │ Units Out │ Ratio  │ Time (ms) ║
    ╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════╪══════╪══════════╪═══════════╪════════╪═══════════╣
    ║ 0  │ 1      │ -      │ DFESolutionInjection │ solutions=[]                        │ -    │ 0        │ 1         │ 0.00   │ 0.01      ║
    ║    │        │        │                      │ outSchema=[?1]                      │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 1  │ 2      │ 3      │ DFETee               │ -                                   │ -    │ 1        │ 2         │ 2.00   │ 0.01      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?1                           │ -    │ 1        │ 1         │ 1.00   │ 0.21      ║
    ║    │        │        │                      │ ordered=false                       │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?1]                           │ -    │ 1        │ 1         │ 1.00   │ 0.03      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Edge((?1)-[?7:?5]->(?6))    │ -    │ 1        │ 242       │ 242.00 │ 0.51      ║
    ║    │        │        │                      │ constraints=[]                      │      │          │           │        │           ║
    ║    │        │        │                      │ patternEstimate=9223372036854775807 │      │          │           │        │           ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 5  │ 6      │ 7      │ DFESync              │ -                                   │ -    │ 243      │ 243       │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                   │ -    │ 1        │ 1         │ 1.00   │ 0.01      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                   │ -    │ 242      │ 242       │ 1.00   │ 0.02      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                   │ -    │ 243      │ 242       │ 1.00   │ 0.31      ║
    ╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼────────┼───────────╢
    ║ 9  │ -      │ -      │ DFEDrain             │ -                                   │ -    │ 242      │ 0         │ 0.00   │ 0.01      ║
    ╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════╧══════╧══════════╧═══════════╧════════╧═══════════╝


    Runtime (ms)
    ============
    Query Execution: 11.744

    Traversal Metrics
    =================
    Step                                                               Count  Traversers       Time (ms)    % Dur
    -------------------------------------------------------------------------------------------------------------
    DFEStep(Vertex)                                                      242         242          10.849    95.48
    NeptuneTraverserConverterDFEStep                                     242         242           0.514     4.52
                                                >TOTAL                     -           -          11.363        -

    Predicates
    ==========
    # of predicates: 18

    Results
    =======
    Count: 242


    Index Operations
    ================
    Query execution:
        # of statement index ops: 0
        # of terms materialized: 0
```

**Nota**  
Poiché il motore DFE è una funzionalità sperimentale rilasciata in modalità di laboratorio, il formato esatto dell'output di `profile` è soggetto a modifiche.

# Ottimizzazione delle query Gremlin con `explain` e `profile`
<a name="gremlin-traversal-tuning"></a>

[[Spesso puoi ottimizzare le tue query Gremlin in Amazon Neptune per ottenere prestazioni migliori, utilizzando le informazioni disponibili nei report che ottieni dalla descrizione e dal profilo di Neptune.](gremlin-profile-api.md)](gremlin-explain-api.md) APIs A tale scopo, è utile capire come Neptune elabora gli attraversamenti di Gremlin.

**Importante**  
Nella TinkerPop versione 3.4.11 è stata apportata una modifica che migliora la correttezza del modo in cui le query vengono elaborate, ma per il momento a volte può influire seriamente sulle prestazioni delle query.  
Una query di questo tipo, ad esempio, può essere eseguita molto più lentamente:  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  out()
```
I vertici dopo il passaggio limite vengono ora recuperati in modo non ottimale a causa della modifica 3.4.11. TinkerPop Per evitare il problema, puoi modificare la query aggiungendo il passaggio barrier() in qualsiasi punto dopo `order().by()`. Esempio:  

```
g.V().hasLabel('airport').
  order().
    by(out().count(),desc).
  limit(10).
  barrier().
  out()
```
TinkerPop [3.4.11 è stato abilitato nella versione 1.0.5.0 del motore Neptune.](engine-releases-1.0.5.0.md)

## Informazioni sull'elaborazione degli attraversamenti di Gremlin in Neptune
<a name="gremlin-traversal-processing"></a>

Quando un attraversamento Gremlin viene inviato a Neptune, ci sono tre processi principali che trasformano l'attraversamento in un piano di esecuzione sottostante che il motore deve eseguire. Questi sono l'analisi, la conversione e l'ottimizzazione:

![\[3 processi trasformano una query Gremlin in un piano di esecuzione.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/Gremlin_traversal_processing.png)


### Processo di analisi di un attraversamento
<a name="gremlin-traversal-processing-parsing"></a>

Il primo passaggio nell'elaborazione di un attraversamento consiste nell'analizzarlo in un linguaggio comune. [In Neptune, quel linguaggio comune è l'insieme TinkerPop di passaggi che fanno parte dell'API. TinkerPop](http://tinkerpop.apache.org/javadocs/3.4.8/full/org/apache/tinkerpop/gremlin/process/traversal/Step.html) Ciascuno di questi passaggi rappresenta un'unità di calcolo all'interno dell'attraversamento.

È possibile inviare un attraversamento Gremlin a Neptune come stringa o come bytecode. L'endpoint REST e il metodo `submit()` del driver client Java inviano gli attraversamenti come stringhe, come in questo esempio:

```
client.submit("g.V()")
```

Le applicazioni e i driver di linguaggio che utilizzano le [varianti del linguaggio Gremlin (GLV)](https://tinkerpop.apache.org/docs/current/tutorials/gremlin-language-variants/) inviano attraversamenti in bytecode.

### Processo di conversione di un attraversamento
<a name="gremlin-traversal-processing-conversion"></a>

Il secondo passaggio nell'elaborazione di un attraversamento consiste nel convertire TinkerPop i suoi passaggi in un insieme di passaggi di Nettuno convertiti e non convertiti. La maggior parte dei passaggi del linguaggio di interrogazione Apache TinkerPop Gremlin viene convertita in passaggi specifici di Neptune ottimizzati per l'esecuzione sul motore Neptune sottostante. Quando si incontra un TinkerPop passaggio senza un equivalente di Neptune in un attraversamento, quel passaggio e tutti i passaggi successivi dell'attraversamento vengono elaborati dal motore di query. TinkerPop 

Per ulteriori informazioni su quali passaggi possono essere convertiti e in quali circostanze, consulta [Supporto dei passaggi Gremlin](gremlin-step-support.md).

### Processo di ottimizzazione di un attraversamento
<a name="gremlin-traversal-processing-optimization"></a>

Il passaggio finale dell'elaborazione di un attraversamento consiste nell'eseguire la serie di passaggi convertiti e non convertiti tramite l'ottimizzatore, per cercare di determinare il miglior piano di esecuzione. Il risultato di questa ottimizzazione è il piano di esecuzione elaborato dal motore Neptune.

## Utilizzo dell'API `explain` di Gremlin in Neptune per ottimizzare le query
<a name="gremlin-traversal-tuning-explain"></a>

L'API explain di Neptune non è la stessa del passaggio `explain()` di Gremlin. Restituisce il piano di esecuzione finale che il motore Neptune elaborerà durante l'esecuzione della query. Poiché non esegue alcuna elaborazione, restituisce lo stesso piano indipendentemente dai parametri utilizzati e l'output non contiene statistiche sull'esecuzione effettiva.

Considerare il semplice attraversamento seguente che trova tutti i vertici dell'aeroporto di Anchorage:

```
g.V().has('code','ANC')
```

Esistono due modi per eseguire questo attraversamento tramite l'API Neptune `explain`. Il primo modo è effettuare una chiamata REST all'endpoint explain, come riportato di seguito:

```
curl -X POST https://your-neptune-endpoint:port/gremlin/explain -d '{"gremlin":"g.V().has('code','ANC')"}'
```

Il secondo modo consiste nell'utilizzare il comando magic di cella [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) di Neptune Workbench con il parametro `explain`. In questo modo si passa l'attraversamento contenuto nel corpo della cella all'API Neptune `explain` e quindi si visualizza l'output risultante quando si esegue la cella:

```
%%gremlin explain

g.V().has('code','ANC')
```

L'output dell'API `explain` risultante descrive il piano di esecuzione di Neptune per l'attraversamento. Come si può vedere nell'immagine seguente, il piano include ognuno dei 3 passaggi della pipeline di elaborazione:

![\[Output dell'API explain per un semplice attraversamento Gremlin.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/Gremlin_explain_output_1.png)


### Ottimizzazione di un attraversamento osservando i passaggi non convertiti
<a name="gremlin-traversal-tuning-explain-non-converted-steps"></a>

Una delle prime cose da verificare nell'output dell'API Neptune `explain` riguarda la presenza di passaggi Gremlin non convertiti in passaggi nativi Neptune. In un piano di query, quando viene rilevato un passaggio che non può essere convertito in un passaggio nativo Neptune, questo passaggio e tutti i passaggi successivi del piano vengono elaborati dal server Gremlin.

Nell'esempio riportato sopra, tutti i passaggi dell'attraversamento sono stati convertiti. Esaminiamo l'output dell'API `explain` per questo attraversamento:

```
g.V().has('code','ANC').out().choose(hasLabel('airport'), values('code'), constant('Not an airport'))
```

Come si può vedere nell'immagine qui sotto, Neptune non è riuscito a convertire il passaggio `choose()`:

![\[Output dell'API explain in cui non tutti i passaggi possono essere convertiti.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/Gremlin_explain_output_2.png)


Ci sono diverse cose che si possono fare per ottimizzare le prestazioni dell'attraversamento. La prima sarebbe quella di riscriverlo in modo tale da eliminare il passaggio che non può essere convertito. Un'altra potrebbe essere quella di spostare il passaggio alla fine dell'attraversamento in modo che tutti gli altri passaggi possano essere convertiti in passaggi nativi.

Non è sempre necessario ottimizzare un piano di query con passaggi non convertiti. Se i passaggi che non possono essere convertiti si trovano alla fine dell'attraversamento e sono correlati al modo in cui viene formattato l'output anziché a come viene attraversato il grafo, possono avere un effetto minimo sulle prestazioni.

### 
<a name="gremlin-traversal-tuning-explain-unindexed-lookups"></a>

Un'altra cosa da considerare quando si esamina l'output dell'API Neptune `explain` sono i passaggi che non utilizzano indici. Il seguente attraversamento trova tutti gli aeroporti con voli che atterrano ad Anchorage:

```
g.V().has('code','ANC').in().values('code')
```

L'output dell'API explain per questo attraversamento è:

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().has('code','ANC').in().values('code')

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,vertex), PropertiesStep([code],value)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, <code>, "ANC", ?) . project ask .]
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
            PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1}
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=INFINITY}
            PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 26

WARNING: reverse traversal with no edge label(s) - .in() / .both() may impact query performance
```

Il messaggio `WARNING` nella parte inferiore dell'output è dovuto al fatto che il passaggio `in()` dell'attraversamento non può essere gestito utilizzando uno dei 3 indici gestiti da Neptune (vedi [In che modo le dichiarazioni vengono indicizzate in Neptune](feature-overview-storage-indexing.md) e [Dichiarazioni Gremlin in Neptune](gremlin-explain-background-statements.md)). Poiché il passaggio `in()` non contiene alcun filtro per gli archi, non può essere risolto utilizzando l'indice `SPOG`, `POGS` o `GPSO`. Neptune deve invece eseguire una scansione di unione per trovare i vertici richiesti, il che è molto meno efficiente.

Esistono due modi per ottimizzare l'attraversamento in questa situazione. Il primo consiste nell'aggiungere uno o più criteri di filtro al passaggio `in()` in modo da poter utilizzare una ricerca indicizzata per risolvere la query. Per l'esempio precedente, si avrà:

```
g.V().has('code','ANC').in('route').values('code')
```

L'output dell'API Neptune `explain` per l'attraversamento rivisto non contiene più il messaggio `WARNING`:

```
*******************************************************
                Neptune Gremlin Explain
*******************************************************

Query String
============

g.V().has('code','ANC').in('route').values('code')

Original Traversal
==================
[GraphStep(vertex,[]), HasStep([code.eq(ANC)]), VertexStep(IN,[route],vertex), PropertiesStep([code],value)]

Converted Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <~label>, ?2, <~>) . project distinct ?1 .]
            PatternNode[(?1, <code>, "ANC", ?) . project ask .]
            PatternNode[(?3, ?5, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) . ContainsFilter(?5 in (<route>)) .]
            PatternNode[(?3, <~label>, ?4, <~>) . project ask .]
            PatternNode[(?3, ?7, ?8, <~>) . project ?3,?8 . ContainsFilter(?7 in (<code>)) .]
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Optimized Traversal
===================
Neptune steps:
[
    NeptuneGraphQueryStep(PropertyValue) {
        JoinGroupNode {
            PatternNode[(?1, <code>, "ANC", ?) . project ?1 .], {estimatedCardinality=1}
            PatternNode[(?3, ?5=<route>, ?1, ?6) . project ?1,?3 . IsEdgeIdFilter(?6) .], {estimatedCardinality=32042}
            PatternNode[(?3, ?7=<code>, ?8, <~>) . project ?3,?8 .], {estimatedCardinality=7564}
        }, annotations={path=[Vertex(?1):GraphStep, Vertex(?3):VertexStep, PropertyValue(?8):PropertiesStep], maxVarId=9}
    },
    NeptuneTraverserConverterStep
]

Predicates
==========
# of predicates: 26
```

Un'altra opzione se si eseguono molti attraversamenti di questo tipo è quella di eseguirli in un cluster database Neptune con l'indice `OSGP` opzionale abilitato (vedi [Abilitazione di un indice OSGP](feature-overview-storage-indexing.md#feature-overview-storage-indexing-osgp)). L'abilitazione di un indice `OSGP` presenta degli svantaggi:
+ Deve essere abilitato in un cluster database prima che vengano caricati i dati.
+ La velocità di inserimento di vertici e archi può rallentare fino al 23%.
+ L'utilizzo dello spazio di archiviazione aumenterà di circa il 20%.
+ Le query di lettura che distribuiscono le richieste su tutti gli indici possono avere latenze maggiori.

Avere un indice `OSGP` è molto utile per un insieme limitato di modelli di query, ma a meno che non li si esegua frequentemente, in genere è preferibile cercare di garantire che gli attraversamenti scritti possano essere risolti utilizzando i tre indici primari.

### Utilizzo di un numero elevato di predicati
<a name="gremlin-traversal-tuning-explain-many-predicates"></a>

Neptune considera ogni etichetta di arco e ogni nome distinto di proprietà di vertice o arco nel grafo come predicato ed è progettato per impostazione predefinita per funzionare con un numero relativamente basso di predicati distinti. Quando i dati del grafo contengono più di qualche migliaio di predicati, le prestazioni possono peggiorare.

L'output di Neptune `explain` avviserà se questo è il caso:

```
Predicates
==========
# of predicates: 9549
WARNING: high predicate count (# of distinct property names and edge labels)
```

Se non è conveniente rielaborare il modello di dati per ridurre il numero di etichette e proprietà, e quindi il numero di predicati, il modo migliore per ottimizzare gli attraversamenti è eseguirli in un cluster database con l'indice `OSGP` abilitato, come descritto in precedenza.

## Utilizzo dell'API `profile` di Gremlin in Neptune per ottimizzare gli attraversamenti
<a name="gremlin-traversal-tuning-profile"></a>

L'API Neptune `profile` è molto diversa dal passaggio `profile()` di Gremlin. Come l'API `explain`, il relativo output include il piano di query utilizzato dal motore Neptune durante l'esecuzione dell'attraversamento. Inoltre, l'output di `profile` include le statistiche di esecuzione effettive per l'attraversamento, in base a come sono impostati i parametri.

Considerare anche in questo caso il semplice attraversamento che trova tutti i vertici dell'aeroporto di Anchorage:

```
g.V().has('code','ANC')
```

Come per l'API `explain`, è possibile richiamare l'API `profile` tramite una chiamata REST:

```
curl -X POST https://your-neptune-endpoint:port/gremlin/profile -d '{"gremlin":"g.V().has('code','ANC')"}'
```

È anche possibile utilizzare il comando magic di cella [%%gremlin](notebooks-magics.md#notebooks-cell-magics-gremlin) di Neptune Workbench con il parametro `profile`. In questo modo si passa l'attraversamento contenuto nel corpo della cella all'API Neptune `profile` e quindi si visualizza l'output risultante quando si esegue la cella:

```
%%gremlin profile

g.V().has('code','ANC')
```

L'output dell'API `profile` risultante contiene sia il piano di esecuzione di Neptune per l'attraversamento che le statistiche sull'esecuzione del piano, come si può vedere in questa immagine:

![\[Un esempio di output dell'API Neptune profile.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/Gremlin_profile_output_1.png)


Nell'output di `profile`, la sezione del piano di esecuzione contiene solo il piano di esecuzione finale per l'attraversamento, non i passaggi intermedi. La sezione della pipeline contiene le operazioni della pipeline fisica che sono state eseguite e il tempo effettivo (in millisecondi) impiegato dall'esecuzione dell'attraversamento. La metrica di runtime è estremamente utile per confrontare i tempi impiegati da due diverse versioni di un attraversamento durante l'ottimizzazione.

**Nota**  
Il runtime iniziale di un attraversamento è generalmente più lungo rispetto ai runtime successivi, poiché il primo fa sì che i dati pertinenti vengano memorizzati nella cache.

La terza sezione dell'output di `profile` contiene le statistiche di esecuzione e i risultati dell'attraversamento. Per capire come queste informazioni possano essere utili per ottimizzare un attraversamento, considerare il seguente attraversamento, che trova tutti gli aeroporti il cui nome inizia con "Anchora" e tutti gli aeroporti raggiungibili in due fermate da tali aeroporti, indicando i codici aeroportuali, le rotte di volo e le distanze:

```
%%gremlin profile

g.withSideEffect("Neptune#fts.endpoint", "{your-OpenSearch-endpoint-URL").
    V().has("city", "Neptune#fts Anchora~").
    repeat(outE('route').inV().simplePath()).times(2).
    project('Destination', 'Route').
        by('code').
        by(path().by('code').by('dist'))
```

### Metriche di attraversamento nell'output dell'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-traversal-metrics"></a>

Il primo set di metriche disponibile in tutti gli output di `profile` è costituito dalle metriche di attraversamento. Sono simili alle metriche del passaggio `profile()` di Gremlin, con alcune differenze:

```
Traversal Metrics
=================
Step                                                               Count  Traversers       Time (ms)    % Dur
-------------------------------------------------------------------------------------------------------------
NeptuneGraphQueryStep(Vertex)                                       3856        3856          91.701     9.09
NeptuneTraverserConverterStep                                       3856        3856          38.787     3.84
ProjectStep([Destination, Route],[value(code), ...                  3856        3856         878.786    87.07
  PathStep([value(code), value(dist)])                              3856        3856         601.359
                                            >TOTAL                     -           -        1009.274        -
```

La prima colonna della tabella delle metriche di attraversamento elenca i passaggi eseguiti dall'attraversamento. I primi due passaggi sono generalmente i passaggi specifici di Neptune, `NeptuneGraphQueryStep` e `NeptuneTraverserConverterStep`.

`NeptuneGraphQueryStep` rappresenta il tempo di esecuzione per l'intera porzione dell'attraversamento che potrebbe essere convertito ed eseguito in modo nativo dal motore Neptune.

`NeptuneTraverserConverterStep`rappresenta il processo di conversione dell'output di tali passaggi convertiti in TinkerPop traverser che consentono di elaborare i passaggi che non possono essere convertiti, se presenti, o di restituire i risultati in un formato compatibile. TinkerPop

Nell'esempio precedente, abbiamo diversi passaggi non convertiti, quindi vediamo che ognuno di questi TinkerPop passaggi (`ProjectStep`,`PathStep`) appare quindi come una riga nella tabella.

[La seconda colonna della tabella riporta il numero di traverser *rappresentati* che hanno completato il passaggio, mentre la terza colonna riporta il numero di traverser che hanno superato quel passaggio, come spiegato nella documentazione della fase del profilo. `Count``Traversers` TinkerPop](https://tinkerpop.apache.org/docs/current/reference/#profile-step)

Nell'esempio ci sono 3.856 vertici e 3.856 traverser restituiti da `NeptuneGraphQueryStep`, e questi numeri rimangono invariati per tutta l'elaborazione rimanente perché `ProjectStep` e `PathStep` stanno formattando i risultati, non li filtrano.

**Nota**  
Al contrario TinkerPop, il motore Neptune non ottimizza le prestazioni *ingombrando* i suoi passaggi. `NeptuneGraphQueryStep` `NeptuneTraverserConverterStep` Il bulking è l' TinkerPopoperazione che combina i trasversali sullo stesso vertice per ridurre il sovraccarico operativo, e questo è ciò che causa la differenza tra i numeri e. `Count` `Traversers` Poiché il bulking si verifica solo nelle fasi a cui Neptune è delegato e non nelle fasi gestite TinkerPop da Neptune in modo nativo, le colonne and raramente differiscono. `Count` `Traverser`

La colonna Time riporta il numero di millisecondi impiegato dal passaggio e la colonna `% Dur` riporta la percentuale del tempo di elaborazione totale impiegato dal passaggio. Queste sono le metriche che indicano dove concentrare gli sforzi di ottimizzazione, mostrando i passaggi che hanno richiesto più tempo.

### Metriche delle operazioni di indicizzazione nell'output dell'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-index-operations"></a>

Un altro set di metriche nell'output dell'API Neptune profile è costituito dalle operazioni di indicizzazione:

```
Index Operations
================
Query execution:
    # of statement index ops: 23191
    # of unique statement index ops: 5960
    Duplication ratio: 3.89
    # of terms materialized: 0
```

Queste metriche riportano:
+ Numero totale di ricerche nell'indice.
+ Numero di ricerche univoche eseguite nell'indice.
+ Rapporto tra le ricerche totali nell'indice e quelle univoche. Un rapporto più basso indica una minore ridondanza.
+ Numero di termini materializzati dal dizionario dei termini.

### Metriche di ripetizione nell'output dell'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-repeat-metrics"></a>

Se l'attraversamento utilizza un passaggio `repeat()` come nell'esempio precedente, nell'output di `profile` viene visualizzata una sezione contenente le metriche di ripetizione:

```
Repeat Metrics
==============
Iteration  Visited   Output    Until     Emit     Next
------------------------------------------------------
        0        2        0        0        0        2
        1       53        0        0        0       53
        2     3856     3856     3856        0        0
------------------------------------------------------
              3911     3856     3856        0       55
```

Queste metriche riportano:
+ Conteggio dei cicli per una riga (colonna `Iteration`).
+ Numero di elementi visitati dal ciclo (colonna `Visited`).
+ Numero di elementi restituiti dal ciclo (colonna `Output`).
+ Ultimo elemento restituito dal ciclo (colonna `Until`).
+ Numero di elementi emessi dal ciclo (colonna `Emit`).
+ Numero di elementi passati dal ciclo al ciclo successivo (colonna `Next`).

Queste metriche di ripetizione sono molto utili per comprendere il fattore di ramificazione dell'attraversamento e per avere un'idea di quanto lavoro venga svolto dal database. È possibile utilizzare questi numeri per diagnosticare problemi di prestazioni, soprattutto quando lo stesso attraversamento si comporta in modo notevolmente diverso con parametri diversi.

### Metriche di ricerca full-text nell'output dell'API Neptune `profile`
<a name="gremlin-traversal-tuning-profile-fts-metrics"></a>

Quando un attraversamento utilizza una [ricerca full-text](full-text-search.md), come nell'esempio precedente, nell'output di `profile` viene visualizzata una sezione contenente le metriche di ricerca full-text (FTS):

```
FTS Metrics
==============
SearchNode[(idVar=?1, query=Anchora~, field=city) . project ?1 .],
    {endpoint=your-OpenSearch-endpoint-URL, incomingSolutionsThreshold=1000, estimatedCardinality=INFINITY,
    remoteCallTimeSummary=[total=65, avg=32.500000, max=37, min=28],
    remoteCallTime=65, remoteCalls=2, joinTime=0, indexTime=0, remoteResults=2}

    2 result(s) produced from SearchNode above
```

Questo mostra la query inviata al cluster ElasticSearch (ES) e riporta diverse metriche sull'interazione con le quali è possibile individuare i problemi di prestazioni relativi alla ricerca ElasticSearch di testo completo:
+ Informazioni di riepilogo sulle chiamate all'indice: ElasticSearch 
  + Numero totale di millisecondi richiesti da tutti gli oggetti remoteCalls per soddisfare la query (`total`).
  + Numero medio di millisecondi trascorsi in un oggetto remoteCall (`avg`).
  + Numero minimo di millisecondi trascorsi in un oggetto remoteCall (`min`).
  + Numero massimo di millisecondi trascorsi in un oggetto remoteCall (`max`).
+ Tempo totale impiegato da RemoteCalls to ElasticSearch ()`remoteCallTime`.
+ Il numero di chiamate RemoteCall effettuate a (). ElasticSearch `remoteCalls`
+ Il numero di millisecondi spesi per unire i risultati (). ElasticSearch `joinTime`
+ Numero di millisecondi trascorsi nelle ricerche nell'indice (`indexTime`).
+ Il numero totale di risultati restituiti da (). ElasticSearch `remoteResults`

# Supporto nativo dei passaggi Gremlin in Amazon Neptune
<a name="gremlin-step-support"></a>

Il motore Amazon Neptune attualmente non dispone del supporto nativo completo di tutti i passaggi Gremlin, come spiegato in [Ottimizzazione di query Gremlin](gremlin-traversal-tuning.md). Il supporto attuale si divide in quattro categorie:
+ [Passaggi Gremlin che possono sempre essere convertiti in operazioni native del motore Neptune](#gremlin-steps-always)
+ [Passaggi Gremlin che possono essere convertiti in operazioni native del motore Neptune in alcuni casi](#gremlin-steps-sometimes) 
+ [Passaggi Gremlin che non vengono mai convertiti in operazioni native del motore Neptune](#gremlin-steps-never) 
+ [Passaggi Gremlin che non sono affatto supportati in Neptune](#neptune-gremlin-steps-unsupported) 

## Passaggi Gremlin che possono sempre essere convertiti in operazioni native del motore Neptune
<a name="gremlin-steps-always"></a>

Molti passaggi Gremlin possono essere convertiti in operazioni native del motore Neptune purché soddisfino le seguenti condizioni:
+ Non devono essere preceduti nella query da un passaggio che non possa essere convertito.
+ Il relativo passaggio padre, se presente, deve poter essere convertito.
+ Tutti i relativi attraversamenti figlio, se presenti, devono poter essere convertiti.

I seguenti passaggi Gremlin vengono sempre convertiti in operazioni native del motore Neptune se soddisfino queste condizioni:
+ [and( )](http://tinkerpop.apache.org/docs/current/reference/#and-step)
+ [as( )](http://tinkerpop.apache.org/docs/current/reference/#as-step)
+ [count( )](http://tinkerpop.apache.org/docs/current/reference/#count-step)
+ [E( )](http://tinkerpop.apache.org/docs/current/reference/#graph-step)
+ [emit( )](http://tinkerpop.apache.org/docs/current/reference/#emit-step)
+ [explain( )](http://tinkerpop.apache.org/docs/current/reference/#explain-step)
+ [group( )](http://tinkerpop.apache.org/docs/current/reference/#group-step)
+ [groupCount( )](http://tinkerpop.apache.org/docs/current/reference/#groupcount-step)
+ [identity( )](http://tinkerpop.apache.org/docs/current/reference/#identity-step)
+ [is( )](http://tinkerpop.apache.org/docs/current/reference/#is-step)
+ [key( )](http://tinkerpop.apache.org/docs/current/reference/#key-step)
+ [label( )](http://tinkerpop.apache.org/docs/current/reference/#label-step)
+ [limit( )](http://tinkerpop.apache.org/docs/current/reference/#limit-step)
+ [local( )](http://tinkerpop.apache.org/docs/current/reference/#local-step)
+ [loops( )](http://tinkerpop.apache.org/docs/current/reference/#loops-step)
+ [not( )](http://tinkerpop.apache.org/docs/current/reference/#not-step)
+ [or( )](http://tinkerpop.apache.org/docs/current/reference/#or-step)
+ [profile( )](http://tinkerpop.apache.org/docs/current/reference/#profile-step)
+ [properties( )](http://tinkerpop.apache.org/docs/current/reference/#properties-step)
+ [subgraph( )](http://tinkerpop.apache.org/docs/current/reference/#subgraph-step)
+ [until( )](http://tinkerpop.apache.org/docs/current/reference/#until-step)
+ [V( )](http://tinkerpop.apache.org/docs/current/reference/#graph-step)
+ [value](http://tinkerpop.apache.org/docs/current/reference/#value-step)
+ [valueMap( )](http://tinkerpop.apache.org/docs/current/reference/#valuemap-step)
+ [values( )](http://tinkerpop.apache.org/docs/current/reference/#values-step)

## Passaggi Gremlin che possono essere convertiti in operazioni native del motore Neptune in alcuni casi
<a name="gremlin-steps-sometimes"></a>

Alcuni passaggi Gremlin possono essere convertiti in operazioni native del motore Neptune in alcune situazioni ma non in altre:
+ [addE( )](http://tinkerpop.apache.org/docs/current/reference/#addedge-step): il passaggio `addE()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che non sia immediatamente seguito da un passaggio `property()` contenente un attraversamento come chiave.
+ [addV( )](http://tinkerpop.apache.org/docs/current/reference/#addvertex-step): il passaggio `addV()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che non sia immediatamente seguito da un passaggio `property()` contenente un attraversamento come chiave o a meno che non vengano assegnate più etichette.
+ [aggregate( )](http://tinkerpop.apache.org/docs/current/reference/#store-step): il passaggio `aggregate()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che il passaggio non venga utilizzato in un attraversamento figlio o sottoattraversamento oppure a meno che il valore archiviato non sia qualcosa di diverso da un valore di vertice, arco, ID, etichetta o proprietà.

  Nell'esempio seguente, `aggregate()` non viene convertito perché viene utilizzato in un attraversamento figlio:

  ```
  g.V().has('code','ANC').as('a')
       .project('flights').by(select('a')
       .outE().aggregate('x'))
  ```

  In questo esempio, aggregate() non viene convertito perché ciò che viene archiviato è il valore `min()` di un valore:

  ```
  g.V().has('code','ANC').outE().aggregate('x').by(values('dist').min())
  ```
+ [barrier( )](http://tinkerpop.apache.org/docs/current/reference/#barrier-step): il passaggio `barrier()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che il passaggio successivo non venga convertito.
+ [cap( )](http://tinkerpop.apache.org/docs/current/reference/#cap-step): l'unico caso in cui il passaggio `cap()` viene convertito è quando viene combinato con il passaggio `unfold()` per restituire una versione espansa di un aggregato di valori di vertice, arco, ID o proprietà. In questo esempio, `cap()` verrà convertito perché è seguito da `.unfold()`:

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```

  Tuttavia, se si rimuove `.unfold()`, `cap()` non verrà convertito:

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport')
  ```
+ [coalesce ()](http://tinkerpop.apache.org/docs/current/reference/#coalesce-step) [— L'unico caso in cui il `coalesce()` passaggio viene convertito è quando segue lo [schema Upsert](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) consigliato nella pagina delle TinkerPop ricette.](http://tinkerpop.apache.org/docs/current/recipes/) Altri modelli coalesce() non sono consentiti. La conversione è limitata al caso in cui tutti gli attraversamenti figlio possano essere convertiti, producano tutti lo stesso tipo di output (vertice, arco, ID, valore, chiave o etichetta), attraversino tutti un nuovo elemento e non contengano il passaggio `repeat()`.
+ [constant( )](http://tinkerpop.apache.org/docs/current/reference/#constant-step): il passaggio constant() viene attualmente convertito solo se viene utilizzato all'interno di una parte `sack().by()` di un attraversamento per assegnare un valore costante, come questo:

  ```
  g.V().has('code','ANC').sack(assign).by(constant(10)).out().limit(2)
  ```
+ [cyclicPath( )](http://tinkerpop.apache.org/docs/current/reference/#cyclicpath-step): il passaggio `cyclicPath()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che il passaggio non venga utilizzato con i modulatori `by()`, `from()` o `to()`. Nelle seguenti query, ad esempio, `cyclicPath()` non viene convertito:

  ```
  g.V().has('code','ANC').as('a').out().out().cyclicPath().by('code')
  g.V().has('code','ANC').as('a').out().out().cyclicPath().from('a')
  g.V().has('code','ANC').as('a').out().out().cyclicPath().to('a')
  ```
+ [drop( )](http://tinkerpop.apache.org/docs/current/reference/#drop-step): il passaggio `drop()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che il passaggio non venga utilizzato all'interno di un passaggio `sideEffect(`) o `optional()`.
+ [fold ()](http://tinkerpop.apache.org/docs/current/reference/#fold-step) — Ci sono solo due situazioni in cui il passaggio fold () può essere convertito, vale a dire quando viene utilizzato nel [pattern Upsert](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) consigliato nella [pagina delle TinkerPop ricette](http://tinkerpop.apache.org/docs/current/recipes/) e quando viene utilizzato in un contesto come questo: `group().by()`

  ```
  g.V().has('code','ANC').out().group().by().by(values('code', 'city').fold())
  ```
+  [has ()](http://tinkerpop.apache.org/docs/current/reference/#has-step) — La fase `has () `può generalmente essere convertita in un funzionamento nativo del motore Neptune a condizione che le interrogazioni con `T` utilizzino il predicato `p.EQ`, `P.neq` o `p.contains`. Aspettatevi variazioni di `has () `che implicano che anche quelle istanze di `P` vengano convertite in native, come `hasID ('id1234')` che è equivalente a `has (eq, T.id, 'id1234') `. 
+ [id( )](http://tinkerpop.apache.org/docs/current/reference/#id-step): il passaggio `id()` viene convertito a meno che non venga utilizzato su una proprietà, come in questo caso:

  ```
  g.V().has('code','ANC').properties('code').id()
  ```
+  [mergEE ()](https://tinkerpop.apache.org/docs/current/reference/#mergeedge-step) — Il `mergeE()` passo può essere convertito in un funzionamento del motore Neptune nativo se i parametri (la condizione di unione, `onCreate` e`onMatch`) sono costanti (una costante o `null` di a). `Map` `select()` `Map` Tutti gli esempi di ribaltamento degli spigoli possono essere [convertiti](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-efficient-upserts.html#gremlin-upserts-edges). 
+  [mergeV ()](https://tinkerpop.apache.org/docs/current/reference/#mergevertex-step) — La fase mergeV () può essere convertita in un funzionamento nativo del motore Neptune se i parametri (la condizione di unione, `onCreate` and`onMatch`) sono costanti (una costante o `null` di un). `Map` `select()` `Map` [Tutti gli esempi di vertici di ribaltamento possono essere convertiti.](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-efficient-upserts.html#gremlin-upserts-vertices) 
+ [order( )](http://tinkerpop.apache.org/docs/current/reference/#order-step): il passaggio `order()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che non si verifichi una delle seguenti condizioni:
  + Il passaggio `order()` si trova all'interno di un attraversamento figlio annidato, come questo:

    ```
    g.V().has('code','ANC').where(V().out().order().by(id))
    ```
  + Viene utilizzato l'ordinamento locale, come ad esempio con `order(local)`.
  + Nella modulazione `by()` viene utilizzato un comparatore personalizzato per l'ordinamento. Un esempio è l'uso di `sack()` in questo modo:

    ```
    g.withSack(0).
      V().has('code','ANC').
          repeat(outE().sack(sum).by('dist').inV()).times(2).limit(10).
          order().by(sack())
    ```
  + Esistono più ordinamenti sullo stesso elemento.
+ [project( )](http://tinkerpop.apache.org/docs/current/reference/#project-step): il passaggio `project()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che il numero di istruzioni `by()` che segue `project()` non corrisponda al numero di etichette specificate, come in questo caso:

  ```
  g.V().has('code','ANC').project('x', 'y').by(id)
  ```
+ [range( )](http://tinkerpop.apache.org/docs/current/reference/#range-step): il passaggio `range()` viene convertito solo quando il limite inferiore dell'intervallo in questione è zero (ad esempio, `range(0,3)`).
+ [repeat( )](http://tinkerpop.apache.org/docs/current/reference/#repeat-step): il passaggio `repeat()` può generalmente essere convertito in un'operazione nativa del motore Neptune, a meno che non sia annidato all'interno di un altro passaggio `repeat()`, come in questo caso:

  ```
  g.V().has('code','ANC').repeat(out().repeat(out()).times(2)).times(2)
  ```
+ [sack( )](http://tinkerpop.apache.org/docs/current/reference/#sack-step): il passaggio `sack()` può generalmente essere convertito in un'operazione nativa del motore Neptune, tranne nei casi seguenti:
  + Se viene utilizzato un operatore sack non numerico.
  + Se viene utilizzato un operatore sack numerico diverso da `+`, `-`, `mult`, `div`, `min` e `max`.
  + Se `sack()` viene utilizzato all'interno di un passaggio `where()` per filtrare in base a un valore sack, come in questo caso:

    ```
    g.V().has('code','ANC').sack(assign).by(values('code')).where(sack().is('ANC'))
    ```
+ [sum( )](http://tinkerpop.apache.org/docs/current/reference/#sum-step): il passaggio `sum()` può generalmente essere convertito in un'operazione nativa del motore Neptune, ma non quando viene utilizzato per calcolare una somma globale, come in questo caso:

  ```
  g.V().has('code','ANC').outE('routes').values('dist').sum()
  ```
+ [union( )](http://tinkerpop.apache.org/docs/current/reference/#union-step): il passaggio `union()` può essere convertito in un'operazione nativa del motore Neptune purché sia l'ultimo passaggio della query a parte il passaggio terminale.
+ [unfold ()](http://tinkerpop.apache.org/docs/current/reference/#unfold-step) — Il `unfold()` passaggio può essere convertito in un funzionamento del motore Neptune nativo solo quando viene utilizzato nel pattern [Upsert consigliato nella](http://tinkerpop.apache.org/docs/current/recipes/#element-existence) pagina [TinkerPopdelle ricette](http://tinkerpop.apache.org/docs/current/recipes/) e quando viene utilizzato insieme a questo: `cap()`

  ```
  g.V().has('airport','country','IE').aggregate('airport').limit(2)
       .cap('airport').unfold()
  ```
+ [where( )](http://tinkerpop.apache.org/docs/current/reference/#where-step): il passaggio `where()` può generalmente essere convertito in un'operazione nativa del motore Neptune, tranne nei casi seguenti:
  + Quando vengono utilizzate le modulazioni by(), come in questo caso:

    ```
    g.V().hasLabel('airport').as('a')
         .where(gt('a')).by('runways')
    ```
  + Quando vengono utilizzati operatori di confronto diversi da `eq`, `neq`, `within` e `without`.
  + Quando vengono utilizzate aggregazioni fornite dall'utente.

## Passaggi Gremlin che non vengono mai convertiti in operazioni native del motore Neptune
<a name="gremlin-steps-never"></a>

I seguenti passaggi Gremlin sono supportati in Neptune ma non vengono mai convertiti in operazioni native del motore Neptune. Vengono invece eseguiti dal server Gremlin.
+ [choose( )](http://tinkerpop.apache.org/docs/current/reference/#choose-step)
+ [coin( )](http://tinkerpop.apache.org/docs/current/reference/#coin-step)
+ [inject( )](http://tinkerpop.apache.org/docs/current/reference/#inject-step)
+ [match( )](http://tinkerpop.apache.org/docs/current/reference/#match-step)
+ [math( )](http://tinkerpop.apache.org/docs/current/reference/#math-step)
+ [max( )](http://tinkerpop.apache.org/docs/current/reference/#max-step)
+ [mean( )](http://tinkerpop.apache.org/docs/current/reference/#mean-step)
+ [min( )](http://tinkerpop.apache.org/docs/current/reference/#min-step)
+ [option( )](http://tinkerpop.apache.org/docs/current/reference/#option-step)
+ [optional( )](http://tinkerpop.apache.org/docs/current/reference/#optional-step)
+ [path( )](http://tinkerpop.apache.org/docs/current/reference/#path-step)
+ [propertyMap( )](http://tinkerpop.apache.org/docs/current/reference/#propertymap-step)
+ [sample( )](http://tinkerpop.apache.org/docs/current/reference/#sample-step)
+ [skip( )](http://tinkerpop.apache.org/docs/current/reference/#skip-step)
+ [tail( )](http://tinkerpop.apache.org/docs/current/reference/#tail-step)
+ [timeLimit( )](http://tinkerpop.apache.org/docs/current/reference/#timelimit-step)
+ [tree( )](http://tinkerpop.apache.org/docs/current/reference/#tree-step)

## Passaggi Gremlin che non sono affatto supportati in Neptune
<a name="neptune-gremlin-steps-unsupported"></a>

I seguenti passaggi Gremlin non sono affatto supportati in Neptune. Nella maggior parte dei casi ciò è dovuto al fatto che richiedono un oggetto `GraphComputer`, che Neptune attualmente non supporta.
+ [connectedComponent( )](http://tinkerpop.apache.org/docs/current/reference/#connectedcomponent-step)
+ [io( )](http://tinkerpop.apache.org/docs/current/reference/#io-step)
+ [shortestPath( )](http://tinkerpop.apache.org/docs/current/reference/#shortestpath-step)
+ [withComputer( )](http://tinkerpop.apache.org/docs/current/reference/#with-step)
+ [pageRank( )](http://tinkerpop.apache.org/docs/current/reference/#pagerank-step)
+ [peerPressure( )](http://tinkerpop.apache.org/docs/current/reference/#peerpressure-step)
+ [program( )](http://tinkerpop.apache.org/docs/current/reference/#program-step)

Il passaggio `io()` è in realtà parzialmente supportato, in quanto può essere utilizzato per eseguire un passaggio `read()` da un URL ma non per eseguire un passaggio `write()`.

# Utilizzo di Gremlin con il motore di query Neptune DFE
<a name="gremlin-with-dfe"></a>

Se abiliti il [motore di query alternativo](neptune-dfe-engine.md) di Neptunes noto come DFE in [modalità lab](features-lab-mode.md) (impostando il parametro del cluster `neptune_lab_mode` DB su`DFEQueryEngine=enabled`), Neptune traduce Gremlin di sola lettura queries/traversals in una rappresentazione logica intermedia e li esegue sul motore DFE quando possibile.

Tuttavia, il motore DFE non supporta ancora tutti i passaggi Gremlin. Quando un passaggio non può essere eseguito in modo nativo sul DFE, Neptune torna a eseguire il passaggio. TinkerPop I report `explain` e `profile` includono avvisi quando ciò accade.

# Copertura dei passaggi di Gremlin in DFE
<a name="gremlin-step-coverage-in-DFE"></a>

 Gremlin DFE è una funzionalità labmode e può essere utilizzata abilitando il parametro cluster o utilizzando il suggerimento di interrogazione. `Neptune#useDFE` Per maggiori informazioni, consulta [Usare Gremlin con il motore di interrogazione Neptune DFE](https://docs.aws.amazon.com//neptune/latest/userguide/gremlin-with-dfe.html). 

 I seguenti passaggi sono disponibili per l'uso in Gremlin DFE. 

## Percorso e fasi di attraversamento:
<a name="DFE-path-and-traversal"></a>

 [asDate ()](https://tinkerpop.apache.org/docs/current/reference/#asDate-step)[, [barrier ()](https://tinkerpop.apache.org/docs/current/reference/#barrier-step), [call ()](https://tinkerpop.apache.org/docs/current/reference/#call-step), [cap ()](https://tinkerpop.apache.org/docs/current/reference/#cap-step), [dateAdd ()](https://tinkerpop.apache.org/docs/current/reference/#dateadd-step), [dateDiff ()](https://tinkerpop.apache.org/docs/current/reference/#datediff-step), [disjunct ()](https://tinkerpop.apache.org/docs/current/reference/#disjunct-step), [drop ()](https://tinkerpop.apache.org/docs/current/reference/#drop-step), [fail ()](https://tinkerpop.apache.org/docs/current/reference/#fail-step), [filter ()](https://tinkerpop.apache.org/docs/current/reference/#filter-step), [flatMap (), id ()](https://tinkerpop.apache.org/docs/current/reference/#flatmap-step)[, identity ()](https://tinkerpop.apache.org/docs/current/reference/#id-step)[, index ()](https://tinkerpop.apache.org/docs/current/reference/#identity-step)[, intersect ()](https://tinkerpop.apache.org/docs/current/reference/#index-step)[, inject ()](https://tinkerpop.apache.org/docs/current/reference/#intersect-step)[, label ()](https://tinkerpop.apache.org/docs/current/reference/#inject-step)[, length ()](https://tinkerpop.apache.org/docs/current/reference/#label-step)[, loop ()](https://tinkerpop.apache.org/docs/current/reference/#length-step)[, mappa (), ordine ()](https://tinkerpop.apache.org/docs/current/reference/#loops-step)[()](https://tinkerpop.apache.org/docs/current/reference/#map-step), [ordine (locale)](https://tinkerpop.apache.org/docs/current/reference/#order-step)[, percorso (](https://tinkerpop.apache.org/docs/current/reference/#order-step)),](https://tinkerpop.apache.org/docs/current/reference/#path-step) [project ()](https://tinkerpop.apache.org/docs/current/reference/#project-step), [range ()](https://tinkerpop.apache.org/docs/current/reference/#range-step), [repeat ()](https://tinkerpop.apache.org/docs/current/reference/#repeat-step), [reverse ()](https://tinkerpop.apache.org/docs/current/reference/#reverse-step), [sack ()](https://tinkerpop.apache.org/docs/current/reference/#sack-step), [sample ()](https://tinkerpop.apache.org/docs/current/reference/#sample-step), [select ()](https://tinkerpop.apache.org/docs/current/reference/#select-step), [sideEffect ()](https://tinkerpop.apache.org/docs/current/reference/#sideeffect-step), [split ()](https://tinkerpop.apache.org/docs/current/reference/#split-step), [unfold ()](https://tinkerpop.apache.org/docs/current/reference/#unfold-step), [union ()](https://tinkerpop.apache.org/docs/current/reference/#union-step) 

## Fasi di aggregazione e raccolta:
<a name="DFE-aggregate-and-collection"></a>

 [aggregate (globale)](https://tinkerpop.apache.org/docs/current/reference/#aggregate-step)[, [combine (), count ()](https://tinkerpop.apache.org/docs/current/reference/#combine-step)[, dedup ()](https://tinkerpop.apache.org/docs/current/reference/#count-step), [dedup (locale)](https://tinkerpop.apache.org/docs/current/reference/#dedup-step)[, fold (), group ()](https://tinkerpop.apache.org/docs/current/reference/#dedup-step)[[, groupCount (](https://tinkerpop.apache.org/docs/current/reference/#group-step))](https://tinkerpop.apache.org/docs/current/reference/#fold-step),](https://tinkerpop.apache.org/docs/current/reference/#groupcount-step) 

## Fasi matematiche:
<a name="DFE-mathematical"></a>

 [max ()](https://tinkerpop.apache.org/docs/current/reference/#max-step), [media ()](https://tinkerpop.apache.org/docs/current/reference/#mean-step), [min ()](https://tinkerpop.apache.org/docs/current/reference/#min-step), [somma (](https://tinkerpop.apache.org/docs/current/reference/#sum-step)) 

## Fasi degli elementi:
<a name="DFE-element"></a>

 [otherV ()](https://tinkerpop.apache.org/docs/current/reference/#otherv-step), [elementMap (), element ()](https://tinkerpop.apache.org/docs/current/reference/#elementmap-step)[, v ()](https://tinkerpop.apache.org/docs/current/reference/#element-step)[, out ()](https://tinkerpop.apache.org/docs/current/reference/#graph-step)[, in (), entrambi (), outE (), inE (), boThe (), outV (), inV (), inV (), bothV (), altroV ()](https://tinkerpop.apache.org/docs/current/reference/#vertex-step) 

## Fasi della proprietà:
<a name="DFE-property"></a>

 [proprietà ()](https://tinkerpop.apache.org/docs/current/reference/#properties-step), [chiave ()](https://tinkerpop.apache.org/docs/current/reference/#key-step), [valueMap ()](https://tinkerpop.apache.org/docs/current/reference/#propertymap-step), [valore (](https://tinkerpop.apache.org/docs/current/reference/#value-step)) 

## Passaggi del filtro:
<a name="DFE-filter"></a>

 [and ()](https://tinkerpop.apache.org/docs/current/reference/#and-step), [coalesce ()](https://tinkerpop.apache.org/docs/current/reference/#coalesce-step), [coin ()](https://tinkerpop.apache.org/docs/current/reference/#coin-step), [has ()](https://tinkerpop.apache.org/docs/current/reference/#has-step), [is ()](https://tinkerpop.apache.org/docs/current/reference/#is-step), [local ()](https://tinkerpop.apache.org/docs/current/reference/#local-step), [none ()](https://tinkerpop.apache.org/docs/current/reference/#none-step), [not ()](https://tinkerpop.apache.org/docs/current/reference/#not-step) [o ()](https://tinkerpop.apache.org/docs/current/reference/#or-step), [where (](https://tinkerpop.apache.org/docs/current/reference/#where-step)) 

## Fasi di manipolazione delle stringhe:
<a name="DFE-string-manipulation"></a>

 [concat ()](https://tinkerpop.apache.org/docs/current/reference/#concat-step)[, [LTrim (), rTrim ()](https://tinkerpop.apache.org/docs/current/reference/#lTrim-step)[, [sottostringa (), toLower ()](https://tinkerpop.apache.org/docs/current/reference/#substring-step), toUpper ()[,](https://tinkerpop.apache.org/docs/current/reference/#toUpper-step) trim](https://tinkerpop.apache.org/docs/current/reference/#rtrim-step)[(](https://tinkerpop.apache.org/docs/current/reference/#toLower-step))](https://tinkerpop.apache.org/docs/current/reference/#trim-step) 

## Predicati:
<a name="DFE-predicates"></a>
+  [Confronta: eq, neq, lt, lte, gt, gte](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [Contiene: all'interno, all'esterno](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [Testo P: che termina con, contiene,, non contiene notStartingWith notEndingWith](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 
+  [P: e, o, tra, all'esterno, all'interno](https://tinkerpop.apache.org/docs/current/reference/#a-note-on-predicates) 

## Limitazioni
<a name="gremlin-with-dfe-limitations"></a>

 Repeat with Limit, Labels inside repeat traversal e dedup non sono ancora supportate in DFE. 

```
// With Limit inside the repeat traversal
  g.V().has('code','AGR').repeat(out().limit(5)).until(has('code','FRA'))
  
  // With Labels inside the repeat traversal
  g.V().has('code','AGR').repeat(out().as('a')).until(has('code','FRA'))
  
  // With Dedup inside the repeat traversal
  g.V().has('code','AGR').repeat(out().dedup()).until(has('code','FRA'))
```

 I percorsi con ripetizioni annidate o passaggi di ramificazione non sono ancora supportati. 

```
// Path with branching steps
  g.V().has('code','AGR').union(identity, outE().inV()).path().by('code')
  
  
  // With nested repeat
  g.V().has('code','AGR').repeat(out().union(identity(), out())).path().by('code')
```

## Interleaving della pianificazione delle query
<a name="gremlin-with-dfe-interleaving"></a>

Quando il processo di conversione incontra un passaggio Gremlin che non ha un operatore DFE nativo corrispondente, prima di tornare a usare Tinkerpop cerca di trovare altre parti di query intermedie che possano essere eseguite in modo nativo sul motore DFE. Lo fa applicando la logica di interleaving all'attraversamento di livello superiore. Il risultato è che i passaggi supportati vengono utilizzati laddove possibile.

Tale conversione di query intermedia, senza prefisso viene rappresentata utilizzando `NeptuneInterleavingStep` negli output di `explain` e `profile`.

Per confrontare le prestazioni, si potrebbe voler disattivare l'interleaving in una query, continuando a utilizzare il motore DFE per eseguire la parte del prefisso. In alternativa, potresti voler utilizzare solo il TinkerPop motore per l'esecuzione di query senza prefisso. A tale scopo, utilizzare l'hint di query `disableInterleaving`.

Proprio come l'hint di query [useDFE](gremlin-query-hints-useDFE.md) con il valore `false` impedisce del tutto l'esecuzione di una query sul motore DFE, l'hint di query `disableInterleaving` con il valore `true` disattiva l'interleaving del motore DFE per la conversione di una query. Esempio:

```
g.with('Neptune#disableInterleaving', true)
 .V().has('genre','drama').in('likes')
```

## Output aggiornato di `explain` e `profile` di Gremlin
<a name="gremlin-with-dfe-explain-update"></a>

Gremlin [explain](gremlin-explain.md) fornisce dettagli sull'attraversamento ottimizzato utilizzato da Neptune per eseguire una query. Consultare l'[output di esempio di `explain` del motore DFE](gremlin-explain-api.md#gremlin-explain-dfe) per un esempio di come appare l'output di `explain` quando il motore DFE è abilitato.

L'[API Gremlin `profile`](gremlin-profile-api.md) esegue un attraversamento Gremlin specificato, raccoglie varie metriche sull'esecuzione e produce un report di profile che contiene dettagli sul piano di interrogazione ottimizzato e sulle statistiche di runtime di vari operatori. Consultare l'[output di esempio di `profile` del motore DFE](gremlin-profile-api.md#gremlin-profile-sample-dfe-output) per un esempio di come appare l'output di `profile` quando il motore DFE è abilitato.

**Nota**  
Poiché il motore DFE è una funzionalità sperimentale rilasciata in modalità di laboratorio, il formato esatto dell'output di `explain` e `profile` è soggetto a modifiche.

# Accesso al grafo di Neptune con openCypher
<a name="access-graph-opencypher"></a>

Neptune supporta la creazione di applicazioni a grafo mediante openCypher, attualmente uno dei linguaggi di query più popolari per gli sviluppatori che lavorano con database a grafo. Sviluppatori, analisti aziendali e data scientist apprezzano la sintassi ispirata a SQL di openCypher perché fornisce una struttura familiare per comporre query per applicazioni a grafo.

**openCypher** è un linguaggio di query dichiarativo per grafi di proprietà che è stato sviluppato originariamente da Neo4j, per poi diventare open source nel 2015, e che ha contribuito al progetto [openCypher](http://www.opencypher.org/) con una licenza open source Apache 2. La sintassi di openCypher è documentata in [Cypher Query Language Reference, versione 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf).

Per le limitazioni e le differenze nel supporto di Neptune della specifica openCypher, vedi [Conformità alle specifiche OpenCypher in Amazon Neptune](feature-opencypher-compliance.md).

**Nota**  
L'attuale implementazione Neo4j del linguaggio di query Cypher si è discostata in qualche modo dalla specifica openCypher. Se si sta eseguendo la migrazione del codice Neo4j Cypher corrente a Neptune, consulta [Compatibilità di Neptune con Neo4j](migration-compatibility.md) e [Riscrittura delle query Cypher da eseguire in openCypher su Neptune](migration-opencypher-rewrites.md) per ulteriori informazioni.

A partire dal rilascio 1.1.1.0 del motore, openCypher è disponibile per l'uso in produzione in Neptune.

## Gremlin e openCypher: somiglianze e differenze
<a name="access-graph-opencypher-overview-with-gremlin"></a>

Gremlin e openCypher sono entrambi linguaggi di query per grafi di proprietà e sono complementari in molti modi.

Gremlin è stato progettato per attrarre i programmatori e adattarsi perfettamente al codice. Di conseguenza, Gremlin è fondamentale fin dalla progettazione, mentre la sintassi dichiarativa di openCypher può sembrare più familiare a chi ha esperienza con SQL o SPARQL. Gremlin potrebbe sembrare più naturale per un data scientist che utilizza Python in un notebook Jupyter, mentre openCypher potrebbe sembrare più intuitivo per un utente aziendale con un background SQL.

L'aspetto positivo è che in Neptune **non è necessario scegliere** tra Gremlin e openCypher. Le query in entrambi i linguaggi possono operare sullo stesso grafo indipendentemente da quale dei due linguaggi sia stato utilizzato per inserire i dati. A seconda di ciò che si fa, può essere più conveniente usare Gremlin per alcune cose e openCypher per altre.

Gremlin utilizza una sintassi imperativa che consente di controllare il modo in cui ci si sposta nel grafo in una serie di passaggi, ognuno dei quali riceve un flusso di dati, esegue alcune azioni su di esso (utilizzando un filtro, una mappa e così via) e quindi invia i risultati al passaggio successivo. Una query Gremlin di solito assume il formato `g.V()`, seguito da passaggi aggiuntivi.

In openCypher si utilizza una sintassi dichiarativa, ispirata a SQL, che specifica un modello di nodi e relazioni da trovare nel grafo utilizzando una sintassi basata su Motif (come `()-[]->()`). Una query openCypher spesso inizia con una clausola `MATCH`, seguita da altre clausole come `WHERE`, `WITH` e `RETURN`.

# Nozioni di base sull'uso di openCypher
<a name="access-graph-opencypher-overview-getting-started"></a>

È possibile eseguire query sui dati del grafo delle proprietà in Neptune utilizzando openCypher indipendentemente da come sono stati caricati, ma non è possibile utilizzare openCypher per eseguire query sui dati caricati come RDF.

Lo [strumento di caricamento in blocco Neptune](bulk-load.md) accetta i dati del grafo delle proprietà in [formato CSV per Gremlin](bulk-load-tutorial-format-gremlin.md) e in [formato CSV per openCypher](bulk-load-tutorial-format-opencypher.md). Inoltre, ovviamente, puoi aggiungere dati di proprietà al tuo grafico usando le query and/or Gremlin OpenCypher.

Sono disponibili molti tutorial online per imparare il linguaggio di query Cypher. Qui, alcuni rapidi esempi di query openCypher possono aiutarti a farti un'idea del linguaggio, ma di gran lunga il modo migliore e più semplice per iniziare a usare openCypher per eseguire query sul grafo Neptune è usare i notebook openCypher in [Neptune Workbench](graph-notebooks.md). L'ambiente di lavoro è open source ed è ospitato su. GitHub [https://github.com/aws-samples/amazon-neptune-samples](https://github.com/aws-samples/amazon-neptune-samples/)

[Troverai i taccuini OpenCypher nel repository di taccuini grafici Neptune. GitHub ](https://github.com/aws/graph-notebook/tree/main/src/graph_notebook/notebooks) In particolare, consulta i notebook [Air-routes visualization](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/Air-Routes-openCypher.ipynb) e [English Premier Teams](https://github.com/aws/graph-notebook/blob/main/src/graph_notebook/notebooks/02-Visualization/EPL-openCypher.ipynb) per openCypher.

I dati elaborati da OpenCypher assumono la forma di una serie non ordinata di mappe. key/value Il modo principale per rifinire, manipolare e aumentare queste mappe consiste nell'utilizzare clausole che eseguono attività come la corrispondenza dei modelli, l'inserimento, l'aggiornamento e l'eliminazione sulle coppie. key/value 

Esistono diverse clausole in openCypher per trovare modelli di dati nel grafo, di cui `MATCH` è la più comune. `MATCH` consente di specificare il modello di nodi, relazioni e filtri che si desidera cercare nel grafo. Esempio:
+ **Ottenere tutti i nodi**

  ```
  MATCH (n) RETURN n
  ```
+ **Trovare i nodi connessi**

  ```
  MATCH (n)-[r]->(d) RETURN n, r, d
  ```
+ **Trovare un percorso**

  ```
  MATCH p=(n)-[r]->(d) RETURN p
  ```
+ **Ottenere tutti i nodi con un'etichetta**

  ```
  MATCH (n:airport) RETURN n
  ```

Notare che la prima query restituisce ogni singolo nodo del grafo mentre le due successive restituiscono ogni nodo che ha una relazione: questa operazione non è generalmente consigliata. In quasi tutti i casi, si desidera restringere i dati restituiti, specificando le etichette e le proprietà dei nodi o delle relazioni, come nel quarto esempio.

È possibile trovare un pratico riepilogo di informazioni sulla sintassi di openCypher nel [repository di esempi GitHub](https://github.com/aws-samples/amazon-neptune-samples/tree/master/opencypher/Cheatsheet.md) di Neptune.

# Servlet di stato ed endpoint di stato openCypher di Neptune
<a name="access-graph-opencypher-status"></a>

L'endpoint di stato openCypher fornisce l'accesso alle informazioni sulle query attualmente in esecuzione sul server o in attesa di essere eseguite. Consente inoltre di annullare tali query. L'endpoint è:

```
https://(the server):(the port number)/openCypher/status
```

È possibile utilizzare i metodi HTTP `GET` e `POST` per ottenere lo stato corrente dal server o per annullare una query. È inoltre possibile utilizzare il metodo `DELETE` per annullare una query in esecuzione o in attesa.

## Parametri per le richieste di stato
<a name="access-graph-opencypher-status-parameters"></a>

**Parametri delle query di stato**
+ **`includeWaiting`** (`true` o `false`): se impostato su `true` e non sono presenti altri parametri, vengono restituite le informazioni sullo stato per le query in attesa e per quelle in esecuzione.
+ **`cancelQuery`**: utilizzato solo con i metodi `GET` e `POST`, per indicare che si tratta di una richiesta di annullamento. Il metodo `DELETE` non richiede questo parametro.

  Il valore del parametro `cancelQuery` non viene utilizzato, ma quando `cancelQuery` è presente, è necessario il parametro `queryId` per identificare la query da annullare.
+ **`queryId`**: contiene l'ID di una query specifica.

  Se utilizzato con il metodo `GET` o `POST` e il parametro `cancelQuery` non è presente, `queryId` restituisce informazioni sullo stato per la query specifica che identifica. Se il parametro `cancelQuery` è presente, la query specifica identificata da `queryId` viene annullata.

  Se utilizzato con il metodo `DELETE`, `queryId` indica sempre una query specifica da annullare.
+ **`silent`**: utilizzato solo quando si annulla una query. Se impostato su `true`, l'annullamento avviene senza alcun avviso.

## Campi di risposta della richiesta di stato
<a name="access-graph-opencypher-status-response-fields"></a>

**Campi di risposta di stato se non viene fornito l'ID di una query specifica**
+ **acceptedQueryCount**— Il numero di interrogazioni che sono state accettate ma non ancora completate, incluse le interrogazioni in coda.
+ **runningQueryCount**— Il numero di query OpenCypher attualmente in esecuzione.
+ **queries**: elenco delle query openCypher correnti.

**Campi di risposta di stato per una query specifica**
+ **queryId**: ID GUID della query. Neptune assegna automaticamente questo valore ID a ogni query oppure è possibile assegnare un ID personalizzato (consulta [Inserimento di un ID personalizzato in una query Neptune Gremlin o SPARQL](features-query-id.md)).
+ **queryString**: la query inviata. Questa è troncata a 1024 caratteri nel caso in cui sia più lunga.
+ **queryEvalStats**— Statistiche per questa interrogazione:
  + **waited**: indica il tempo di attesa della query, in millisecondi.
  + **elapsed**: numero di millisecondi in cui la query è stata eseguita finora.
  + **cancelled**: `True` indica che la query è stata annullata, `False` che non è stata annullata.

## Esempi di richieste e risposte di stato
<a name="access-graph-opencypher-status-samples"></a>
+ **Richiesta dello stato di tutte le query, comprese quelle in attesa:**

  ```
  curl https://server:port/openCypher/status \
    --data-urlencode "includeWaiting=true"
  ```

  *Risposta:*

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **Richiesta dello stato delle query in esecuzione, **escluse** quelle in attesa:**

  ```
  curl https://server:port/openCypher/status
  ```

  *Risposta:*

  ```
  {
    "acceptedQueryCount" : 0,
    "runningQueryCount" : 0,
    "queries" : [ ]
  }
  ```
+ **Richiesta dello stato di una singola query:**

  ```
  curl https://server:port/openCypher/status \
   --data-urlencode "queryId=eadc6eea-698b-4a2f-8554-5270ab17ebee"
  ```

  *Risposta:*

  ```
  {
    "queryId" : "eadc6eea-698b-4a2f-8554-5270ab17ebee",
    "queryString" : "MATCH (n1)-[:knows]->(n2), (n2)-[:knows]->(n3), (n3)-[:knows]->(n4), (n4)-[:knows]->(n5), (n5)-[:knows]->(n6), (n6)-[:knows]->(n7), (n7)-[:knows]->(n8), (n8)-[:knows]->(n9), (n9)-[:knows]->(n10) RETURN COUNT(n1);",
    "queryEvalStats" : {
      "waited" : 0,
      "elapsed" : 23463,
      "cancelled" : false
    }
  }
  ```
+ **Richieste di annullamento di una query**

  1. Con `POST`:

  ```
  curl -X POST https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=f43ce17b-db01-4d37-a074-c76d1c26d7a9"
  ```

  *Risposta:*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  2. Con `GET`:

  ```
  curl -X GET https://server:port/openCypher/status \
    --data-urlencode "cancelQuery" \
    --data-urlencode "queryId=588af350-cfde-4222-bee6-b9cedc87180d"
  ```

  *Risposta:*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

  3. Con `DELETE`:

  ```
  curl -X DELETE \
    -s "https://server:port/openCypher/status?queryId=b9a516d1-d25c-4301-bb80-10b2743ecf0e"
  ```

  *Risposta:*

  ```
  {
    "status" : "200 OK",
    "payload" : true
  }
  ```

# L'endpoint HTTPS di Amazon OpenCypher Neptune
<a name="access-graph-opencypher-queries"></a>

**Topics**
+ [

## OpenCypher query di lettura e scrittura sull'endpoint HTTPS
](#access-graph-opencypher-queries-read-write)
+ [

## Il formato dei risultati OpenCypher JSON predefinito
](#access-graph-opencypher-queries-results-simple-JSON)
+ [

## Intestazioni finali HTTP opzionali per risposte in più parti OpenCypher
](#optional-http-trailing-headers)

**Nota**  
Neptune attualmente non supporta HTTP/2 per le richieste API REST. I client devono utilizzare HTTP/1.1 per la connessione agli endpoint.

## OpenCypher query di lettura e scrittura sull'endpoint HTTPS
<a name="access-graph-opencypher-queries-read-write"></a>

L'endpoint OpenCypher HTTPS supporta le query di lettura e aggiornamento utilizzando sia il metodo che il`GET`. `POST` I metodi `DELETE` e `PUT` non sono supportati.

Le seguenti istruzioni illustrano la connessione all' OpenCypher endpoint utilizzando il `curl` comando e HTTPS. Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

La sintassi è:

```
HTTPS://(the server):(the port number)/openCypher
```

Ecco alcune query di lettura di esempio, una che utilizza `POST` e una che utilizza `GET`:

1. Con `POST`:

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n1) RETURN n1;"
```

2. Con `GET` (la stringa di query è codificata come URL):

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n1)%20RETURN%20n1"
```

Ecco alcuni esempi di write/update query, una che utilizza `POST` e l'altra che utilizza: `GET`

1. Con `POST`:

```
curl HTTPS://server:port/openCypher \
  -d "query=CREATE (n:Person { age: 25 })"
```

2. Con `GET` (la stringa di query è codificata come URL):

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=CREATE%20(n%3APerson%20%7B%20age%3A%2025%20%7D)"
```

## Il formato dei risultati OpenCypher JSON predefinito
<a name="access-graph-opencypher-queries-results-simple-JSON"></a>

Il seguente formato JSON viene restituito per impostazione predefinita o impostando l'intestazione della richiesta in modo esplicito su `Accept: application/json`. Questo formato è stato progettato per essere facilmente analizzato in oggetti utilizzando le funzionalità del linguaggio nativo della maggior parte delle librerie.

Il documento JSON restituito contiene un campo, `results`, che contiene i valori restituiti dalla query. Gli esempi seguenti mostrano la formattazione JSON per i valori comuni.

**Esempio di risposta di valore:**

```
{
  "results": [
    {
      "count(a)": 121
    }
  ]
}
```

**Esempio di risposta di nodo:**

```
{
  "results": [
    {
      "a": {
        "~id": "22",
        "~entityType": "node",
        "~labels": [
          "airport"
        ],
        "~properties": {
          "desc": "Seattle-Tacoma",
          "lon": -122.30899810791,
          "runways": 3,
          "type": "airport",
          "country": "US",
          "region": "US-WA",
          "lat": 47.4490013122559,
          "elev": 432,
          "city": "Seattle",
          "icao": "KSEA",
          "code": "SEA",
          "longest": 11901
        }
      }
    }
  ]
}
```

**Esempio di risposta di relazione:**

```
{
  "results": [
    {
      "r": {
        "~id": "7389",
        "~entityType": "relationship",
        "~start": "22",
        "~end": "151",
        "~type": "route",
        "~properties": {
          "dist": 956
        }
      }
    }
  ]
}
```

**Esempio di risposta di percorso:**

```
{
  "results": [
    {
      "p": [
        {
          "~id": "22",
          "~entityType": "node",
          "~labels": [
            "airport"
          ],
          "~properties": {
            "desc": "Seattle-Tacoma",
            "lon": -122.30899810791,
            "runways": 3,
            "type": "airport",
            "country": "US",
            "region": "US-WA",
            "lat": 47.4490013122559,
            "elev": 432,
            "city": "Seattle",
            "icao": "KSEA",
            "code": "SEA",
            "longest": 11901
          }
        },
        {
          "~id": "7389",
          "~entityType": "relationship",
          "~start": "22",
          "~end": "151",
          "~type": "route",
          "~properties": {
            "dist": 956
          }
        },
        {
          "~id": "151",
          "~entityType": "node",
          "~labels": [
            "airport"
          ],
          "~properties": {
            "desc": "Ontario International Airport",
            "lon": -117.600997924805,
            "runways": 2,
            "type": "airport",
            "country": "US",
            "region": "US-CA",
            "lat": 34.0559997558594,
            "elev": 944,
            "city": "Ontario",
            "icao": "KONT",
            "code": "ONT",
            "longest": 12198
          }
        }
      ]
    }
  ]
}
```

## Intestazioni finali HTTP opzionali per risposte in più parti OpenCypher
<a name="optional-http-trailing-headers"></a>

 [Questa funzionalità è disponibile a partire dalla versione 1.4.5.0 del motore Neptune.](https://docs.aws.amazon.com/releases/release-1.4.5.0.xml) 

 La risposta HTTP alle OpenCypher domande e agli aggiornamenti viene in genere restituita in più blocchi. Quando si verificano errori dopo l'invio dei blocchi di risposta iniziali (con un codice di stato HTTP di 200), può essere difficile diagnosticare il problema. Per impostazione predefinita, `Neptune segnala tali errori aggiungendo un messaggio di errore al corpo del messaggio, che potrebbe essere danneggiato a causa della natura di streaming della risposta. 

**Usare le intestazioni finali**  
 Per migliorare il rilevamento e la diagnosi degli errori, puoi abilitare le intestazioni finali includendo un'intestazione trailers (te: trailers) con codifica di trasferimento (TE) nella richiesta. In questo modo Neptune includerà due nuovi campi di intestazione nelle intestazioni finali dei blocchi di risposta: 
+  `X-Neptune-Status`— contiene il codice di risposta seguito da un nome breve. Ad esempio, in caso di esito positivo, l'intestazione finale sarà: `X-Neptune-Status: 200 OK`. In caso di errore, il codice di risposta sarebbe un codice di errore del motore Neptune come. `X-Neptune-Status: 500 TimeLimitExceededException` 
+  `X-Neptune-Detail`— è vuoto per le richieste andate a buon fine. In caso di errori, contiene il messaggio di errore JSON. Poiché nei valori di intestazione HTTP sono consentiti solo caratteri ASCII, la stringa JSON è codificata come URL. Inoltre, al corpo del messaggio di risposta viene anche aggiunto il messaggio di errore. 

 Per ulteriori informazioni, consulta la [pagina MDN sulle intestazioni delle richieste TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE). 

**OpenCypher esempio di utilizzo delle intestazioni finali**  
 Questo esempio dimostra come le intestazioni finali aiutano a diagnosticare una query che supera il limite di tempo: 

```
curl --raw 'https://your-neptune-endpoint:port/openCypher' \
-H 'TE: trailers' \
-d 'query=MATCH(n) RETURN n.firstName'
 
 
Output:
< HTTP/1.1 200 OK
< transfer-encoding: chunked
< trailer: X-Neptune-Status, X-Neptune-Detail
< content-type: application/json;charset=UTF-8
< 
< 
{
  "results": [{
      "n.firstName": "Hossein"
    }, {
      "n.firstName": "Jan"
    }, {
      "n.firstName": "Miguel"
    }, {
      "n.firstName": "Eric"
    }, 
{"detailedMessage":"Operation terminated (deadline exceeded)",
"code":"TimeLimitExceededException",
"requestId":"a7e9d2aa-fbb7-486e-8447-2ef2a8544080",
"message":"Operation terminated (deadline exceeded)"}
0
X-Neptune-Status: 500 TimeLimitExceededException
X-Neptune-Detail: %7B%22detailedMessage%22%3A%22Operation+terminated+%28deadline+exceeded%29%22%2C%22code%22%3A%22TimeLimitExceededException%22%2C%22requestId%22%3A%22a7e9d2aa-fbb7-486e-8447-2ef2a8544080%22%2C%22message%22%3A%22Operation+terminated+%28deadline+exceeded%29%22%7D
```

**Suddivisione della risposta:**  
 L'esempio precedente mostra come una OpenCypher risposta con intestazioni finali può aiutare a diagnosticare gli errori delle query. Qui vediamo quattro parti sequenziali: (1) intestazioni iniziali con stato 200 OK che indica l'inizio dello streaming, (2) risultati JSON parziali (interrotti) trasmessi correttamente prima dell'errore, (3) il messaggio di errore aggiunto che mostra il timeout e (4) le intestazioni finali contenenti lo stato finale (500) e informazioni dettagliate sull'errore. TimeLimitExceededException 

# Utilizzo dell'SDK per eseguire query OpenCypher AWS
<a name="access-graph-opencypher-sdk"></a>

Con l' AWS SDK, puoi eseguire query OpenCypher sul tuo grafico di Neptune utilizzando un linguaggio di programmazione a tua scelta. L'SDK Neptune data API (`neptunedata`nome del servizio) fornisce l'azione per [ExecuteOpenCypherQuery](https://docs.aws.amazon.com/neptune/latest/data-api/API_ExecuteOpenCypherQuery.html)l'invio di query OpenCypher.

È necessario eseguire questi esempi da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) del cluster Neptune DB o da una posizione che dispone di connettività di rete all'endpoint del cluster.

Di seguito sono disponibili collegamenti diretti alla documentazione di riferimento dell'API per il `neptunedata` servizio in ogni lingua SDK:


| Linguaggio di programmazione | Riferimento all'API neptunedata | 
| --- | --- | 
| C\$1\$1 | [https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html](https://sdk.amazonaws.com/cpp/api/LATEST/aws-cpp-sdk-neptunedata/html/annotated.html) | 
| Go | [https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/](https://docs.aws.amazon.com/sdk-for-go/api/service/neptunedata/) | 
| Java | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/neptunedata/package-summary.html) | 
| JavaScript | [https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-neptunedata/) | 
| Kotlin | [https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html](https://sdk.amazonaws.com/kotlin/api/latest/neptunedata/index.html) | 
| .NET | [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Neptunedata/NNeptunedata.html) | 
| PHP | [https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html](https://docs.aws.amazon.com/aws-sdk-php/v3/api/namespace-Aws.Neptunedata.html) | 
| Python | [https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/neptunedata.html) | 
| Ruby | [https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Neptunedata.html) | 
| Rust | [https://crates.io/crates/aws-sdk-neptunedata](https://crates.io/crates/aws-sdk-neptunedata) | 
| CLI | [https://docs.aws.amazon.com/cli/latest/reference/neptunedata/](https://docs.aws.amazon.com/cli/latest/reference/neptunedata/) | 

## Esempi di OpenCypher AWS SDK
<a name="access-graph-opencypher-sdk-examples"></a>

Gli esempi seguenti mostrano come configurare un `neptunedata` client, eseguire una query OpenCypher e stampare i risultati. Sostituisci *YOUR\$1NEPTUNE\$1HOST* e *YOUR\$1NEPTUNE\$1PORT* con l'endpoint e la porta del tuo cluster Neptune DB.

**Timeout lato client e nuovo tentativo di configurazione**  
*Il timeout del client SDK controlla per quanto tempo il client attende una risposta.* Non controlla per quanto tempo viene eseguita la query sul server. Se il client scade prima del termine del server, la query può continuare a essere eseguita su Neptune mentre il client non ha modo di recuperare i risultati.  
[Ti consigliamo di impostare il timeout di lettura lato client su `0` (nessun timeout) o su un valore che sia almeno qualche secondo più lungo rispetto all'impostazione neptune\$1query\$1timeout lato server sul tuo cluster Neptune DB.](parameters.md#parameters-db-cluster-parameters-neptune_query_timeout) Ciò consente a Neptune di controllare il timeout delle query.  
Consigliamo inoltre di impostare il numero massimo di tentativi su `1` (nessun tentativo). Se l'SDK riprova a eseguire una query ancora in esecuzione sul server, le operazioni possono essere duplicate. Ciò è particolarmente importante per le query di mutazione, in cui un nuovo tentativo potrebbe causare scritture duplicate non intenzionali.

------
#### [ Python ]

1. Segui le istruzioni di [installazione per installare Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html).

1. Crea un file denominato `openCypherExample.py` e incolla il seguente codice:

   ```
   import boto3
   import json
   from botocore.config import Config
   
   # Disable the client-side read timeout and retries so that
   # Neptune's server-side neptune_query_timeout controls query duration.
   client = boto3.client(
       'neptunedata',
       endpoint_url=f'https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT',
       config=Config(read_timeout=None, retries={'total_max_attempts': 1})
   )
   
   response = client.execute_open_cypher_query(
       openCypherQuery='MATCH (n) RETURN n LIMIT 1'
   )
   
   print(json.dumps(response['results'], indent=2))
   ```

1. Esegui l'esempio: `python openCypherExample.py`

------
#### [ Java ]

1. Segui le [istruzioni di installazione](https://docs.aws.amazon.com//sdk-for-java/latest/developer-guide/setup.html) per configurare l' AWS SDK for Java.

1. Usa il codice seguente per configurare una`NeptunedataClient`, eseguire una query OpenCypher e stampare il risultato:

   ```
   import java.net.URI;
   import java.time.Duration;
   import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
   import software.amazon.awssdk.core.retry.RetryPolicy;
   import software.amazon.awssdk.services.neptunedata.NeptunedataClient;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteOpenCypherQueryRequest;
   import software.amazon.awssdk.services.neptunedata.model.ExecuteOpenCypherQueryResponse;
   
   // Disable the client-side timeout and retries so that
   // Neptune's server-side neptune_query_timeout controls query duration.
   NeptunedataClient client = NeptunedataClient.builder()
       .endpointOverride(URI.create("https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT"))
       .overrideConfiguration(ClientOverrideConfiguration.builder()
           .apiCallTimeout(Duration.ZERO)
           .retryPolicy(RetryPolicy.none())
           .build())
       .build();
   
   ExecuteOpenCypherQueryRequest request = ExecuteOpenCypherQueryRequest.builder()
       .openCypherQuery("MATCH (n) RETURN n LIMIT 1")
       .build();
   
   ExecuteOpenCypherQueryResponse response = client.executeOpenCypherQuery(request);
   
   System.out.println(response.results().toString());
   ```

------
#### [ JavaScript ]

1. Segui le [istruzioni di installazione](https://docs.aws.amazon.com//sdk-for-javascript/v3/developer-guide/getting-started-nodejs.html) per configurare l'SDK per. AWS JavaScript Installa il pacchetto client neptunedata:. `npm install @aws-sdk/client-neptunedata`

1. Crea un file denominato `openCypherExample.js` e incolla il seguente codice:

   ```
   import { NeptunedataClient, ExecuteOpenCypherQueryCommand } from "@aws-sdk/client-neptunedata";
   import { NodeHttpHandler } from "@smithy/node-http-handler";
   
   const config = {
       endpoint: "https://YOUR_NEPTUNE_HOST:YOUR_NEPTUNE_PORT",
       // Disable the client-side request timeout so that
       // Neptune's server-side neptune_query_timeout controls query duration.
       requestHandler: new NodeHttpHandler({
           requestTimeout: 0
       }),
       maxAttempts: 1
   };
   
   const client = new NeptunedataClient(config);
   
   const input = {
       openCypherQuery: "MATCH (n) RETURN n LIMIT 1"
   };
   
   const command = new ExecuteOpenCypherQueryCommand(input);
   const response = await client.send(command);
   
   console.log(JSON.stringify(response, null, 2));
   ```

1. Esegui l'esempio: `node openCypherExample.js`

------

# Utilizzo del protocollo Bolt per effettuare query openCypher in Neptune
<a name="access-graph-opencypher-bolt"></a>

[Bolt](https://boltprotocol.org/) [è un client/server protocollo orientato alle istruzioni inizialmente sviluppato da Neo4j e concesso in licenza con la licenza Creative Commons 3.0 Attribution-. ShareAlike](https://creativecommons.org/licenses/by-sa/3.0/) È basato sul client, il che significa che il client avvia sempre lo scambio di messaggi.

Per connettersi a Neptune utilizzando i driver Bolt di Neo4j, è sufficiente sostituire l'URL e il numero di porta con gli endpoint del cluster utilizzando lo schema URI `bolt`. Se è in esecuzione una singola istanza di Neptune, usare l'endpoint read\$1write. Se sono in esecuzione più istanze, si consigliano due driver, uno per la scrittura e l'altro per tutte le repliche di lettura. Se si dispone solo dei due endpoint predefiniti, sono sufficienti un driver read\$1write e uno read\$1only, ma se si dispone anche di endpoint personalizzati, valutare la possibilità di creare un'istanza del driver per ciascuno di essi.

**Nota**  
Sebbene le specifiche Bolt affermino che Bolt può connettersi tramite TCP o WebSockets, Neptune supporta solo connessioni TCP per Bolt.

Neptune consente fino a 1000 connessioni Bolt simultanee su tutte le dimensioni delle istanze ad eccezione di t3.medium e t4g.medium. Sulle istanze t3.medium e t4g.medium sono consentite solo 512 connessioni.

Per esempi di query openCypher in vari linguaggi che utilizzano i driver Bolt, consulta la documentazione [Drivers & Language Guides](https://neo4j.com/developer/language-guides/) di Neo4j.

**Importante**  
I driver Neo4j Bolt per Python JavaScript, .NET e Golang inizialmente non supportavano il rinnovo automatico dei token di autenticazione Signature v4. AWS Ciò significa che dopo la scadenza della firma (spesso dopo 5 minuti), il driver non riusciva ad autenticarsi e le richieste successive avevano esito negativo. Gli esempi Python JavaScript, .NET e Go riportati di seguito sono stati tutti interessati da questo problema.  
[Per ulteriori informazioni, vedere [Neo4j Python numero \$1834, [Neo4j .NET numero \$1664](https://github.com/neo4j/neo4j-dotnet-driver/issues/664), driver](https://github.com/neo4j/neo4j-python-driver/issues/834) Neo4j numero [\$1993 e JavaScript driver Neo4j GoLang numero \$1429](https://github.com/neo4j/neo4j-javascript-driver/issues/993).](https://github.com/neo4j/neo4j-go-driver/issues/429)  
A partire dalla versione 5.8.0 del driver, è stata rilasciata una nuova API di riautenticazione in anteprima per il driver Go (vedi [v5.8.0 - Feedback wanted on re-authentication](https://github.com/neo4j/neo4j-go-driver/discussions/482)).

## Utilizzo di Bolt con Java per connettersi a Neptune
<a name="access-graph-opencypher-bolt-java"></a>

È possibile scaricare un driver per la versione che si desidera utilizzare dal [repository MVN](https://mvnrepository.com/artifact/org.neo4j.driver/neo4j-java-driver) Maven o aggiungere questa dipendenza al progetto:

```
<dependency>
  <groupId>org.neo4j.driver</groupId>
  <artifactId>neo4j-java-driver</artifactId>
  <version>4.3.3</version>
</dependency>
```

Quindi, per connetterti a Neptune in Java utilizzando uno di questi driver Bolt, crea un'istanza di driver per primary/writer l'istanza nel tuo cluster utilizzando un codice come il seguente:

```
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;

final Driver driver =
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
    AuthTokens.none(),
    Config.builder().withEncryption()
                    .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                    .build());
```

Se si dispone di una o più repliche di lettura, è possibile creare in modo analogo un'istanza del driver per tali repliche utilizzando un codice simile al seguente:

```
final Driver read_only_driver =              // (without connection timeout)
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
      Config.builder().withEncryption()
                      .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                      .build());
```

Oppure, con un timeout:

```
final Driver read_only_timeout_driver =      // (with connection timeout)
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)",
    Config.builder().withConnectionTimeout(30, TimeUnit.SECONDS)
                    .withEncryption()
                    .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                    .build());
```

Se si dispone di endpoint personalizzati, può anche essere utile creare un'istanza del driver per ognuno di essi.

## Esempio di query openCypher in Python con Bolt
<a name="access-graph-opencypher-bolt-python"></a>

Ecco come creare una query openCypher in Python con Bolt:

```
python -m pip install neo4j
```

```
from neo4j import GraphDatabase
uri = "bolt://(your cluster endpoint URL):(your cluster port)"
driver = GraphDatabase.driver(uri, auth=("username", "password"), encrypted=True)
```

Notare che i parametri `auth` vengono ignorati.

## Esempio di query openCypher in .NET con Bolt
<a name="access-graph-opencypher-bolt-dotnet"></a>

Per creare una query OpenCypher in .NET utilizzando Bolt, il primo passo consiste nell'installare il driver Neo4j utilizzando. NuHet Per effettuare chiamate sincrone, usare la versione `.Simple`, come in questo caso:

```
Install-Package Neo4j.Driver.Simple-4.3.0
```

```
using Neo4j.Driver;

namespace hello
{
  // This example creates a node and reads a node in a Neptune
  // Cluster where IAM Authentication is not enabled.
  public class HelloWorldExample : IDisposable
  {
    private bool _disposed = false;
    private readonly IDriver _driver;
    private static string url = "bolt://(your cluster endpoint URL):(your cluster port)";
    private static string createNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'";
    private static string readNodeQuery = "MATCH(n:Greeting) RETURN n.message";

    ~HelloWorldExample() => Dispose(false);

    public HelloWorldExample(string uri)
    {
      _driver = GraphDatabase.Driver(uri, AuthTokens.None, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted));
    }

    public void createNode()
    {
      // Open a session
      using (var session = _driver.Session())
      {
         // Run the query in a write transaction
        var greeting = session.WriteTransaction(tx =>
        {
          var result = tx.Run(createNodeQuery);
          // Consume the result
          return result.Consume();
        });

        // The output will look like this:
        //   ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample".....
        Console.WriteLine(greeting);
      }
    }

    public void retrieveNode()
    {
      // Open a session
      using (var session = _driver.Session())
      {
        // Run the query in a read transaction
        var greeting = session.ReadTransaction(tx =>
        {
          var result = tx.Run(readNodeQuery);
          // Consume the result. Read the single node
          // created in a previous step.
          return result.Single()[0].As<string>();
        });
        // The output will look like this:
        //   HelloWorldExample
        Console.WriteLine(greeting);
      }
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (_disposed)
        return;
      if (disposing)
      {
        _driver?.Dispose();
      }
      _disposed = true;
    }

    public static void Main()
    {
      using (var apiCaller = new HelloWorldExample(url))
      {
        apiCaller.createNode();
        apiCaller.retrieveNode();
      }
    }
  }
}
```

## Esempio di query openCypher in Java con Bolt e autenticazione IAM
<a name="access-graph-opencypher-bolt-java-iam-auth"></a>

Il codice Java riportato di seguito mostra come effettuare query openCypher in Java con Bolt e autenticazione IAM. Il commento JavaDoc ne descrive l'utilizzo. Una volta disponibile un'istanza del driver, è possibile utilizzarla per effettuare più richieste autenticate.

```
package software.amazon.neptune.bolt;

import com.amazonaws.DefaultRequest;
import com.amazonaws.Request;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.http.HttpMethodName;
import com.google.gson.Gson;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import org.neo4j.driver.Value;
import org.neo4j.driver.Values;
import org.neo4j.driver.internal.security.InternalAuthToken;
import org.neo4j.driver.internal.value.StringValue;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static com.amazonaws.auth.internal.SignerConstants.AUTHORIZATION;
import static com.amazonaws.auth.internal.SignerConstants.HOST;
import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_DATE;
import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_SECURITY_TOKEN;

/**
 * Use this class instead of `AuthTokens.basic` when working with an IAM
 * auth-enabled server. It works the same as `AuthTokens.basic` when using
 * static credentials, and avoids making requests with an expired signature
 * when using temporary credentials. Internally, it generates a new signature
 * on every invocation (this may change in a future implementation).
 *
 * Note that authentication happens only the first time for a pooled connection.
 *
 * Typical usage:
 *
 * NeptuneAuthToken authToken = NeptuneAuthToken.builder()
 *     .credentialsProvider(credentialsProvider)
 *     .region("aws region")
 *     .url("cluster endpoint url")
 *     .build();
 *
 * Driver driver = GraphDatabase.driver(
 *     authToken.getUrl(),
 *     authToken,
 *     config
 * );
 */

public class NeptuneAuthToken extends InternalAuthToken {
  private static final String SCHEME = "basic";
  private static final String REALM = "realm";
  private static final String SERVICE_NAME = "neptune-db";
  private static final String HTTP_METHOD_HDR = "HttpMethod";
  private static final String DUMMY_USERNAME = "username";
  @NonNull
  private final String region;
  @NonNull
  @Getter
  private final String url;
  @NonNull
  private final AWSCredentialsProvider credentialsProvider;
  private final Gson gson = new Gson();

  @Builder
  private NeptuneAuthToken(
      @NonNull final String region,
      @NonNull final String url,
      @NonNull final AWSCredentialsProvider credentialsProvider
  ) {
      // The superclass caches the result of toMap(), which we don't want
      super(Collections.emptyMap());
      this.region = region;
      this.url = url;
      this.credentialsProvider = credentialsProvider;
  }

  @Override
  public Map<String, Value> toMap() {
    final Map<String, Value> map = new HashMap<>();
    map.put(SCHEME_KEY, Values.value(SCHEME));
    map.put(PRINCIPAL_KEY, Values.value(DUMMY_USERNAME));
    map.put(CREDENTIALS_KEY, new StringValue(getSignedHeader()));
    map.put(REALM_KEY, Values.value(REALM));

    return map;
  }

  private String getSignedHeader() {
    final Request<Void> request = new DefaultRequest<>(SERVICE_NAME);
    request.setHttpMethod(HttpMethodName.GET);
    request.setEndpoint(URI.create(url));
    // Comment out the following line if you're using an engine version older than 1.2.0.0
    request.setResourcePath("/opencypher");

    final AWS4Signer signer = new AWS4Signer();
    signer.setRegionName(region);
    signer.setServiceName(request.getServiceName());
    signer.sign(request, credentialsProvider.getCredentials());

    return getAuthInfoJson(request);
  }

  private String getAuthInfoJson(final Request<Void> request) {
    final Map<String, Object> obj = new HashMap<>();
    obj.put(AUTHORIZATION, request.getHeaders().get(AUTHORIZATION));
    obj.put(HTTP_METHOD_HDR, request.getHttpMethod());
    obj.put(X_AMZ_DATE, request.getHeaders().get(X_AMZ_DATE));
    obj.put(HOST, request.getHeaders().get(HOST));
    obj.put(X_AMZ_SECURITY_TOKEN, request.getHeaders().get(X_AMZ_SECURITY_TOKEN));

    return gson.toJson(obj);
  }
}
```

## Esempio di query openCypher in Python con Bolt e autenticazione IAM
<a name="access-graph-opencypher-bolt-python-iam-auth"></a>

La classe Python seguente consente di effettuare query openCypher in Python con Bolt e autenticazione IAM:

```
import json

from neo4j import Auth
from botocore.awsrequest import AWSRequest
from botocore.credentials import Credentials
from botocore.auth import (
  SigV4Auth,
  _host_from_url,
)

SCHEME = "basic"
REALM = "realm"
SERVICE_NAME = "neptune-db"
DUMMY_USERNAME = "username"
HTTP_METHOD_HDR = "HttpMethod"
HTTP_METHOD = "GET"
AUTHORIZATION = "Authorization"
X_AMZ_DATE = "X-Amz-Date"
X_AMZ_SECURITY_TOKEN = "X-Amz-Security-Token"
HOST = "Host"


class NeptuneAuthToken(Auth):
  def __init__(
    self,
    credentials: Credentials,
    region: str,
    url: str,
    **parameters
  ):
    # Do NOT add "/opencypher" in the line below if you're using an engine version older than 1.2.0.0
    request = AWSRequest(method=HTTP_METHOD, url=url + "/opencypher")
    request.headers.add_header("Host", _host_from_url(request.url))
    sigv4 = SigV4Auth(credentials, SERVICE_NAME, region)
    sigv4.add_auth(request)

    auth_obj = {
      hdr: request.headers[hdr]
      for hdr in [AUTHORIZATION, X_AMZ_DATE, X_AMZ_SECURITY_TOKEN, HOST]
    }
    auth_obj[HTTP_METHOD_HDR] = request.method
    creds: str = json.dumps(auth_obj)
    super().__init__(SCHEME, DUMMY_USERNAME, creds, REALM, **parameters)
```

Utilizzare questa classe per creare un driver come segue:

```
  authToken = NeptuneAuthToken(creds, REGION, URL)
  driver = GraphDatabase.driver(URL, auth=authToken, encrypted=True)
```

## Esempio di Node.js con autenticazione IAM e Bolt
<a name="access-graph-opencypher-bolt-nodejs-iam-auth"></a>

Il codice Node.js riportato di seguito utilizza l' AWS SDK per la JavaScript versione 3 e la ES6 sintassi per creare un driver che autentica le richieste:

```
import neo4j from "neo4j-driver";
import { HttpRequest }  from "@smithy/protocol-http";
import { defaultProvider } from "@aws-sdk/credential-provider-node";
import { SignatureV4 } from "@smithy/signature-v4";
import crypto from "@aws-crypto/sha256-js";
const { Sha256 } = crypto;
import assert from "node:assert";

const region = "us-west-2";
const serviceName = "neptune-db";
const host = "(your cluster endpoint URL)";
const port = 8182;
const protocol = "bolt";
const hostPort = host + ":" + port;
const url = protocol + "://" + hostPort;
const createQuery = "CREATE (n:Greeting {message: 'Hello'}) RETURN ID(n)";
const readQuery = "MATCH(n:Greeting) WHERE ID(n) = $id RETURN n.message";

async function signedHeader() {
  const req = new HttpRequest({
    method: "GET",
    protocol: protocol,
    hostname: host,
    port: port,
    // Comment out the following line if you're using an engine version older than 1.2.0.0
    path: "/opencypher",
    headers: {
      host: hostPort
    }
  });

  const signer = new SignatureV4({
    credentials: defaultProvider(),
    region: region,
    service: serviceName,
    sha256: Sha256
  });

  return signer.sign(req, { unsignableHeaders: new Set(["x-amz-content-sha256"]) })
    .then((signedRequest) => {
      const authInfo = {
        "Authorization": signedRequest.headers["authorization"],
        "HttpMethod": signedRequest.method,
        "X-Amz-Date": signedRequest.headers["x-amz-date"],
        "Host": signedRequest.headers["host"],
        "X-Amz-Security-Token": signedRequest.headers["x-amz-security-token"]
      };
      return JSON.stringify(authInfo);
    });
}

async function createDriver() {
  let authToken = { scheme: "basic", realm: "realm", principal: "username", credentials: await signedHeader() };

  return neo4j.driver(url, authToken, {
      encrypted: "ENCRYPTION_ON",
      trust: "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES",
      maxConnectionPoolSize: 1,
      // logging: neo4j.logging.console("debug")
    }
  );
}

async function unmanagedTxn(driver) {
  const session = driver.session();
  const tx = session.beginTransaction();
  try {
    const created = await tx.run(createQuery);
    const matched = await tx.run(readQuery, { id: created.records[0].get(0) });
    const msg = matched.records[0].get("n.message");
    assert.equal(msg, "Hello");
    await tx.commit();
  } catch (err) {
    // The transaction will be rolled back, now handle the error.
    console.log(err);
  } finally {
    await session.close();
  }
}

const driver = await createDriver();
try {
  await unmanagedTxn(driver);
} catch (err) {
  console.log(err);
} finally {
  await driver.close();
}
```

## Esempio di query openCypher in .NET con Bolt e autenticazione IAM
<a name="access-graph-opencypher-bolt-dotnet-iam-auth"></a>

Per abilitare l'autenticazione IAM in .NET, è necessario firmare una richiesta quando si stabilisce la connessione. L'esempio seguente mostra come creare un helper `NeptuneAuthToken` per generare un token di autenticazione:

```
using Amazon.Runtime;
using Amazon.Util;
using Neo4j.Driver;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Web;

namespace Hello
{
  /*
   * Use this class instead of `AuthTokens.None` when working with an IAM-auth-enabled server.
   *
   * Note that authentication happens only the first time for a pooled connection.
   *
   * Typical usage:
   *
   * var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host);
   * _driver = GraphDatabase.Driver(Url, authToken, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted));
   */

  public class NeptuneAuthToken
  {
    private const string ServiceName = "neptune-db";
    private const string Scheme = "basic";
    private const string Realm = "realm";
    private const string DummyUserName = "username";
    private const string Algorithm = "AWS4-HMAC-SHA256";
    private const string AWSRequest = "aws4_request";

    private readonly string _accessKey;
    private readonly string _secretKey;
    private readonly string _region;

    private readonly string _emptyPayloadHash;

    private readonly SHA256 _sha256;


    public NeptuneAuthToken(string awsKey = null, string secretKey = null, string region = null)
    {
      var awsCredentials = awsKey == null || secretKey == null
        ? FallbackCredentialsFactory.GetCredentials().GetCredentials()
        : null;

      _accessKey = awsKey ?? awsCredentials.AccessKey;
      _secretKey = secretKey ?? awsCredentials.SecretKey;
      _region = region ?? FallbackRegionFactory.GetRegionEndpoint().SystemName; //ex: us-east-1

      _sha256 = SHA256.Create();
      _emptyPayloadHash = Hash(Array.Empty<byte>());
    }

    public IAuthToken GetAuthToken(string url)
    {
      return AuthTokens.Custom(DummyUserName, GetCredentials(url), Realm, Scheme);
    }

    /******************** AWS SIGNING FUNCTIONS *********************/
    private string Hash(byte[] bytesToHash)
    {
      return ToHexString(_sha256.ComputeHash(bytesToHash));
    }

    private static byte[] HmacSHA256(byte[] key, string data)
    {
      return new HMACSHA256(key).ComputeHash(Encoding.UTF8.GetBytes(data));
    }

    private byte[] GetSignatureKey(string dateStamp)
    {
      var kSecret = Encoding.UTF8.GetBytes($"AWS4{_secretKey}");
      var kDate = HmacSHA256(kSecret, dateStamp);
      var kRegion = HmacSHA256(kDate, _region);
      var kService = HmacSHA256(kRegion, ServiceName);
      return HmacSHA256(kService, AWSRequest);
    }

    private static string ToHexString(byte[] array)
    {
      return Convert.ToHexString(array).ToLowerInvariant();
    }

    private string GetCredentials(string url)
    {
      var request = new HttpRequestMessage
      {
        Method = HttpMethod.Get,
        RequestUri = new Uri($"https://{url}/opencypher")
      };

      var signedrequest = Sign(request);

      var headers = new Dictionary<string, object>
      {
        [HeaderKeys.AuthorizationHeader] = signedrequest.Headers.GetValues(HeaderKeys.AuthorizationHeader).FirstOrDefault(),
        ["HttpMethod"] = HttpMethod.Get.ToString(),
        [HeaderKeys.XAmzDateHeader] = signedrequest.Headers.GetValues(HeaderKeys.XAmzDateHeader).FirstOrDefault(),
        // Host should be capitalized, not like in Amazon.Util.HeaderKeys.HostHeader
        ["Host"] = signedrequest.Headers.GetValues(HeaderKeys.HostHeader).FirstOrDefault(),
      };

      return JsonSerializer.Serialize(headers);
    }

    private HttpRequestMessage Sign(HttpRequestMessage request)
    {
      var now = DateTimeOffset.UtcNow;
      var amzdate = now.ToString("yyyyMMddTHHmmssZ");
      var datestamp = now.ToString("yyyyMMdd");

      if (request.Headers.Host == null)
      {
        request.Headers.Host = $"{request.RequestUri.Host}:{request.RequestUri.Port}";
      }

      request.Headers.Add(HeaderKeys.XAmzDateHeader, amzdate);

      var canonicalQueryParams = GetCanonicalQueryParams(request);

      var canonicalRequest = new StringBuilder();
      canonicalRequest.Append(request.Method + "\n");
      canonicalRequest.Append(request.RequestUri.AbsolutePath + "\n");
      canonicalRequest.Append(canonicalQueryParams + "\n");

      var signedHeadersList = new List<string>();
      foreach (var header in request.Headers.OrderBy(a => a.Key.ToLowerInvariant()))
      {
        canonicalRequest.Append(header.Key.ToLowerInvariant());
        canonicalRequest.Append(':');
        canonicalRequest.Append(string.Join(",", header.Value.Select(s => s.Trim())));
        canonicalRequest.Append('\n');
        signedHeadersList.Add(header.Key.ToLowerInvariant());
      }
      canonicalRequest.Append('\n');

      var signedHeaders = string.Join(";", signedHeadersList);
      canonicalRequest.Append(signedHeaders + "\n");
      canonicalRequest.Append(_emptyPayloadHash);

      var credentialScope = $"{datestamp}/{_region}/{ServiceName}/{AWSRequest}";
      var stringToSign = $"{Algorithm}\n{amzdate}\n{credentialScope}\n"
        + Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString()));

      var signing_key = GetSignatureKey(datestamp);
      var signature = ToHexString(HmacSHA256(signing_key, stringToSign));

      request.Headers.TryAddWithoutValidation(HeaderKeys.AuthorizationHeader,
        $"{Algorithm} Credential={_accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}");

      return request;
    }

    private static string GetCanonicalQueryParams(HttpRequestMessage request)
    {
      var querystring = HttpUtility.ParseQueryString(request.RequestUri.Query);

      // Query params must be escaped in upper case (i.e. "%2C", not "%2c").
      var queryParams = querystring.AllKeys.OrderBy(a => a)
        .Select(key => $"{key}={Uri.EscapeDataString(querystring[key])}");
      return string.Join("&", queryParams);
    }
  }
}
```

Ecco come creare una query openCypher in .NET con Bolt e autenticazione IAM. L'esempio seguente utilizza l'helper `NeptuneAuthToken`:

```
using Neo4j.Driver;

namespace Hello
{
  public class HelloWorldExample
  {
    private const string Host = "(your hostname):8182";
    private const string Url = $"bolt://{Host}";
    private const string CreateNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'";
    private const string ReadNodeQuery = "MATCH(n:Greeting) RETURN n.message";

    private const string AccessKey = "(your access key)";
    private const string SecretKey = "(your secret key)";
    private const string Region = "(your AWS region)"; // e.g. "us-west-2"

    private readonly IDriver _driver;

    public HelloWorldExample()
    {
      var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host);

      // Note that when the connection is reinitialized after max connection lifetime
      // has been reached, the signature token could have already been expired (usually 5 min)
      // You can face exceptions like:
      //   `Unexpected server exception 'Signature expired: XXXX is now earlier than YYYY (ZZZZ - 5 min.)`
      _driver = GraphDatabase.Driver(Url, authToken, o =>
                o.WithMaxConnectionLifetime(TimeSpan.FromMinutes(60)).WithEncryptionLevel(EncryptionLevel.Encrypted));
    }

    public async Task CreateNode()
    {
      // Open a session
      using (var session = _driver.AsyncSession())
      {
        // Run the query in a write transaction
        var greeting = await session.WriteTransactionAsync(async tx =>
        {
          var result = await tx.RunAsync(CreateNodeQuery);
          // Consume the result
          return await result.ConsumeAsync();
        });

        // The output will look like this:
        //   ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample".....
        Console.WriteLine(greeting.Query);
      }
    }

    public async Task RetrieveNode()
    {
      // Open a session
      using (var session = _driver.AsyncSession())
      {
        // Run the query in a read transaction
        var greeting = await session.ReadTransactionAsync(async tx =>
        {
          var result = await tx.RunAsync(ReadNodeQuery);
          var records = await result.ToListAsync();

          // Consume the result. Read the single node
          // created in a previous step.
          return records[0].Values.First().Value;
        });
        // The output will look like this:
        //   HelloWorldExample
        Console.WriteLine(greeting);
      }
    }
  }
}
```

Questo esempio può essere avviato eseguendo il codice sottostante su `.NET 6` o `.NET 7` con i seguenti pacchetti:
+ **`Neo4j`**`.Driver=4.3.0`
+ **`AWSSDK`**`.Core=3.7.102.1`

```
namespace Hello
{
  class Program
  {
    static async Task Main()
    {
      var apiCaller = new HelloWorldExample();

      await apiCaller.CreateNode();
      await apiCaller.RetrieveNode();
    }
  }
}
```

## Esempio di query openCypher in Golang con Bolt e autenticazione IAM
<a name="access-graph-opencypher-bolt-golang-iam-auth"></a>

Il pacchetto Golang seguente mostra come effettuare query openCypher nel linguaggio Go con Bolt e autenticazione IAM:

```
package main

import (
  "context"
  "encoding/json"
  "fmt"
  "github.com/aws/aws-sdk-go/aws/credentials"
  "github.com/aws/aws-sdk-go/aws/signer/v4"
  "github.com/neo4j/neo4j-go-driver/v5/neo4j"
  "log"
  "net/http"
  "os"
  "time"
)

const (
  ServiceName   = "neptune-db"
  DummyUsername = "username"
)

// Find node by id using Go driver
func findNode(ctx context.Context, region string, hostAndPort string, nodeId string) (string, error) {
  req, err := http.NewRequest(http.MethodGet, "https://"+hostAndPort+"/opencypher", nil)

  if err != nil {
    return "", fmt.Errorf("error creating request, %v", err)
  }

  // credentials must have been exported as environment variables
  signer := v4.NewSigner(credentials.NewEnvCredentials())
  _, err = signer.Sign(req, nil, ServiceName, region, time.Now())

  if err != nil {
    return "", fmt.Errorf("error signing request: %v", err)
  }

  hdrs := []string{"Authorization", "X-Amz-Date", "X-Amz-Security-Token"}
  hdrMap := make(map[string]string)
  for _, h := range hdrs {
    hdrMap[h] = req.Header.Get(h)
  }

  hdrMap["Host"] = req.Host
  hdrMap["HttpMethod"] = req.Method

  password, err := json.Marshal(hdrMap)
  if err != nil {
    return "", fmt.Errorf("error creating JSON, %v", err)
  }
  authToken := neo4j.BasicAuth(DummyUsername, string(password), "")
  // +s enables encryption with a full certificate check
  // Use +ssc to disable client side TLS verification
  driver, err := neo4j.NewDriverWithContext("bolt+s://"+hostAndPort+"/opencypher", authToken)
  if err != nil {
    return "", fmt.Errorf("error creating driver, %v", err)
  }

  defer driver.Close(ctx)

  if err := driver.VerifyConnectivity(ctx); err != nil {
    log.Fatalf("failed to verify connection, %v", err)
  }

  config := neo4j.SessionConfig{}

  session := driver.NewSession(ctx, config)
  defer session.Close(ctx)

  result, err := session.Run(
    ctx,
    fmt.Sprintf("MATCH (n) WHERE ID(n) = '%s' RETURN n", nodeId),
    map[string]any{},
  )
  if err != nil {
    return "", fmt.Errorf("error running query, %v", err)
  }

  if !result.Next(ctx) {
    return "", fmt.Errorf("node not found")
  }

  n, found := result.Record().Get("n")
  if !found {
    return "", fmt.Errorf("node not found")
  }

  return fmt.Sprintf("+%v\n", n), nil
}

func main() {
  if len(os.Args) < 3 {
    log.Fatal("Usage: go main.go (region) (host and port)")
  }
  region := os.Args[1]
  hostAndPort := os.Args[2]
  ctx := context.Background()

  res, err := findNode(ctx, region, hostAndPort, "72c2e8c1-7d5f-5f30-10ca-9d2bb8c4afbc")
  if err != nil {
    log.Fatal(err)
  }
  fmt.Println(res)
}
```

## Comportamento della connessione Bolt in Neptune
<a name="access-graph-opencypher-bolt-connections"></a>

Di seguito sono elencati alcuni punti da tenere a mente sulle connessioni Bolt in Neptune:
+ Poiché le connessioni Bolt vengono create a livello TCP, non è possibile utilizzare un [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html) con tali connessioni, come è possibile fare con un endpoint HTTP.
+ La porta utilizzata da Neptune per le connessioni Bolt è la porta del cluster database.
+ In base al preambolo Bolt che gli è stato passato, il server Neptune seleziona la versione Bolt più elevata appropriata (1, 2, 3 o 4.0).
+ Il numero massimo di connessioni al server Neptune che un client può avere aperte in qualsiasi momento è 1.000.
+ Se il client non chiude una connessione dopo una query, tale connessione può essere utilizzata per eseguire la query successiva.
+ Tuttavia, se una connessione rimane inattiva per 20 minuti, il server la chiude automaticamente.
+ Se l'autenticazione IAM non è abilitata, è possibile utilizzare `AuthTokens.none()` anziché fornire un nome utente e una password fittizi. Ad esempio, in Java:

  ```
  GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(),
      Config.builder().withEncryption().withTrustStrategy(TrustStrategy.trustSystemCertificates()).build());
  ```
+ Quando l'autenticazione IAM è abilitata, una connessione Bolt viene sempre disconnessa 10 giorni e alcuni minuti dopo essere stata stabilita, se non è già stata chiusa per qualche altro motivo.
+ Se il client invia una query per l'esecuzione tramite una connessione senza aver utilizzato i risultati di una query precedente, la nuova query viene eliminata. Per eliminare invece i risultati precedenti, il client deve inviare un messaggio di ripristino tramite la connessione.
+ Su una determinata connessione è possibile creare una sola transazione alla volta.
+ Se si verifica un'eccezione durante una transazione, il server Neptune esegue il rollback della transazione e chiude la connessione. In questo caso, il driver crea una nuova connessione per la query successiva.
+ Tenere presente che le sessioni non sono thread-safe. Più operazioni parallele devono utilizzare più sessioni separate.

# Esempi di query openCypher parametrizzate
<a name="opencypher-parameterized-queries"></a>

Neptune supporta query openCypher parametrizzate. Ciò consente di utilizzare la stessa struttura di query più volte con argomenti diversi. Poiché la struttura della query non cambia, Neptune può memorizzare nella cache l'albero sintattico astratto (AST) invece di doverlo analizzare più volte.

## Esempio di una query openCypher parametrizzata con l'endpoint HTTPS
<a name="opencypher-http-parameterized-queries"></a>

Di seguito è riportato un esempio di utilizzo di una query parametrizzata con l'endpoint HTTPS openCypher di Neptune. La query è:

```
MATCH (n {name: $name, age: $age})
RETURN n
```

I parametri sono definiti come segue:

```
parameters={"name": "john", "age": 20}
```

Con `GET` è possibile inviare la query parametrizzata in questo modo:

```
curl -k \
  "https://localhost:8182/openCypher?query=MATCH%20%28n%20%7Bname:\$name,age:\$age%7D%29%20RETURN%20n&parameters=%7B%22name%22:%22john%22,%22age%22:20%7D"
```

In alternativa, è possibile utilizzare `POST`:

```
curl -k \
  https://localhost:8182/openCypher \
  -d "query=MATCH (n {name: \$name, age: \$age}) RETURN n" \
  -d "parameters={\"name\": \"john\", \"age\": 20}"
```

Oppure, con `DIRECT POST`:

```
curl -k \
   -H "Content-Type: application/opencypher" \
  "https://localhost:8182/openCypher?parameters=%7B%22name%22:%22john%22,%22age%22:20%7D" \
  -d "MATCH (n {name: \$name, age: \$age}) RETURN n"
```

## Esempi di query openCypher parametrizzate con Bolt
<a name="opencypher-bolt-parameterized-queries"></a>

Ecco un esempio Python di una query openCypher parametrizzata che utilizza il protocollo Bolt:

```
from neo4j import GraphDatabase
uri = "bolt://[neptune-endpoint-url]:8182"
driver = GraphDatabase.driver(uri, auth=("", ""))

def match_name_and_age(tx, name, age):
  # Parameterized Query
  tx.run("MATCH (n {name: $name, age: $age}) RETURN n", name=name, age=age)

with driver.session() as session:
  # Parameters
  session.read_transaction(match_name_and_age, "john", 20)

driver.close()
```

Ecco un esempio Java di una query openCypher parametrizzata che utilizza il protocollo Bolt:

```
Driver driver = GraphDatabase.driver("bolt+s://(your cluster endpoint URL):8182");
HashMap<String, Object> parameters = new HashMap<>();
parameters.put("name", "john");
parameters.put("age", 20);
String queryString = "MATCH (n {name: $name, age: $age}) RETURN n";
Result result = driver.session().run(queryString, parameters);
```

# Modello di dati openCypher
<a name="access-graph-opencypher-data-model"></a>

Il motore openCypher di Neptune si basa sullo stesso modello di grafo delle proprietà di Gremlin. In particolare:
+ Ogni nodo ha una o più etichette. Se si inserisce un nodo senza etichette, viene associata un'etichetta predefinita denominata `vertex`. Se si tenta di eliminare tutte le etichette di un nodo, viene generato un errore.
+ Una relazione è un'entità che ha esattamente un tipo di relazione e che forma una connessione unidirezionale tra due nodi (ovvero *da* uno dei nodi *a*ll'altro).
+ Sia i nodi che le relazioni possono avere proprietà, ma non è obbligatorio. Neptune supporta nodi e relazioni con zero proprietà.
+ Neptune non supporta le metaproprietà, che non sono incluse nemmeno nelle specifiche openCypher.
+ Le proprietà del grafo possono contenere più valori se sono state create con Gremlin. In altre parole, la proprietà di un nodo o di una relazione può avere un insieme di valori diversi anziché uno solo. Neptune ha esteso la semantica di openCypher per gestire correttamente le proprietà multivalore.

I tipi di dati supportati sono documentati in [Formato dati openCypher](bulk-load-tutorial-format-opencypher.md). Tuttavia, al momento non è consigliabile inserire i valori della proprietà `Array` in un grafo openCypher. Sebbene sia possibile inserire un valore della proprietà array utilizzando lo strumento di caricamento in blocco, il rilascio corrente openCypher di Neptune lo tratta come un insieme di proprietà multivalore anziché come un singolo valore di elenco.

Di seguito è riportato l'elenco dei tipi di dati supportati in questo rilascio:
+ `Bool`
+ `Byte`
+ `Short`
+ `Int` 
+ `Long`
+ `Float` (include \$1/- Infinity e NaN, ma non INF)
+ `Double` (include \$1/- Infinity e NaN, ma non INF)
+ `DateTime` 
+ `String`

# Funzionalità `explain` di openCypher
<a name="access-graph-opencypher-explain"></a>

La funzionalità `explain` di openCypher è uno strumento self-service di Amazon Neptune che consente di comprendere l'approccio di esecuzione adottato dal motore Neptune. Per richiamare explain, si passa un parametro a una richiesta [HTTPS](access-graph-opencypher-queries.md) openCypher con `explain=mode`, dove il valore `mode` può essere uno dei seguenti:

****
+ **`static`**: in modalità `static`, `explain` visualizza solo la struttura statica del piano di query. Non esegue effettivamente la query.
+ **`dynamic`**: in modalità `dynamic`, `explain` esegue anche la query e include gli aspetti dinamici del piano di query. Questi aspetti potrebbero includere il numero di associazioni intermedie che passano attraverso gli operatori, il rapporto tra le associazioni in entrata e quelle in uscita e il tempo totale impiegato da ogni operatore.
+ **`details`**: in modalità `details`, `explain` visualizza le informazioni mostrate in modalità dynamic oltre a dettagli aggiuntivi, come la stringa di query openCypher effettiva e il calcolo dell'intervallo stimato per il modello sottostante un operatore join.

  

Ad esempio, con `POST`:

```
curl HTTPS://server:port/openCypher \
  -d "query=MATCH (n) RETURN n LIMIT 1;" \
  -d "explain=dynamic"
```

Oppure, con `GET`:

```
curl -X GET \
  "HTTPS://server:port/openCypher?query=MATCH%20(n)%20RETURN%20n%20LIMIT%201&explain=dynamic"
```

## Limitazioni per `explain` di openCypher in Neptune
<a name="access-graph-opencypher-explain-limitations"></a>

Il rilascio corrente di explain di openCypher presenta le seguenti limitazioni:
+ I piani di explain sono attualmente disponibili solo per le query che eseguono operazioni di sola lettura. Le query che eseguono qualsiasi tipo di mutazione, come `CREATE`, `DELETE`, `MERGE`, `SET` e così via non sono supportate.
+ Gli operatori e l'output di un piano specifico potrebbero cambiare nei rilasci futuri.

## Operatori DFE nell'output di `explain` di openCypher
<a name="access-graph-opencypher-dfe-operators"></a>

Per utilizzare le informazioni fornite dalla funzionalità `explain` di openCypher, è necessario comprendere alcuni dettagli su come funziona il [motore di query DFE](neptune-dfe-engine.md) (DFE è il motore utilizzato da Neptune per elaborare le query openCypher).

Il motore DFE traduce ogni query SPARQL in una pipeline di operatori. Partendo dal primo operatore, le soluzioni intermedie passano da un operatore all'altro attraverso questa pipeline di operatori. Ogni riga della tabella di explain rappresenta un risultato, fino al punto di valutazione.

Gli operatori che possono essere presenti in un piano di query DFE sono i seguenti:

**DFEApply**— Esegue la funzione specificata nella sezione arguments, sul valore memorizzato nella variabile specificata

**DFEBindRelazione**: unisce le variabili con i nomi specificati

**DFEChunkLocalSubQuery**— Si tratta di un'operazione non bloccante che funge da involucro per l'esecuzione delle sottoquery.

**DFEDistinctColonna** — Restituisce il sottoinsieme distinto dei valori di input in base alla variabile specificata.

**DFEDistinctRelazione**: restituisce il sottoinsieme distinto delle soluzioni di input in base alla variabile specificata.

**DFEDrain**— Viene visualizzato alla fine di una sottoquery e funge da passaggio di terminazione per quella sottoquery. Il numero di soluzioni viene registrato come `Units In`. `Units Out` è sempre zero.

**DFEForwardValore**: copia tutti i blocchi di input direttamente come blocchi di output da passare al relativo operatore a valle.

**DFEGroupByHashIndex**— Esegue un'operazione di raggruppamento sulle soluzioni di input in base a un indice hash calcolato in precedenza (utilizzando l'operazione). `DFEHashIndexBuild` Analogamente a un output, l'input specificato viene esteso di una colonna contenente una chiave di gruppo per ogni soluzione di input.

**DFEHashIndexBuild**— Crea un indice hash su un insieme di variabili come effetto collaterale. Questo indice hash viene in genere riutilizzato nelle operazioni successive. Consulta `DFEHashIndexJoin` o `DFEGroupByHashIndex` per informazione su dove potrebbe essere necessario utilizzare questo indice.

**DFEHashIndexJoin**— Esegue un join sulle soluzioni in entrata rispetto a un indice hash creato in precedenza. Consulta `DFEHashIndexBuild` per informazioni su dove potrebbe essere necessario creare questo indice.

**DFEJoinEsiste**: accetta una relazione di input sinistra e destra e mantiene i valori della relazione di sinistra che hanno un valore corrispondente nella relazione destra, come definito dalle variabili di join specificate. 

****: si tratta di un'operazione non bloccante che funge da wrapper per una sottoquery, consentendone l'esecuzione ripetuta per l'utilizzo nei cicli.

**DFEMergeChunks**: si tratta di un'operazione di blocco che combina i blocchi dell'operatore a monte in un unico blocco di soluzioni da passare all'operatore a valle (inverso di). `DFESplitChunks`

**DFEMinus**— Accetta una relazione di input sinistra e destra e mantiene i valori della relazione di sinistra che non hanno un valore corrispondente nella relazione destra, come definito dalle variabili di join fornite. Se non vi è alcuna sovrapposizione nelle variabili tra entrambe le relazioni, questo operatore restituisce semplicemente la relazione di input sinistra.

**DFENotEsiste**: accetta una relazione di input sinistra e destra e mantiene i valori della relazione di sinistra che non hanno un valore corrispondente nella relazione destra, come definito dalle variabili di join fornite. Se non vi è alcuna sovrapposizione nelle variabili in entrambe le relazioni, questo operatore restituisce una relazione vuota.

**DFEOptionalJoin**: esegue un join esterno sinistro (chiamato anche join OPZIONALE): le soluzioni dal lato sinistro che hanno almeno un partner di unione sul lato destro vengono unite e le soluzioni dal lato sinistro senza partner di unione sul lato destro vengono inoltrate così come sono. Questa è un'operazione bloccante.

**DFEPipelineUnisci**: unisce l'input allo schema di tuple definito dall'argomento. `pattern`

**DFEPipelineRangeCount**— Conta il numero di soluzioni che corrispondono a un determinato modello e restituisce una singola soluzione unidirezionale contenente il valore di conteggio.

**DFEPipelineScansione**: esegue la scansione del database alla ricerca dell'`pattern`argomento specificato, con o senza un determinato filtro sulle colonne.

**DFEProject**— Richiede più colonne di input e proietta solo le colonne desiderate.

**DFEReduce**— Esegue la funzione di aggregazione specificata su variabili specificate.

DFERelationalJoin - **Unisce** l'input dell'operatore precedente in base alle chiavi dello schema specificate utilizzando un merge join. Questa è un'operazione bloccante.

**DFERouteChunks**: preleva i blocchi di input dal suo singolo bordo in entrata e li indirizza lungo i suoi molteplici bordi in uscita.

**DFESelectRighe**: questo operatore preleva selettivamente le righe dalle soluzioni di relazione di input sinistro per inoltrarle all'operatore a valle. Le righe selezionate in base agli identificatori di riga forniti nella relazione di input destra dell'operatore.

**DFESerialize**— Serializza i risultati finali di una query in una serializzazione di stringhe JSON, mappando ogni soluzione di input al nome di variabile appropriato. Per i risultati di nodi ed edge, questi risultati vengono serializzati in una mappa delle proprietà e dei metadati delle entità.

**DFESort**— Accetta una relazione di input e produce una relazione ordinata in base alla chiave di ordinamento fornita.

**DFESplitByGroup**— Divide ogni singolo blocco di input da un bordo di ingresso in blocchi di output più piccoli corrispondenti ai gruppi di righe identificati dalla riga IDs dal blocco di input corrispondente dall'altro bordo in entrata.

**DFESplitChunk: divide ogni singolo blocco di input in blocchi** di output più piccoli (inversi di). `DFEMergeChunks`

**DFEStreamingHashIndexBuild**— `DFEHashIndexBuild` Versione in streaming di.

**DFEStreamingGroupByHashIndex**— Versione in streaming di`DFEGroupByHashIndex`.

**DFESubquery**— Questo operatore appare all'inizio di tutti i piani e riassume le parti del piano eseguite sul [motore DFE](neptune-dfe-engine.md), che è l'intero piano per OpenCypher.

**DFESymmetricHashJoin**— Unisce l'input dell'operatore precedente in base alle chiavi del pattern specificato utilizzando un hash join. Questa è un'operazione non bloccante.

**DFESync**— Questo operatore è un operatore di sincronizzazione che supporta piani non bloccanti. Accetta le soluzioni da due edge in entrata e le inoltra agli edge a valle appropriati. Ai fini della sincronizzazione, gli input lungo uno di questi edge possono essere bufferizzati internamente. 

**DFETee**— Si tratta di un operatore di filiale che invia lo stesso set di soluzioni a più operatori.

**DFETermRisoluzione**: esegue un'operazione di localizzazione o globalizzazione sui relativi input, generando colonne rispettivamente di identificatori localizzati o globalizzati.

****: espande gli elenchi di valori da una colonna di input nella colonna di output come singoli elementi.

**DFEUnion**— Accetta due o più relazioni di input e produce un'unione di tali relazioni utilizzando lo schema di output desiderato.

**SolutionInjection**— Viene visualizzato prima di tutto il resto nell'output di spiegazione, con un valore di 1 nella colonna Units Out. Tuttavia, non genera alcuna operazione e in realtà non inserisce alcuna soluzione nel motore DFE.

**TermResolution**— Appare alla fine dei piani e traduce gli oggetti dal motore Neptune in oggetti OpenCypher.

## Colonne nell'output di `explain` di openCypher
<a name="access-graph-opencypher-explain-columns"></a>

Le informazioni sul piano di query che Neptune genera come output di explain di openCypher contengono tabelle con un operatore per riga. La tabella contiene le seguenti colonne:

**ID**: ID numerico di questo operatore nel piano.

**Out \$11** (e **Out \$12**): ID degli operatori downstream rispetto a questo operatore. Possono esserci al massimo due operatori downstream.

**Name**: nome di questo operatore.

**Arguments**: qualsiasi dettaglio rilevante per l'operatore. Ciò include elementi come lo schema di input, lo schema di output, il modello (per `PipelineScan` e `PipelineJoin`) e così via.

**Mode**: etichetta che descrive il comportamento fondamentale dell'operatore. Questa colonna è per lo più vuota (`-`). Un'eccezione è `TermResolution`, dove mode può essere `id2value_opencypher`, che indica una risoluzione dall'ID al valore openCypher.

**Units In**: numero di soluzioni passate come input a questo operatore. Gli operatori senza operatori upstream, come `DFEPipelineScan`, `SolutionInjections` e `DFESubquery` senza valore statico inserito, avranno valore zero.

**Units Out**: numero di soluzioni prodotte come output di questo operatore. `DFEDrain` è un caso speciale, in cui il numero di soluzioni da eliminare viene registrato in `Units In` e `Units Out` è sempre zero.

**Ratio**: rapporto tra `Units Out` e `Units In`.

**Time (ms)**: tempo della CPU utilizzato da questo operatore, in millisecondi.

## Esempio di base dell'output di explain di openCypher
<a name="access-graph-opencypher-explain-basic-example"></a>

Il seguente è un esempio di base dell'output di `explain` di openCypher. La query è una ricerca a nodo singolo nel set di dati delle rotte aeree per un nodo con il codice aeroportuale `ATL` che richiama `explain` usando la modalità `details` nel formato di output ASCII predefinito:

```
curl -d "query=MATCH (n {code: 'ATL'}) RETURN n" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                      ~
Query:
MATCH (n {code: 'ATL'}) RETURN n

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?n]          │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 2.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?n) with property 'code' as ?n_code2 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.21      ║
║    │        │        │                       │ inlineFilters=[(?n_code2 IN ["ATL"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEProject            │ columns=[?n]                                                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#9d84f97c-c3b0-459a-98d5-955a8726b159/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?n, ?n_code2]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?n                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.20      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?n]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?n) with property 'ALL' and label '?n_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.35      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

Al livello superiore, `SolutionInjection` appare prima di ogni altra cosa, con 1 come valore di Units In. Notare che in realtà non inserisce alcuna soluzione. Si può vedere che l'operatore successivo `DFESubquery` ha 0 come valore di Units Out.

Dopo `SolutionInjection` al livello più alto, ci sono gli operatori `DFESubquery` e `TermResolution`. `DFESubquery` incapsula le parti del piano di esecuzione delle query che viene inviato al [motore DFE](neptune-dfe-engine.md) (per le query openCypher, l'intero piano di esecuzione delle query viene eseguito dal motore DFE). Tutti gli operatori del piano di query sono annidati all'interno di `subQuery1` a cui fa riferimento `DFESubquery`. L'unica eccezione è che si materializza internamente in oggetti `TermResolution` OpenCypher completamente serializzati. IDs 

Tutti gli operatori che vengono inviati al motore DFE hanno nomi che iniziano con un prefisso `DFE`. Come accennato in precedenza, l'intero piano di query di openCypher viene eseguito dal motore DFE, quindi, tutti gli operatori tranne l'operatore finale `TermResolution` iniziano con `DFE`.

All'interno di `subQuery1` possono essere presenti zero o più operatori `DFEChunkLocalSubQuery` o `DFELoopSubQuery` che incapsulano una parte del piano di esecuzione inviato che viene eseguito in un meccanismo con limiti di memoria. `DFEChunkLocalSubQuery` qui contiene un solo `SolutionInjection` che viene utilizzato come input per la sottoquery. Per trovare la tabella per tale sottoquery nell'output, cercare `subQuery=graph URI` specificato nella colonna `Arguments` per l'operatore `DFEChunkLocalSubQuery` o `DFELoopSubQuery`.

In `subQuery1`, `DFEPipelineScan` con `ID` 0 analizza il database alla ricerca di un oggetto `pattern` specificato. Il modello cerca un'entità con proprietà `code` salvata come variabile `?n_code2` su tutte le etichette (è possibile filtrare in base a un'etichetta specifica aggiungendo `airport` a `n:airport`). L'argomento `inlineFilters` mostra il filtro per la proprietà `code` uguale a `ATL`.

Successivamente, l'operatore `DFEChunkLocalSubQuery` esegue il join dei risultati intermedi di una sottoquery che contiene `DFEPipelineJoin`. Ciò garantisce che `?n` sia effettivamente un nodo, poiché l'operatore precedente `DFEPipelineScan` cerca qualsiasi entità con la proprietà `code`.

# Esempio di output di `explain` per una ricerca di relazioni con un limite
<a name="access-graph-opencypher-explain-example-2"></a>

Questa query cerca le relazioni tra due nodi anonimi con tipo `route` e ne restituisce al massimo 10. Anche in questo caso, la modalità `explain` è `details` e il formato di output è il formato ASCII predefinito. Ecco l'output di `explain`:

Qui, `DFEPipelineScan` cerca gli archi che iniziano dal nodo anonimo `?anon_node7` e terminano in un altro nodo anonimo `?anon_node21`, con un tipo di relazione salvato come `?p_type1`. Esiste un filtro per `?p_type1` che è `el://route` (dove `el` indica l'etichetta dell'arco), che corrisponde a `[p:route]` nella stringa di query.

`DFEDrain` raccoglie la soluzione di output con un limite di 10, come mostrato nella relativa colonna `Arguments`. `DFEDrain` termina una volta raggiunto il limite o quando sono state prodotte tutte le soluzioni, a seconda dell'evento che si verifica per primo.

```
curl -d "query=MATCH ()-[p:route]->() RETURN p LIMIT 10" -k https://localhost:8182/openCypher -d "explain=details"                                                                                              ~
Query:
MATCH ()-[p:route]->() RETURN p LIMIT 10

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 10        │ 0.00  │ 5.00      ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?p]          │ id2value_opencypher │ 10       │ 10        │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═════════════════╤═══════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name            │ Arguments                                                 │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═════════════════╪═══════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan │ pattern=Edge((?anon_node7)-[?p:?p_type1]->(?anon_node21)) │ -    │ 0        │ 1000      │ 0.00  │ 0.66      ║
║    │        │        │                 │ inlineFilters=[(?p_type1 IN [<el://route>])]              │      │          │           │       │           ║
║    │        │        │                 │ patternEstimate=26219                                     │      │          │           │       │           ║
╟────┼────────┼────────┼─────────────────┼───────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEProject      │ columns=[?p]                                              │ -    │ 1000     │ 1000      │ 1.00  │ 0.14      ║
╟────┼────────┼────────┼─────────────────┼───────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ DFEDrain        │ limit=10                                                  │ -    │ 1000     │ 0         │ 0.00  │ 0.11      ║
╚════╧════════╧════════╧═════════════════╧═══════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Esempio di output di `explain` per una funzione di espressione di valori
<a name="access-graph-opencypher-explain-example-3"></a>

La funzione è:

```
MATCH (a) RETURN DISTINCT labels(a)
```

Nell'output di `explain` seguente, `DFEPipelineScan` (ID 0) cerca tutte le etichette dei nodi. Ciò corrisponde a `MATCH (a`).

`DFEChunkLocalSubquery` (ID 1) aggrega l'etichetta di `?a` per ogni `?a`. Ciò corrisponde a `labels(a)`. Si può vederlo attraverso `DFEApply` e `DFEReduce`.

`BindRelation` (ID 2) viene utilizzato per rinominare la colonna generica `?__gen_labelsOfa2` in `?labels(a)`.

`DFEDistinctRelation` (ID 4) recupera solo le etichette distinte (più nodi :airport restituiranno valori labels(a) duplicati: ["airport"]). Ciò corrisponde a `DISTINCT labels(a)`.

```
curl -d "query=MATCH (a) RETURN DISTINCT labels(a)" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                    ~
Query:
MATCH (a) RETURN DISTINCT labels(a)

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 5         │ 0.00  │ 81.00     ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?labels(a)]  │ id2value_opencypher │ 5        │ 5         │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?a) with property 'ALL' and label '?a_label1'                                                   │ -    │ 0        │ 3750      │ 0.00  │ 26.77     ║
║    │        │        │                       │ patternEstimate=3506                                                                                         │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#8b314f55-2cc7-456a-a48a-c76a0465cfab/graph_1 │ -    │ 3750     │ 3750      │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEBindRelation       │ inputVars=[?a, ?__gen_labelsOfa2, ?__gen_labelsOfa2]                                                         │ -    │ 3750     │ 3750      │ 1.00  │ 0.08      ║
║    │        │        │                       │ outputVars=[?a, ?__gen_labelsOfa2, ?labels(a)]                                                               │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEProject            │ columns=[?labels(a)]                                                                                         │ -    │ 3750     │ 3750      │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEDistinctRelation   │ -                                                                                                            │ -    │ 3750     │ 5         │ 0.00  │ 2.78      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 5        │ 0         │ 0.00  │ 0.03      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#8b314f55-2cc7-456a-a48a-c76a0465cfab/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?a]                                             │ -        │ 0        │ 3750      │ 0.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -        │ 3750     │ 7500      │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEProject           │ columns=[?a]                                               │ -        │ 3750     │ 3750      │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 17     │ -      │ DFEOptionalJoin      │ -                                                          │ -        │ 7500     │ 3750      │ 0.50  │ 0.44      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEDistinctRelation  │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 2.23      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ DFEDistinctColumn    │ column=?a                                                  │ -        │ 3750     │ 3750      │ 1.00  │ 1.50      ║
║    │        │        │                      │ ordered=false                                              │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 7      │ -      │ DFEPipelineJoin      │ pattern=Node(?a) with property 'ALL' and label '?a_label3' │ -        │ 3750     │ 3750      │ 1.00  │ 10.58     ║
║    │        │        │                      │ patternEstimate=3506                                       │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ 9      │ DFETee               │ -                                                          │ -        │ 3750     │ 7500      │ 2.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 10     │ -      │ DFEBindRelation      │ inputVars=[?a_label3]                                      │ -        │ 3750     │ 3750      │ 1.00  │ 0.04      ║
║    │        │        │                      │ outputVars=[?100]                                          │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ 11     │ -      │ DFEBindRelation      │ inputVars=[?a, ?a_label3, ?100]                            │ -        │ 7500     │ 3750      │ 0.50  │ 0.07      ║
║    │        │        │                      │ outputVars=[?a, ?a_label3, ?100]                           │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 10 │ 9      │ -      │ DFETermResolution    │ column=?100                                                │ id2value │ 3750     │ 3750      │ 1.00  │ 7.60      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 11 │ 12     │ -      │ DFEBindRelation      │ inputVars=[?a, ?a_label3, ?100]                            │ -        │ 3750     │ 3750      │ 1.00  │ 0.06      ║
║    │        │        │                      │ outputVars=[?a, ?100, ?a_label3]                           │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 12 │ 13     │ -      │ DFEApply             │ functor=nodeLabel(?a_label3)                               │ -        │ 3750     │ 3750      │ 1.00  │ 0.55      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 13 │ 14     │ -      │ DFEProject           │ columns=[?a, ?a_label3_alias4]                             │ -        │ 3750     │ 3750      │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 14 │ 15     │ -      │ DFEMergeChunks       │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 15 │ 16     │ -      │ DFEReduce            │ functor=collect(?a_label3_alias4)                          │ -        │ 3750     │ 3750      │ 1.00  │ 6.37      ║
║    │        │        │                      │ segmentationKey=[?a]                                       │          │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 16 │ 3      │ -      │ DFEMergeChunks       │ -                                                          │ -        │ 3750     │ 3750      │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 17 │ -      │ -      │ DFEDrain             │ -                                                          │ -        │ 3750     │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Esempio di output di `explain` per una funzione di espressione di valori matematici
<a name="access-graph-opencypher-explain-example-4"></a>

In questo esempio, `RETURN abs(-10)` esegue una valutazione semplice, accettando il valore assoluto di una costante `-10`.

`DFEChunkLocalSubQuery` (ID 1) esegue l'inserimento di una soluzione per il valore statico `-10`, che viene archiviato nella variabile `?100`.

`DFEApply` (ID 2) è l'operatore che esegue la funzione di valore assoluto `abs()` sul valore statico archiviato nella variabile `?100`.

Ecco la query e l'output di `explain` risultante:

```
curl -d "query=RETURN abs(-10)" -k https://localhost:8182/openCypher  -d "explain=details"                                                                                                                       ~
Query:
RETURN abs(-10)

╔════╤════════╤════════╤═══════════════════╤═══════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments             │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]        │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1    │ -                   │ 0        │ 1         │ 0.00  │ 4.00      ║
╟────┼────────┼────────┼───────────────────┼───────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?_internalVar1] │ id2value_opencypher │ 1        │ 1         │ 1.00  │ 1.00      ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection  │ outSchema=[]                                                                                                 │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#c4cc6148-cce3-4561-93c0-deb91f257356/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEApply              │ functor=abs(?100)                                                                                            │ -    │ 1        │ 1         │ 1.00  │ 0.26      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEBindRelation       │ inputVars=[?_internalVar2, ?_internalVar2]                                                                   │ -    │ 1        │ 1         │ 1.00  │ 0.04      ║
║    │        │        │                       │ outputVars=[?_internalVar2, ?_internalVar1]                                                                  │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEProject            │ columns=[?_internalVar1]                                                                                     │ -    │ 1        │ 1         │ 1.00  │ 0.06      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 1        │ 0         │ 0.00  │ 0.05      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝

subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#c4cc6148-cce3-4561-93c0-deb91f257356/graph_1
╔════╤════════╤════════╤══════════════════════╤═════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                           │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪═════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ solutions=[?100 -> [-10^^<LONG>]]   │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
║    │        │        │                      │ outSchema=[?100]                    │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 3      │ -      │ DFERelationalJoin    │ joinVars=[]                         │ -    │ 2        │ 1         │ 0.50  │ 0.18      ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 1      │ -      │ DFESolutionInjection │ outSchema=[]                        │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼─────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ -      │ -      │ DFEDrain             │ -                                   │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧═════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Esempio di output di `explain` per una query con percorso a lunghezza variabile (VLP)
<a name="access-graph-opencypher-explain-example-5"></a>

Questo è un esempio di un piano di query più complesso per la gestione di una query con percorso a lunghezza variabile. Questo esempio mostra solo una parte dell'output di `explain`, per motivi di chiarezza.

In `subQuery1`, `DFEPipelineScan` (ID 0) e `DFEChunkLocalSubQuery` (ID 1), che inserisce la sottoquery `...graph_1`, sono responsabili della ricerca di un nodo con il codice `YPO`.

In `subQuery1`, `DFEChunkLocalSubQuery` (ID 2), che inserisce la sottoquery `...graph_2`, è responsabile della ricerca di un nodo con il codice `LAX`.

In`subQuery1`, `DFEChunkLocalSubQuery` (ID 3) inserisce la sottoquery `...graph3`, che contiene `DFELoopSubQuery` (ID 17), che a sua volta inserisce la sottoquery `...graph5`. Questa operazione è responsabile della risoluzione del modello a lunghezza variabile `-[*2]->` nella stringa di query tra due nodi.

```
curl -d "query=MATCH p=(a {code: 'YPO'})-[*2]->(b{code: 'LAX'}) return p" -k https://localhost:8182/openCypher -d "explain=details"                                                                                                                                                                                ~
Query:
MATCH p=(a {code: 'YPO'})-[*2]->(b{code: 'LAX'}) return p

╔════╤════════╤════════╤═══════════════════╤════════════════════╤═════════════════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments          │ Mode                │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪════════════════════╪═════════════════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]     │ -                   │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFESubquery       │ subQuery=subQuery1 │ -                   │ 0        │ 0         │ 0.00  │ 84.00     ║
╟────┼────────┼────────┼───────────────────┼────────────────────┼─────────────────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ -      │ -      │ TermResolution    │ vars=[?p]          │ id2value_opencypher │ 0        │ 0         │ 0.00  │ 0         ║
╚════╧════════╧════════╧═══════════════════╧════════════════════╧═════════════════════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery1
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan       │ pattern=Node(?a) with property 'code' as ?a_code7 and label 'ALL'                                            │ -    │ 0        │ 1         │ 0.00  │ 0.68      ║
║    │        │        │                       │ inlineFilters=[(?a_code7 IN ["YPO"^^xsd:string])]                                                            │      │          │           │       │           ║
║    │        │        │                       │ patternEstimate=1                                                                                            │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_1 │ -    │ 1        │ 1         │ 1.00  │ 0.03      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_2 │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ DFEChunkLocalSubQuery │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_3 │ -    │ 1        │ 0         │ 0.00  │ 0.04      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEBindRelation       │ inputVars=[?__gen_path6, ?anon_rel26, ?b_code8, ?b, ?a_code7, ?a, ?__gen_path6]                              │ -    │ 0        │ 0         │ 0.00  │ 0.10      ║
║    │        │        │                       │ outputVars=[?__gen_path6, ?anon_rel26, ?b_code8, ?b, ?a_code7, ?a, ?p]                                       │      │          │           │       │           ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ DFEProject            │ columns=[?p]                                                                                                 │ -    │ 0        │ 0         │ 0.00  │ 0.05      ║
╟────┼────────┼────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ -      │ -      │ DFEDrain              │ -                                                                                                            │ -    │ 0        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧═══════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_1
╔════╤════════╤════════╤══════════════════════╤════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                  │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFESolutionInjection │ outSchema=[?a, ?a_code7]                                   │ -    │ 0        │ 1         │ 0.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ 3      │ DFETee               │ -                                                          │ -    │ 1        │ 2         │ 2.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFEDistinctColumn    │ column=?a                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.25      ║
║    │        │        │                      │ ordered=false                                              │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 5      │ -      │ DFEHashIndexBuild    │ vars=[?a]                                                  │ -    │ 1        │ 1         │ 1.00  │ 0.05      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ DFEPipelineJoin      │ pattern=Node(?a) with property 'ALL' and label '?a_label1' │ -    │ 1        │ 1         │ 1.00  │ 0.47      ║
║    │        │        │                      │ patternEstimate=3506                                       │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ 7      │ DFESync              │ -                                                          │ -    │ 2        │ 2         │ 1.00  │ 0.04      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 7  │ 8      │ -      │ DFEForwardValue      │ -                                                          │ -    │ 1        │ 1         │ 1.00  │ 0.01      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 8  │ 9      │ -      │ DFEHashIndexJoin     │ -                                                          │ -    │ 2        │ 1         │ 0.50  │ 0.26      ║
╟────┼────────┼────────┼──────────────────────┼────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 9  │ -      │ -      │ DFEDrain             │ -                                                          │ -    │ 1        │ 0         │ 0.00  │ 0.02      ║
╚════╧════════╧════════╧══════════════════════╧════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_2
╔════╤════════╤════════╤══════════════════════╤═══════════════════════════════════════════════════════════════════╤══════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                 │ Arguments                                                         │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪══════════════════════╪═══════════════════════════════════════════════════════════════════╪══════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan      │ pattern=Node(?b) with property 'code' as ?b_code8 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.38      ║
║    │        │        │                      │ inlineFilters=[(?b_code8 IN ["LAX"^^xsd:string])]                 │      │          │           │       │           ║
║    │        │        │                      │ patternEstimate=1                                                 │      │          │           │       │           ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ DFEMergeChunks       │ -                                                                 │ -    │ 1        │ 1         │ 1.00  │ 0.02      ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 4      │ -      │ DFERelationalJoin    │ joinVars=[]                                                       │ -    │ 2        │ 1         │ 0.50  │ 0.19      ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 2      │ -      │ DFESolutionInjection │ outSchema=[?a, ?a_code7]                                          │ -    │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼──────────────────────┼───────────────────────────────────────────────────────────────────┼──────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ DFEDrain             │ -                                                                 │ -    │ 1        │ 0         │ 0.00  │ 0.01      ║
╚════╧════════╧════════╧══════════════════════╧═══════════════════════════════════════════════════════════════════╧══════╧══════════╧═══════════╧═══════╧═══════════╝


subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_3
╔════╤════════╤════════╤═══════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name                  │ Arguments                                                                                                    │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
...
║ 17 │ 18     │ -      │ DFELoopSubQuery       │ subQuery=http://aws.amazon.com/neptune/vocab/v01/dfe/past/graph#cc05129f-d07e-4622-bbe3-9e99558eca46/graph_5 │ -        │ 1        │ 2         │ 2.00  │ 0.31      ║
...
```

# Transazioni in Neptune openCypher
<a name="access-graph-opencypher-transactions"></a>

L'implementazione openCypher in Amazon Neptune utilizza la [semantica delle transazioni definita da Neptune](transactions-neptune.md). Tuttavia, i livelli di isolamento forniti dal driver Bolt hanno alcune implicazioni specifiche per la semantica delle transazioni Bolt, come descritto nelle sezioni seguenti.

## Query sulle transazioni Bolt di sola lettura
<a name="access-graph-opencypher-transactions-ro"></a>

Esistono vari modi in cui è possibile elaborare le query di sola lettura, con diversi modelli di transazione e livelli di isolamento, come segue:

### Query sulle transazioni implicite di sola lettura
<a name="access-graph-opencypher-transactions-ro-implicit"></a>

Di seguito è illustrato un esempio di transazione implicita di sola lettura:

```
public void executeReadImplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
          Config.builder().withEncryption()
                          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
                          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig.builder()
                                             .withFetchSize(1000)
                                             .withDefaultAccessMode(AccessMode.READ)
                                             .build();

  // run the query as access mode read
  driver.session(sessionConfig).readTransaction(new TransactionWork<String>()
    {
      final StringBuilder resultCollector = new StringBuilder();

      @Override
      public String execute(final Transaction tx)
      {
        // execute the query
        Result queryResult = tx.run(READ_QUERY);

        // Read the result
        for (Record record : queryResult.list())
        {
          for (String key : record.keys())
          {
            resultCollector.append(key)
                           .append(":")
                           .append(record.get(key).asNode().toString());
          }
        }
        return resultCollector.toString();
      }

    }
  );

  // close the driver.
  driver.close();
}
```

Poiché le repliche di lettura accettano solo query di sola lettura, tutte le query relative sulle repliche di lettura vengono eseguite come transazioni implicite di lettura indipendentemente dalla modalità di accesso impostata nella configurazione della sessione. Neptune valuta le transazioni implicite di lettura come [query di sola lettura](transactions-neptune.md#transactions-neptune-read-only) in base alla semantica di isolamento `SNAPSHOT`.

In caso di errore, le transazioni implicite di lettura vengono ripetute per impostazione predefinita.

### Query sulle transazioni di sola lettura con commit automatico
<a name="access-graph-opencypher-transactions-ro-autocommit"></a>

Di seguito è illustrato un esempio di transazione di sola lettura con commit automatico:

```
public void executeAutoCommitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // Create the session config.
  final SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.READ)
    .build();

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // result collector
  final StringBuilder resultCollector = new StringBuilder();

  // create a session
  final Session session = driver.session(sessionConfig);

  // run the query
  final Result queryResult = session.run(READ_QUERY);
  for (final Record record : queryResult.list())
  {
    for (String key : record.keys())
    {
      resultCollector.append(key)
                     .append(":")
                     .append(record.get(key).asNode().toString());
    }
  }

  // close the session
  session.close();

  // close the driver
  driver.close();
}
```

Se la modalità di accesso è impostata su `READ` nella configurazione della sessione, Neptune valuta le query sulle transazioni con commit automatico come [query di sola lettura](transactions-neptune.md#transactions-neptune-read-only) in base alla semantica di isolamento `SNAPSHOT`. Notare che le repliche di lettura accettano solo query di sola lettura.

Se non si esegue una configurazione di sessione, le query con commit automatico vengono elaborate per impostazione predefinita con l'isolamento delle query di mutazione, quindi è importante eseguire una configurazione di sessione che imposti esplicitamente la modalità di accesso su `READ`.

In caso di errore, le query di sola lettura con commit automatico non vengono ripetute.

### Query sulle transazioni esplicite di sola lettura
<a name="access-graph-opencypher-transactions-ro-explicit"></a>

Di seguito è illustrato un esempio di transazione esplicita di sola lettura:

```
public void executeReadExplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // read query
  final String READ_QUERY = "MATCH (n) RETURN n limit 10";

  // Create the session config.
  final SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.READ)
    .build();

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // result collector
  final StringBuilder resultCollector = new StringBuilder();

  // create a session
  final Session session = driver.session(sessionConfig);

  // begin transaction
  final Transaction tx = session.beginTransaction();

  // run the query on transaction
  final List<Record> list = tx.run(READ_QUERY).list();

  // read the result
  for (final Record record : list)
  {
    for (String key : record.keys())
    {
      resultCollector
        .append(key)
        .append(":")
        .append(record.get(key).asNode().toString());
    }
  }

  // commit the transaction and for rollback we can use beginTransaction.rollback();
  tx.commit();

  // close the driver
  driver.close();
}
```

Se la modalità di accesso è impostata su `READ` nella configurazione della sessione, Neptune valuta le transazioni esplicite di sola lettura come [query di sola lettura](transactions-neptune.md#transactions-neptune-read-only) in base alla semantica di isolamento `SNAPSHOT`. Notare che le repliche di lettura accettano solo query di sola lettura.

Se non si esegue una configurazione di sessione, le transazioni esplicite di sola lettura vengono elaborate per impostazione predefinita con l'isolamento delle query di mutazione, quindi è importante eseguire una configurazione di sessione che imposti esplicitamente la modalità di accesso su `READ`.

In caso di errore, le query esplicite di sola lettura vengono ripetute per impostazione predefinita.

## Query sulle transazioni di mutazione Bolt
<a name="access-graph-opencypher-transactions-wr"></a>

Come per le query di sola lettura, esistono vari modi in cui è possibile elaborare le query di mutazione, con diversi modelli di transazione e livelli di isolamento, come segue:

### Query sulle transazioni di mutazione implicite
<a name="access-graph-opencypher-transactions-wr-implicit"></a>

Di seguito è illustrato un esempio di transazione di mutazione implicita:

```
public void executeWriteImplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // create node with label as label and properties.
  final String WRITE_QUERY = "CREATE (n:label {name : 'foo'})";

  // Read the vertex created with label as label.
  final String READ_QUERY = "MATCH (n:label) RETURN n";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.WRITE)
    .build();

  final StringBuilder resultCollector = new StringBuilder();

  // run the query as access mode write
  driver.session(sessionConfig).writeTransaction(new TransactionWork<String>()
  {
    @Override
    public String execute(final Transaction tx)
    {
      // execute the write query and consume the result.
      tx.run(WRITE_QUERY).consume();

      // read the vertex written in the same transaction
      final List<Record> list = tx.run(READ_QUERY).list();

      // read the result
      for (final Record record : list)
      {
        for (String key : record.keys())
        {
          resultCollector
            .append(key)
            .append(":")
            .append(record.get(key).asNode().toString());
        }
      }
      return resultCollector.toString();
    }
  }); // at the end, the transaction is automatically committed.

  // close the driver.
  driver.close();
}
```

Le letture effettuate come parte delle query di mutazione vengono eseguite in base all'isolamento `READ COMMITTED` con le consuete garanzie per le [transazioni di mutazione di Neptune](transactions-neptune.md#transactions-neptune-mutation).

Indipendentemente dal fatto che si esegua o meno specificamente una configurazione di sessione, la transazione viene sempre considerata come una transazione di scrittura.

Per i conflitti, consulta [Risoluzione dei conflitti tramite timeout di attesa di blocco](transactions-neptune.md#transactions-neptune-conflicts).

### Query sulle transazioni di mutazione con commit automatico
<a name="access-graph-opencypher-transactions-wr-autocommit"></a>

Le query di mutazione con commit automatico ereditano lo stesso comportamento delle transazioni di mutazione implicite.

Se non si esegue una configurazione di sessione, la transazione viene considerata come una transazione di scrittura per impostazione predefinita.

In caso di errore, le query di mutazione con commit automatico non vengono ripetute automaticamente.

### Query sulle transazioni di mutazione esplicite
<a name="access-graph-opencypher-transactions-wr-explicit"></a>

Di seguito è illustrato un esempio di transazione di mutazione esplicita:

```
public void executeWriteExplicitTransaction()
{
  // end point
  final String END_POINT = "(End Point URL)";

  // create node with label as label and properties.
  final String WRITE_QUERY = "CREATE (n:label {name : 'foo'})";

  // Read the vertex created with label as label.
  final String READ_QUERY = "MATCH (n:label) RETURN n";

  // create the driver
  final Driver driver = GraphDatabase.driver(END_POINT, AuthTokens.none(),
    Config.builder()
          .withEncryption()
          .withTrustStrategy(TrustStrategy.trustSystemCertificates())
          .build());

  // create the session config
  SessionConfig sessionConfig = SessionConfig
    .builder()
    .withFetchSize(1000)
    .withDefaultAccessMode(AccessMode.WRITE)
    .build();

  final StringBuilder resultCollector = new StringBuilder();

  final Session session = driver.session(sessionConfig);

  // run the query as access mode write
  final Transaction tx = driver.session(sessionConfig).beginTransaction();

  // execute the write query and consume the result.
  tx.run(WRITE_QUERY).consume();

  // read the result from the previous write query in a same transaction.
  final List<Record> list = tx.run(READ_QUERY).list();

  // read the result
  for (final Record record : list)
  {
    for (String key : record.keys())
    {
      resultCollector
        .append(key)
        .append(":")
        .append(record.get(key).asNode().toString());
    }
  }

  // commit the transaction and for rollback we can use tx.rollback();
  tx.commit();

  // close the session
  session.close();

  // close the driver.
  driver.close();
}
```

Le query di mutazione esplicita ereditano lo stesso comportamento delle transazioni di mutazione implicite.

Se non si esegue una configurazione di sessione, la transazione viene considerata come una transazione di scrittura per impostazione predefinita.

Per i conflitti, consulta [Risoluzione dei conflitti tramite timeout di attesa di blocco](transactions-neptune.md#transactions-neptune-conflicts).

# Suggerimenti per le interrogazioni OpenCypher
<a name="opencypher-query-hints"></a>

**Importante**  
 [Il suggerimento per le query OpenCypher è disponibile solo a partire dalla versione 1.3.2.0 del motore e successive.](https://docs.aws.amazon.com//neptune/latest/userguide/engine-releases-1.3.2.0.html) 

 In Amazon Neptune, puoi utilizzare la clausola per specificare i suggerimenti di query per `USING` le query OpenCypher. Questi suggerimenti consentono di controllare le strategie di ottimizzazione e valutazione. 

 La sintassi per i suggerimenti di interrogazione è: 

```
USING {scope}:{hint} {value}
```

1.  `{scope}`definisce l'ambito in cui il suggerimento si applica a: o. `Query` `Clause` 

    Un valore di ambito `Query` indica che il suggerimento della query si applica all'intera query (a livello di query). 

    Un valore di ambito `Clause` indica che il suggerimento alla query si applica alla clausola che precede il suggerimento (a livello di clausola). 

1.  `{hint}`è il nome del suggerimento di interrogazione applicato. 

1.  `{value}`è l'argomento per. `{hint}` 

 I valori possono non fare distinzione tra maiuscole e minuscole. 

 Ad esempio, per abilitare la cache del piano di interrogazione per una query: 

```
Using QUERY:PLANCACHE "enabled" 
MATCH (a:Person {firstName: "Erin", lastName: $lastName})
 RETURN a
```

**Nota**  
 **Attualmente, sono supportati i suggerimenti della **query** Query scope **PLANCACHE**, **TIMEOUTMILLISECONDS** e Types. assumeConsistentData** I suggerimenti di interrogazione supportati sono elencati di seguito. 

**Topics**
+ [

# Suggerimento per la cache del piano di query OpenCypher
](opencypher-query-hints-qpc-hint.md)
+ [

# AssumeConsistentDataTypes suggerimento
](opencypher-query-hints-AssumeConsistentDataTypes.md)
+ [

# Suggerimento per il timeout della query OpenCypher
](opencypher-query-hints-timeout-hint.md)

# Suggerimento per la cache del piano di query OpenCypher
<a name="opencypher-query-hints-qpc-hint"></a>

 Il comportamento della cache del piano di query può essere sovrascritto per singola query (parametrizzata o meno) mediante un suggerimento di query a livello di query. `QUERY:PLANCACHE` Deve essere usato con la clausola. `USING` Il suggerimento di interrogazione accetta `enabled` o `disabled` come valore. Per ulteriori informazioni sulla cache del piano di interrogazione, vedere[Cache del piano di query in Amazon Neptune](access-graph-qpc.md). 

```
# Forcing plan to be cached or reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" MATCH(n) RETURN n LIMIT 1"
  
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"enabled\" RETURN \$arg" \
  -d "parameters={\"arg\": 123}"
  
# Forcing plan to be neither cached nor reused
% curl -k https://<endpoint>:<port>/opencypher \
  -d "query=Using QUERY:PLANCACHE \"disabled\" MATCH(n) RETURN n LIMIT 1"
```

# AssumeConsistentDataTypes suggerimento
<a name="opencypher-query-hints-AssumeConsistentDataTypes"></a>

 OpenCypher segue un paradigma in cui le corrispondenze di tipi di dati numerici (ad esempio int, byte, short, long, ecc.) vengono eseguite secondo la semantica di promozione dei tipi. Ad esempio, quando si cercano tutte le proprietà con un valore di input 10 con tipo breve, nella semantica di promozione dei tipi, si troveranno anche le proprietà che hanno 10 come valore lungo. In alcuni casi, il type casting può comportare un sovraccarico e portare a piani di interrogazione meno efficienti di quanto potrebbero essere se non fosse stata eseguita alcuna conversione di tipi. In particolare, nei casi in cui i tipi di dati vengono utilizzati in modo coerente nei dati (ad esempio, se l'età di tutte le persone viene memorizzata come valore lungo), l'esecuzione di promozioni di tipo causa un sovraccarico senza influire sul risultato della query. 

 Per consentire l'ottimizzazione nei casi in cui è noto che i valori dei dati delle proprietà numeriche memorizzati nel database sono di tipo coerente, è possibile utilizzare un suggerimento di interrogazione chiamato `assumeConsistentDataTypes` (con valore`true/false`, per impostazione predefinita). `false` Quando questo suggerimento di interrogazione viene fornito con un valore di`true`, il motore presuppone che gli unici valori delle proprietà siano sempre lunghi o doppi e ignorerà la semantica di promozione dei tipi. I valori numerici specificati nella query sono considerati valori lunghi (per valori non a virgola mobile) e doppi (per valori a virgola mobile). 

 Se i dati utilizzano costantemente un unico tipo di dati (ad esempio tutte le età sono memorizzate come`long`), l'utilizzo del `assumeConsistentDataTypes` hint può ottimizzare la query saltando i controlli di uguaglianza non necessari per diversi tipi numerici. Tuttavia, se i dati hanno tipi di dati non coerenti per la stessa proprietà, l'utilizzo del hint può far sì che alcuni risultati vengano persi, poiché la query corrisponderà solo al singolo tipo di dati assunto dal suggerimento. 

```
# Database loaded with following openCypher CSV's

# File 1
:ID,age:Int
n1,20
n2,25

# File 2
:ID,age:Long
n3,25


# Example (no hint)
MATCH (n:Person) 
WHERE n.age >= 25
RETURN n

# Result
n2
n3

Returns all person whose age is >= 25 and the values >= 25 can be with any of these datatypes
i.e. byte, short, int, long, double or float

-----------------------------------------------------------------------------------

# Example (with hint present)
USING QUERY:assumeConsistentDataTypes "true"
MATCH (n:Person)
WHERE n.age >= 25
RETURN n

# Result
n3

Returns only "n3" and not "n2". The reason is that even though the numerical value
matches (25), the datatype is "int" and is considered a non-match.
```

 La differenza può essere convalidata anche tramite la spiegazione. 

 Senza la spiegazione: 

```
# Query
MATCH (n)
WHERE n.age = 20
RETURN n

# Explain Snippet
╔═════╤══════════╤══════════╤══════════════════════════════╤═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤════════╤════════════╤══════════════╤═════════╤══════════════╗
║ ID │ Out #1 │ Out #2 │ Name                   │ Arguments                                                                                                                            │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠═════╪══════════╪══════════╪══════════════════════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪════════╪════════════╪══════════════╪═════════╪══════════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan (DFX)  │ pattern=Node(?n) with property 'age' as ?n_age2 and label 'ALL'                                                                      │ -    │ 0        │ 1         │ 0.00  │ 0.10      ║
║    │        │        │                        │ inlineFilters=[(?n_age2 IN ["20"^^xsd:byte, "20"^^xsd:int, "20"^^xsd:long, "20"^^xsd:short, "20.0"^^xsd:double, "20.0"^^xsd:float])] │      │          │           │       │           ║
║    │        │        │                        │ patternEstimate=1                                                                                                                    │      │          │           │       │           ║
╟─────┼──────────┼──────────┼──────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────┼──────────────┼─────────┼──────────────╢

# The inFilters field contains all numeric types
```

 Con il suggerimento: 

```
# Query
MATCH (n)
WHERE n.age = 20
RETURN n

# Explain Snippet
╔═════╤══════════╤══════════╤══════════════════════════════╤═════════════════════════════════════════════════════════════════════════════════╤════════╤════════════╤══════════════╤═════════╤══════════════╗
║ ID │ Out #1 │ Out #2 │ Name                   │ Arguments                                                       │ Mode │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠═════╪══════════╪══════════╪══════════════════════════════╪═════════════════════════════════════════════════════════════════════════════════╪════════╪════════════╪══════════════╪═════════╪══════════════╣
║ 0  │ 1      │ -      │ DFEPipelineScan (DFX)  │ pattern=Node(?n) with property 'age' as ?n_age2 and label 'ALL' │ -    │ 0        │ 1         │ 0.00  │ 0.07      ║
║    │        │        │                        │ inlineFilters=[(?n_age2 IN ["20"^^xsd:long])]                   │      │          │           │       │           ║
║    │        │        │                        │ patternEstimate=1                                               │      │          │           │       │           ║
╟─────┼──────────┼──────────┼──────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────┼────────┼────────────┼──────────────┼─────────┼──────────────╢

# The inFilters field only contains long datatype
```

# Suggerimento per il timeout della query OpenCypher
<a name="opencypher-query-hints-timeout-hint"></a>

 Il comportamento di timeout della query può essere configurato in base alla query mediante un suggerimento di interrogazione a livello di query. `QUERY:TIMEOUTMILLISECONDS` Deve essere utilizzato con la clausola. `USING` Il suggerimento di interrogazione accetta un valore long non negativo. 

```
# Using query-level timeout hint 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 100 MATCH(n) RETURN n LIMIT 1"
```

 Il comportamento del timeout della query prenderà in considerazione il timeout minimo a livello di cluster e il timeout a livello di query. Consulta gli esempi seguenti per comprendere il comportamento del timeout delle query. [Per ulteriori informazioni sul timeout delle query a livello di cluster, vedere neptune\$1query\$1timeout.](https://docs.aws.amazon.com/neptune/latest/userguide/parameters.html#parameters-db-cluster-parameters-neptune_query_timeout) 

```
# Suppose `neptune_query_timeout` is 10000 ms and query-level timeout is set to 100 ms
# It will consider 100 ms as the final timeout 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 100 MATCH(n) RETURN n LIMIT 1"

# Suppose `neptune_query_timeout` is 100 ms and query-level timeout is set to 10000 ms
# It will still consider 100 ms as the final timeout 

% curl https://<endpoint>:<port>/opencypher \
  -d "query=USING QUERY:TIMEOUTMILLISECONDS 10000 MATCH(n) RETURN n LIMIT 1"
```

# Restrizioni di Neptune openCypher
<a name="access-graph-opencypher-limitations"></a>

Il rilascio di openCypher di Amazon Neptune non supporta ancora tutto ciò che è specificato in [Cypher Query Language Reference, versione 9](https://s3.amazonaws.com/artifacts.opencypher.org/openCypher9.pdf) come descritto in [Conformità alle specifiche OpenCypher](feature-opencypher-compliance.md). Si prevede che i rilasci futuri risolvano molte di queste limitazioni.

# Eccezioni di Neptune openCypher
<a name="access-graph-opencypher-exceptions"></a>

Quando si usa openCypher in Amazon Neptune, possono verificarsi diverse eccezioni. Di seguito sono elencate le eccezioni più comuni che si possono ricevere dall'endpoint HTTPS o dal driver Bolt (tutte le eccezioni del driver Bolt sono segnalate come eccezioni dello stato del server):


| Codice HTTP | Messaggio di errore | Recuperabile? | Soluzione | 
| --- | --- | --- | --- | 
| 400 | *(errore di sintassi, propagato direttamente dal parser openCypher)* | No | Correggere la sintassi della query, quindi riprovare. | 
| 500 | `Operation terminated (out of memory)` | Sì | Rielaborare la query per aggiungere criteri di filtro aggiuntivi per ridurre la memoria richiesta | 
| 500 | Operazione terminata (scadenza superata) | Sì | Aumentare il timeout della query nel gruppo di parametri del cluster database o [ripetere la richiesta](https://docs.aws.amazon.com/general/latest/gr/api-retries.html). | 
| 500 | Operazione terminata (annullata dall'utente) | Sì | Riprova la richiesta . | 
| 500 | Il ripristino del database è in corso. Riprova a eseguire la query dopo che il cluster diventa disponibile. | Sì | Riprovare quando il ripristino è stato completato. | 
| 500 | Operazione non riuscita a causa di operazioni simultanee in conflitto (riprova). Le transazioni sono attualmente in fase di rollback. | Sì | Riprovare utilizzando una [strategia di backoff esponenziale e ripetizione dei tentativi](best-practices-opencypher-retry-logic.md). | 
| 400 | *(operation name)* operation/feature eccezione non supportata | No | L'operazione specificata non è supportata. | 
| 400 | Tentativo di aggiornamento di openCypher su una replica di sola lettura | No | Cambiare l'endpoint di destinazione con l'endpoint di scrittura. | 
| 400 | MalformedQueryException (Neptune non mostra lo stato interno del parser) | No | Correggere la sintassi della query e riprovare. | 
| 400 | Impossibile eliminare il nodo, perché ha ancora delle relazioni. Per eliminare questo nodo, devi prima eliminare le sue relazioni. | No | Invece di usare `MATCH (n) DELETE n` usare `MATCH(n) DETACH DELETE(n)` | 
| 400 | Operazione non valida: tentativo di rimuovere l'ultima etichetta di un nodo. Un nodo deve avere almeno un'etichetta. | No | Neptune richiede che tutti i nodi abbiano almeno un'etichetta. Se i nodi vengono creati senza un'etichetta esplicita, viene assegnata un'etichetta predefinita `vertex`. Modificate la logica and/or dell'applicazione di interrogazione in modo da non eliminare l'ultima etichetta. L'etichetta singleton di un nodo può essere aggiornata impostando una nuova etichetta e quindi rimuovendo quella vecchia. | 
| 500 | Il numero massimo di richieste è stato violato, ConfiguredQueueCapacity = \$1\$1 per ConnID = \$1\$1 | Sì | Attualmente è possibile elaborare solo 8.192 richieste simultanee, indipendentemente dallo stack e dal protocollo. | 
| 500 | Limite massimo di connessioni violato. | Sì | Sono consentite solo 1.000 connessioni Bolt simultanee per istanza (per HTTP non esiste alcun limite). | 
| 400 | Era previsto uno dei seguenti elementi [nodo, relazione o percorso] ed è stato ottenuto un valore letterale | No | Verificare che siano stati passati gli argomenti corretti, correggere la sintassi della query e riprovare. | 
| 400 | Il valore della proprietà deve essere un valore letterale semplice. Oppure: era prevista una mappa per le proprietà Set ma non ne è stata trovata una. | No | Una clausola SET accetta solo valori letterali semplici, non tipi compositi. | 
| 400 | L'entità passata per l'eliminazione non è stata trovata | No | Verificare che l'entità che si sta cercando di eliminare esista nel database.  | 
| 400 | L'utente non ha accesso al database. | No | Controllare la policy sul ruolo IAM utilizzato. | 
| 400 | Non è stato passato alcun token come parte della richiesta | No | Un token firmato correttamente deve essere passato come parte della richiesta di query su un cluster abilitato per IAM. | 
| 400 | Il messaggio di errore viene propagato. | No | Contatta l' AWS assistenza con l'ID della richiesta. | 
| 500 | Operazione terminata (errore interno) | Sì | Contatta l' AWS assistenza con l'ID della richiesta. | 

# Estensioni OpenCypher in Amazon Neptune
<a name="access-graph-opencypher-extensions"></a>

 Amazon Neptune supporta la versione di riferimento della specifica OpenCypher 9. Per ulteriori informazioni, [Conformità alle specifiche OpenCypher in Amazon Neptune](feature-opencypher-compliance.md) consulta Amazon Neptune. Inoltre, Amazon Neptune supporta le funzionalità elencate qui. A meno che non vengano menzionate versioni specifiche, le funzionalità sono disponibili in Neptune Database e Neptune Analytics. 

## Accesso ai dati Query-time S3
<a name="opencypher-compliance-neptune-read"></a>

Disponibile in Neptune Database 1.4.7.0 e versioni successive.

Neptune supporta `neptune.read()` la funzione per leggere i dati CSV o Parquet da Amazon S3 direttamente all'interno delle query OpenCypher. A differenza del bulk loader che importa i dati prima dell'esecuzione delle query, accede ai dati di `neptune.read()` Amazon S3 al momento dell'esecuzione delle query.

Per la documentazione completa, consulta. [neptune.read ()](access-graph-opencypher-21-extensions-s3-read.md)

## Funzione `join()` specifica di Neptune
<a name="opencypher-compliance-join-function"></a>

Disponibile in Neptune Database e Neptune Analytics.

Neptune implementa una funzione `join()` che non è presente nella specifica openCypher. Crea un valore letterale di stringa da un elenco di valori letterali di stringa e da un delimitatore di stringa. Accetta due argomenti:
+ Il primo argomento è un elenco di valori letterali di stringa.
+ Il secondo argomento è la stringa del delimitatore, che può essere composta da zero, uno o più caratteri.

Esempio:

```
join(["abc", "def", "ghi"], ", ")    // Returns "abc, def, ghi"
```

## Funzione `removeKeyFromMap()` specifica di Neptune
<a name="opencypher-compliance-removeKeyFromMap-function"></a>

Disponibile in Neptune Database e Neptune Analytics.

Neptune implementa una funzione `removeKeyFromMap()` che non è presente nella specifica openCypher. Rimuove una chiave specificata da una mappa e restituisce la nuova mappa risultante.

La funzione accetta due argomenti:
+ Il primo argomento è la mappa da cui rimuovere la chiave.
+ Il primo argomento è la chiave da rimuovere dalla mappa.

La funzione `removeKeyFromMap()` è particolarmente utile in situazioni in cui si desidera impostare valori per un nodo o una relazione utilizzando un elenco di mappe. Esempio:

```
UNWIND [{`~id`: 'id1', name: 'john'}, {`~id`: 'id2', name: 'jim'}] as val
CREATE (n {`~id`: val.`~id`})
SET n = removeKeyFromMap(val, '~id')
```

## Valori ID personalizzati per le proprietà dei nodi e delle relazioni
<a name="opencypher-compliance-custom-ids"></a>

Disponibile in Neptune Database 1.2.0.2 e versioni successive e Neptune Analytics.

A partire dal [rilascio 1.2.0.2 del motore](engine-releases-1.2.0.2.md), Neptune ha esteso la specifica openCypher in modo che ora sia possibile specificare i valori `id` per i nodi e le relazioni nelle clausole `CREATE`, `MERGE` e `MATCH`. Ciò consente di assegnare stringhe intuitive anziché quelle generate dal sistema per identificare nodi e relazioni. UUIDs 

In Neptune Analytics, i valori ID personalizzati non sono disponibili per i bordi.

**avvertimento**  
Questa estensione della specifica openCypher è incompatibile con le versioni precedenti, perché `~id` ora è considerato un nome di proprietà riservato. Se si utilizza già `~id` come proprietà nei dati e nelle query, è necessario migrare la proprietà esistente a una nuova chiave di proprietà e rimuovere quella precedente. Per informazioni, consulta [Cosa fare se attualmente si utilizza `~id` come proprietà](#opencypher-compliance-custom-ids-migrating).

Ecco un esempio che mostra come creare nodi e relazioni con ID personalizzati:

```
CREATE (n {`~id`: 'fromNode', name: 'john'})
  -[:knows {`~id`: 'john-knows->jim', since: 2020}]
  ->(m {`~id`: 'toNode', name: 'jim'})
```

Se si tenta di creare un ID personalizzato già in uso, Neptune genera un errore `DuplicateDataException`.

Ecco un esempio di utilizzo di un ID personalizzato in una clausola `MATCH`:

```
MATCH (n {`~id`: 'id1'})
RETURN n
```

Ecco un esempio di utilizzo di custom IDs in una `MERGE` clausola:

```
MATCH (n {name: 'john'}), (m {name: 'jim'})
MERGE (n)-[r {`~id`: 'john->jim'}]->(m)
RETURN r
```

### Cosa fare se attualmente si utilizza `~id` come proprietà
<a name="opencypher-compliance-custom-ids-migrating"></a>

Con il [rilascio 1.2.0.2 del motore](engine-releases-1.2.0.2.md), la chiave `~id` nelle clausole openCypher viene ora trattata come `id` anziché come proprietà. Ciò significa che se si dispone di una proprietà denominata `~id`, accedervi diventa impossibile.

Se si utilizza una proprietà `~id`, prima di aggiornare il motore al rilascio `1.2.0.2` o superiore è necessario migrare la proprietà `~id` esistente a una nuova chiave di proprietà e quindi rimuovere la proprietà `~id`. Ad esempio, la query seguente:
+ Crea una nuova proprietà denominata 'newId' per tutti i nodi,
+ copia il valore della proprietà '\$1id' nella proprietà 'newId'
+ e rimuove la proprietà '\$1id' dai dati

```
MATCH (n)
WHERE exists(n.`~id`)
SET n.newId = n.`~id`
REMOVE n.`~id`
```

La stessa cosa deve essere fatta per tutte le relazioni nei dati che hanno una proprietà `~id`.

È inoltre necessario modificare tutte le query utilizzate che fanno riferimento a una proprietà `~id`. Ad esempio, questa query:

```
MATCH (n)
WHERE n.`~id` = 'some-value'
RETURN n
```

...verrà modificata in questa:

```
MATCH (n)
WHERE n.newId = 'some-value'
RETURN n
```

## Supporto per subquery CALL in Neptune
<a name="call-subquery-support"></a>

 Disponibile in Neptune Database 1.4.1.0 e versioni successive e Neptune Analytics. 

 Amazon `CALL` Neptune supporta le subquery. Una `CALL` sottoquery è una parte della query principale che viene eseguita in un ambito isolato per ogni input della sottoquery. `CALL` 

 Ad esempio, supponiamo che un grafico contenga dati sulle persone, i loro amici e le città in cui hanno vissuto. Possiamo recuperare le due città più grandi in cui viveva ogni amico di qualcuno utilizzando una `CALL` sottoquery: 

```
MATCH (person:Person)-[:knows]->(friend) 
CALL { 
  WITH friend 
  MATCH (friend)-[:lived_in]->(city) 
  RETURN city 
  ORDER BY city.population DESC
  LIMIT 2 
} 
RETURN person, friend, city
```

 In questo esempio, la parte di interrogazione interna `CALL { ... }` viene eseguita per ognuna di esse `friend` che corrisponde alla clausola MATCH precedente. Quando viene eseguita la query interna, le `LIMIT` clausole `ORDER` and sono locali delle città in cui viveva un determinato amico, quindi otteniamo (al massimo) due città per amico. 

 Tutte le clausole di interrogazione sono disponibili all'interno delle sottoquery. `CALL` Ciò include anche le sottoquery `CALL` annidate. Esistono alcune restrizioni per la prima `WITH` clausola e le variabili emesse e sono spiegate di seguito. 

### Ambito delle variabili all'interno della sottoquery CALL
<a name="variable-scope-inside-call-subquery"></a>

 Le variabili delle clausole precedenti alla `CALL` sottoquery utilizzate al suo interno devono essere importate dalla clausola iniziale. `WITH` A differenza delle `WITH` clausole normali, può contenere solo un elenco di variabili ma non consente l'aliasing e non può essere utilizzata insieme a,,, o. `DISTINCT` `ORDER BY` `WHERE` `SKIP` `LIMIT` 

### Variabili restituite dalla sottoquery CALL
<a name="variables-returned-call-subquery"></a>

 Le variabili emesse dalla `CALL` sottoquery vengono specificate con la clausola finale. `RETURN` Nota che le variabili emesse non possono sovrapporsi alle variabili precedenti alla sottoquery. `CALL` 

### Limitazioni
<a name="call-subquery-limitations"></a>

 Al momento, gli aggiornamenti all'interno di una `CALL` sottoquery non sono supportati. 

## Funzioni OpenCypher di Neptune
<a name="opencypher-compliance-new-functions"></a>

 Disponibile in Neptune Database 1.4.1.0 e versioni successive e Neptune Analytics. 

**textIndexOf**

 `textIndexOf(text :: STRING, lookup :: STRING, from = 0 :: INTEGER?, to = -1 :: INTEGER?) :: (INTEGER?)` 

 Restituisce l'indice della prima occorrenza `lookup` nell'intervallo compreso tra offset `from` (incluso) e offset (esclusivo). `text` `to` Se `to` è -1, l'intervallo continua fino alla fine di. `text` L'indicizzazione è a base zero ed è espressa in valori scalari Unicode (punti di codice non surrogati). 

```
RETURN textIndexOf('Amazon Neptune', 'e')
{
  "results": [{
      "textIndexOf('Amazon Neptune', 'e')": 8
    }]
}
```

**collToSet**

 `collToSet(values :: LIST OF ANY?) :: (LIST? OF ANY?)` 

 Restituisce un nuovo elenco contenente solo gli elementi unici dell'elenco originale. L'ordine dell'elenco originale viene **mantenuto** (ad esempio `[1, 6, 5, 1, 5]` ritorni`[1, 6, 5]`). 

```
RETURN collToSet([1, 6, 5, 1, 1, 5])
{
  "results": [{
      "collToSet([1, 6, 5, 1, 1, 5])": [1, 6, 5]
    }]
}
```

**CollSubtract**

 `collSubtract(first :: LIST OF ANY?, second :: LIST OF ANY?) :: (LIST? OF ANY?)` 

 Restituisce un nuovo elenco contenente tutti gli elementi unici da cui sono `first` esclusi gli elementi. `second` 

```
RETURN collSubtract([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collSubtract([2, 5, 1, 0], [1, 5])": [0, 2]
    }]
}
```

**CollInterSection**

 `collIntersection(first :: LIST? OF ANY?, second :: LIST? OF ANY?) :: (LIST? OF ANY?)` 

 Restituisce un nuovo elenco contenente tutti gli elementi unici dell'intersezione di e. `first` `second` 

```
RETURN collIntersection([2, 5, 1, 0], [1, 5])
{
  "results": [{
      "collIntersection([2, 5, 1, 0], [1, 5])": [1, 5]
    }]
}
```

## Funzioni di ordinamento
<a name="sorting-functions"></a>

 Le seguenti sezioni definiscono le funzioni per ordinare le raccolte. Queste funzioni accettano (in alcuni casi opzionali) argomenti di `config` mappa, o un elenco di più mappe di questo tipo, che definiscono la chiave di ordinamento, and/or la direzione di ordinamento: 

```
{ key: STRING, order: STRING }
```

 `key`Ecco una proprietà della mappa o del nodo il cui valore deve essere usato per l'ordinamento. `order`è "" o "`asc``desc`" (senza distinzione tra maiuscole e minuscole) per specificare rispettivamente un ordinamento crescente o decrescente. Per impostazione predefinita, l'ordinamento verrà eseguito in ordine crescente. 

**CollSort**

 `collSort(coll :: LIST OF ANY, config :: MAP?) :: (LIST? OF ANY?)` 

 Restituisce un nuovo elenco ordinato contenente gli elementi dell'elenco `coll` di input. 

```
RETURN collSort([5, 3, 1], {order: 'asc'})
{
  "results": [{
      "collSort([5, 3, 1])": [1, 3, 5]
    }]
}
```

**collSortMaps**

 `collSortMaps(coll :: LIST OF MAP, config :: MAP) :: (LIST? OF ANY?)` 

 Restituisce un elenco di mappe ordinate in base al valore della proprietà specificata`key`. 

```
RETURN collSortMaps([{name: 'Alice', age: 25}, {name: 'Bob', age: 35}, {name: 'Charlie', age: 18}], {key: 'age', order: 'desc'})
{
  "results": [{
      "x": [{
          "age": 35,
          "name": "Bob"
        }, {
          "age": 25,
          "name": "Alice"
        }, {
          "age": 18,
          "name": "Charlie"
        }]
    }]
}
```

**collSortMulti**

```
collSortMulti(coll :: LIST OF MAP?, 
configs = [] :: LIST OF MAP, 
limit = -1 :: INTEGER?, 
skip = 0 :: INTEGER?) :: (LIST? OF ANY?)
```

 Restituisce un elenco di mappe ordinate in base al valore delle `key` proprietà specificate, applicando facoltativamente limit e skip. 

```
RETURN collSortMulti([{name: 'Alice', age: 25}, {name: 'Bob', age: 35}, {name: 'Charlie', age: 18}], [{key: 'age', order: 'desc'}, {key:'name'}]) as x
{
  "results": [{
      "x": [{
          "age": 35,
          "name": "Bob"
        }, {
          "age": 25,
          "name": "Alice"
        }, {
          "age": 18,
          "name": "Charlie"
        }]
    }]
}
```

**collSortNodes**

 `collSortNodes(coll :: LIST OF NODE, config :: MAP) :: (LIST? OF NODE?)` 

 Restituisce una versione ordinata dell'elenco di `coll` input, ordinando gli elementi del nodo in base ai valori delle rispettive proprietà. `key` 

```
create (n:person {name: 'Alice', age: 23}), (m:person {name: 'Eve', age: 21}), (o:person {name:'Bob', age:25})
{"results":[]}

match (n:person) with collect(n) as people return collSortNodes(people, {key: 'name', order: 'desc'})
{
  "results": [{
      "collSortNodes(people, 'name')": [{
          "~id": "e599240a-8c23-4337-8aa8-f603c8fb5488",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 21,
            "name": "Eve"
          }
        }, {
          "~id": "8a6ef785-59e3-4a0b-a0ff-389655a9c4e6",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 25,
            "name": "Bob"
          }
        }, {
          "~id": "466bc826-f47f-452c-8a27-6b7bdf7ae9b4",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 23,
            "name": "Alice"
          }
        }]
    }]
}

match (n:person) with collect(n) as people return collSortNodes(people, {key: 'age'})
{
  "results": [{
      "collSortNodes(people, '^age')": [{
          "~id": "e599240a-8c23-4337-8aa8-f603c8fb5488",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 21,
            "name": "Eve"
          }
        }, {
          "~id": "466bc826-f47f-452c-8a27-6b7bdf7ae9b4",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 23,
            "name": "Alice"
          }
        }, {
          "~id": "8a6ef785-59e3-4a0b-a0ff-389655a9c4e6",
          "~entityType": "node",
          "~labels": ["person"],
          "~properties": {
            "age": 25,
            "name": "Bob"
          }
        }]
    }]
}
```

## Funzioni temporali
<a name="temporal-functions"></a>

 [Le funzioni temporali sono disponibili a partire dalla versione 1.4.5.0 di Neptune.](https://docs.aws.amazon.com/releases/release-1.4.5.0.xml) 

### giorno
<a name="temporal-functions-day"></a>

 `day(temporal :: (datetime | date)) :: (LONG)` 

 Restituisce il numero `day` del mese da un valore or. `datetime` `date` Per`datetime`: i valori vengono normalizzati in UTC in base all'input prima dell'estrazione del giorno. Per`date`: il giorno viene estratto in base al fuso orario. 

 L'`datetime`input è disponibile sia in Neptune Database che in Neptune Analytics: 

```
RETURN day(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "day(datetime('2021-06-03T01:48:14Z'))": 3
    }]
}
```

 Qui, `datetime` è normalizzato all'UTC, quindi \$1 08:00 torna al 2 giugno. 

```
RETURN day(datetime('2021-06-03T00:00:00+08:00'))
{
  "results": [{
      "day(datetime('2021-06-03T00:00:00+08:00'))": 2
    }]
}
```

 L'`date`input è disponibile solo in Neptune Analytics: 

```
RETURN day(date('2021-06-03Z'))
{
  "results": [{
      "day(date('2021-06-03Z'))": 3
    }]
}
```

 Il fuso orario di `date` Preserve, mantiene il 3 giugno. 

```
RETURN day(date('2021-06-03+08:00'))
{
  "results": [{
      "day(date('2021-06-03+08:00'))": 3
    }]
}
```

### mese
<a name="temporal-functions-month"></a>

 `month(temporal :: (datetime | date)) :: (LONG)` 

 Restituisce il mese a partire da un `date` valore `datetime` or (1-12). Per`datetime`: i valori vengono normalizzati in UTC in base all'input prima dell'estrazione del mese. Per`date`: il mese viene estratto in base al fuso orario. 

 L'`datetime`input è disponibile sia in Neptune Database che in Neptune Analytics: 

```
RETURN month(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "month(datetime('2021-06-03T01:48:14Z'))": 6
    }]
}
```

 Qui, `datetime` è normalizzato all'UTC, quindi \$1 08:00 torna al 31 maggio. 

```
RETURN month(datetime('2021-06-01T00:00:00+08:00'))
{
  "results": [{
      "month(datetime('2021-06-01T00:00:00+08:00'))": 5
    }]
}
```

 L'`date`input è disponibile solo in Neptune Analytics: 

```
RETURN month(date('2021-06-03Z'))
{
  "results": [{
      "month(date('2021-06-03Z'))": 6
    }]
}
```

 Il fuso orario di `date` Preserve, mantiene il 1° giugno. 

```
RETURN month(date('2021-06-01+08:00'))
{
  "results": [{
      "month(date('2021-06-01+08:00'))": 6
    }]
}
```

### anno
<a name="temporal-functions-year"></a>

 `year(temporal :: (datetime | date)) :: (LONG)` 

 Restituisce l'anno da un `datetime` valore or. `date` Per`datetime`: i valori vengono normalizzati in UTC in base all'input prima dell'estrazione dell'anno. Per`date`: l'anno viene estratto in base al fuso orario. 

 L'`datetime`input è disponibile sia in Neptune Database che in Neptune Analytics: 

```
RETURN year(datetime('2021-06-03T01:48:14Z'))
{
  "results": [{
      "year(datetime('2021-06-03T01:48:14Z'))": 2021
    }]
}
```

 Qui, `datetime` è normalizzato in UTC, quindi \$1 08:00 torna al 31 dicembre 2020. 

```
RETURN year(datetime('2021-01-01T00:00:00+08:00'))
{
  "results": [{
      "year(datetime('2021-01-01T00:00:00+08:00'))": 2020
    }]
}
```

 L'`date`input è disponibile solo in Neptune Analytics: 

```
RETURN year(date('2021-06-03Z'))
{
  "results": [{
      "year(date('2021-06-03Z'))": 2021
    }]
}
```

 Il fuso orario di `date` Preserve, mantenuto nel mese di giugno 2021. 

```
RETURN year(date('2021-01-01+08:00'))
{
  "results": [{
      "year(date('2021-01-01+08:00'))": 2021
    }]
}
```

### Funzioni OpenCypher di Neptune
<a name="openCypher-functions"></a>

 Disponibile in Neptune Database 1.4.6.0 e versioni successive e Neptune Analytics. 

#### ridurre ()
<a name="openCypher-functions-reduce"></a>

 Reduce elabora in sequenza ogni elemento dell'elenco combinandolo con un totale corrente o «accumulatore». A partire da un valore iniziale, aggiorna l'accumulatore dopo ogni operazione e utilizza quel valore aggiornato nell'iterazione successiva. 

 `for i in (0, ..., n) acc = acc X list[I], where X denotes any binary operator` 

 Una volta che tutti gli elementi sono stati elaborati, restituisce il risultato finale accumulato. 

 Una tipica struttura reduce () sarebbe - `reduce(accumulator = initial , variable IN list | expression)` 

**Specifiche del tipo:**  
 `- initial: starting value for the accumulator :: (Long | FLOAT | STRING | LIST? OF (STRING, LONG, FLOAT)) - list: the input list :: LIST OF T where T matches initial type - variable :: represents each element in the input list - expression :: Only supports '+' and '*' operator - return :: Same type as initial ` 

**Limitazioni:**  
 Attualmente, l'`reduce()`espressione supporta solo: 
+  Moltiplicazione numerica 
+  Addizione numerica 
+  Concatenamento di stringhe 
+  Concatenazione di elenchi 

 Sono rappresentati dall'operatore or. `+` `*` L'espressione deve essere un'espressione binaria come specificato di seguito - `expression pattern: accumulator + any variable or accumulator * any variable` 

**Gestione dell'overflow:**  
 Neptune rileva l'overflow numerico durante la valutazione e risponde in modo diverso in `reduce()` base al tipo di dati: 

```
LONG (signed 64‑bit)
--------------------
• Valid range: –9 223 372 036 854 775 808 … 9 223 372 036 854 775 807  
• If any intermediate or final value falls outside this range,
  Neptune aborts the query with long overflow error message.
  
FLOAT (IEEE‑754 double)
-----------------------
• Largest finite value ≈ 1.79 × 10^308  
• Larger results overflow to INF
  Once `INF` is produced, it propagates through the remainder
  of the reduction.
```

**Esempi:**  
Vedi i seguenti esempi per la funzione reduce ().

```
1. Long Addition:
RETURN reduce(sum = 0, n IN [1, 2, 3] | sum + n)
{
  "results": [{
      "reduce(sum = 0, n IN [1, 2, 3] | sum + n)": 6
    }]
}

2. String Concatenation:
RETURN reduce(str = "", x IN ["A", "B", "C"] | str + x) 
{
  "results": [{
      "reduce(str = "", x IN ["A", "B", "C"] | str + x)": "ABC"
    }]
}

3. List Combination:
RETURN reduce(lst = [], x IN [1, 2, 3] | lst + x)
{
  "results": [{
      "reduce(lst = [], x IN [1, 2, 3] | lst + x)": [1, 2, 3]
    }]
}

4. Float Addition:
RETURN reduce(total = 0.0, x IN [1.5, 2.5, 3.5] | total + x) 
{
  "results": [{
      "reduce(total = 0.0, x IN [1.5, 2.5, 3.5] | total + x)": 7.5
    }]
}

5. Long Multiplication:
RETURN reduce(product = 1, n IN [1, 2, 3] | product * n)
{
  "results": [{
      "reduce(product = 0, n IN [1, 2, 3] | product * n)": 6
    }]
}

6. Float Multiplication:
RETURN reduce(product = 1.0, n IN [1.5, 2.5, 3.5] | product * n)
{
  "results": [{
      "reduce(product = 1.0, n IN [1.5, 2.5, 3.5] | product * n)": 13.125
    }]
}

7. Long Overflow (Exception):
RETURN reduce(s = 9223372036854775807, x IN [2, 3] | s * x) AS result
{
"results": [{
    "reduce(s = 9223372036854775807, x IN [2, 3] | s * x) AS result": long overflow
    }]
}

8. Float Overflow:
RETURN reduce(s = 9.0e307, x IN [8.0e307, 1.0e307] | s + x) AS result
{
"results": [{
    "reduce(s = 9.0e307, x IN [8.0e307, 1.0e307] | s + x) AS result": INF
    }]
}
```

# neptune.read ()
<a name="access-graph-opencypher-21-extensions-s3-read"></a>

 Neptune supporta `CALL` una `neptune.read` procedura per leggere i dati da Amazon S3 e quindi eseguire una query OpenCypher (lettura, inserimento, aggiornamento) utilizzando i dati. La procedura restituisce ogni riga del file come riga di variabile di risultato dichiarata. Utilizza le credenziali IAM del chiamante per accedere ai dati in Amazon S3. Vedi [Gestione delle autorizzazioni per neptune.read ()](access-graph-opencypher-21-extensions-s3-read-permissions.md) per configurare le autorizzazioni. La AWS regione del bucket Amazon S3 deve trovarsi nella stessa regione in cui si trova l'istanza. Attualmente, le letture tra regioni non sono supportate. 

 **Sintassi** 

```
CALL neptune.read(
  {
    source: "string",
    format: "parquet/csv",
    concurrency: 10
  }
)
YIELD row
...
```

**Input**
+  **source** (obbligatorio): URI Amazon S3 per un **singolo** oggetto. Il prefisso Amazon S3 per più oggetti non è supportato. 
+  **formato** (obbligatorio) - `parquet` e `csv` sono supportati. 
  +  Maggiori dettagli sul formato Parquet supportato sono disponibili in[Tipi di colonne Parquet supportati](access-graph-opencypher-21-extensions-s3-read-parquet.md#access-graph-opencypher-21-extensions-s3-read-parquet-column-types). 
  +  Per ulteriori informazioni sul formato csv supportato, consulta[Formato di caricamento dei dati openCypher](bulk-load-tutorial-format-opencypher.md). 
+  **concurrency** (opzionale): digitare un numero intero pari o superiore a 0. Impostazione predefinita: 0. Speciifica il numero di thread da utilizzare per leggere il file. Se il valore è 0, verrà utilizzato il numero massimo di thread consentito dalla risorsa. Per Parquet, si consiglia di impostare un numero di gruppi di righe. 

**Output**

 Il neptune.read restituisce: 
+  **riga** - Tipo:map 
  +  Ogni riga del file, dove le chiavi sono le colonne e i valori sono i dati trovati in ogni colonna. 
  +  Puoi accedere ai dati di ogni colonna come una proprietà access (`row.col`). 

## Le migliori pratiche per neptune.read ()
<a name="access-graph-opencypher-21-extensions-s3-read-best-practices"></a>

Le operazioni di lettura di Neptune S3 possono richiedere molta memoria. Utilizza tipi di istanze adatti ai carichi di lavoro di produzione, come indicato in [Scelta dei tipi di istanze per Amazon Neptune](instance-types.md).

L'utilizzo della memoria e le prestazioni delle `neptune.read()` richieste sono influenzati da una serie di fattori come la dimensione del file, il numero di colonne, il numero di righe e il formato del file. A seconda della struttura, i file di piccole dimensioni (ad esempio, file CSV di dimensioni pari o inferiori a 100 MB, file Parquet di dimensioni pari o inferiori a 20 MB) possono funzionare in modo affidabile sulla maggior parte dei tipi di istanze adatti alla produzione, mentre i file più grandi possono richiedere una notevole quantità di memoria che i tipi di istanze più piccoli non sono in grado di fornire.

Durante il test di questa funzionalità, si consiglia di iniziare con file di piccole dimensioni e di ridimensionarla gradualmente per garantire che il carico di lavoro di lettura possa essere adattato alle dimensioni dell'istanza. Se notate che `neptune.read()` le richieste portano a out-of-memory eccezioni o al riavvio dell'istanza, prendete in considerazione la possibilità di suddividere i file in blocchi più piccoli, ridurre la complessità dei file o passare a tipi di istanze più grandi.

# Esempi di query che utilizzano il parquet
<a name="access-graph-opencypher-21-extensions-s3-read-parquet"></a>

La seguente query di esempio restituisce il numero di righe in un determinato file Parquet:

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
RETURN count(row)
```

È possibile eseguire l'esempio di query utilizzando l'`execute-open-cypher-query`operazione in AWS CLI eseguendo il codice seguente:

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'parquet'}) YIELD row RETURN count(row)" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

Una query può essere flessibile nelle operazioni eseguite con le righe lette da un file Parquet. Ad esempio, la seguente query crea un nodo con un campo impostato sui dati trovati nel file Parquet:

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "parquet"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**avvertimento**  
Non è considerata buona prassi utilizzare una clausola di grandi dimensioni che produca risultati come quella `MATCH(n)` precedente a una clausola. `CALL` Ciò comporterebbe una query di lunga durata, dovuta al prodotto incrociato tra le soluzioni in entrata delle clausole precedenti e le righe lette da neptune.read. Si consiglia di avviare la query con neptune.read. `CALL`

## Tipi di colonne Parquet supportati
<a name="access-graph-opencypher-21-extensions-s3-read-parquet-column-types"></a>

**Tipi di dati Parquet:**
+ NULL
+ BOOLEAN
+ FLOAT
+ DOUBLE
+ STRING
+ NUMERO INTERO CON SEGNO: UINT8, UINT16, UINT32 UINT64
+ MAP: supporta solo un livello. Non supporta nidificato.
+ LIST: supporta solo un livello. Non supporta nidificato.

**Tipi di dati specifici per Neptune:**

A differenza delle intestazioni delle colonne delle proprietà del formato CSV, le intestazioni delle colonne delle proprietà del formato Parquet devono avere solo i nomi delle proprietà, quindi non è necessario avere i nomi dei tipi né la cardinalità.

Esistono tuttavia alcuni tipi di colonna speciali nel formato Parquet che richiedono l'annotazione nei metadati, tra cui il tipo Any, il tipo Date, il tipo DateTime e il tipo Geometry. L'oggetto seguente è un esempio dell'annotazione dei metadati richiesta per i file contenenti colonne di questi tipi speciali:

```
"metadata": {
    "anyTypeColumns": ["UserCol1"],
    "dateTypeColumns": ["UserCol2"],
    "dateTimeTypeColumns": ["UserCol3"],
    "geometryTypeColumns": ["UserCol4"]
}
```

Di seguito sono riportati i dettagli sul payload previsto associato a questi tipi:
+ Nelle colonne utente è supportato un tipo di colonna Any. Un tipo Any è un tipo «zucchero sintattico» per tutti gli altri tipi che supportiamo. È estremamente utile se una colonna utente contiene più tipi. Il payload di un valore Any type è un elenco di stringhe json come segue:`{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`, che ha un campo di valore e un campo di tipo in ogni singola stringa json. Il valore di cardinalità di una colonna Any è impostato, il che significa che la colonna può accettare più valori. 
  + Neptune supporta i seguenti tipi in qualsiasi tipo: Bool (o Boolean), Byte, Short, Int, Long,,,, Float, Double, Date UnsignedByte UnsignedShort UnsignedInt, UnsignedLong DateTime, String e Geometry.
  + Il tipo vettoriale non è supportato in nessun tipo.
  + Nidato Qualsiasi tipo non è supportato. Ad esempio, `{"value": {"value": "10", "type": "Int"}, "type": "Any"}`.
+ Le colonne di tipo Date e DateTime sono supportate nelle colonne utente. Il payload di queste colonne deve essere fornito come stringhe secondo il formato XSD o uno dei formati seguenti: 
  + yyyy-MM-dd
  + YYYY-MM-DTHH:mm
  + aaaa-mm-ggh: mm: ss
  + aaaa-mm-ggH:mm:ssz
  + aaaa-mm-ggH:mm:ss.ssz
  + aaaa-MM-GGTHH:mm:ss [\$1\$1-] hhmm
  + YYYY-MM-GGTHH:mm:ss.sss [\$1\$1-] hhmm
+ Nelle colonne utente è supportato un tipo di colonna Geometry. Il payload di queste colonne deve contenere solo primitive Geometry di tipo Point, fornite come stringhe nel formato Wekonful text (WKT). Ad esempio, POINT (30 10) sarebbe un valore Geometry valido.

## Esempio di output del parquet
<a name="sample-parquet-output"></a>

Dato un file Parquet come questo:

```
<s3 path>

Parquet Type:
    int8     int16       int32             int64              float      double    string
+--------+---------+-------------+----------------------+------------+------------+----------+
|   Byte |   Short |       Int   |                Long  |     Float  |    Double  | String   |
|--------+---------+-------------+----------------------+------------+------------+----------|
|   -128 |  -32768 | -2147483648 | -9223372036854775808 |    1.23456 |    1.23457 | first    |
|    127 |   32767 |  2147483647 |  9223372036854775807 |  nan       |  nan       | second   |
|      0 |       0 |           0 |                    0 | -inf       | -inf       | third    |
|      0 |       0 |           0 |                    0 |  inf       |  inf       | fourth   |
+--------+---------+-------------+----------------------+------------+------------+----------+
```

Ecco un esempio dell'output restituito da neptune.read utilizzando la seguente query:

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'parquet'}) YIELD row RETURN row" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

```
{
 "results": [{
 "row": {
 "Float": 1.23456,
 "Byte": -128,
 "Int": -2147483648,
 "Long": -9223372036854775808,
 "String": "first",
 "Short": -32768,
 "Double": 1.2345678899999999
 }
 }, {
 "row": {
 "Float": "NaN",
 "Byte": 127,
 "Int": 2147483647,
 "Long": 9223372036854775807,
 "String": "second",
 "Short": 32767,
 "Double": "NaN"
 }
 }, {
 "row": {
 "Float": "-INF",
 "Byte": 0,
 "Int": 0,
 "Long": 0,
 "String": "third",
 "Short": 0,
 "Double": "-INF"
 }
 }, {
 "row": {
 "Float": "INF",
 "Byte": 0,
 "Int": 0,
 "Long": 0,
 "String": "fourth",
 "Short": 0,
 "Double": "INF"
 }
 }]
}
```

Attualmente, non è possibile impostare un'etichetta di nodo o di spigolo su un campo di dati proveniente da un file Parquet. Si consiglia di suddividere le interrogazioni in più interrogazioni, una per ogni etichetta/tipo.

```
CALL neptune.read({source: '<s3 path>', format: 'parquet'})
 YIELD row 
WHERE row.`~label` = 'airport'
CREATE (n:airport)

CALL neptune.read({source: '<s3 path>', format: 'parquet'})
YIELD row 
WHERE row.`~label` = 'country'
CREATE (n:country)
```

# Esempi di query utilizzando CSV
<a name="access-graph-opencypher-21-extensions-s3-read-csv"></a>

In questo esempio, la query restituisce il numero di righe in un determinato file CSV:

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
RETURN count(row)
```

È possibile eseguire l'esempio di query utilizzando l' execute-open-cypher-queryoperazione in AWS CLI eseguendo il codice seguente:

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'csv'}) YIELD row RETURN count(row)" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

Una query può essere flessibile nelle operazioni eseguite con le righe lette da un file CSV. Ad esempio, la seguente query crea un nodo con un campo impostato sui dati di un file CSV:

```
CALL neptune.read(
  {
    source: "<s3 path>",
    format: "csv"
  }
)
YIELD row
CREATE (n {someField: row.someCol}) 
RETURN n
```

**avvertimento**  
Non è considerata buona prassi utilizzare una clausola di grandi dimensioni che produca risultati come MATCH (n) prima di una clausola CALL. Ciò comporterebbe una query di lunga durata a causa del prodotto incrociato tra le soluzioni in entrata delle clausole precedenti e le righe lette da neptune.read. Si consiglia di avviare la query con CALL neptune.read.

## Intestazioni di colonna di proprietà
<a name="property-column-headers"></a>

È possibile specificare una colonna (`:`) per una proprietà utilizzando la sintassi seguente. Per i nomi dei tipi non viene fatta distinzione tra maiuscole e minuscole. Se all'interno del nome di una proprietà sono presenti due punti, è necessario evitarlo facendola precedere da una barra rovesciata:. `\:`

```
propertyname:type
```

**Nota**  
Lo spazio, la virgola, i caratteri di ritorno e di nuova riga non sono consentiti nelle intestazioni delle colonne, quindi i nomi delle proprietà non possono includere questi caratteri.
È possibile specificare una colonna per un tipo di matrice aggiungendo `[]` al tipo:  

  ```
                          propertyname:type[]
  ```
Le proprietà edge possono avere solo un singolo valore e verrà generato un errore se viene specificato un tipo di array o un secondo valore. L'esempio seguente mostra l'intestazione di colonna per una proprietà denominata age di tipo Int:  

  ```
  age:Int
  ```

Ogni riga del file dovrà avere un valore intero in quella posizione o essere lasciata vuota. Le matrici di stringhe sono consentite, ma le stringhe di un array non possono includere il carattere punto e virgola (`;`) a meno che non venga eliminato utilizzando una barra rovesciata (). `\;`

## Tipi di colonne CSV supportati
<a name="supported-csv-column-types"></a>
+ **BOOL (o BOOLEAN)** - Valori consentiti: true, false. Indica un campo Booleano. Qualsiasi valore diverso da true verrà considerato falso.
+ **FLOAT** - Intervallo: virgola mobile IEEE 754 a 32 bit, inclusi Infinity, INF, -Infinity, -INF e NaN (). not-a-number
+ **DOUBLE** - Intervallo: virgola mobile IEEE 754 a 64 bit, inclusi Infinity, INF, -Infinity, -INF e NaN (). not-a-number
+ **STRINGA -** 
  + Le virgolette sono facoltative. I caratteri restituiti da virgole, newline e carriage vengono automaticamente eliminati se sono inclusi in una stringa racchiusa tra virgolette doppie («). Esempio: «Hello, World».
  + Per includere le virgolette in una stringa tra virgolette, puoi evitare le virgolette usandone due di seguito: Esempio: «Hello «" World" "».
  + Le matrici di stringhe sono consentite, ma le stringhe di una matrice non possono includere il carattere punto e virgola (;) a meno che non venga eliminato utilizzando una barra rovesciata (\$1;).
  + Se desideri racchiudere le stringhe in una matrice con le virgolette, devi racchiudere l'intera matrice con una serie di virgolette. Esempio: «String one; String 2; String 3".
+ **DATE, DATETIME** - I valori datetime possono essere forniti nel formato XSD o in uno dei seguenti formati: 
  + yyyy-MM-dd
  + YYYY-MM-DTHH:mm
  + aaaa-mm-ggh: mm: ss
  + aaaa-mm-ggH:mm:ssz
  + aaaa-mm-ggH:mm:ss.ssz
  + aaaa-MM-GGTHH:mm:ss [\$1\$1-] hhmm
  + YYYY-MM-GGTHH:mm:ss.sss [\$1\$1-] hhmm
+ **NUMERO INTERO CON SEGNO -** 
  + Byte: da -128 a 127
  + Breve: da -32768 a 32767
  + Int: da -2^31 a 2^31-1
  + Lungo: da -2^63 a 2^63-1

**Tipi di colonne specifici per Nettuno:**
+ Un tipo di colonna Any è supportato nelle colonne utente. Un tipo Any è un tipo «zucchero sintattico» per tutti gli altri tipi che supportiamo. È estremamente utile se una colonna utente contiene più tipi. Il payload di un valore Any type è un elenco di stringhe json come segue:`{"value": "10", "type": "Int"};{"value": "1.0", "type": "Float"}`, che ha un campo di valore e un campo di tipo in ogni singola stringa json. L'intestazione di colonna di un tipo Any è PropertyName:Any. Il valore di cardinalità di una colonna Any è impostato, il che significa che la colonna può accettare più valori. 
  + Neptune supporta i seguenti tipi in qualsiasi tipo: Bool (o Boolean), Byte, Short, Int, Long,,,, Float, Double, Date UnsignedByte UnsignedShort UnsignedInt, UnsignedLong DateTime, String e Geometry.
  + Il tipo vettoriale non è supportato in nessun tipo.
  + Nidato Qualsiasi tipo non è supportato. Ad esempio, `{"value": {"value": "10", "type": "Int"}, "type": "Any"}`.
+ Nelle colonne utente è supportato un tipo di colonna Geometry. Il payload di queste colonne deve contenere solo primitive Geometry di tipo Point, fornite come stringhe nel formato Wekonful text (WKT). Ad esempio, POINT (30 10) sarebbe un valore Geometry valido.

## Esempio di output CSV
<a name="sample-csv-output"></a>

Dato il seguente file CSV:

```
<s3 path>
colA:byte,colB:short,colC:int,colD:long,colE:float,colF:double,colG:string
-128,-32768,-2147483648,-9223372036854775808,1.23456,1.23457,first
127,32767,2147483647,9223372036854775807,nan,nan,second
0,0,0,0,-inf,-inf,third
0,0,0,0,inf,inf,fourth
```

Questo esempio mostra l'output restituito da neptune.read utilizzando la seguente query:

```
aws neptunedata execute-open-cypher-query \
--open-cypher-query "CALL neptune.read({source: '<s3 path>', format: 'csv'}) YIELD row RETURN row" \
--endpoint-url https://my-cluster-name.cluster-abcdefgh1234.us-east-1.neptune.amazonaws.com:8182
```

```
{
  "results": [{
      "row": {
        "colD": -9223372036854775808,
        "colC": -2147483648,
        "colE": 1.23456,
        "colB": -32768,
        "colF": 1.2345699999999999,
        "colG": "first",
        "colA": -128
      }
    }, {
      "row": {
        "colD": 9223372036854775807,
        "colC": 2147483647,
        "colE": "NaN",
        "colB": 32767,
        "colF": "NaN",
        "colG": "second",
        "colA": 127
      }
    }, {
      "row": {
        "colD": 0,
        "colC": 0,
        "colE": "-INF",
        "colB": 0,
        "colF": "-INF",
        "colG": "third",
        "colA": 0
      }
    }, {
      "row": {
        "colD": 0,
        "colC": 0,
        "colE": "INF",
        "colB": 0,
        "colF": "INF",
        "colG": "fourth",
        "colA": 0
      }
    }]
}
```

Attualmente, non è possibile impostare un'etichetta di nodo o di bordo su un campo di dati proveniente da un file CSV. Si consiglia di suddividere le interrogazioni in più interrogazioni, una per ogni etichetta/tipo.

```
CALL neptune.read({source: '<s3 path>', format: 'csv'})
 YIELD row 
WHERE row.`~label` = 'airport'
CREATE (n:airport)

CALL neptune.read({source: '<s3 path>', format: 'csv'})
YIELD row 
WHERE row.`~label` = 'country'
CREATE (n:country)
```

# Gestione delle autorizzazioni per neptune.read ()
<a name="access-graph-opencypher-21-extensions-s3-read-permissions"></a>

## Politiche IAM richieste
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-iam"></a>

Per eseguire le query OpenCypher che utilizzano`neptune.read()`, è necessario disporre delle autorizzazioni appropriate per accedere ai dati nel database Neptune. Le `ReadDataViaQuery` interrogazioni di sola lettura richiedono l'azione. Le interrogazioni che modificano i dati richiedono l'inserimento o `WriteDataViaQuery` l'eliminazione. `DeleteDataViaQuery` L'esempio seguente concede tutte e tre le azioni sul cluster specificato.

Inoltre, sono necessarie le autorizzazioni per accedere al bucket S3 contenente i file di dati. L'informativa sulla politica di Neptunes3Access concede le autorizzazioni S3 richieste:
+ **`s3:ListBucket`**: necessario per verificare l'esistenza del bucket e il contenuto dell'elenco.
+ **`s3:GetObject`**: necessario per accedere all'oggetto specificato in modo che il suo contenuto possa essere letto per l'integrazione nelle query OpenCypher.

Se il tuo bucket S3 utilizza la crittografia lato server con, devi anche concedere le autorizzazioni KMS. AWS KMS L'KMSAccess informativa sulla politica di Neptunes3 consente a Neptune di decrittografare i dati e generare chiavi dati quando si accede a oggetti S3 crittografati. La condizione limita le operazioni KMS alle richieste provenienti dai servizi S3 e RDS nella tua regione.
+ **`kms:Decrypt`**: necessario per eseguire la decrittografia dell'oggetto crittografato in modo che i relativi dati possano essere letti da Neptune.
+ **`kms:GenerateDataKey`**: Richiesto anche dall'API S3 utilizzata per recuperare gli oggetti da leggere.

```
{
  "Sid": "NeptuneQueryAccess",
  "Effect": "Allow",
  "Action": [
      "neptune-db:ReadDataViaQuery",
      "neptune-db:WriteDataViaQuery",
      "neptune-db:DeleteDataViaQuery"
  ],
  "Resource": "arn:aws:neptune-db:<REGION>:<AWS_ACCOUNT_ID>:<CLUSTER_RESOURCE_ID>/*"
},
{
  "Sid": "NeptuneS3Access",
  "Effect": "Allow",
  "Action": [
      "s3:ListBucket",
      "s3:GetObject"
  ],
  "Resource": [
      "arn:aws:s3:::neptune-read-bucket",
      "arn:aws:s3:::neptune-read-bucket/*"
  ]
},
{
  "Sid": "NeptuneS3KMSAccess",
  "Effect": "Allow",
  "Action": [
      "kms:Decrypt",
      "kms:GenerateDataKey"
  ],
  "Resource": "arn:aws:kms:<REGION>:<AWS_ACCOUNT_ID>:key/<KEY_ID>",
  "Condition": {
      "StringEquals": {
        "kms:ViaService": [
            "s3.<REGION>.amazonaws.com",
            "rds.<REGION>.amazonaws.com"
        ]
      }
  }
}
```

## Prerequisiti importanti
<a name="access-graph-opencypher-21-extensions-s3-read-permissions-prerequisites"></a>

Queste autorizzazioni e prerequisiti garantiscono l'integrazione sicura e affidabile dei dati S3 nelle query OpenCypher, mantenendo al contempo controlli di accesso e misure di protezione dei dati adeguati.
+ **Autenticazione IAM**: questa funzionalità è supportata solo per i cluster Neptune con autenticazione IAM abilitata. Consulta [la sezione Protezione del database Amazon Neptune](security.md) per istruzioni dettagliate su come creare e connettersi a cluster abilitati all'autenticazione IAM.
+ **Endpoint VPC**:
  + È necessario un endpoint VPC di tipo gateway per Amazon S3 per consentire a Neptune di comunicare con Amazon S3.
  + Per utilizzare la AWS KMS crittografia personalizzata nella query, AWS KMS è necessario un endpoint VPC di tipo interfaccia per cui consentire a Neptune di comunicare con. AWS KMS
  + Per istruzioni dettagliate su come configurare questo endpoint, consulta [Creazione dell'endpoint VPC Amazon S3](bulk-load-tutorial-IAM.md).

# Dati spaziali
<a name="access-graph-opencypher-22-spatial-data"></a>

Amazon Neptune ora supporta le query spaziali, consentendoti di archiviare e analizzare dati geometrici nel tuo grafico. Sebbene siano comunemente utilizzate per posizioni geografiche (come le coordinate su una mappa), le caratteristiche spaziali funzionano con qualsiasi dato bidimensionale in cui posizione e prossimità sono importanti. Utilizza questa funzione per rispondere a domande come «Quali negozi si trovano nel raggio di 5 miglia da questo cliente?» , «Trova tutte le rotte di consegna che si intersecano con questa area di servizio» o «Quali componenti di questa planimetria si sovrappongono alla zona HVAC?» Neptune implementa il supporto spaziale utilizzando funzioni Spatial Types standard del settore che funzionano con punti, poligoni e altre forme geometriche. È possibile memorizzare i dati spaziali come proprietà su nodi e bordi, quindi utilizzare le funzioni spaziali per calcolare le distanze, verificare se i punti rientrano nei limiti o trovare regioni sovrapposte, il tutto all'interno delle query OpenCypher.

**Casi** d'uso comuni:
+ **Applicazioni geografiche**: raccomandazioni basate sulla posizione, geofencing, pianificazione del percorso e analisi del territorio
+ **Gestione della struttura e dello spazio**: layout della planimetria, posizionamento delle apparecchiature e copertura delle zone
+ **Topologia di rete**: mappatura dell'infrastruttura fisica, aree di copertura e confini del servizio
+ **Progettazione e CAD**: posizionamento dei componenti, rilevamento delle collisioni e relazioni spaziali nei progetti 2D
+ **Sviluppo del gioco**: posizionamento del personaggio, rilevamento delle collisioni e calcoli area-of-effect

L'implementazione dei tipi spaziali in Amazon Neptune ISO/IEC segue le direttive 13249-3:2016, come altri database. Sono [Funzioni spaziali](access-graph-opencypher-22-spatial-functions.md) disponibili nel linguaggio di interrogazione OpenCypher.

## Sistema di coordinate
<a name="access-graph-opencypher-22-spatial-data-coordinate-system"></a>

Neptune dispone di un unico Spatial Reference Identifier (SRID) per un intero database. L'omogeneità del sistema di coordinate riduce gli errori degli utenti nelle interrogazioni e migliora le prestazioni del database. La prima versione (1.4.7.0) supporta il sistema di coordinate cartesiane, noto anche come SRID 0.

L'implementazione Neptune di SRID 0 è compatibile con i valori di longitudine e latitudine. Viene utilizzato `ST_DistanceSpheroid` per calcolare le distanze in base a /SRID 4326. WGS84

L'attuale implementazione supporta la memorizzazione di coordinate tridimensionali. Le funzioni spaziali attualmente supportano solo l'utilizzo delle coordinate degli assi x e y (bidimensionali). Le coordinate dell'asse z non sono attualmente supportate dalle funzioni spaziali disponibili.

## Memorizzazione dei dati sulla posizione
<a name="storing-spatial-data"></a>

Memorizzate i dati di posizione su nodi e spigoli utilizzando il tipo di proprietà Geometry. Crea valori geometrici dal formato Wooden Text (WKT), un modo standard per rappresentare le forme geografiche come testo. Ad esempio, per memorizzare la posizione di un punto:

```
CREATE (n:airport {code: 'ATL', location: ST_GeomFromText('POINT (-84.4281 33.6367)')})
```

Quando si lavora con le coordinate geografiche, il primo argomento (x) rappresenta la longitudine e il secondo argomento (y) rappresenta la latitudine. Questo segue l'ordine di coordinate standard utilizzato nei database spaziali e lo standard ISO 19125.

**Nota**  
 Neptune ora supporta un nuovo tipo di dati chiamato «Geometria». La proprietà Geometry di un nodo o di uno spigolo può essere creata da una stringa WKT utilizzando la funzione. `ST_GeomFromText`  
Neptune memorizzerà automaticamente i dati dei punti in un indice spaziale specializzato per migliorare le prestazioni delle funzioni dei tipi spaziali. Ad esempio, `ST_Contains` usato per trovare i punti all'interno di un poligono viene accelerato dall'indice spaziale specializzato.  
[Pagina di Wikipedia per la rappresentazione della geometria in un testo ben noto](https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry)

## Caricamento di dati spaziali in blocco
<a name="loading-spatial-data-bulk"></a>

Quando carichi dati in blocco, specifica il tipo di geometria nell'intestazione CSV. Neptune analizzerà le stringhe WKT e creerà le proprietà geometriche appropriate:

```
:ID,:LABEL,code:String,city:String,location:Geometry
21,airport,ATL,Atlanta,POINT (-84.42810059 33.63669968)
32,airport,ANC,Anchorage,POINT (-149.9960022 61.17440033)
43,airport,AUS,Austin,POINT (-97.66989899 30.19449997)
```

[Per i dettagli completi sul formato CSV, consulta il formato di caricamento in blocco di OpenCypher.](bulk-load-tutorial-format-opencypher.md)

## Query su dati spaziali
<a name="querying-spatial-data"></a>

I seguenti esempi di query utilizzano il [set di dati delle rotte aeree](https://github.com/krlawrence/graph/tree/main/sample-data) per dimostrare come utilizzare le funzioni spaziali in Neptune.

Se i dati hanno proprietà di latitudine e longitudine separate anziché una proprietà Geometry, è possibile convertirli in punti al momento della query. Trova i 10 aeroporti più vicini a una determinata località:

```
MATCH (a:airport)
WITH a, ST_GeomFromText('POINT (' + a.lon + ' ' + a.lat + ')') AS airportLocation
WITH a, airportLocation, ST_Distance(ST_GeomFromText('POINT (-84.4281 33.6367)'), airportLocation) AS distance
WHERE distance IS NOT NULL
RETURN a.code, a.city, distance
ORDER BY distance ASC
LIMIT 10
```

Se disponi già di sedi memorizzate`ST_Point`, puoi utilizzare direttamente tali valori di posizione:

1. Impostazione della proprietà 

   ```
   MATCH (a:airport)
   SET a.location = ST_GeomFromText('POINT (' + a.lon + ' ' + a.lat + ')')
   ```

1. Interrogazione utilizzando ST\$1Distance:

   ```
   MATCH (a:airport)
   WHERE a.location IS NOT NULL
   WITH a, ST_Distance(ST_GeomFromText('POINT (-84.4281 33.6367)'), a.location) AS distance
   RETURN a.code, a.city, distance
   ORDER BY distance ASC
   LIMIT 10
   ```

### Utilizzo del driver Bolt
<a name="querying-spatial-data-bolt"></a>

La maggior parte dei metodi di interrogazione restituisce i valori di Geometry come stringhe WKT, che sono leggibili dall'uomo. Se si utilizza il driver Bolt, i valori di Geometry vengono restituiti nel formato WKB (Wellknown Binary) per maggiore efficienza. Converti WKB in un oggetto geometrico nella tua applicazione:

```
try (Session session = driver.session()) {
    Result result = session.run("MATCH (n:airport {code: 'ATL'}) RETURN n.location as geom");
    
    Record record = result.single();
    byte[] wkbBytes = record.get("geom").asByteArray();
    
    // Convert WKB to Geometry object using JTS library
    WKBReader wkbReader = new WKBReader();
    Geometry geom = wkbReader.read(wkbBytes);
}
```

# Funzioni spaziali
<a name="access-graph-opencypher-22-spatial-functions"></a>

Le seguenti funzioni spaziali sono disponibili in Neptune OpenCypher per lavorare con i tipi di dati geometrici:
+ [ST\$1Point](access-graph-opencypher-22-spatial-functions-st-point.md)
+ [ST\$1 GeomFromText](access-graph-opencypher-22-spatial-functions-st-geomfromtext.md)
+ [ST\$1 AsText](access-graph-opencypher-22-spatial-functions-st-astext.md)
+ [ST\$1 GeometryType](access-graph-opencypher-22-spatial-functions-st-geometrytype.md)
+ [ST\$1Equals](access-graph-opencypher-22-spatial-functions-st-equals.md)
+ [ST\$1Contains](access-graph-opencypher-22-spatial-functions-st-contains.md)
+ [ST\$1Intersects](access-graph-opencypher-22-spatial-functions-st-intersect.md)
+ [ST\$1Distance](access-graph-opencypher-22-spatial-functions-st-distance.md)
+ [ST\$1 DistanceSpheroid](access-graph-opencypher-22-spatial-functions-st-distancespheroid.md)
+ [ST\$1Envelope](access-graph-opencypher-22-spatial-functions-st-envelope.md)
+ [ST\$1Buffer](access-graph-opencypher-22-spatial-functions-st-buffer.md)

# ST\$1Point
<a name="access-graph-opencypher-22-spatial-functions-st-point"></a>

ST\$1Point restituisce un punto dai valori delle coordinate di input.

**Sintassi**

```
ST_Point(x, y, z)
```

**Arguments (Argomenti)**
+ `x`- Un valore del tipo di dati DOUBLE PRECISION che rappresenta una prima coordinata.
+ `y`- Un valore del tipo di dati DOUBLE PRECISION che rappresenta una seconda coordinata.
+ `z`- (opzionale)

**Ordine delle coordinate**

Quando si lavora con le coordinate geografiche, il primo argomento (`x`) rappresenta la **longitudine** e il secondo argomento (`y`) rappresenta la **latitudine**. Questo segue l'ordine di coordinate standard utilizzato nei database spaziali e lo standard ISO 19125.

```
// Correct: longitude first, latitude second
ST_Point(-84.4281, 33.6367)  // Atlanta airport

// Incorrect: latitude first, longitude second
ST_Point(33.6367, -84.4281)  // This will return NaN in distance calculations
```

**Intervalli di coordinate validi**

Per i dati geografici, assicurati che le coordinate rientrino in intervalli validi:
+ Longitudine (`x`): da -180 a 180
+ Latitudine (`y`): da -90 a 90

Le coordinate al di fuori di questi intervalli verranno restituite `NaN` (non un numero) se utilizzate con funzioni di calcolo della distanza come. `ST_DistanceSpheroid`

**Tipo restituito**

GEOMETRIA del sottotipo POINT

Se x o y sono nulli, allora viene restituito il valore nullo.

**Esempi**

Quanto segue costruisce una geometria puntuale a partire dalle coordinate di input.

```
RETURN ST_Point(5.0, 7.0); 
POINT(5 7)
```

# ST\$1 GeomFromText
<a name="access-graph-opencypher-22-spatial-functions-st-geomfromtext"></a>

ST\$1 GeomFromText costruisce un oggetto geometrico a partire da una rappresentazione testuale ben nota (WKT) di una geometria di input.

**Sintassi**

```
ST_GeomFromText(wkt_string)
```

**Arguments (Argomenti)**
+ `wkt_string`- Un valore di tipo di dati STRING che è una rappresentazione WKT di una geometria.

**Tipo restituito**

GEOMETRY

Se wkt\$1string è nullo, allora viene restituito nullo.

Se wkt\$1string non è valido, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')             
POLYGON((0 0,0 1,1 1,1 0,0 0))
```

# ST\$1 AsText
<a name="access-graph-opencypher-22-spatial-functions-st-astext"></a>

ST\$1 AsText restituisce la rappresentazione testuale ben nota (WKT) di una geometria di input.

**Sintassi**

```
ST_AsText(geo)
```

**Arguments (Argomenti)**
+ `geo`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce una GEOMETRY.

**Tipo restituito**

STRING

Se geo è nullo, allora viene restituito il valore nullo.

Se il parametro di input non è una geometria, viene restituito a. BadRequestException 

Se il risultato è più grande di una STRINGA da 64 KB, viene restituito un errore.

**Esempi**

```
RETURN ST_AsText(ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))'))             
POLYGON((0 0,0 1,1 1,1 0,0 0))
```

# ST\$1 GeometryType
<a name="access-graph-opencypher-22-spatial-functions-st-geometrytype"></a>

ST\$1 GeometryType restituisce il tipo di geometria sotto forma di stringa.

**Sintassi**

```
ST_GeometryType(geom)
```

**Arguments (Argomenti)**
+ `geom`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.

**Tipo restituito**

STRING

Se geom è nullo, allora viene restituito il valore nullo.

Se il parametro di input non è una geometria, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_GeometryType(ST_GeomFromText('LINESTRING(77.29 29.07,77.42 29.26,77.27 29.31,77.29 29.07)'));
ST_LineString
```

# ST\$1Equals
<a name="access-graph-opencypher-22-spatial-functions-st-equals"></a>

ST\$1equals restituisce true se le proiezioni 2D delle geometrie di input sono topologicamente uguali. Le geometrie sono considerate topologicamente uguali se hanno insiemi di punti uguali. Nelle geometrie topologicamente uguali, l'ordine dei vertici può differire pur mantenendo questa uguaglianza.

**Sintassi**

```
ST_Equals(geom1, geom2)
```

**Arguments (Argomenti)**
+ `geom1`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `geom2`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY. Questo valore è confrontato con geom1 per determinare se è uguale a geom1.

**Tipo restituito**

BOOLEAN

Se geom1 o geom2 sono nulli, allora viene restituito il valore nullo.

Se geom1 o geom2 non sono geometrie, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_Equals(
    ST_GeomFromText('POLYGON ((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 3,2 1,0 -3,-1 3))'));
false
```

Quanto segue controlla se le due stringhe di linea sono geometricamente uguali.

```
RETURN ST_Equals(
    ST_GeomFromText('LINESTRING (1 0, 10 0)'), 
    ST_GeomFromText('LINESTRING(1 0,5 0,10 0)'));
true
```

# ST\$1Contains
<a name="access-graph-opencypher-22-spatial-functions-st-contains"></a>

ST\$1Contains restituisce true se la proiezione 2D della prima geometria di input contiene la proiezione 2D della seconda geometria di input. La geometria A contiene la geometria B se ogni punto in B è un punto in A e i relativi interni hanno intersezioni non vuote. ST\$1contains (A, B) è equivalente a ST\$1Within (B, A).

**Sintassi**

```
ST_Contains(geom1, geom2)
```

**Arguments (Argomenti)**
+ `geom1`- Un valore di tipo GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `geom2`- Un valore di tipo GEOMETRY o un'espressione che restituisce un tipo di GEOMETRY. Questo valore è confrontato con geom1 per determinare se è contenuto all'interno di geom1.

**Tipo restituito**

BOOLEAN

Se geom1 o geom2 sono nulli, allora viene restituito il valore nullo.

Se il parametro di input non è una geometria, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_Contains(
    ST_GeomFromText('POLYGON((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 3,2 1,0 -3,-1 3))'));
false
```

# ST\$1Intersects
<a name="access-graph-opencypher-22-spatial-functions-st-intersect"></a>

ST\$1Intersects restituisce true se le proiezioni 2D delle due geometrie di input hanno almeno un punto in comune.

**Sintassi**

```
ST_Intersects(geom1, geom2)
```

**Arguments (Argomenti)**
+ `geom1`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `geom2`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.

**Tipo restituito**

BOOLEAN

Se geom1 o geom2 sono nulli, allora viene restituito il valore nullo.

Se il parametro di input non è una geometria, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_Intersects(
    ST_GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(2 2,2 5,5 5,5 2,2 2))'), 
    ST_GeomFromText('MULTIPOINT((4 4),(6 6))'));
true
```

# ST\$1Distance
<a name="access-graph-opencypher-22-spatial-functions-st-distance"></a>

Per le geometrie di input, ST\$1Distance restituisce la distanza euclidea minima tra le proiezioni 2D dei due valori della geometria di input.

**Sintassi**

```
ST_Distance(geo1, geo2)
```

**Arguments (Argomenti)**
+ `geo1`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `geo2`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un valore GEOMETRY.

**Tipo restituito**

DOPPIA PRECISIONE nelle stesse unità delle geometrie di input.

Se geo1 o geo2 sono nulli, viene restituito null.

Se il parametro di input non è una geometria, viene restituito a. BadRequestException 

**Esempi**

```
RETURN ST_Distance(
    ST_GeomFromText('POLYGON((0 2,1 1,0 -1,0 2))'), 
    ST_GeomFromText('POLYGON((-1 -3,-2 -1,0 -3,-1 -3))'));
1.4142135623731
```

# ST\$1 DistanceSpheroid
<a name="access-graph-opencypher-22-spatial-functions-st-distancespheroid"></a>

Restituisce la distanza minima in metri tra due lon/lat geometrie. Lo sferoide è WGS84 /SRID 4326.

**Sintassi**

```
ST_DistanceSpheroid(geom1, geom2);
```

**Arguments (Argomenti)**
+ `geom1`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `geom2`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.

**Tipo restituito**

FLOAT

Se geom è nullo, allora viene restituito il valore nullo.

**Esempi**

```
RETURN ST_DistanceSpheroid(
    ST_GeomFromText('POINT(-110 42)'),
    ST_GeomFromText('POINT(-118 38)'))
814278.77
```

# ST\$1Envelope
<a name="access-graph-opencypher-22-spatial-functions-st-envelope"></a>

ST\$1Envelope restituisce il riquadro di delimitazione minimo della geometria di input, come segue:
+ Se la geometria di input è vuota, la geometria restituita sarà POINT EMPTY.
+ Se il riquadro di delimitazione minimo della geometria di input degenera in un punto, la geometria restituita è un punto.
+ Se nessuna delle precedenti condizioni è vera, la funzione restituisce un counter-clockwise-oriented poligono i cui vertici sono gli angoli del riquadro di delimitazione minimo.

Per tutti gli input non vuoti, la funzione opera sulla proiezione 2D della geometria di input.

**Sintassi**

```
ST_Envelope(geom)
```

**Arguments (Argomenti)**
+ `geom`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.

**Tipo restituito**

GEOMETRY

Se geom è nullo, allora viene restituito il valore nullo.

**Esempi**

```
RETURN ST_Envelope(ST_GeomFromText("POLYGON ((2 1, 4 3, 6 1, 5 5, 3 4, 2 1))"))
POLYGON ((2 1, 6 1, 6 5, 2 5, 2 1))
```

# ST\$1Buffer
<a name="access-graph-opencypher-22-spatial-functions-st-buffer"></a>

ST\$1Buffer restituisce la geometria 2D che rappresenta tutti i punti la cui distanza dalla geometria di input proiettata sul piano cartesiano XY è minore o uguale alla distanza di input.

**Sintassi**

```
ST_Buffer(geom, distance, number_of_segments_per_quarter_circle)
```

**Arguments (Argomenti)**
+ `geom`- Un valore del tipo di dati GEOMETRY o un'espressione che restituisce un tipo GEOMETRY.
+ `distance`- Un valore del tipo di dati DOUBLE PRECISION che rappresenta la distanza (o il raggio) del buffer.
+ `number_of_segments_per_quarter_circle`- Un valore del tipo di dati INTEGER (deve essere maggiore o uguale a 0). Questo valore determina il numero di punti per approssimare un quarto di cerchio attorno a ciascun vertice della geometria di input. Per impostazione predefinita, i valori negativi sono zero. Il valore di default è 8.

**Tipo restituito**

GEOMETRY

La funzione ST\$1Buffer restituisce una geometria bidimensionale (2D) nel piano cartesiano XY.

**Esempi**

```
RETURN ST_Buffer(ST_GeomFromText('LINESTRING (1 2,5 2,5 8)'), 2, 4);
POLYGON ((3 4, 3 8, 3.1522409349774265 8.76536686473018,
         3.585786437626905 9.414213562373096, 4.234633135269821 9.847759065022574,
         5 10, 5.765366864730179 9.847759065022574,
         6.414213562373095 9.414213562373096, 6.847759065022574 8.76536686473018,
         7 8, 7 2, 6.847759065022574 1.2346331352698203,
         6.414213562373095 0.5857864376269051, 5.765366864730179 0.1522409349774265,
         5 0, 1 0, 0.2346331352698193 0.152240934977427,
         -0.4142135623730954 0.5857864376269051,
         -0.8477590650225737 1.2346331352698208, -1 2.0000000000000004,
         -0.8477590650225735 2.7653668647301797,
         -0.4142135623730949 3.414213562373095,
         0.2346331352698206 3.8477590650225735, 1 4, 3 4))
```

Quanto segue restituisce il buffer della geometria del punto di input che approssima un cerchio. Poiché il comando specifica 3 come numero di segmenti per quarto di cerchio, per approssimare il quarto di cerchio la funzione utilizza tre segmenti.

```
RETURN ST_Buffer(ST_GeomFromText('POINT (1 1)'), 1.0, 8));
POLYGON ((2 1, 1.9807852804032304 0.8049096779838718,
     1.9238795325112867 0.6173165676349102, 1.8314696123025453 0.4444297669803978,
     1.7071067811865475 0.2928932188134525, 1.5555702330196022 0.1685303876974548,
     1.3826834323650898 0.0761204674887133, 1.1950903220161284 0.0192147195967696,
     1 0, 0.8049096779838718 0.0192147195967696, 0.6173165676349103 0.0761204674887133,
    0.444429766980398 0.1685303876974545, 0.2928932188134525 0.2928932188134524,
     0.1685303876974546 0.4444297669803978, 0.0761204674887133 0.6173165676349102,
     0.0192147195967696 0.8049096779838714, 0 0.9999999999999999,
     0.0192147195967696 1.1950903220161284, 0.0761204674887132 1.3826834323650896,
     0.1685303876974545 1.555570233019602, 0.2928932188134523 1.7071067811865475,
     0.4444297669803978 1.8314696123025453, 0.6173165676349097 1.9238795325112865,
     0.8049096779838714 1.9807852804032304, 0.9999999999999998 2,
     1.1950903220161284 1.9807852804032304, 1.38268343236509 1.9238795325112865,
     1.5555702330196017 1.8314696123025453, 1.7071067811865475 1.7071067811865477,
     1.8314696123025453 1.5555702330196022, 1.9238795325112865 1.3826834323650905,
     1.9807852804032304 1.1950903220161286, 2 1))
```

# Accesso al grafo Neptune con SPARQL
<a name="access-graph-sparql"></a>

SPARQL è un linguaggio di query per l'RDF (Resource Description Framework), un formato di dati a grafo progettato per il Web. Amazon Neptune è compatibile con SPARQL 1.1. Questo ti consente di connetterti a un'istanza database Neptune ed eseguire query sul grafo utilizzando il linguaggio di query descritto nella specifica [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

 Una query in SPARQL consiste di una clausola `SELECT` per specificare le variabili da restituire e una clausola `WHERE` per specificare i dati da abbinare nel grafo. Per ulteriori informazioni sulle query SPARQL, vedere [Writing Simple Queries](https://www.w3.org/TR/sparql11-query/#WritingSimpleQueries) (Scrittura di query semplici) in [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

**Importante**  
Per caricare i dati, `SPARQL UPDATE INSERT` potrebbe funzionare bene per un set di dati di piccole dimensioni, ma se è necessario caricare una notevole quantità di dati da un file, vedere [Utilizzo del bulk loader Amazon Neptune per importare dati](bulk-load.md).

Per ulteriori informazioni sulle specifiche dell'implementazione SPARQL di Neptune, consulta [Conformità agli standard SPARQL](feature-sparql-compliance.md).

Prima di iniziare, devi disporre di quanto segue:
+ Istanza database Neptune. Per informazioni sulla creazione di un'istanza database Neptune, consulta [Creazione di un cluster Amazon Neptune](get-started-create-cluster.md).
+ Istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

**Topics**
+ [

# Utilizzo della console RDF4 J per connettersi a un'istanza DB di Neptune
](access-graph-sparql-rdf4j-console.md)
+ [

# Utilizzo di RDF4 J Workbench per connettersi a un'istanza DB di Neptune
](access-graph-sparql-rdf4j-workbench.md)
+ [

# Utilizzo di Java per connettersi a un'istanza database Neptune
](access-graph-sparql-java.md)
+ [

# API SPARQL HTTP
](sparql-api-reference.md)
+ [

# Hint di query SPARQL
](sparql-query-hints.md)
+ [

# Comportamento di SPARQL DESCRIBE rispetto al grafo predefinito
](sparql-default-describe.md)
+ [

# API di stato delle query SPARQL
](sparql-api-status.md)
+ [

# Annullamento della query SPARQL
](sparql-api-status-cancel.md)
+ [

# Utilizzo del protocollo HTTP Graph Store Protocol (GSP) SPARQL 1.1 in Amazon Neptune
](sparql-graph-store-protocol.md)
+ [

# Analisi dell'esecuzione di query Neptune tramite la funzionalità SPARQL `explain`
](sparql-explain.md)
+ [

# Query federate SPARQL in Neptune che utilizzano l'estensione `SERVICE`
](sparql-service.md)

# Utilizzo della console RDF4 J per connettersi a un'istanza DB di Neptune
<a name="access-graph-sparql-rdf4j-console"></a>



La console RDF4 J consente di sperimentare con i grafici e le query del Resource Description Framework (RDF) in un ambiente REPL (loop). read-eval-print 

È possibile aggiungere un database grafico remoto come repository e interrogarlo dalla console J. RDF4 Questa sezione illustra la configurazione della console RDF4 J per la connessione remota a un'istanza DB di Neptune.

**Per connettersi a Neptune utilizzando la console J RDF4**

1. Scarica l'SDK RDF4 J dalla [pagina Download](http://rdf4j.org/download/) del sito Web di RDF4 J.

1. Decomprimi il file zip RDF4 J SDK.

1. In un terminale, vai alla directory RDF4 J SDK, quindi inserisci il seguente comando per eseguire la RDF4 console J:

   ```
   bin/console.sh
   ```

   Verrà visualizzato un output simile al seguente:

   ```
   14:11:51.126 [main] DEBUG o.e.r.c.platform.PlatformFactory - os.name = linux
   14:11:51.130 [main] DEBUG o.e.r.c.platform.PlatformFactory - Detected Posix platform
   Connected to default data directory
   RDF4J Console 3.6.1
   
   3.6.1
   Type 'help' for help.
   >
   ```

   Ora ti trovi al prompt `>`. Questa è la richiesta generale per la console RDF4 J. Puoi usare questo prompt per la configurazione degli archivi e altre operazioni. Un archivio ha il proprio prompt per l'esecuzione di query.

1. Al prompt `>`, digita quanto segue per creare un repository SPARQL per l'istanza database Neptune:

    

   ```
   create sparql
   ```

1. La console RDF4 J richiede i valori per le variabili necessarie per connettersi all'endpoint SPARQL.

   ```
   Please specify values for the following variables:
   ```

   Specifica i seguenti valori:    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/access-graph-sparql-rdf4j-console.html)

   Per informazioni su come trovare l'indirizzo dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

   Se l'operazione ha esito positivo, visualizzerai il messaggio seguente:

    

   ```
   Repository created
   ```

1. Al prompt `>`, immetti quanto segue per connetterti all'istanza database Neptune:

   ```
   open neptune
   ```

   Se l'operazione ha esito positivo, visualizzerai il messaggio seguente:

    

   ```
   Opened repository 'neptune'
   ```

   Ora ti trovi al prompt `neptune>`. Da questo prompt, puoi eseguire le query sul grafo Neptune.

    
**Nota**  
Una volta aggiunto il repository, alla successiva esecuzione di `bin/console.sh` puoi eseguire immediatamente il comando `open neptune` per connetterti all'istanza database Neptune.

1. Al `neptune>` prompt, inserisci quanto segue per eseguire una query SPARQL che restituisca fino a 10 delle triple (subject-predicate-object) nel grafico utilizzando la `?s ?p ?o` query con un limite di 10. Per eseguire una query su qualcos'altro, sostituire il testo dopo il comando `sparql` con un'altra query SPARQL.

   ```
   sparql select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

# Utilizzo di RDF4 J Workbench per connettersi a un'istanza DB di Neptune
<a name="access-graph-sparql-rdf4j-workbench"></a>

Questa sezione illustra come connettersi a un'istanza DB di Amazon Neptune RDF4 utilizzando J RDF4 Workbench e J Server. RDF4J Server è necessario perché funge da proxy tra l'endpoint Neptune SPARQL HTTP REST e J Workbench. RDF4 

RDF4J Workbench fornisce un'interfaccia semplice per sperimentare con un grafico, incluso il caricamento di file locali. Per informazioni, consulta la [sezione Aggiungi](https://rdf4j.org/documentation/tools/server-workbench/#add) nella documentazione di RDF4 J.

**Prerequisiti**  
Prima di iniziare, esegui queste attività:
+ Installazione di Java 1.8 o versione successiva.
+ Installa RDF4 J Server e RDF4 J Workbench. Per informazioni, vedere [Installazione di RDF4 J Server e RDF4 J Workbench](https://rdf4j.org/documentation/tools/server-workbench/#installing-rdf4j-server-and-rdf4j-workbench).

**Per utilizzare RDF4 J Workbench per connettersi a Neptune**

1. In un browser Web, accedi all'URL in cui è distribuita l'app web RDF4 J Workbench. [Ad esempio, se utilizzi Apache Tomcat, l'URL è: https: //:8080/rdf4j-workbench/. *ec2\$1hostname*](http://localhost:8080/rdf4j-workbench/)

1. Se ti viene chiesto di **connetterti a RDF4 J Server**, verifica che **RDF4J Server** sia installato, in esecuzione e che l'URL del server sia corretto. Quindi, passare alla fase successiva.

1. Nel riquadro a sinistra, scegliere **New repository** (Nuovo archivio).

   In **New repository** (Nuovo archivio):
   + Dall'elenco a discesa **Type (Tipo)**, scegli **SPARQL endpoint proxy (Proxy dell'endpoint SPARQL)**.
   + Per **ID**, digitare **neptune**.
   + Per **Titolo**, digita **Istanza database Neptune**.

   Scegli **Next (Successivo)**.

1. In **New repository** (Nuovo archivio):
   + Per **SPARQL query endpoint URL (URL endpoint query SPARQL)**, digitare `https://your-neptune-endpoint:port/sparql`.
   + Per **SPARQL update endpoint URL (URL endpoint aggiornamento SPARQL)**, digitare `https://your-neptune-endpoint:port/sparql`.

   Per informazioni su come trovare l'indirizzo dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md). 

   Scegli **Create** (Crea).

1. Ora l'archivio di **neptune (Neptune)** viene visualizzato nell'elenco degli archivi. Potrebbero essere necessari alcuni minuti prima di poter utilizzare il nuovo archivio.

1. Nella colonna **Id** della tabella, scegliere il collegamento **neptune**.

1. Nel riquadro a sinistra, scegliere **Query**. 

    
**Nota**  
Se le voci del menu in **Esplora** sono disabilitate, potrebbe essere necessario riconnettersi al RDF4 J Server e scegliere nuovamente il repository **neptune**.  
Puoi eseguire questa operazione tramite i link **[change]** (modifica) nella parte superiore destra.

1. Nel campo di query, digita la query SPARQL seguente, quindi scegli **Execute** (Esegui).

    

   ```
   select ?s ?p ?o where {?s ?p ?o} limit 10
   ```

    

L'esempio precedente restituisce fino a 10 delle triple (subject-predicate-object) nel grafico utilizzando la `?s ?p ?o` query con un limite di 10. 

# Utilizzo di Java per connettersi a un'istanza database Neptune
<a name="access-graph-sparql-java"></a>

Questa sezione illustra come eseguire un esempio di Java completo che si connette a un'istanza database Amazon Neptune ed esegue una query SPARQL.

Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

**Per connettersi a Neptune tramite Java**

1. Installare Apache Maven sull'istanza EC2. Se usi Amazon Linux 2023 (preferito), usa:

   ```
   sudo dnf update -y
   sudo dnf install maven -y
   ```

   Se usi Amazon Linux 2, scarica il file binario più recente da [https://maven.apache.org/download.cgi:](https://maven.apache.org/download.cgi:)

   ```
   sudo yum remove maven -y
   wget https://dlcdn.apache.org/maven/maven-3/ <version>/binaries/apache-maven-<version>-bin.tar.gz
   sudo tar -xzf apache-maven-<version>-bin.tar.gz -C /opt/
   sudo ln -sf /opt/apache-maven-<version> /opt/maven
   echo 'export MAVEN_HOME=/opt/maven' >> ~/.bashrc
   echo 'export PATH=$MAVEN_HOME/bin:$PATH' >> ~/.bashrc
   source ~/.bashrc
   ```

1. Questo esempio è stato testato solo con Java 8. Per installare Java 8 sull'istanza EC2, digitare quanto segue:

   ```
   sudo yum install java-1.8.0-devel
   ```

1. Per impostare Java 8 come runtime predefinito sull'istanza EC2, digitare quanto segue:

   ```
   sudo /usr/sbin/alternatives --config java
   ```

   Quando richiesto, immetti il numero per Java 8.

1. Per impostare Java 8 come compilatore predefinito sull'istanza EC2, immettere quanto segue: 

   ```
   sudo /usr/sbin/alternatives --config javac
   ```

   Quando richiesto, immetti il numero per Java 8.

1. In una nuova directory , creare un file `pom.xml`, quindi aprirlo in un editor di testo.

1. Copia quanto segue nel file `pom.xml` e salvalo (di solito puoi modificare i numeri di versione in base all'ultima versione stabile):

   ```
   <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.amazonaws</groupId>
     <artifactId>RDFExample</artifactId>
     <packaging>jar</packaging>
     <version>1.0-SNAPSHOT</version>
     <name>RDFExample</name>
     <url>https://maven.apache.org</url>
     <dependencies>
       <dependency>
         <groupId>org.eclipse.rdf4j</groupId>
         <artifactId>rdf4j-runtime</artifactId>
         <version>3.6</version>
       </dependency>
     </dependencies>
     <build>
       <plugins>
         <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>exec-maven-plugin</artifactId>
             <version>1.2.1</version>
             <configuration>
               <mainClass>com.amazonaws.App</mainClass>
             </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
             <source>1.8</source>
             <target>1.8</target>
           </configuration>
         </plugin>
       </plugins>
     </build>
   </project>
   ```
**Nota**  
Se stai modificando un progetto Maven esistente, la dipendenza necessaria è evidenziata nel codice precedente.

1. Per creare sottodirectory per il codice sorgente di esempio (`src/main/java/com/amazonaws/`), immettere quanto segue nella riga di comando:

   ```
   mkdir -p src/main/java/com/amazonaws/
   ```

1. Nella directory `src/main/java/com/amazonaws/`, creare un file denominato `App.java`, quindi aprirlo in un editor di testo.

1. Copiare quanto segue nel file `App.java`. Sostituisci *your-neptune-endpoint* con l'indirizzo della tua istanza DB Neptune.
**Nota**  
Per informazioni su come trovare il nome host dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md). 

   ```
   package com.amazonaws;
   
   import org.eclipse.rdf4j.repository.Repository;
   import org.eclipse.rdf4j.repository.http.HTTPRepository;
   import org.eclipse.rdf4j.repository.sparql.SPARQLRepository;
   
   import java.util.List;
   import org.eclipse.rdf4j.RDF4JException;
   import org.eclipse.rdf4j.repository.RepositoryConnection;
   import org.eclipse.rdf4j.query.TupleQuery;
   import org.eclipse.rdf4j.query.TupleQueryResult;
   import org.eclipse.rdf4j.query.BindingSet;
   import org.eclipse.rdf4j.query.QueryLanguage;
   import org.eclipse.rdf4j.model.Value;
   
   public class App
   {
       public static void main( String[] args )
       {
           String sparqlEndpoint = "https://your-neptune-endpoint:port/sparql";
           Repository repo = new SPARQLRepository(sparqlEndpoint);
           repo.initialize();
   
           try (RepositoryConnection conn = repo.getConnection()) {
              String queryString = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } limit 10";
   
              TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
   
              try (TupleQueryResult result = tupleQuery.evaluate()) {
                 while (result.hasNext()) {  // iterate over the result
                      BindingSet bindingSet = result.next();
   
                      Value s = bindingSet.getValue("s");
                      Value p = bindingSet.getValue("p");
                      Value o = bindingSet.getValue("o");
   
                      System.out.print(s);
                      System.out.print("\t");
                      System.out.print(p);
                      System.out.print("\t");
                      System.out.println(o);
                 }
              }
           }
       }
   }
   ```

1. Per compilare ed eseguire l'esempio, usare il comando Maven seguente:

   ```
   mvn compile exec:java
   ```

L'esempio precedente restituisce fino a 10 delle triple (subject-predicate-object) nel grafico utilizzando la `?s ?p ?o` query con un limite di 10. Per eseguire una query su qualcos'altro, sostituire la query con un'altra query SPARQL .

L'iterazione dei risultati dell'esempio stampa il valore di ogni variabile restituita. L'oggetto `Value` viene convertito in `String` e quindi stampato. Se modifichi la parte `SELECT` della query, dovrai modificare il codice.

# API SPARQL HTTP
<a name="sparql-api-reference"></a>

Le richieste SPARQL HTTP vengono accettate negli endpoint seguenti: `https://your-neptune-endpoint:port/sparql`

Per ulteriori informazioni sulla connessione ad Amazon Neptune con SPARQL, vedi [Accesso al grafo Neptune con SPARQL](access-graph-sparql.md).

Per ulteriori informazioni sui protocolli SPARQL e il linguaggio di query, vedi le specifiche [SPARQL 1.1 Protocol](https://www.w3.org/TR/sparql11-protocol/#protocol) e [SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/).

I seguenti argomenti forniscono informazioni sui formati di serializzazione SPARQL RDF e su come utilizzare l'API HTTP di SPARQL con Neptune.

**Contents**
+ [

# Utilizzo dell'endpoint HTTP REST per connettersi a un'istanza database Neptune
](access-graph-sparql-http-rest.md)
+ [

# Intestazioni HTTP finali opzionali per risposte SPARQL in più parti
](access-graph-sparql-http-trailing-headers.md)
+ [

# Tipi di supporti RDF usati da SPARQL in Neptune
](sparql-media-type-support.md)
  + [

## Formati di serializzazione RDF usati da Neptune SPARQL
](sparql-media-type-support.md#sparql-serialization-formats)
  + [

## Formati di serializzazione dei risultati SPARQL utilizzati da Neptune SPARQL
](sparql-media-type-support.md#sparql-serialization-formats-neptune-output)
  + [

## Tipi di supporto che Neptune può utilizzare per importare dati RDF
](sparql-media-type-support.md#sparql-serialization-formats-input)
  + [

## Tipi di supporto utilizzabili da Neptune per esportare risultati di query
](sparql-media-type-support.md#sparql-serialization-formats-output)
+ [

# Utilizzo di SPARQL UPDATE LOAD per l'importazione di dati in Neptune
](sparql-api-reference-update-load.md)
+ [

# Utilizzo di SPARQL UPDATE UNLOAD per eliminare i dati da Neptune
](sparql-api-reference-unload.md)

# Utilizzo dell'endpoint HTTP REST per connettersi a un'istanza database Neptune
<a name="access-graph-sparql-http-rest"></a>

**Nota**  
Neptune attualmente non supporta HTTP/2 per le richieste API REST. I client devono utilizzare HTTP/1.1 per la connessione agli endpoint.

Le istruzioni seguenti illustrano come connettersi a un endpoint di SPARQL utilizzando il comando **curl**, collegandosi tramite HTTPS e usando la sintassi HTTP. Segui queste istruzioni da un'istanza Amazon EC2 nello stesso cloud privato virtuale (VPC) dell'istanza database Neptune.

L'endpoint HTTP per le query SPARQL in un'istanza database Neptune è: `https://your-neptune-endpoint:port/sparql`.

**Nota**  
Per informazioni su come trovare il nome host dell'istanza database Neptune, consulta la sezione [Connessione agli endpoint Amazon Neptune](feature-overview-endpoints.md).

Amazon Neptune fornisce un endpoint HTTP per le query SPARQL. L'interfaccia REST è compatibile con la versione 1.1 di SPARQL.

**QUERY tramite HTTP POST**  
L'esempio seguente utilizza **curl** per inviare una SPARQL **`QUERY`** tramite HTTP **POST**.

```
curl -X POST --data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' https://your-neptune-endpoint:port/sparql
```

L'esempio precedente restituisce fino a 10 delle triple (subject-predicate-object) nel grafico utilizzando la `?s ?p ?o` query con un limite di 10. Per eseguire una query su qualcos'altro, sostituirla con un'altra query SPARQL .

**Nota**  
Il tipo di supporto MIME predefinito di una risposta è `application/sparql-results+json` per le query `SELECT` e `ASK`.  
Il tipo MIME predefinito di una risposta è `application/n-quads` per le query `CONSTRUCT` e `DESCRIBE`.  
Per un elenco dei tipi di supporto utilizzati da Neptune per la serializzazione, consulta [Formati di serializzazione RDF usati da Neptune SPARQL](sparql-media-type-support.md#sparql-serialization-formats).

**UPDATE utilizzando HTTP POST**  
L'esempio seguente utilizza **curl** per inviare una SPARQL **`UPDATE`** tramite HTTP **POST**.

```
curl -X POST --data-binary 'update=INSERT DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }' https://your-neptune-endpoint:port/sparql
```

L'esempio precedente inserisce la seguente tripla nel grafo SPARQL predefinito: `<https://test.com/s> <https://test.com/p> <https://test.com/o>`

# Intestazioni HTTP finali opzionali per risposte SPARQL in più parti
<a name="access-graph-sparql-http-trailing-headers"></a>

La risposta HTTP alle query e agli aggiornamenti SPARQL viene spesso restituita in più parti o blocchi. Può essere difficile diagnosticare un errore che si verifica dopo che una query o un aggiornamento inizia a inviare questi blocchi, soprattutto perché il primo arriva con un codice di stato HTTP di `200`.

A meno che non si richiedano esplicitamente le intestazioni finali, Neptune segnala tale errore solo aggiungendo un messaggio di errore al corpo del messaggio, che di solito è danneggiato.

Per facilitare il rilevamento e la diagnosi di questo tipo di problema, puoi includere nella richiesta un'intestazione transfer-encoding (TE) trailers (`te: trailers`) (vedi, ad esempio, [la pagina MDN sulle intestazioni di richiesta TE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE)). In questo modo Neptune includerà due nuovi campi di intestazione nelle intestazioni finali dei blocchi di risposta:
+ `X-Neptune-Status`: contiene il codice di risposta seguito da un nome breve. Ad esempio, in caso di esito positivo, l'intestazione finale sarà: `X-Neptune-Status: 200 OK`. In caso di errore, il codice di risposta sarà un [codice di errore del motore Neptune](errors-engine-codes.md) come `X-Neptune-Status: 500 TimeLimitExceededException`.
+ `X-Neptune-Detail`: è vuoto per le richieste riuscite. In caso di errori, contiene il messaggio di errore JSON. Poiché nei valori di intestazione HTTP sono consentiti solo caratteri ASCII, la stringa JSON è codificata come URL. Inoltre, al corpo del messaggio di risposta viene anche aggiunto il messaggio di errore.

# Tipi di supporti RDF usati da SPARQL in Neptune
<a name="sparql-media-type-support"></a>

I dati RDF (Resource Description Framework) possono essere serializzati in molti modi diversi e SPARQL può utilizzarne o produrne la maggior parte:

## Formati di serializzazione RDF usati da Neptune SPARQL
<a name="sparql-serialization-formats"></a>
+ **RDF/XML**: serializzazione XML di RDF, definita in [RDF 1.1 XML Syntax](https://www.w3.org/TR/rdf-syntax-grammar/). Tipo di supporto: `application/rdf+xml`. Estensione tipica del file: `.rdf`.
+ **N-Triples**: un formato di testo normale, basato su riga, per la codifica di un grafo RDF, definito in [RDF 1.1 N-Triples](https://www.w3.org/TR/n-triples/). Tipo di supporto: `application/n-triples`, `text/turtle` o `text/plain`. Estensione tipica del file: `.nt`.
+ **N-Quads**: un formato di testo normale, basato su riga, per la codifica di un grafo RDF, definito in [RDF 1.1 N-Quads](https://www.w3.org/TR/n-quads/). Si tratta di un'estensione di N-Triples. Tipo di supporto: `application/n-quads` oppure `text/x-nquads` quando codificato con US-ASCII a 7 bit. Estensione tipica del file: `.nq`.
+ **Turtle**: una sintassi testuale per RDF definita in [RDF 1.1 Turtle](https://www.w3.org/TR/turtle/) che permette a un grafo RDF di essere completamente scritto in una forma di testo naturale e compatta, con abbreviazioni per modelli di utilizzo e tipi di dati comuni. Turtle offre livelli di compatibilità con il formato N-Triples nonché con la sintassi di modello triplice di SPARQL. Tipo di supporto: `text/turtle`Estensione tipica del file `.ttl`.
+ **TriG**: una sintassi testuale per RDF definita in [RDF 1.1 TriG](https://www.w3.org/TR/trig/) che consente a un grafo RDF di essere completamente scritto in una forma di testo naturale e compatta, con abbreviazioni per modelli di utilizzo e tipi di dati comuni. TriG è un'estensione del formato Turtle. Tipo di supporto: `application/trig`. Estensione tipica del file: `.trig`.
+ **N3 (Notation3)**: un linguaggio di asserzione e logica definito in [Notation3 (N3): A readable RDF syntax](https://www.w3.org/TeamSubmission/n3/). N3 estende il modello di dati RDF aggiungendo formule (valori letterali che sono essi stessi grafi), variabili, implicazioni logiche e predicati funzionali e fornisce una sintassi testuale alternativa a RDF/XML. Tipo di supporto: `text/n3`. Estensione tipica del file: `.n3`.
+ **JSON-LD**: un formato di serializzazione dei dati e dei messaggi definito in [JSON-LD 1.0](https://www.w3.org/TR/json-ld/). Tipo di supporto: `application/ld+json`. Estensione tipica del file: `.jsonld`.
+ **TriX**: una serializzazione di RDF in XML, definita in [TriX: triple RDF in XML](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html). Tipo di supporto: `application/trix`. Estensione tipica del file: `.trix`.
+ **SPARQL JSON Results**: una serializzazione di RDF con [SPARQL 1.1 Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json). Tipo di supporto: `application/sparql-results+json`. Estensione tipica del file: `.srj`.
+ **RDF4J Binary Format** [— Un formato binario per la codifica di dati RDF, documentato nel RDF4 formato J Binary RDF.](https://rdf4j.org/documentation/reference/rdf4j-binary) Tipo di supporto: `application/x-binary-rdf`.

## Formati di serializzazione dei risultati SPARQL utilizzati da Neptune SPARQL
<a name="sparql-serialization-formats-neptune-output"></a>
+ **SPARQL XML Results**: un formato XML per i formati di risultati booleani e di vincolo variabili forniti dal linguaggio di query SPARQL, definito in [SPARQL Query Results XML Format (Second Edition)](https://www.w3.org/TR/rdf-sparql-XMLres/). Tipo di supporto: `application/sparql-results+xml`. Estensione tipica del file: `.srx`.
+ **SPARQL CSV and TSV Results**: l'uso di valori separati da virgole e valori separati da tabulazione per esprimere i risultati di query SPARQL da query `SELECT`, definito in [SPARQL 1.1 Query Results CSV and TSV Formats](https://www.w3.org/TR/sparql11-results-csv-tsv/). Tipo di supporto: `text/csv` per valori separati da virgola e `text/tab-separated-values` per valori separati da schede. Estensioni tipiche del file: `.csv` per valori separati da virgola e `.tsv` per valori separati da schede.
+ **Binary Results Table**: un formato binario per la codifica dell'output di query SPARQL. Tipo di supporto: `application/x-binary-rdf-results-table`.
+ **SPARQL JSON Results**: una serializzazione di RDF con [SPARQL 1.1 Query Results JSON Format](https://www.w3.org/TR/sparql11-results-json/). Tipo di supporto: `application/sparql-results+json`.

## Tipi di supporto che Neptune può utilizzare per importare dati RDF
<a name="sparql-serialization-formats-input"></a>

**Tipi di supporto che lo [strumento di caricamento in blocco Neptune](bulk-load.md) può supportare**
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [N-QUAD](https://www.w3.org/TR/n-quads/)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [Turtle](https://www.w3.org/TR/turtle/)

**Tipi di supporto che possono essere importati da SPARQL UPDATE LOAD**
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [N-QUAD](https://www.w3.org/TR/n-quads/)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [TriG](https://www.w3.org/TR/trig/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)

## Tipi di supporto utilizzabili da Neptune per esportare risultati di query
<a name="sparql-serialization-formats-output"></a>

Per specificare il formato di output per una risposta a una query di SPARQL, invia un'intestazione `"Accept: media-type"` con la richiesta di query. Esempio:

```
curl -H "Accept: application/nquads" ...
```

**Tipi di supporto RDF che SPARQL SELECT può produrre da Neptune**
+ [SPARQL JSON Results](https://www.w3.org/TR/sparql11-results-json) (impostazione predefinita)
+ [SPARQL XML Results](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **Binary Results Table** (tipo di supporto: `application/x-binary-rdf-results-table`)
+ [Comma-Separated Values (CSV)](https://www.w3.org/TR/sparql11-results-csv-tsv/)
+ [Tab-Separated Values (TSV)](https://www.w3.org/TR/sparql11-results-csv-tsv/)

**Tipi di supporto RDF che SPARQL ASK può produrre da Neptune**
+ [SPARQL JSON Results](https://www.w3.org/TR/sparql11-results-json) (impostazione predefinita)
+ [SPARQL XML Results](https://www.w3.org/TR/rdf-sparql-XMLres/)
+ **Boolean** (tipo di supporto: `text/boolean`, ovvero "true" o "false")

**Tipi di supporto RDF che SPARQL CONSTRUCT può produrre da Neptune**
+ [N-QUAD](https://www.w3.org/TR/n-quads/) (impostazione predefinita)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [TriX](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html)
+ [TriG](https://www.w3.org/TR/trig/)
+ [SPARQL JSON Results](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4Formato binario RDF J](https://rdf4j.org/documentation/reference/rdf4j-binary)

**Tipi di supporto RDF che SPARQL DESCRIBE può produrre da Neptune**
+ [N-QUAD](https://www.w3.org/TR/n-quads/) (impostazione predefinita)
+ [RDF/XML](https://www.w3.org/TR/rdf-syntax-grammar/)
+ [JSON-LD](https://www.w3.org/TR/json-ld/)
+ [N-Triples](https://www.w3.org/TR/n-triples/)
+ [Turtle](https://www.w3.org/TR/turtle/)
+ [N3](https://www.w3.org/TeamSubmission/n3/)
+ [TriX](https://www.hpl.hp.com/techreports/2004/HPL-2004-56.html)
+ [TriG](https://www.w3.org/TR/trig/)
+ [SPARQL JSON Results](https://www.w3.org/TR/sparql11-results-json)
+ [RDF4J Formato binario RDF](https://rdf4j.org/documentation/reference/rdf4j-binary)

# Utilizzo di SPARQL UPDATE LOAD per l'importazione di dati in Neptune
<a name="sparql-api-reference-update-load"></a>

La sintassi del comando SPARQL UPDATE LOAD è specificata nella [raccomandazione SPARQL 1.1 Update](https://www.w3.org/TR/sparql11-update/#load):

```
LOAD SILENT (URL of data to be loaded) INTO GRAPH (named graph into which to load the data)
```
+ **`SILENT`**: (*facoltativo*) fa sì che l'operazione restituisca un esito positivo anche se si è verificato un errore durante l'elaborazione.

  Ciò può essere utile quando una singola transazione contiene più istruzioni come `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"` e si desidera che la transazione venga completata anche se non è stato possibile elaborare alcuni dati remoti.
+ *URL of data to be loaded*— (*Obbligatorio*) Speciifica un file di dati remoto contenente dati da caricare in un grafico.

  Il file remoto deve avere una delle seguenti estensioni:
  + `.nt`per NTriples.
  + `.nq`per NQuads.
  + `.trig` per Trig.
  + `.rdf` per RDF/XML.
  + `.ttl` per Turtle.
  + `.n3` per N3.
  + `.jsonld` per JSON-LD.
+ **`INTO GRAPH`***(named graph into which to load the data)*— (*Facoltativo*) Speciifica il grafico in cui devono essere caricati i dati.

  Neptune associa ogni tripla a un grafo nominato. È possibile specificare il grafo nominato predefinito utilizzando l'URI di fallback del grafo nominato, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`, in questo modo:

  ```
  INTO GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

**Nota**  
Quando devi caricare molti dati, è consigliabile utilizzare lo strumento di caricamento in blocco Neptune anziché UPDATE LOAD. Per ulteriori informazioni sullo strumento di caricamento in blocco, consulta [Utilizzo del bulk loader Amazon Neptune per importare dati](bulk-load.md).

Puoi utilizzare `SPARQL UPDATE LOAD` per caricare dati direttamente da Amazon S3 o da file ottenuti da un server Web in self-hosting. Le risorse da caricare devono trovarsi nella stessa regione del server Neptune e l'endpoint per le risorse deve essere consentito nel VCP. Per informazioni su come creare un endpoint Amazon S3, vedi [Creazione di un endpoint VPC Amazon S3](bulk-load-data.md#bulk-load-prereqs-s3).

Tutto `SPARQL UPDATE LOAD` URIs deve iniziare con`https://`. Ciò include Amazon S3 URLs.

Diversamente dallo strumento di caricamento in blocco Neptune, una chiamata a `SPARQL UPDATE LOAD` è completamente transazionale.

**Caricare file da Amazon S3 direttamente in Neptune tramite SPARQL UPDATE LOAD**

Poiché Neptune non consente di passare un ruolo IAM ad Amazon S3 quando si utilizza SPARQL UPDATE LOAD, il bucket Amazon S3 in questione deve essere pubblico oppure è necessario utilizzare un [URL Amazon S3 prefirmato](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) nella query LOAD.

Per generare un URL prefirmato per un file Amazon S3, puoi usare AWS CLI un comando come questo:

```
aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to load)
```

Quindi puoi utilizzare l'URL prefirmato risultante nel comando `LOAD`:

```
curl https://(a Neptune endpoint URL):8182/sparql \
  --data-urlencode 'update=load (pre-signed URL of the remote Amazon S3 file of data to be loaded) \
                           into graph (named graph)'
```

Per ulteriori informazioni, consulta [Autenticazione delle richieste: utilizzo dei parametri di query](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html). La [documentazione di Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html) mostra come usare uno script Python per generare un URL prefirmato.

Inoltre, il tipo di contenuto dei file da caricare deve essere impostato correttamente.

1. Imposta il tipo di contenuto dei file quando li carichi in Amazon S3 usando il parametro `-metadata`, ad esempio:

   ```
   aws s3 cp test.nt s3://bucket-name/my-plain-text-input/test.nt --metadata Content-Type=text/plain
   aws s3 cp test.rdf s3://bucket-name/my-rdf-input/test.rdf --metadata Content-Type=application/rdf+xml
   ```

1. Conferma che sia presente l'informazione sul tipo di supporto. Esegui:

   ```
   curl -v bucket-name/folder-name
   ```

   L'output di questo comando mostra le informazioni sul tipo di supporto impostate durante il caricamento dei file.

1. Quindi, puoi utilizzare il comando `SPARQL UPDATE LOAD` per importare questi file in Neptune:

   ```
   curl https://your-neptune-endpoint:port/sparql \
     -d "update=LOAD <https://s3.amazonaws.com/bucket-name/my-rdf-input/test.rdf>"
   ```

I passaggi precedenti funzionano solo per un bucket Amazon S3 pubblico o per un bucket a cui si accede utilizzando un [URL Amazon S3 prefirmato](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html) nella query LOAD.

 È inoltre possibile impostare un server proxy Web per il caricamento da un bucket Amazon S3 privato, come illustrato di seguito:

**Utilizzare un server Web per caricare file in Neptune con SPARQL UPDATE LOAD**

1. Installa un server Web su una macchina in esecuzione nel VPC che ospita Neptune e i file da caricare. Ad esempio, usando Amazon Linux, puoi installare Apache come segue:

   ```
   sudo yum install httpd mod_ssl
   sudo /usr/sbin/apachectl start
   ```

1. Definisci il tipo/i MIME dei contenuti dei file RDF che andrai a caricare. SPARQL utilizza l'intestazione `Content-type` inviata dal server Web per determinare il formato di input dei contenuti, pertanto è necessario definire i tipi MIME per il server Web.

   Ad esempio, supponiamo che desideri utilizzare le seguenti estensioni di file per identificare i formati di file:
   + `.nt`per. NTriples
   + `.nq`per NQuads.
   + `.trig` per Trig.
   + `.rdf` per RDF/XML.
   + `.ttl` per Turtle.
   + `.n3` per N3.
   + `.jsonld` per JSON-LD.

   Se stai usando Apache 2 come server Web, dovrai modificare il file `/etc/mime.types` e aggiungere i seguenti tipi:

   ```
    text/plain nt
    application/n-quads nq
    application/trig trig
    application/rdf+xml rdf
    application/x-turtle ttl
    text/rdf+n3 n3
    application/ld+json jsonld
   ```

1. Conferma che la mappatura del tipo MIME funziona. Una volta che il server Web è in esecuzione e ospita i file RDF nel formato di tua scelta, puoi testare la configurazione inviando una richiesta al server Web dal tuo host locale.

   Ad esempio, potresti inviare una richiesta di questo tipo:

   ```
   curl -v http://localhost:80/test.rdf
   ```

   Quindi, nell'output dettagliato di `curl`, dovresti visualizzare una riga come questa:

   ```
   Content-Type: application/rdf+xml
   ```

   Questo dimostra che la mappatura del tipo di contenuto è stata definita correttamente.

1. Ora puoi caricare i dati usando il comando SPARQL UPDATE:

   ```
   curl https://your-neptune-endpoint:port/sparql \
       -d "update=LOAD <http://web_server_private_ip:80/test.rdf>"
   ```

**Nota**  
Utilizzando `SPARQL UPDATE LOAD` può attivare un timeout sul server Web quando il file di origine che viene caricato è grande. Neptune elabora i dati del file mentre vengono trasmessi in streaming e per un file di grandi dimensioni che può richiedere più tempo del timeout configurato sul server. Questo a sua volta potrebbe causare la chiusura della connessione del server, che può causare il seguente messaggio di errore quando Neptune incontra un EOF imprevisto nel flusso:  

```
{
  "detailedMessage":"Invalid syntax in the specified file",
  "code":"InvalidParameterException"
}
```
Se si riceve questo messaggio e non si ritiene che il file di origine contenga una sintassi non valida, provare ad aumentare le impostazioni di timeout sul server Web. È inoltre possibile diagnosticare il problema abilitando i registri di debug sul server e cercando i timeout.

# Utilizzo di SPARQL UPDATE UNLOAD per eliminare i dati da Neptune
<a name="sparql-api-reference-unload"></a>

Neptune fornisce anche un'operazione SPARQL personalizzata, `UNLOAD`, per rimuovere i dati specificati in un'origine remota. `UNLOAD` può essere considerata una controparte dell'operazione `LOAD`. La sintassi è:

```
UNLOAD SILENT (URL of the remote data to be unloaded) FROM GRAPH (named graph from which to remove the data)
```
+ **`SILENT`**: (*facoltativo*) fa sì che l'operazione restituisca un esito positivo anche se si è verificato un errore durante l'elaborazione dei dati.

  Ciò può essere utile quando una singola transazione contiene più istruzioni come `"LOAD ...; LOAD ...; UNLOAD ...; LOAD ...;"` e si desidera che la transazione venga completata anche se non è stato possibile elaborare alcuni dati remoti.
+ *URL of the remote data to be unloaded*— (*Obbligatorio*) specifica un file di dati remoto contenente dati da scaricare da un grafico.

  Il file remoto deve avere una delle seguenti estensioni (sono gli stessi formati supportati da UPDATE-LOAD):
  + `.nt`per. NTriples
  + `.nq`per NQuads.
  + `.trig` per Trig.
  + `.rdf` per RDF/XML.
  + `.ttl` per Turtle.
  + `.n3` per N3.
  + `.jsonld` per JSON-LD.

  Tutti i dati contenuti in questo file verranno rimossi dal cluster database dall'operazione `UNLOAD`.

  Qualsiasi autenticazione Amazon S3 deve essere inclusa nell'URL affinché i dati vengano scaricati. Puoi prefirmare un file Amazon S3 e quindi utilizzare l'URL risultante per accedervi in modo sicuro. Esempio:

  ```
  aws s3 presign --expires-in (number of seconds) s3://(bucket name)/(path to file of data to unload)
  ```

  Quindi:

  ```
  curl https://(a Neptune endpoint URL):8182/sparql \
    --data-urlencode 'update=unload (pre-signed URL of the remote Amazon S3 data to be unloaded) \
                             from graph (named graph)'
  ```

  Per ulteriori informazioni, consulta [Autenticazione delle richieste: utilizzo dei parametri di query](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html).
+ **`FROM GRAPH `***(named graph from which to remove the data)*— (*Facoltativo*) Speciifica il grafico denominato da cui devono essere scaricati i dati remoti.

  Neptune associa ogni tripla a un grafo nominato. È possibile specificare il grafo nominato predefinito utilizzando l'URI di fallback del grafo nominato, `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`, in questo modo:

  ```
  FROM GRAPH <http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph>
  ```

Nello stesso modo in cui `LOAD` corrisponde a `INSERT DATA { (inline data) }`, `UNLOAD` corrisponde a `DELETE DATA { (inline data) }`. Analogamente a `DELETE DATA`, `UNLOAD` non funziona su dati che contengono nodi vuoti.

Ad esempio, se un server Web locale serve un file denominato `data.nt` che contiene le seguenti 2 triple:

```
<http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#b> .
<http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#c> .
```

Il comando `UNLOAD` seguente eliminerà queste due triple dal grafo nominato `<http://example.org/graph1>`:

```
UNLOAD <http://localhost:80/data.nt> FROM GRAPH <http://example.org/graph1>
```

Ciò avrà lo stesso effetto dell'utilizzo del comando `DELETE DATA` seguente:

```
DELETE DATA {
  GRAPH <http://example.org/graph1> {
    <http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#b> .
    <http://example.org/resource#a> <http://example.org/resource#p> <http://example.org/resource#c> .
  }
}
```

**Eccezioni generate dal comando `UNLOAD`**
+ **`InvalidParameterException`**: sono presenti nodi vuoti nei dati. *Stato HTTP*: 400 Richiesta non valida.

  *Messaggio*: ` Blank nodes are not allowed for UNLOAD`

   
+ **`InvalidParameterException`**: sintassi non corretta nei dati. *Stato HTTP*: 400 Richiesta non valida.

  *Messaggio*: `Invalid syntax in the specified file.`

   
+ **`UnloadUrlAccessDeniedException `**: accesso negato. *Stato HTTP*: 400 Richiesta non valida.

  *Messaggio*: `Update failure: Endpoint (Neptune endpoint) reported access denied error. Please verify access.`

   
+ **`BadRequestException `**: non è possibile recuperare i dati remoti. *Stato HTTP*: 400 Richiesta non valida.

  *Messaggio*: *(dipende dalla risposta HTTP).*

# Hint di query SPARQL
<a name="sparql-query-hints"></a>

È possibile utilizzare gli hint di query per specificare le strategie di ottimizzazione e valutazione per una determinata query SPARQL in Amazon Neptune. 

Gli hint di query vengono espressi utilizzando i modelli di tripla aggiuntivi incorporati nella query SPARQL con le seguenti parti:

```
scope hint value
```
+ *ambito*: determina la parte della query alla quale si applica l'hint di query, come un determinato gruppo nella query o l'intera query.
+ *hint*: identifica il tipo di hint da applicare.
+ *value*: determina il comportamento dell'aspetto del sistema in esame.

Gli ambiti e gli hint di query vengono esposti come termini predefiniti nello spazio dei nomi di Amazon Neptune `http://aws.amazon.com/neptune/vocab/v01/QueryHints#`. Gli esempi di questa sezione includono lo spazio dei nomi come un prefisso `hint` definito e incluso nella query:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```

Ad esempio, la seguente procedura mostra come includere un hint `joinOrder` in una query `SELECT`:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ... {
 hint:Query hint:joinOrder "Ordered" .
 ...
}
```

La query precedente indica al motore Neptune di valutare i join nella query nell'ordine *specificato* e disabilita qualsiasi riordinamento automatico.

Considera le informazioni seguenti durante l'utilizzo dei suggerimenti di query:
+ È possibile combinare diversi suggerimenti di query in una singola richiesta. Ad esempio, è possibile utilizzare l'hint di query `bottomUp` per annotare una sottoquery per una valutazione dal basso verso l'alto e un hint di query `joinOrder` per correggere il join all'interno della sottoquery.
+ È possibile utilizzare lo stesso hint di query più volte, in diversi ambiti non sovrapposti.
+ I suggerimenti di query sono suggerimenti. Sebbene il motore di query generalmente miri a considerare determinati suggerimenti di query, potrebbe anche ignorarli.
+ Per i suggerimenti di query si applica la conservazione della semantica. L'aggiunta di un hint di query non modifica l'output della query (ad eccezione dell'ordine dei potenziali risultati quando non vengono fornite garanzie di ordinamento, ovvero quando l'ordine dei risultati non è esplicitamente applicato utilizzando ORDER BY). 

Le seguenti sezioni forniscono ulteriori informazioni sugli hint di query disponibili e il relativo utilizzo in Neptune.

**Topics**
+ [

## Ambito degli hint di query SPARQL in Neptune
](#sparql-query-hints-scope)
+ [

# Hint di query SPARQL `joinOrder`
](sparql-query-hints-joinOrder.md)
+ [

# Hint di query SPARQL `evaluationStrategy`
](sparql-query-hints-evaluationStrategy.md)
+ [

# Hint di query SPARQL `queryTimeout`
](sparql-query-hints-queryTimeout.md)
+ [

# Hint di query SPARQL `rangeSafe`
](sparql-query-hints-rangeSafe.md)
+ [

# Hint di query SPARQL `queryId`
](sparql-query-hints-queryId.md)
+ [

# Hint di query SPARQL `useDFE`
](sparql-query-hints-useDFE.md)
+ [

# Hint di query SPARQL utilizzati con DESCRIBE
](sparql-query-hints-for-describe.md)

## Ambito degli hint di query SPARQL in Neptune
<a name="sparql-query-hints-scope"></a>

La tabella che segue mostra gli ambiti disponibili, gli hint associati e le descrizioni per gli hint di query SPARQL in Amazon Neptune. Il prefisso `hint` in queste voci rappresenta lo spazio dei nomi Neptune per gli hint:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
```


| Scope | Hint supportato | Description | 
| --- | --- | --- | 
| hint:Query | [joinOrder](sparql-query-hints-joinOrder.md) | L'hint di query si applica all'intera query. | 
| hint:Query | [queryTimeout](sparql-query-hints-queryTimeout.md) | Il valore di timeout si applica all'intera query. | 
| hint:Query | [rangeSafe](sparql-query-hints-rangeSafe.md) | La promozione dei tipi è disabilitata per l'intera query. | 
| hint:Query | [queryId](sparql-query-hints-queryId.md) | Il valore dell'ID della query si applica all'intera query. | 
| hint:Query | [useDFE](sparql-query-hints-useDFE.md) | L'uso del motore DFE è abilitato (o disabilitato) per l'intera query. | 
| hint:Group | [joinOrder](sparql-query-hints-joinOrder.md) | L'hint di query si applica agli elementi di primo livello nel gruppo specificato, ma non agli elementi nidificati (come le sottoquery) o agli elementi padre. | 
| hint:SubQuery | [evaluationStrategy](sparql-query-hints-evaluationStrategy.md) | l'hint viene specificato e applicato a una sottoquery SELECT nidificata. La sottoquery viene valutata in modo indipendente, senza considerare le soluzioni calcolate prima della sottoquery. | 

# Hint di query SPARQL `joinOrder`
<a name="sparql-query-hints-joinOrder"></a>

Quando invii una query SPARQL, il motore di query Amazon Neptune controlla la struttura della query. Riordina le parti della query e tenta di ridurre al minimo la quantità di lavoro richiesta per la valutazione e il tempo di risposta della query.

Ad esempio, una sequenza di modelli di tripla collegati non viene generalmente valutata nell'ordine specificato. Viene riordinato utilizzando l'euristica e le statistiche come la selettività dei singoli modelli e il modo in cui sono collegati tramite variabili condivise. Inoltre, se la tua query contiene modelli più complessi come sottoquery o blocchi OPTIONAL o MINUS complessi FILTERs, il motore di query Neptune li riordina ove possibile, con l'obiettivo di un ordine di valutazione efficiente.

Per richieste più complesse, l'ordine nel quale Neptune sceglie di valutare la query potrebbe non essere sempre ottimale. Ad esempio, è possibile che Neptune non consideri caratteristiche specifiche dei dati dell'istanza (come la possibilità di raggiungere nodi di potenza nel grafo) che emergono durante la valutazione delle query.

Se conosci le caratteristiche esatte dei dati e desideri indicare manualmente l'ordine di esecuzione della query, utilizza l'hint di query Neptune `joinOrder` per specificare che la query deve essere valutata nell'ordine specificato.

## Sintassi dell'hint SPARQL `joinOrder`
<a name="sparql-query-hints-joinOrder-syntax"></a>

l'hint di query `joinOrder` viene specificato come modello di tripla incluso in una query SPARQL.

Per chiarezza, la sintassi seguente utilizza un prefisso `hint` definito e incluso nella query per specificare lo spazio dei nomi dell'hint di query Neptune:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
scope hint:joinOrder "Ordered" .
```

**Ambiti disponibili**
+ `hint:Query`
+ `hint:Group`

Per ulteriori informazioni sugli ambiti dei suggerimenti di query, consulta [Ambito degli hint di query SPARQL in Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Esempio dell'hint SPARQL `joinOrder`
<a name="sparql-query-hints-joinOrder-example"></a>

Questa sezione mostra una query scritta con e senza l'hint di query `joinOrder` e le ottimizzazioni correlate.

Per questo esempio si presuppone che il set di dati contenga quanto segue:
+ Una sola persona di nome `John` che `:likes` 1000 persone, inclusa `Jane`.
+ Una sola persona di nome `Jane` che `:likes` 10 persone, incluso `John`.

**Nessun hint di query**  
La seguente query SPARQL estrae tutte le coppie di persone di nome `John` e `Jane` che hanno specificato "like" reciprocamente da un set di dati di social networking:

```
PREFIX : <https://example.com/>
SELECT ?john ?jane {
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

Il motore di query Neptune può valutare le istruzioni in un ordine diverso rispetto a quello scritto. Ad esempio, potrebbe scegliere di valutare nel seguente ordine:

1. Trova tutte le persone di nome `John`.

1. Trova tutte le persone collegate a `John` con un edge `:likes`.

1. Filtra questo set in base alle persone di nome `Jane`.

1. Filtra questo set in base alle persone collegate a `John` con un edge `:likes`.

In base al set di dati, la valutazione in questo ordine comporta l'estrazione di 1.000 entità nel secondo passaggio. Il terzo passaggio limita ulteriormente la valutazione fino al singolo nodo `Jane`. Il passaggio finale determina che anche `Jane` ha specificato `:likes` per il nodo `John`.

**hint di query**  
Sarebbe preferibile iniziare con il nodo `Jane` perché ha solo 10 edge `:likes` in uscita. Ciò riduce la quantità di lavoro durante la valutazione della query evitando l'estrazione delle 1.000 entità durante il secondo passaggio.

L'esempio seguente usa l'hint di query **joinOrder** per assicurare che il nodo `Jane` e i relativi archi in uscita vengano elaborati per primi disabilitando il riordinamento automatico di tutti i join per la query:

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

Uno scenario applicabile del mondo reale potrebbe essere un'applicazione di social network in cui le persone nella rete sono classificate come influencer con molte connessioni o come utenti normali con poche connessioni. In tale scenario, puoi garantire che l'utente normale (`Jane`) venga elaborato prima dell'influencer (`John`) in una query come nell'esempio precedente.

**hint di query e riordinamento**  
Puoi eseguire questo esempio per aumentare le tue conoscenze. Se sai che l'attributo `:name` è univoco per un singolo nodo, puoi velocizzare la query tramite il riordinamento e utilizzando l'hint di query `joinOrder`. In questo modo, i nodi univoci vengono estratti per primi.

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ?john ?jane {
  hint:Query hint:joinOrder "Ordered" .
  ?person1 :name "Jane" .
  ?person2 :name "John" .
  ?person1 :likes ?person2 .
  ?person2 :likes ?person1 .
}
```

In questo caso, puoi limitare la query alle seguenti singole operazioni in ciascuna fase:

1. Trova il nodo della singola persona con `:name` `Jane`.

1. Trova il nodo della singola persona con `:name` `John`.

1. Controlla che il primo nodo sia collegato al secondo con un edge `:likes`.

1. Controlla che il secondo nodo sia collegato al primo con un edge `:likes`.



**Importante**  
Se scegli l'ordine non corretto, l'hint di query `joinOrder` può causare una notevole riduzione delle prestazioni. Ad esempio, l'esempio precedente sarebbe inefficiente se gli attributi `:name` non sono univoci. Se tutti i 100 nodi sono stati denominati `Jane` e tutti i 1.000 nodi sono stati denominati `John`, la query finirebbe per controllare 1.000 \$1 100 (100.000) coppie di edge `:likes`.

# Hint di query SPARQL `evaluationStrategy`
<a name="sparql-query-hints-evaluationStrategy"></a>

L'hint di query `evaluationStrategy` indica al motore di query Amazon Neptune che il frammento della query annotata deve essere valutato dal basso verso l'alto come unità indipendente. Ciò significa che non vengono utilizzate le soluzioni dei precedenti passaggi di valutazione per calcolare il frammento della query. Il frammento di query viene valutato come un'unità indipendente e le soluzioni prodotte vengono unite al resto della query dopo che è stata calcolata.

L'uso dell'hint di query `evaluationStrategy` implica un piano di query di blocco (non pipeline), ovvero le soluzioni del frammento annotato con l'hint di query sono materializzate e memorizzate nella memoria principale. L'uso di questo hint di query può aumentare significativamente la quantità di memoria principale necessaria per valutare la query, soprattutto se il frammento di query annotato calcola un numero elevato di risultati.

## Sintassi dell'hint SPARQL `evaluationStrategy`
<a name="sparql-query-hints-evaluationStrategy-syntax"></a>

l'hint di query `evaluationStrategy` viene specificato come modello di tripla incluso in una query SPARQL.

Per chiarezza, la sintassi seguente utilizza un prefisso `hint` definito e incluso nella query per specificare lo spazio dei nomi dell'hint di query Neptune:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
hint:SubQuery hint:evaluationStrategy "BottomUp" .
```

**Ambiti disponibili**
+ `hint:SubQuery`

**Nota**  
Questo hint di query è supportato solo nelle sottoquery nidificate.

Per ulteriori informazioni sugli ambiti dei suggerimenti di query, consulta [Ambito degli hint di query SPARQL in Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Esempio dell'hint SPARQL `evaluationStrategy`
<a name="sparql-query-hints-evaluationStrategy-example"></a>



Questa sezione mostra una query scritta con e senza l'hint di query `evaluationStrategy` e le ottimizzazioni correlate.

Per questo esempio si presuppone che il set di dati abbia le seguenti caratteristiche:
+ Contiene 1.000 edge con etichetta `:connectedTo`.
+ Ogni nodo `component` è connesso a una media di altri 100 nodi `component`.
+ Il numero tipico di connessioni cicliche a quattro hop tra i nodi è di circa 100.

In un tipico esempio, l'hint `evaluationStrategy` può essere utile per ottimizzare i modelli di query contenenti cicli.

**Nessun hint di query**  
La seguente query SPARQL estrae tutti i nodi `component` che sono ciclicamente collegati tra loro mediante quattro hop:

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
  ?component1 :connectedTo ?component2 .
  ?component2 :connectedTo ?component3 .
  ?component3 :connectedTo ?component4 .
  ?component4 :connectedTo ?component1 .
}
```

L'approccio del motore di query Neptune è quello di valutare questa query utilizzando i seguenti passaggi:
+ Estrai tutti i 1.000 edge `connectedTo` nel grafico.
+ Espandi per 100x (il numero di edge `connectedTo` in uscita dal component2).

  Risultati intermedi: 100.000 nodi.
+ Espandi per 100x (il numero di edge `connectedTo` in uscita dal component3).

  Risultati intermedi: 10.000.000 nodi.
+ Analizza i 10.000.000 nodi per il ciclo chiuso.

Ciò si traduce in un piano di query in streaming che ha una quantità costante di memoria principale.

**hint di query e sottoquery**  
Potresti voler scambiare lo spazio di memoria principale per il calcolo accelerato. Riscrivendo la query utilizzando un hint di query `evaluationStrategy` è possibile forzare il motore a calcolare un join tra due sottoinsiemi più piccoli e materializzati.

```
PREFIX : <https://example.com/>
          PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
  {
    SELECT * WHERE {
      hint:SubQuery hint:evaluationStrategy "BottomUp" .
      ?component1 :connectedTo ?component2 .
      ?component2 :connectedTo ?component3 .
    }
  }
  {
    SELECT * WHERE {
      hint:SubQuery hint:evaluationStrategy "BottomUp" .
      ?component3 :connectedTo ?component4 .
      ?component4 :connectedTo ?component1 .
    }
  }
}
```

Invece di valutare i modelli di tripla in sequenza mentre vengono utilizzati in modo iterativo i risultati del modello di tripla precedente come input per i successivi modelli, l'hint `evaluationStrategy` fa in modo che le due sottoquery vengano valutate in modo indipendente. Entrambe le sottoquery producono 100.000 nodi per i risultati intermedi che vengono quindi uniti per formare l'output finale. 

In particolare, quando esegui Neptune nei tipi di istanza più grandi, l'archiviazione temporanea di questi due sottoinsiemi da 100.000 nodi nella memoria principale aumenta l'utilizzo della memoria in cambio di una significativa accelerazione della valutazione.

# Hint di query SPARQL `queryTimeout`
<a name="sparql-query-hints-queryTimeout"></a>

l'hint di query `queryTimeout` specifica un timeout più breve rispetto al valore `neptune_query_timeout` impostato nel gruppo di parametri di database.

Se la query termina come risultato di questo hint, viene generata un'eccezione `TimeLimitExceededException`, con un messaggio `Operation terminated (deadline exceeded)`.

## Sintassi dell'hint SPARQL `queryTimeout`
<a name="sparql-query-hints-queryTimeout-syntax"></a>

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT ... WHERE {
    hint:Query hint:queryTimeout 10 .
    # OR
    hint:Query hint:queryTimeout "10" .
    # OR
    hint:Query hint:queryTimeout "10"^^xsd:integer .
 ...
}
```

Il valore di timeout viene espresso in millisecondi.

Il valore di timeout deve essere inferiore al valore `neptune_query_timeout` impostato nel gruppo di parametri di database. In caso contrario, viene generata un'eccezione `MalformedQueryException` con un messaggio `Malformed query: Query hint 'queryTimeout' must be less than neptune_query_timeout DB Parameter Group`.

l'hint di query `queryTimeout` dovrebbe essere specificato nella clausola `WHERE` della query principale oppure nella clausola `WHERE` di una delle sottoquery, come illustrato nell'esempio seguente.

Deve essere impostato una sola volta in tutte le sezioni queries/subqueries e SPARQL Updates (come INSERT e DELETE). In caso contrario, viene generata un'eccezione `MalformedQueryException` con un messaggio `Malformed query: Query hint 'queryTimeout' must be set only once`.

**Ambiti disponibili**

L'hint `queryTimeout` può essere applicato sia alle query sia agli aggiornamenti SPARQL.
+ In una query SPARQL, può comparire nella clausola WHERE della query principale o di una sottoquery.
+ In un aggiornamento SPARQL, può essere impostato nella clausola INSERT, DELETE o WHERE. Se sono presenti più clausole di aggiornamento, può essere impostato solo in una di esse.

Per ulteriori informazioni sugli ambiti dei suggerimenti di query, consulta [Ambito degli hint di query SPARQL in Neptune](sparql-query-hints.md#sparql-query-hints-scope).

## Esempio dell'hint SPARQL `queryTimeout`
<a name="sparql-query-hints-queryTimeout-example"></a>

Di seguito è illustrato un esempio di utilizzo di `hint:queryTimeout` nella clausola `WHERE` principale di una query `UPDATE`:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
INSERT {
    ?s ?p ?o
} WHERE {
    hint:Query hint:queryTimeout 100 .
    ?s ?p ?o .
}
```

Di seguito, `hint:queryTimeout` si trova nella clausola `WHERE` di una sottoquery:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
   ?s ?p ?o .
   {
      SELECT ?s WHERE {
         hint:Query hint:queryTimeout 100 .
         ?s ?p1 ?o1 .
      }
   }
}
```

# Hint di query SPARQL `rangeSafe`
<a name="sparql-query-hints-rangeSafe"></a>

Usare questo hint di query per disattivare la promozione dei tipi per una query SPARQL.

Quando invii una query SPARQL che include un oggetto `FILTER` su un valore o intervallo numerico, il motore di query Neptune deve normalmente utilizzare la promozione dei tipi quando esegue la query. Ciò significa che deve esaminare i valori di ogni tipo che potrebbe contenere il valore in base al quale stai filtrando.

Ad esempio, se filtri per valori pari a 55, il motore deve cercare numeri interi pari a 55, numeri interi long pari a 55L, numeri a virgola mobile pari a 55.0 e così via. Ogni promozione di tipo richiede una ricerca aggiuntiva nell'archiviazione, che può far sì che una query apparentemente semplice richieda un tempo inaspettatamente lungo per essere completata.

Spesso la promozione dei tipi non è necessaria perché si sa in anticipo che è necessario trovare solo valori di un tipo specifico. In questo caso, puoi velocizzare notevolmente le query utilizzando l'hint di query `rangeSafe` per disattivare la promozione dei tipi.

## Sintassi dell'hint SPARQL `rangeSafe`
<a name="sparql-query-hints-rangeSafe-syntax"></a>

L'hint di query `rangeSafe` accetta il valore `true` per disattivare la promozione dei tipi. Accetta anche il valore `false` (impostazione predefinita).

**Esempio.** L'esempio seguente mostra come disattivare la promozione dei tipi quando si filtra per un valore intero `o` maggiore di 1:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * {
   ?s ?p ?o .
   hint:Prior hint:rangeSafe 'true' .
   FILTER (?o > '1'^^<http://www.w3.org/2001/XMLSchema#int>)
```

# Hint di query SPARQL `queryId`
<a name="sparql-query-hints-queryId"></a>

Utilizza questo hint di query per assegnare il tuo valore queryId a una query SPARQL.

Esempio:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
SELECT * WHERE {
  hint:Query hint:queryId "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47"
  {?s ?p ?o}}
```

Il valore assegnato deve essere univoco per tutte le query nel database Neptune.

# Hint di query SPARQL `useDFE`
<a name="sparql-query-hints-useDFE"></a>

Utilizzare questo hint di query per abilitare l'uso del motore DFE per l'esecuzione della query. Per impostazione predefinita, Neptune non utilizza il motore DFE senza che questo hint di query sia impostato su `true`, poiché il parametro di istanza [neptune\$1dfe\$1query\$1engine](parameters.md#parameters-instance-parameters-neptune_dfe_query_engine) è impostato su `viaQueryHint`. Se imposti il parametro di istanza su `enabled`, il motore DFE viene utilizzato per tutte le query ad eccezione di quelle con l'hint di query `useDFE` impostato su `false`.

Esempio di abilitazione dell'uso del motore DFE per una query:

```
PREFIX : <https://example.com/>
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>

SELECT ?john ?jane
{
  hint:Query hint:useDFE true .
  ?person1 :name "Jane" .
  ?person1 :likes ?person2 .
  ?person2 :name "John" .
  ?person2 :likes ?person1 .
}
```

# Hint di query SPARQL utilizzati con DESCRIBE
<a name="sparql-query-hints-for-describe"></a>

Una query SPARQL `DESCRIBE` fornisce un meccanismo flessibile per richiedere descrizioni di risorse. Tuttavia, le specifiche SPARQL non definiscono la semantica precisa di `DESCRIBE`.

A partire dal [rilascio 1.2.0.2 del motore](engine-releases-1.2.0.2.md), Neptune supporta diverse modalità e algoritmi `DESCRIBE` adatti a diverse situazioni.

Questo set di dati di esempio può aiutare a illustrare le diverse modalità:

```
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix : <https://example.com/> .

:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JohnDoe :firstName "John" .
:JaneDoe :knows _:b1 .
_:b1 :knows :RichardRoe .

:RichardRoe :knows :JaneDoe .
:RichardRoe :firstName "Richard" .

_:s1 rdf:type rdf:Statement .
_:s1 rdf:subject :JaneDoe .
_:s1 rdf:predicate :knows .
_:s1 rdf:object :JohnDoe .
_:s1 :knowsFrom "Berlin" .

:ref_s2 rdf:type rdf:Statement .
:ref_s2 rdf:subject :JaneDoe .
:ref_s2 rdf:predicate :knows .
:ref_s2 rdf:object :JohnDoe .
:ref_s2 :knowsSince 1988 .
```

Gli esempi seguenti presuppongono che venga richiesta una descrizione della risorsa `:JaneDoe` utilizzando una query SPARQL in questo modo:

```
DESCRIBE <https://example.com/JaneDoe>
```

## Hint di query SPARQL `describeMode`
<a name="sparql-query-hints-describeMode"></a>

L'hint di query SPARQL `hint:describeMode` viene utilizzato per selezionare una delle seguenti modalità SPARQL `DESCRIBE` supportate da Neptune:

### Modalità DESCRIBE `ForwardOneStep`
<a name="sparql-query-hints-describeMode-ForwardOneStep"></a>

È possibile richiamare la modalità `ForwardOneStep` con l'hint di query `describeMode` in questo modo:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "ForwardOneStep"
}
```

La modalità `ForwardOneStep` restituisce solo gli attributi e i collegamenti diretti della risorsa da descrivere. Nel caso di esempio, ciò significa che restituisce le triple che hanno `:JaneDoe`, la risorsa da descrivere, come oggetto:

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b301990159 .
```

Nota che la query DESCRIBE può restituire triple con nodi vuoti, ad esempio`_:b301990159`, che sono IDs ogni volta diverse rispetto al set di dati di input.

### Modalità DESCRIBE `SymmetricOneStep`
<a name="sparql-query-hints-describeMode-SymmetricOneStep"></a>

`SymmetricOneStep` è la modalità DESCRIBE predefinita se non si fornisce un hint di query. Puoi anche richiamarlo esplicitamente con l'hint di query `describeMode` in questo modo:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SymmetricOneStep"
}
```

Nella semantica `SymmetricOneStep`, `DESCRIBE` restituisce gli attributi, i collegamenti diretti e i collegamenti inversi della risorsa da descrivere:

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b318767375 .

_:b318767631 rdf:subject :JaneDoe .

:RichardRoe :knows :JaneDoe .

:ref_s2 rdf:subject :JaneDoe .
```

### Modalità DESCRIBE Concise Bounded Description (`CBD`)
<a name="sparql-query-hints-describeMode-CBD"></a>

La modalità Concise Bounded Description (`CBD`) viene richiamata utilizzando l'hint di query `describeMode` in questo modo:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "CBD"
}
```

Nella semantica `CBD`, `DESCRIBE` restituisce la modalità Concise Bounded Description (come [definito da W3C](http://www.w3.org/Submission/CBD)) della risorsa da descrivere:

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b285212943 .
_:b285212943 :knows :RichardRoe .

_:b285213199 rdf:subject :JaneDoe .
_:b285213199 rdf:type rdf:Statement .
_:b285213199 rdf:predicate :knows .
_:b285213199 rdf:object :JohnDoe .
_:b285213199 :knowsFrom "Berlin" .

:ref_s2 rdf:subject :JaneDoe .
```

La Concise Bounded Description di una risorsa RDF (ovvero un nodo in un grafo RDF) è il sottografo più piccolo incentrato su quel nodo che può essere autonomo. In pratica ciò significa che se si pensa a questo grafo come a un albero, con il nodo designato come radice, non ci sono nodi vuoti (bnodi) come foglie di quell'albero. Poiché i bnodi non possono essere indirizzati esternamente o utilizzati nelle query successive, per l'esplorazione del grafo non è sufficiente trovare i singoli hop successivi dal nodo corrente. Devi anche andare abbastanza lontano per trovare qualcosa che possa essere usato nelle query successive (cioè qualcosa di diverso da un bnodo).

#### Calcolo della CBD
<a name="sparql-query-hints-describeMode-CBD-computing"></a>

Dato un particolare nodo (il nodo iniziale o radice) nel grafo RDF di origine, la CBD di quel nodo viene calcolata come segue:

1. Includere nel sottografo tutte le istruzioni del grafo di origine in cui il *soggetto* dell'istruzione è il nodo iniziale.

1. Ricorsivamente, per tutte le istruzioni del sottografo che finora hanno un *oggetto* nodo vuoto, includere nel sottografo tutte le istruzioni del grafo di origine in cui il *soggetto* dell'istruzione è quel nodo vuoto e che non sono già incluse nel sottografo.

1. Ricorsivamente, per tutte le istruzioni incluse nel sottografo finora, per tutte le reificazioni di queste istruzioni del grafo di origine, includere la CBD a partire dal nodo `rdf:Statement` di ogni reificazione.

Si ottiene così un sottografo in cui i nodi *oggetto* sono riferimenti o valori letterali IRI oppure nodi vuoti che non fungono da *soggetto* di alcuna istruzione del grafo. Notare che la CBD non può essere calcolata utilizzando una singola query SPARQL SELECT o CONSTRUCT.

### Modalità DESCRIBE Symmetric Concise Bounded Description (`SCBD`)
<a name="sparql-query-hints-describeMode-SCBD"></a>

La modalità Symmetric Concise Bounded Description (`SCBD`) viene richiamata utilizzando l'hint di query `describeMode` in questo modo:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE <https://example.com/JaneDoe>
{
  hint:Query hint:describeMode "SCBD"
}
```

Nella semantica `SCBD`, `DESCRIBE` restituisce la Symmetric Concise Bounded Description della risorsa (come definito da W3C in [Describing Linked Datasets with the VOID Vocabulary)](http://www.w3.org/TR/void/):

```
:JaneDoe :firstName "Jane" .
:JaneDoe :knows :JohnDoe .
:JaneDoe :knows _:b335544591 .
_:b335544591 :knows :RichardRoe .

:RichardRoe :knows :JaneDoe .

_:b335544847 rdf:subject :JaneDoe .
_:b335544847 rdf:type rdf:Statement .
_:b335544847 rdf:predicate :knows .
_:b335544847 rdf:object :JohnDoe .
_:b335544847 :knowsFrom "Berlin" .

:ref_s2 rdf:subject :JaneDoe .
```

Il vantaggio di CBD e SCBD rispetto alle modalità `ForwardOneStep` e `SymmetricOneStep` è che i nodi vuoti vengono sempre espansi per includere la relativa rappresentazione. Questo può essere un vantaggio importante perché non è possibile eseguire query su un nodo vuoto utilizzando SPARQL. Inoltre, le modalità CBD e SCBD considerano anche le reificazioni.

Notare che l'hint di query `describeMode` può anche far parte di una clausola `WHERE`:

```
PREFIX hint: <http://aws.amazon.com/neptune/vocab/v01/QueryHints#>
DESCRIBE ?s
WHERE {
  hint:Query hint:describeMode "CBD" .
  ?s rdf:type <https://example.com/Person>
}
```

## Hint di query SPARQL `describeIterationLimit`
<a name="sparql-query-hints-describeIterationLimit"></a>

L'hint di query SPARQL `hint:describeIterationLimit` fornisce un vincolo **opzionale** sul numero massimo di espansioni iterative da eseguire per gli algoritmi DESCRIBE iterativi come CBD e SCBD.

I limiti di DESCRIBE coincidono ANDed . Pertanto, se vengono specificati sia il limite di iterazione che il limite di istruzioni, entrambi i limiti devono essere soddisfatti prima che la query DESCRIBE venga interrotta.

Il valore predefinito per questo valore è 5. È possibile impostarlo su ZERO (0) per specificare NESSUN limite al numero di espansioni iterative.

## Hint di query SPARQL `describeStatementLimit`
<a name="sparql-query-hints-describeStatementLimit"></a>

L'hint di query SPARQL `hint:describeStatementLimit` fornisce un vincolo **opzionale** sul numero massimo di istruzioni che possono essere presenti in una risposta alla query DESCRIBE. Viene applicato solo per algoritmi DESCRIBE iterativi come CBD e SCBD.

DESCRIVI i limiti ANDed coincidono. Pertanto, se vengono specificati sia il limite di iterazione che il limite di istruzioni, entrambi i limiti devono essere soddisfatti prima che la query DESCRIBE venga interrotta.

Il valore predefinito per questo valore è 5000. È possibile impostarlo su ZERO (0) per specificare NESSUN limite al numero di istruzioni restituite.

# Comportamento di SPARQL DESCRIBE rispetto al grafo predefinito
<a name="sparql-default-describe"></a>

Il modulo di query SPARQL [https://www.w3.org/TR/sparql11-query/#describe](https://www.w3.org/TR/sparql11-query/#describe) consente di recuperare informazioni sulle risorse senza conoscere la struttura dei dati e senza dover comporre una query. Il modo in cui queste informazioni vengono assemblate dipende dall'implementazione SPARQL. Neptune fornisce [diversi hint di query](sparql-query-hints-for-describe.md) che richiamano diverse modalità e algoritmi da utilizzare per `DESCRIBE`.

Nell'implementazione di Neptune, indipendentemente dalla modalità, `DESCRIBE` utilizza solo i dati presenti nel [grafo SPARQL predefinito](feature-sparql-compliance.md#sparql-default-graph). Ciò è coerente con il modo in cui SPARQL tratta i set di dati (vedi [Specifying RDF Datasets](https://www.w3.org/TR/sparql11-query/#specifyingDataset) nella specifica SPARQL).

In Neptune, il grafico predefinito contiene tutte le triple univoche nell'unione di tutti i grafici denominati nel database, a meno che particolari grafici con nome non vengano specificati utilizzando clausole. `FROM` and/or `FROM NAMED` Tutti i dati RDF in Neptune sono archiviati in un grafo nominato. Se una tripla viene inserita senza un contesto del grafo nominato, Neptune la archivia in un grafo nominato designato `http://aws.amazon.com/neptune/vocab/v01/DefaultNamedGraph`.

Quando uno o più grafi nominati vengono specificati utilizzando la clausola `FROM`, il grafo predefinito è l'unione di tutte le triple univoche presenti in tali grafi nominati. Se non è presente alcuna clausola `FROM` e sono presenti una o più clausole `FROM NAMED`, il grafo predefinito è vuoto.

## Esempi di SPARQL `DESCRIBE`
<a name="sparql-default-describe-examples"></a>

Considerare i dati seguenti:

```
PREFIX ex: <https://example.com/>

GRAPH ex:g1 {
    ex:s ex:p1 "a" .
    ex:s ex:p2 "c" .
}

GRAPH ex:g2 {
    ex:s ex:p3 "b" .
    ex:s ex:p2 "c" .
}

ex:s ex:p3 "d" .
```

Per questa query:

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s
FROM ex:g1
FROM NAMED ex:g2
WHERE {
  GRAPH ex:g2 { ?s ?p "b" . }
}
```

Neptune restituirà:

```
ex:s ex:p1 "a" .
ex:s ex:p2 "c" .
```

In questo caso, il modello di grafo `GRAPH ex:g2 { ?s ?p "b" }` viene valutato per primo, ottenendo le associazioni per `?s` e quindi la parte `DESCRIBE` viene valutata rispetto al grafo predefinito, che ora è solo `ex:g1`.

Tuttavia, per questa query:

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
FROM NAMED ex:g1 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

Neptune non restituirà nulla, perché quando è presente una clausola `FROM NAMED` senza una clausola `FROM`, il grafo predefinito è vuoto.

Nella seguente query, `DESCRIBE` viene utilizzato senza che sia presente una clausola `FROM` o `FROM NAMED`:

```
PREFIX ex: <https://example.com/>
DESCRIBE ?s 
WHERE { 
  GRAPH ex:g1 { ?s ?p "a" . } 
}
```

In questa situazione, il grafo predefinito è composto da tutte le triple univoche nell'unione di tutti i grafi nominati nel database (formalmente, l'unione RDF), quindi Neptune restituirà:

```
ex:s ex:p1 "a" . 
ex:s ex:p2 "c" . 
ex:s ex:p3 "b" .
ex:s ex:p3 "d" .
```

# API di stato delle query SPARQL
<a name="sparql-api-status"></a>

Per ottenere lo stato delle query SPARQL, utilizza l'operazione HTTP `GET` o `POST` per effettuare una richiesta all'endpoint `https://your-neptune-endpoint:port/sparql/status`. 

## Parametri della richiesta di stato della query SPARQL
<a name="sparql-api-status-get-request"></a>

**queryId (opzionale)**  
L'ID di una query SPARQL in esecuzione. Viene mostrato solo lo stato della query specificata.

## Sintassi della risposta di stato della query SPARQL
<a name="sparql-api-status-get-response-syntax"></a>

```
{
    "acceptedQueryCount": integer,
    "runningQueryCount": integer,
    "queries": [
      {
        "queryId":"guid",
        "queryEvalStats":
          {
            "subqueries": integer,
            "elapsed": integer,
            "cancelled": boolean
          },
        "queryString": "string"
      }
    ]
}
```

## Valori della risposta di stato della query SPARQL
<a name="sparql-api-status-get-response-values"></a>

**acceptedQueryCount**  
Numero di query accettate dall'ultimo riavvio del motore Neptune.

**runningQueryCount**  
Il numero delle query SPARQL in esecuzione.

**queries**  
Un elenco delle query SPARQL correnti.

**queryId**  
Un ID GUID per la query. Neptune assegna automaticamente questo valore ID a ogni query oppure è possibile assegnare un ID personalizzato (consulta [Inserimento di un ID personalizzato in una query Neptune Gremlin o SPARQL](features-query-id.md)). 

**queryEvalStats**  
Le statistiche relative a questa query.

**subqueries**  
Numero di sottoquery in questa query.

**elapsed**  
Il numero di millisecondi durante i quali è stata eseguita la query (fino a questo momento).

**cancelled**  
Il valore True indica che la query è stata annullata.

**queryString**  
La query inviata.

## Esempio di stato della query SPARQL
<a name="sparql-api-status-get-example"></a>

Di seguito è riportato un esempio del comando di stato che utilizza `curl` e l'operazione HTTP `GET`.

```
curl https://your-neptune-endpoint:port/sparql/status
```

Questo output mostra una sola query in esecuzione.

```
{
    "acceptedQueryCount":9,
    "runningQueryCount":1,
    "queries": [
        {
            "queryId":"fb34cd3e-f37c-4d12-9cf2-03bb741bf54f",
            "queryEvalStats":
                {
                    "subqueries": 0,
                    "elapsed": 29256,
                    "cancelled": false
                },
            "queryString": "SELECT ?s ?p ?o WHERE {?s ?p ?o}"
        }
    ]
}
```

# Annullamento della query SPARQL
<a name="sparql-api-status-cancel"></a>

Per ottenere lo stato delle query SPARQL, utilizza l'operazione HTTP `GET` o `POST` per effettuare una richiesta all'endpoint `https://your-neptune-endpoint:port/sparql/status`.

## Parametri della richiesta di annullamento delle query SPARQL
<a name="sparql-api-status-cancel-request"></a>

**cancelQuery**  
(Obbligatorio) Indica al comando di stato di annullare una query. Questo parametro non accetta un valore.

**queryId**  
(Obbligatorio) L'ID della query SPARQL in esecuzione da annullare.

**silent**  
(Facoltativo) Se `silent=true`, la query in esecuzione viene annullata e il codice di risposta HTTP è 200. Se `silent` non è presente o `silent=false`, la query viene annullata con un codice di stato HTTP 500.

## Esempi di annullamento di query SPARQL
<a name="sparql-api-status-cancel-example"></a>

**Esempio 1: annullamento con `silent=false`**  
Di seguito è riportato un esempio del comando di stato che utilizza `curl` per annullare una query con il parametro `silent` impostato su `false`:

```
curl https://your-neptune-endpoint:port/sparql/status \
  -d "cancelQuery" \
  -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47" \
  -d "silent=false"
```

A meno che la query non abbia già avviato i risultati in streaming, la query annullata restituirebbe un codice HTTP 500 con una risposta come questa:

```
{
  "code": "CancelledByUserException",
  "requestId": "4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47",
  "detailedMessage": "Operation terminated (cancelled by user)"
}
```

Se la query ha già restituito un codice HTTP 200 (OK) e ha iniziato lo streaming dei risultati prima di essere annullata, le informazioni sull'eccezione di timeout vengono inviate al flusso di output normale.

**Esempio 2: annullamento con `silent=true`**  
Di seguito è riportato un esempio dello stesso comando di stato di cui sopra, tranne che il parametro `silent` è ora impostato su `true`:

```
curl https://your-neptune-endpoint:port/sparql/status \
  -d "cancelQuery" \
  -d "queryId=4d5c4fae-aa30-41cf-9e1f-91e6b7dd6f47" \
  -d "silent=true"
```

Questo comando restituisce la stessa risposta del caso `silent=false`, ma la query annullata restituisce ora un codice HTTP 200 con una risposta simile alla seguente:

```
{
  "head" : {
    "vars" : [ "s", "p", "o" ]
  },
  "results" : {
    "bindings" : [ ]
  }
}
```

# Utilizzo del protocollo HTTP Graph Store Protocol (GSP) SPARQL 1.1 in Amazon Neptune
<a name="sparql-graph-store-protocol"></a>

Nella raccomandazione [SPARQL 1.1 Graph Store HTTP Protocol](https://www.w3.org/TR/sparql11-http-rdf-update/), il W3C ha definito un protocollo HTTP per la gestione dei grafi RDF. Definisce le operazioni per la rimozione, la creazione e la sostituzione del contenuto del grafo RDF, nonché per l'aggiunta di istruzioni RDF al contenuto esistente.

Il protocollo GSP (Graph-Store Protocol) offre un modo pratico per manipolare l'intero grafo senza dover scrivere query SPARQL complesse.

Neptune supporta pienamente questo protocollo.

L'endpoint del protocollo GSP (Graph-Store Protocol) è:

```
https://your-neptune-cluster:port/sparql/gsp/
```

Per accedere al grafo predefinito con GSP, usare:

```
https://your-neptune-cluster:port/sparql/gsp/?default
```

Per accedere a un grafo nominato con GSP, usare:

```
https://your-neptune-cluster:port/sparql/gsp/?graph=named-graph-URI
```

## Dettagli speciali sull'implementazione di Neptune GSP
<a name="sparql-graph-store-protocol-special"></a>

Neptune implementa pienamente la [raccomandazione W3C](https://www.w3.org/TR/sparql11-http-rdf-update/) che definisce il protocollo GSP. Tuttavia, ci sono alcune situazioni che la specifica non copre.

Una di queste è il caso in cui una richiesta `PUT` o `POST` specifichi uno o più grafi nominati nel corpo della richiesta che differiscono dal grafo specificato dall'URL della richiesta. Ciò può accadere solo quando il formato RDF del corpo della richiesta supporta grafici nominati, come, ad esempio, con `Content-Type: application/n-quads` o `Content-Type: application/trig`.

In questa situazione, Neptune aggiunge o aggiorna tutti i grafi nominati presenti nel corpo, oltre al grafo nominato specificato nell'URL.

Ad esempio, supponiamo che partendo da un database vuoto, si invii una richiesta `PUT` per trasformare i voti in tre grafi. Uno, denominato `urn:votes`, contiene tutti i voti di tutti gli anni elettorali. Altri due, denominati `urn:votes:2005` e `urn:votes:2019`, contengono i voti di specifici anni elettorali. La richiesta e il relativo payload avranno un aspetto simile al seguente:

```
PUT "http://your-Neptune-cluster:port/sparql/gsp/?graph=urn:votes"
  Host: example.com
  Content-Type: application/n-quads

  PAYLOAD:

  <urn:JohnDoe> <urn:votedFor> <urn:Labour> <urn:votes:2005>
  <urn:JohnDoe> <urn:votedFor> <urn:Conservative> <urn:votes:2019>
  <urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes:2005>
  <urn:JaneSmith> <urn:votedFor> <urn:Conservative> <urn:votes:2019>
```

Dopo l'esecuzione della richiesta, i dati nel database avranno un aspetto simile al seguente:

```
<urn:JohnDoe>   <urn:votedFor> <urn:Labour>           <urn:votes:2005>
<urn:JohnDoe>   <urn:votedFor> <urn:Conservative>     <urn:votes:2019>
<urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes:2005>
<urn:JaneSmith> <urn:votedFor> <urn:Conservative>     <urn:votes:2019>
<urn:JohnDoe>   <urn:votedFor> <urn:Labour>           <urn:votes>
<urn:JohnDoe>   <urn:votedFor> <urn:Conservative>     <urn:votes>
<urn:JaneSmith> <urn:votedFor> <urn:LiberalDemocrats> <urn:votes>
<urn:JaneSmith> <urn:votedFor> <urn:Conservative>     <urn:votes>
```

Un'altra situazione ambigua è quella in cui più di un grafo viene specificato nell'URL della richiesta stesso, utilizzando uno qualsiasi di `PUT`, `POST`, `GET` o `DELETE`. Esempio:

```
POST "http://your-Neptune-cluster:port/sparql/gsp/?graph=urn:votes:2005&graph=urn:votes:2019"
```

O:

```
GET "http://your-Neptune-cluster:port/sparql/gsp/?default&graph=urn:votes:2019"
```

In questa situazione, Neptune restituisce un errore HTTP 400 con un messaggio che indica che è possibile specificare un solo grafo nell'URL della richiesta.

# Analisi dell'esecuzione di query Neptune tramite la funzionalità SPARQL `explain`
<a name="sparql-explain"></a>

Amazon Neptune ha aggiunto una funzionalità SPARQL denominata *explain*. Questa funzionalità è uno strumento self-service che consente di comprendere l'approccio di esecuzione adottato dal motore Neptune. È possibile richiamarla aggiungendo un parametro `explain` a una chiamata HTTP che invia una query SPARQL.

La funzione `explain` fornisce informazioni sulla struttura logica dei piani di esecuzione di query. È possibile utilizzare queste informazioni per individuare potenziali colli di bottiglia nella valutazione ed esecuzione. È quindi possibile utilizzare [hint di query](sparql-query-hints.md) per migliorare i piani di esecuzione delle query.

**Topics**
+ [

# Funzionamento del motore di query SPARQL in Neptune
](sparql-explain-engine.md)
+ [

# Come utilizzare SPARQL `explain` per analizzare l'esecuzione di query Neptune
](sparql-explain-using.md)
+ [

# Esempi di chiamate di SPARQL `explain` in Neptune
](sparql-explain-examples.md)
+ [

# Operatori di SPARQL `explain` in Neptune
](sparql-explain-operators.md)
+ [

# Limitazioni di SPARQL `explain` in Neptune
](sparql-explain-limitations.md)

# Funzionamento del motore di query SPARQL in Neptune
<a name="sparql-explain-engine"></a>

Per usare le informazioni fornite dalla funzionalità SPARQL `explain`, è necessario conoscere alcuni dettagli su come funziona il motore di query SPARQL di Amazon Neptune.

Il motore traduce ogni query SPARQL in una pipeline di operatori. A partire dal primo operatore, le soluzioni intermedie note come *elenchi vincolanti* passano attraverso questa pipeline di operatori. Si può considerare un elenco vincolante come una tabella in cui le intestazioni di tabella sono un sottoinsieme delle variabili utilizzate nella query. Ogni riga della tabella rappresenta un risultato, fino al punto di valutazione.

Supponiamo che siano stati definiti due prefissi di spazio dei nomi per i dati:

```
  @prefix ex:   <http://example.com> .
  @prefix foaf: <http://xmlns.com/foaf/0.1/> .
```

Il seguente è un esempio di un elenco vincolante semplice in questo contesto:

```
  ?person       | ?firstName
  ------------------------------------------------------
  ex:JaneDoe    | "Jane"
  ex:JohnDoe    | "John"
  ex:RichardRoe | "Richard"
```

Per ognuna delle tre persone, l'elenco associa la variabile `?person` a un identificatore della persona e la variabile `?firstName` al nome della persona.

In generale, le variabili possono rimanere non vincolate se, per esempio, c'è una selezione `OPTIONAL` di una variabile in una query per la quale non è presente nessun valore nei dati.

L'operatore `PipelineJoin` è un esempio di un operatore del motore di query Neptune presente nell'output di `explain`. Prende come input un set vincolante in entrata dall'operatore precedente ed esegue il join in base a un modello triplice, tipo `(?person, foaf:lastName, ?lastName)`. Questa operazione utilizza le associazioni per la variabile `?person` nel flusso di input, le sostituisce nel modello triplice e cerca le triple dal database.

Quando viene eseguito nel contesto delle associazioni in entrata dalla tabella precedente, `PipelineJoin` valuta tre ricerche, ovvero le seguenti:

```
  (ex:JaneDoe,    foaf:lastName, ?lastName)
  (ex:JohnDoe,    foaf:lastName, ?lastName)
  (ex:RichardRoe, foaf:lastName, ?lastName)
```

Questo approccio è definito valutazione *as-bound*. Le soluzioni di questo processo di valutazione verranno unite alle soluzioni in entrata, inserendo il `?lastName` rilevato nelle soluzioni in entrata. Supponendo che si trovi un cognome per tutte e tre le persone, l'operatore produrrebbe un elenco vincolante in uscita simile a questo:

```
  ?person       | ?firstName | ?lastName
  ---------------------------------------
  ex:JaneDoe    | "Jane"     | "Doe"
  ex:JohnDoe    | "John"     | "Doe"
  ex:RichardRoe | "Richard"  | "Roe"
```

Questo elenco vincolante in uscita quindi serve come input per l'operatore successivo nella pipeline. Al termine, l'output dell'ultimo operatore nella pipeline definisce il risultato della query.

Le pipeline di operatori sono spesso lineari, nel senso che ogni operatore genera soluzioni per un unico operatore collegato. Tuttavia, in alcuni casi, possono avere più strutture complesse. Ad esempio, un operatore `UNION` in una query SPARQL viene mappato a un'operazione `Copy`. Questa operazione duplica le associazioni e inoltra le copie in due piani secondari, uno per il lato sinistro e l'altro per il lato destro di `UNION`.

Per ulteriori informazioni sugli operatori, vedi [Operatori di SPARQL `explain` in Neptune](sparql-explain-operators.md).

# Come utilizzare SPARQL `explain` per analizzare l'esecuzione di query Neptune
<a name="sparql-explain-using"></a>

La funzionalità SPARQL `explain` è uno strumento self-service di Amazon Neptune che consente di comprendere l'approccio di esecuzione adottato dal motore Neptune. Per richiamare `explain`, si passa un parametro a una richiesta HTTP o HTTPS nel formato `explain=mode`.

Il valore della modalità può essere `static`, `dynamic` o `details`.
+ In modalità *statica*, `explain` visualizza solo la struttura statica del piano di query.
+ In modalità *dinamica*, `explain` include anche gli aspetti dinamici del piano di query. Questi aspetti potrebbero includere il numero di associazioni intermedie che passano attraverso gli operatori e il rapporto tra le associazioni in entrata e quelle in uscita e il tempo totale impiegato dagli operatori.
+ Nella modalità *dettagli* `explain` stampa le informazioni visualizzate in modalità `dynamic` oltre a dettagli aggiuntivi, come la stringa di query SPARQL effettiva e il calcolo dell'intervallo stimato per il modello sottostante a un operatore join.

Neptune supporta l'utilizzo di `explain` con tutti e tre i protocolli di accesso alle query SPARQL elencati nella specifica [W3C SPARQL 1.1 Protocol](https://www.w3.org/TR/sparql11-protocol/#query-operation), ovvero:

1. HTTP GET

1. HTTP POST utilizzando i parametri di codifica URL

1. HTTP POST usando i parametri di testo

Per ulteriori informazioni sul motore di query SPARQL, consulta [Funzionamento del motore di query SPARQL in Neptune](sparql-explain-engine.md).

Per informazioni sul tipo di output ottenuto richiamando SPARQL `explain`, consulta [Esempi di chiamate di SPARQL `explain` in Neptune](sparql-explain-examples.md).

# Esempi di chiamate di SPARQL `explain` in Neptune
<a name="sparql-explain-examples"></a>

Gli esempi di questa sezione mostrano i vari tipi di output che è possibile produrre richiamando la funzionalità SPARQL `explain` per analizzare l'esecuzione di query in Amazon Neptune.

**Topics**
+ [

## Descrizione dell'output di Explain
](#sparql-explain-example-output)
+ [

## Esempio di output con modalità dettagli
](#sparql-explain-example-details)
+ [

## Esempio di output con modalità statica
](#sparql-explain-example-static)
+ [

## Diversi metodi di codifica dei parametri
](#sparql-explain-example-parameters)
+ [

## Altri tipi di output oltre a text/plain
](#sparql-explain-output-options)
+ [

## Esempio di output di SPARQL `explain` quando è abilitato il motore DFE
](#sparql-explain-output-dfe)

## Descrizione dell'output di Explain
<a name="sparql-explain-example-output"></a>

In questo esempio, Jane Doe conosce due persone, ossia John Doe e Richard Roe:

```
@prefix ex: <http://example.com> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

ex:JaneDoe foaf:knows ex:JohnDoe .
ex:JohnDoe foaf:firstName "John" .
ex:JohnDoe foaf:lastName "Doe" .
ex:JaneDoe foaf:knows ex:RichardRoe .
ex:RichardRoe foaf:firstName "Richard" .
ex:RichardRoe foaf:lastName "Roe" .
.
```

Per determinare i nomi di tutte le persone che Jane Doe conosce, puoi scrivere la seguente query:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -H "Accept: text/csv"
```

Questa query semplice restituisce il seguente risultato:

```
firstName
John
Richard
```

Quindi, modifica il comando `curl` per richiamare `explain` aggiungendo `-d "explain=dynamic"` e utilizzando il tipo di output predefinito invece di `text/csv`:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=dynamic"
```

La query restituisce ora l'output in formato ASCII formattato (tipo di contenuto HTTP `text/plain`), che è il tipo di output predefinito:

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        │ 1        │ 2         │ 2.00  │ 1         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        │ 2        │ 2         │ 1.00  │ 1         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   │ 2        │ 2         │ 1.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value │ 2        │ 2         │ 1.00  │ 1         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

Per ulteriori informazioni sulle operazioni nella colonna `Name` e i relativi argomenti, consulta [Operatori explain](sparql-explain-operators.md).

Di seguito viene descritto l'output riga per riga:

1. La prima fase della query principale utilizza sempre l'operatore `SolutionInjection` per introdurre una soluzione. La soluzione viene quindi ampliata per il risultato finale attraverso il processo di valutazione.

   In questo caso, introduce la cosiddetta soluzione universale `{ }`. In presenza di clausole `VALUES` o un `BIND`, questa fase potrebbe anche introdurre associazioni di variabili più complesse per iniziare.

   La colonna `Units Out` indica che questa è l'unica soluzione prodotta dall'operatore. La colonna `Out #1` specifica l'operatore in cui questo operatore immette il risultato. In questo esempio, tutti gli operatori sono collegati all'operatore che segue nella tabella.

1. La seconda fase è un `PipelineJoin`. Riceve come input la soluzione universale (completamente non vincolata) unica prodotta dall'operatore precedente (`Units In := 1`). Esegue il join in base al modello di tupla definito dall'argomento `pattern`. Questo corrisponde a una semplice ricerca del modello. In questo caso, il modello triplice è definito come segue:

   ```
   distinct( ex:JaneDoe, foaf:knows, ?person )
   ```

   L'argomento `joinType := join` indica che questo è un join normale (altri tipi includono join `optional`, `existence check` e così via).

   L'argomento `distinct := true` indica che vengono estratte solo le corrispondenze distinte dal database (senza duplicati) e le corrispondenze distinte vengono associate alla variabile `joinProjectionVars := ?person`, deduplicate.

   Il fatto che il valore della colonna `Units Out` sia 2 indica che ci sono due soluzioni in uscita. Nello specifico, queste sono le associazioni per la variabile `?person`, riflettendo le due persone che i dati indicano che Jane Doe conosce:

   ```
    ?person
    -------------
    ex:JohnDoe
    ex:RichardRoe
   ```

1. Le due soluzioni dalla fase 2 passano come input (`Units In := 2`) al secondo `PipelineJoin`. Questo operatore esegue il join delle due soluzioni precedenti con il seguente modello triplice:

   ```
   distinct(?person, foaf:firstName, ?firstName)
   ```

   La variabile `?person` è associata a `ex:JohnDoe` o a `ex:RichardRoe` dalla soluzione in entrata dell'operatore. A questo punto, `PipelineJoin` estrae i nomi, John e Richard. Le due soluzioni in uscita (Units Out := 2) sono quindi le seguenti:

   ```
    ?person       | ?firstName
    ---------------------------
    ex:JohnDoe    | John
    ex:RichardRoe | Richard
   ```

1. Il successivo operatore di proiezione prende come input le due soluzioni dalla fase 3 (`Units In := 2`) e le proietta alla variabile `?firstName`. Ciò elimina tutte le altre associazioni di variabili nelle mappature e inoltra le due associazioni (`Units Out := 2`):

   ```
    ?firstName
    ----------
    John
    Richard
   ```

1. Per migliorare le prestazioni, Neptune opera ove possibile su identificatori interni assegnati a termini URIs come stringhe letterali, anziché sulle stringhe stesse. L'operatore finale, `TermResolution`, esegue una mappatura da questi identificatori interni verso le stringhe di termini corrispondenti.

   In una valutazione di query regolare (non Explain), il risultato calcolato dall'ultimo operatore viene quindi serializzato nel formato di serializzazione richiesto e trasmesso al client.

## Esempio di output con modalità dettagli
<a name="sparql-explain-example-details"></a>

Si supponga di eseguire la stessa query precedente in modalità *dettagli* anziché in modalità *dinamica*:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=details"
```

Come illustrato in questo esempio, l'output è lo stesso con alcuni dettagli aggiuntivi quali la stringa di query nella parte superiore dell'output e il conteggio `patternEstimate` per l'operatore `PipelineJoin`:

```
Query:
PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/>
SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }

╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        │ 1        │ 2         │ 2.00  │ 13        ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          │          │           │       │           ║
║    │        │        │                   │ patternEstimate=2                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        │ 2        │ 2         │ 1.00  │ 3         ║
║    │        │        │                   │ joinType=join                                         │          │          │           │       │           ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          │          │           │       │           ║
║    │        │        │                   │ patternEstimate=2                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   │ 2        │ 2         │ 1.00  │ 1         ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value │ 2        │ 2         │ 1.00  │ 7         ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

## Esempio di output con modalità statica
<a name="sparql-explain-example-static"></a>

Supponiamo di eseguire la stessa query precedente in modalità *statica* (impostazione predefinita) anziché in modalità *dettagli*:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=PREFIX foaf: <https://xmlns.com/foaf/0.1/> PREFIX ex: <https://www.example.com/> \
       SELECT ?firstName WHERE { ex:JaneDoe foaf:knows ?person . ?person foaf:firstName ?firstName }" \
   -d "explain=static"
```

Come mostrato in questo esempio, l'output è lo stesso ma omette le ultime tre colonne:

```
╔════╤════════╤════════╤═══════════════════╤═══════════════════════════════════════════════════════╤══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                             │ Mode     ║
╠════╪════════╪════════╪═══════════════════╪═══════════════════════════════════════════════════════╪══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                        │ -        ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 1  │ 2      │ -      │ PipelineJoin      │ pattern=distinct(ex:JaneDoe, foaf:knows, ?person)     │ -        ║
║    │        │        │                   │ joinType=join                                         │          ║
║    │        │        │                   │ joinProjectionVars=[?person]                          │          ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 2  │ 3      │ -      │ PipelineJoin      │ pattern=distinct(?person, foaf:firstName, ?firstName) │ -        ║
║    │        │        │                   │ joinType=join                                         │          ║
║    │        │        │                   │ joinProjectionVars=[?person, ?firstName]              │          ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 3  │ 4      │ -      │ Projection        │ vars=[?firstName]                                     │ retain   ║
╟────┼────────┼────────┼───────────────────┼───────────────────────────────────────────────────────┼──────────╢
║ 4  │ -      │ -      │ TermResolution    │ vars=[?firstName]                                     │ id2value ║
╚════╧════════╧════════╧═══════════════════╧═══════════════════════════════════════════════════════╧══════════╝
```

## Diversi metodi di codifica dei parametri
<a name="sparql-explain-example-parameters"></a>

Le query nell'esempio seguente illustrano due diversi metodi per codificare i parametri quando si richiama SPARQL `explain`.

**Utilizzo di codifica URL**: questo esempio utilizza la codifica URL dei parametri e specifica l'output *dinamico*:

```
curl -XGET "http(s)://your_server:your_port/sparql?query=SELECT%20*%20WHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20%7D%20LIMIT%20%31&explain=dynamic"
```

**Specifica diretta dei parametri**: questa è la stessa query precedente con la differenza che trasferisce i parametri direttamente tramite POST:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic"
```

## Altri tipi di output oltre a text/plain
<a name="sparql-explain-output-options"></a>

Gli esempi precedenti utilizzano il tipo di output predefinito `text/plain`. Neptune può anche formattare l'output di SPARQL `explain` in altri due formati di tipo MIME, vale a dire `text/csv` e `text/html`. È possibile richiamarli impostando l'intestazione `Accept` HTTP. A tale scopo, si può utilizzare il flag `-H` in `curl`, come segue:

```
  -H "Accept: output type"
```

Ecco alcuni esempi:

**Output `text/csv`**  
Questa query richiede l'output di tipo MIME CSV specificando `-H "Accept: text/csv"`:

```
 curl http(s)://your_server:your_port/sparql \
   -d "query=SELECT * WHERE { ?s ?p ?o } LIMIT 1" \
   -d "explain=dynamic" \
   -H "Accept: text/csv"
```

Il formato CSV, che è utile per l'importazione in un foglio di calcolo o database, separa i campi in ogni riga `explain` con un punto e virgola ( `;` ), come segue:

```
ID;Out #1;Out #2;Name;Arguments;Mode;Units In;Units Out;Ratio;Time (ms)
0;1;-;SolutionInjection;solutions=[{}];-;0;1;0.00;0
1;2;-;PipelineJoin;pattern=distinct(?s, ?p, ?o),joinType=join,joinProjectionVars=[?s, ?p, ?o];-;1;6;6.00;1
2;3;-;Projection;vars=[?s, ?p, ?o];retain;6;6;1.00;2
3;-;-;Slice;limit=1;-;1;1;1.00;1
```

 

**Output `text/html`**  
Se si specifica `-H "Accept: text/html"`, `explain` genera una tabella HTML:

```
<!DOCTYPE html>
<html>
  <body>
    <table border="1px">
      <thead>
        <tr>
          <th>ID</th>
          <th>Out #1</th>
          <th>Out #2</th>
          <th>Name</th>
          <th>Arguments</th>
          <th>Mode</th>
          <th>Units In</th>
          <th>Units Out</th>
          <th>Ratio</th>
          <th>Time (ms)</th>
        </tr>
      </thead>

      <tbody>
        <tr>
          <td>0</td>
          <td>1</td>
          <td>-</td>
          <td>SolutionInjection</td>
          <td>solutions=[{}]</td>
          <td>-</td>
          <td>0</td>
          <td>1</td>
          <td>0.00</td>
          <td>0</td>
        </tr>

        <tr>
          <td>1</td>
          <td>2</td>
          <td>-</td>
          <td>PipelineJoin</td>
          <td>pattern=distinct(?s, ?p, ?o)<br>
              joinType=join<br>
              joinProjectionVars=[?s, ?p, ?o]</td>
          <td>-</td>
          <td>1</td>
          <td>6</td>
          <td>6.00</td>
          <td>1</td>
        </tr>

        <tr>
          <td>2</td>
          <td>3</td>
          <td>-</td>
          <td>Projection</td>
          <td>vars=[?s, ?p, ?o]</td>
          <td>retain</td>
          <td>6</td>
          <td>6</td>
          <td>1.00</td>
          <td>2</td>
        </tr>

        <tr>
          <td>3</td>
          <td>-</td>
          <td>-</td>
          <td>Slice</td>
          <td>limit=1</td>
          <td>-</td>
          <td>1</td>
          <td>1</td>
          <td>1.00</td>
          <td>1</td>
        </tr>
      </tbody>
    </table>
  </body>
</html>
```

L'HTML viene reso in un browser in modo simile al seguente:

![\[Esempio di output HTML di SPARQL Explain.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/sparql-explain-dynamic-html-output.png)


## Esempio di output di SPARQL `explain` quando è abilitato il motore DFE
<a name="sparql-explain-output-dfe"></a>

Di seguito è riportato un esempio di output di SPARQL `explain` quando è abilitato il motore di query alternativo DFE:

```
╔════╤════════╤════════╤═══════════════════╤═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤══════════╤══════════╤═══════════╤═══════╤═══════════╗
║ ID │ Out #1 │ Out #2 │ Name              │ Arguments                                                                                                                                                                                                               │ Mode     │ Units In │ Units Out │ Ratio │ Time (ms) ║
╠════╪════════╪════════╪═══════════════════╪═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪══════════╪══════════╪═══════════╪═══════╪═══════════╣
║ 0  │ 1      │ -      │ SolutionInjection │ solutions=[{}]                                                                                                                                                                                                          │ -        │ 0        │ 1         │ 0.00  │ 0         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 1  │ 2      │ -      │ HashIndexBuild    │ solutionSet=solutionSet1                                                                                                                                                                                                │ -        │ 1        │ 1         │ 1.00  │ 22        ║
║    │        │        │                   │ joinVars=[]                                                                                                                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │ sourceType=pipeline                                                                                                                                                                                                     │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 2  │ 3      │ -      │ DFENode           │ DFE Stats=                                                                                                                                                                                                                    │ -        │ 101      │ 100       │ 0.99  │ 32        ║
║    │        │        │                   │ ====> DFE execution time (measured by DFEQueryEngine)                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ accepted [micros]=127                                                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ ready [micros]=2                                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ running [micros]=5627                                                                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ finished [micros]=0                                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> DFE execution time (measured in DFENode)                                                                                                                                                                           │          │          │           │       │           ║
║    │        │        │                   │ -> setupTime [ms]=1                                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │ -> executionTime [ms]=14                                                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │ -> resultReadTime [ms]=0                                                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> Static analysis statistics                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 35907 micros spent in parser.                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ --> 7643 micros spent in range count estimation                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 2895 micros spent in value resolution                                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ --> 39974925 micros spent in optimizer loop                                                                                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ DFEJoinGroupNode[ children={                                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │   DFEPatternNode[(?1, TERM[117442062], ?2, ?3) . project DISTINCT[?1, ?2] {rangeCountEstimate=100},                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │     OperatorInfoWithAlternative[                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       rec=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_PIPELINE_JOIN,                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0002,comp=0.0000,mem=0],                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0002,comp=0.0000,mem=0]]],                                                                                                             │          │          │           │       │           ║
║    │        │        │                   │       alt=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_HASH_JOIN,                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0003,comp=0.0000,mem=3212],                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=1.0000,out=100.0000,io=0.0003,comp=0.0000,mem=3212]]]]],                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │   DFEPatternNode[(?1, TERM[150997262], ?4, ?5) . project DISTINCT[?1, ?4] {rangeCountEstimate=100},                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │     OperatorInfoWithAlternative[                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       rec=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_HASH_JOIN,                                                                                                                                                                                     │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0003,comp=0.0000,mem=6400],                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0003,comp=0.0000,mem=6400]]],                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │       alt=OperatorInfo[                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         type=INCREMENTAL_PIPELINE_JOIN,                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │         costEstimates=OperatorCostEstimates[                                                                                                                                                                            │          │          │           │       │           ║
║    │        │        │                   │           costEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0010,comp=0.0000,mem=0],                                                                                                                      │          │          │           │       │           ║
║    │        │        │                   │           worstCaseCostEstimate=OperatorCostEstimate[in=100.0000,out=100.0000,io=0.0010,comp=0.0000,mem=0]]]]]                                                                                                          │          │          │           │       │           ║
║    │        │        │                   │ },                                                                                                                                                                                                                      │          │          │           │       │           ║
║    │        │        │                   │ ]                                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> DFE configuration:                                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │ solutionChunkSize=5000                                                                                                                                                                                                  │          │          │           │       │           ║
║    │        │        │                   │ ouputQueueSize=20                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ numComputeCores=3                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ maxParallelIO=10                                                                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ numInitialPermits=12                                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ====> DFE configuration (reported back)                                                                                                                                                                                 │          │          │           │       │           ║
║    │        │        │                   │ numComputeCores=3                                                                                                                                                                                                       │          │          │           │       │           ║
║    │        │        │                   │ maxParallelIO=2                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ numInitialPermits=12                                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ ===> Statistics & operator histogram                                                                                                                                                                                    │          │          │           │       │           ║
║    │        │        │                   │ ==> Statistics                                                                                                                                                                                                          │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 3668 micros total elapsed (incl. wait / excl. wait)                                                                                                                                                           │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 3 millis total elapse (incl. wait / excl. wait)                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │ -> 3741 / 0 secs total elapsed (incl. wait / excl. wait)                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │ ==> Operator histogram                                                                                                                                                                                                  │          │          │           │       │           ║
║    │        │        │                   │ -> 47.66% of total time (excl. wait): pipelineScan (2 instances)                                                                                                                                                        │          │          │           │       │           ║
║    │        │        │                   │ -> 10.99% of total time (excl. wait): merge (1 instances)                                                                                                                                                               │          │          │           │       │           ║
║    │        │        │                   │ -> 41.17% of total time (excl. wait): symmetricHashJoin (1 instances)                                                                                                                                                   │          │          │           │       │           ║
║    │        │        │                   │ -> 0.19% of total time (excl. wait): drain (1 instances)                                                                                                                                                                │          │          │           │       │           ║
║    │        │        │                   │                                                                                                                                                                                                                         │          │          │           │       │           ║
║    │        │        │                   │ nodeId | out0   | out1 | opName            | args                                             | rowsIn | rowsOut | chunksIn | chunksOut | elapsed* | outWait | outBlocked | ratio    | rate* [M/s] | rate [M/s] | %     │          │          │           │       │           ║
║    │        │        │                   │ ------ | ------ | ---- | ----------------- | ------------------------------------------------ | ------ | ------- | -------- | --------- | -------- | ------- | ---------- | -------- | ----------- | ---------- | ----- │          │          │           │       │           ║
║    │        │        │                   │ node_0 | node_2 | -    | pipelineScan      | (?1, TERM[117442062], ?2, ?3) DISTINCT [?1, ?2]  | 0      | 100     | 0        | 1         | 874      | 0       | 0          | Infinity | 0.1144      | 0.1144     | 23.83 │          │          │           │       │           ║
║    │        │        │                   │ node_1 | node_2 | -    | pipelineScan      | (?1, TERM[150997262], ?4, ?5) DISTINCT [?1, ?4]  | 0      | 100     | 0        | 1         | 874      | 0       | 0          | Infinity | 0.1144      | 0.1144     | 23.83 │          │          │           │       │           ║
║    │        │        │                   │ node_2 | node_4 | -    | symmetricHashJoin |                                                  | 200    | 100     | 2        | 2         | 1510     | 73      | 0          | 0.50     | 0.0662      | 0.0632     | 41.17 │          │          │           │       │           ║
║    │        │        │                   │ node_3 | -      | -    | drain             |                                                  | 100    | 0       | 1        | 0         | 7        | 0       | 0          | 0.00     | 0.0000      | 0.0000     | 0.19  │          │          │           │       │           ║
║    │        │        │                   │ node_4 | node_3 | -    | merge             |                                                  | 100    | 100     | 2        | 1         | 403      | 0       | 0          | 1.00     | 0.2481      | 0.2481     | 10.99 │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 3  │ 4      │ -      │ HashIndexJoin     │ solutionSet=solutionSet1                                                                                                                                                                                                │ -        │ 100      │ 100       │ 1.00  │ 4         ║
║    │        │        │                   │ joinType=join                                                                                                                                                                                                           │          │          │           │       │           ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 4  │ 5      │ -      │ Distinct          │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ -        │ 100      │ 100       │ 1.00  │ 9         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 5  │ 6      │ -      │ Projection        │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ retain   │ 100      │ 100       │ 1.00  │ 2         ║
╟────┼────────┼────────┼───────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼──────────┼──────────┼───────────┼───────┼───────────╢
║ 6  │ -      │ -      │ TermResolution    │ vars=[?s, ?o, ?o1]                                                                                                                                                                                                      │ id2value │ 100      │ 100       │ 1.00  │ 11        ║
╚════╧════════╧════════╧═══════════════════╧═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╧══════════╧══════════╧═══════════╧═══════╧═══════════╝
```

# Operatori di SPARQL `explain` in Neptune
<a name="sparql-explain-operators"></a>

Le seguenti sezioni descrivono gli operatori e i parametri per la funzionalità SPARQL `explain` attualmente disponibile in Amazon Neptune.

**Importante**  
La funzione SPARQL `explain` è ancora in fase di definizione. Gli operatori e i parametri documentati qui potrebbero cambiare nelle prossime versioni.

**Topics**
+ [

## Operatore `Aggregation`
](#sparql-explain-operator-aggregation)
+ [

## Operatore `ConditionalRouting`
](#sparql-explain-operator-conditional-routing)
+ [

## Operatore `Copy`
](#sparql-explain-operator-copy)
+ [

## Operatore `DFENode`
](#sparql-explain-operator-dfenode)
+ [

## Operatore `Distinct`
](#sparql-explain-operator-distinct)
+ [

## Operatore `Federation`
](#sparql-explain-operator-federation)
+ [

## Operatore `Filter`
](#sparql-explain-operator-filter)
+ [

## Operatore `HashIndexBuild`
](#sparql-explain-operator-hash-index-build)
+ [

## Operatore `HashIndexJoin`
](#sparql-explain-operator-hash-index-join)
+ [

## Operatore `MergeJoin`
](#sparql-explain-operator-merge-join)
+ [

## Operatore `NamedSubquery`
](#sparql-explain-operator-named-subquery)
+ [

## Operatore `PipelineJoin`
](#sparql-explain-operator-pipeline-join)
+ [

## Operatore `PipelineCountJoin`
](#sparql-explain-operator-pipeline-count-join)
+ [

## Operatore `PipelinedHashIndexJoin`
](#sparql-explain-operator-pipeline-hash-index-join)
+ [

## Operatore `Projection`
](#sparql-explain-operator-projection)
+ [

## Operatore `PropertyPath`
](#sparql-explain-operator-property-path)
+ [

## Operatore `TermResolution`
](#sparql-explain-operator-term-resolution)
+ [

## Operatore `Slice`
](#sparql-explain-operator-slice)
+ [

## Operatore `SolutionInjection`
](#sparql-explain-operator-solution-injection)
+ [

## Operatore `Sort`
](#sparql-explain-operator-sort)
+ [

## Operatore `VariableAlignment`
](#sparql-explain-operator-variable-alignment)

## Operatore `Aggregation`
<a name="sparql-explain-operator-aggregation"></a>

Esegue una o più aggregazioni, implementando la semantica di operatori di aggregazione SPARQL, come `count`, `max`, `min`, `sum` e così via.

`Aggregation` viene fornito con il raggruppamento opzionale utilizzando le clausole `groupBy` e i vincoli opzionali `having`.

**Arguments (Argomenti)**
+ `groupBy`: (*facoltativo*) fornisce una clausola `groupBy` che specifica la sequenza di espressioni in base a cui le soluzioni in entrata sono raggruppate.
+ `aggregates`: (*obbligatorio*) specifica un elenco ordinato di espressioni di aggregazione.
+ `having`: (*facoltativo*) aggiunge vincoli per filtrare gruppi, come implicito nella clausola `having` della query SPARQL.

## Operatore `ConditionalRouting`
<a name="sparql-explain-operator-conditional-routing"></a>

Instrada le soluzioni in entrata in base a una determinata condizione. Le soluzioni che soddisfano la condizione vengono instradate all'ID operatore a cui fa riferimento `Out #1`, mentre le soluzioni che non la soddisfano vengono instradate all'operatore a cui fa riferimento `Out #2`.

**Arguments (Argomenti)**
+ `condition`: (*obbligatorio*) la condizione di instradamento.

## Operatore `Copy`
<a name="sparql-explain-operator-copy"></a>

Delega il flusso di soluzione come specificato dalla modalità indicata.

**Modalità**
+ `forward`: inoltra le soluzioni all'operatore downstream identificato da `Out #1`. 
+ `duplicate`: duplica le soluzioni e le inoltra a ciascuno dei due operatori identificati da `Out #1` e `Out #2`.

`Copy` non ha argomenti.

## Operatore `DFENode`
<a name="sparql-explain-operator-dfenode"></a>

Questo operatore è un'astrazione del piano eseguito dal motore di query alternativo DFE. Il piano DFE dettagliato è illustrato negli argomenti di questo operatore. L'argomento è attualmente sovraccarico per contenere le statistiche dettagliate di runtime del piano DFE. Contiene il tempo impiegato nei vari passaggi di esecuzione delle query da parte del motore DFE.

L'albero sintattico astratto (AST) logico ottimizzato per il piano di query DFE viene stampato con informazioni sui tipi di operatori presi in considerazione durante la pianificazione e sui costi associati nel caso peggiore e nel caso migliore per l'esecuzione degli operatori. Al momento, l'AST è composto dai seguenti tipi di nodi:
+ `DFEJoinGroupNode`: rappresenta un join di uno o più `DFEPatternNodes`.
+ `DFEPatternNode`: incapsula un modello sottostante con cui le tuple corrispondenti vengono proiettate fuori dal database sottostante.

La sottosezione `Statistics & Operator histogram` contiene dettagli sul tempo di esecuzione del piano `DataflowOp` e sulla ripartizione del tempo di CPU utilizzato da ciascun operatore. Di seguito è riportata una tabella che riporta le statistiche dettagliate di runtime del piano eseguito dal motore DFE.

**Nota**  
Poiché il motore DFE è una funzionalità sperimentale rilasciata in modalità di laboratorio, il formato esatto dell'output di `explain` potrebbe cambiare.

## Operatore `Distinct`
<a name="sparql-explain-operator-distinct"></a>

Calcola la proiezione Distinct su un sottoinsieme di variabili, eliminando i duplicati. Di conseguenza, il numero di soluzioni in entrata è maggiore o uguale al numero di soluzioni in uscita.

**Arguments (Argomenti)**
+ `vars`: (*obbligatorio*) variabili a cui si applica la proiezione `Distinct`.

## Operatore `Federation`
<a name="sparql-explain-operator-federation"></a>

Passa una determinata query a un endpoint SPARQL remoto specifico.

**Arguments (Argomenti)**
+ `endpoint`: (*obbligatorio*) URL dell'endpoint nella dichiarazione SPARQL `SERVICE`. Può essere una stringa costante oppure, se l'endpoint della query è determinato in base a una variabile all'interno della stessa query, il nome della variabile.
+ `query`: (*obbligatorio*) stringa di query ricostruita da inviare all'endpoint remoto. Il motore aggiunge prefissi predefiniti a questa query anche quando non vengono specificati dal client.
+ `silent`: (*obbligatorio*) valore booleano che indica se la parola chiave `SILENT` è visualizzata dopo la parola chiave. `SILENT` indica al motore di non considerare tutta la query non riuscita anche se la parte `SERVICE` remota non riesce.

## Operatore `Filter`
<a name="sparql-explain-operator-filter"></a>

Filtra le soluzioni in entrata. Solo le soluzioni che soddisfano la condizione di filtro vengono inoltrate all'operatore upstream, mentre le altre vengono rilasciate.

**Arguments (Argomenti)**
+ `condition`: (*obbligatorio*) condizione di filtro.

## Operatore `HashIndexBuild`
<a name="sparql-explain-operator-hash-index-build"></a>

Prende un elenco di associazioni e le elabora in un indice hash il cui nome viene definito dall'argomento `solutionSet`. Di solito, gli operatori successivi eseguono join in base a questo set di soluzioni, facendovi riferimento con quel nome.

**Arguments (Argomenti)**
+ `solutionSet`: (*obbligatorio*) nome del set di soluzioni dell'indice hash.
+ `sourceType`: (*obbligatorio*) tipo di origine da cui vengono ottenute le associazioni da archiviare nell'indice hash.
  + `pipeline`: elabora le soluzioni in entrata dall'operatore downstream nella pipeline dell'operatore nell'indice hash.
  + `binding set`: elabora il set di associazioni fisse specificate dall'argomento `sourceBindingSet` nell'indice hash.
+ `sourceBindingSet`: (*facoltativo*) se il valore dell'argomento `sourceType` è `binding set`, questo argomento specifica il set di associazioni statico da elaborare nell'indice hash.

## Operatore `HashIndexJoin`
<a name="sparql-explain-operator-hash-index-join"></a>

Esegue il join delle soluzioni in entrata rispetto al set di soluzioni dell'indice hash identificato dall'argomento `solutionSet`.

**Arguments (Argomenti)**
+ `solutionSet`: (*obbligatorio*) nome del set di soluzioni rispetto al quale eseguire il join. Questo deve essere un indice hash che è stato costruito in una fase precedente utilizzando l'operatore `HashIndexBuild`.
+ `joinType`: (*obbligatorio*) tipo di join da eseguire.
  + `join`: join normale che richiede una corrispondenza esatta tra tutte le variabili condivise.
  + `optional`: join `optional` che usa la semantica dell'operatore SPARQL `OPTIONAL`.
  + `minus`: un'operazione `minus` conserva una mappatura per la quale non esiste alcun partner di join, utilizzando la semantica dell'operatore SPARQL `MINUS`.
  + `existence check`: verifica se c'è un partner di join o meno e associa la variabile `existenceCheckResultVar` al risultato di questo controllo.
+ `constraints`: (*facoltativo*) vincoli di join aggiuntivi considerati durante il join. I join che non soddisfano questi vincoli vengono eliminati.
+ `existenceCheckResultVar`: (*facoltativo*) usato solo per i join in cui `joinType` è uguale a `existence check` (vedi l'argomento `joinType` precedente).

## Operatore `MergeJoin`
<a name="sparql-explain-operator-merge-join"></a>

Un merge join su più set di soluzioni, identificati dall'argomento `solutionSets`.

**Arguments (Argomenti)**
+ `solutionSets`: (*obbligatorio*) set di soluzioni su cui eseguire il join.

## Operatore `NamedSubquery`
<a name="sparql-explain-operator-named-subquery"></a>

Attiva la valutazione della sottoquery identificata dall'argomento `subQuery` ed elabora il risultato nel set di soluzioni specificato dall'argomento `solutionSet`. Le soluzioni in entrata per l'operatore sono inoltrate alla sottoquery e quindi all'operatore successivo.

**Arguments (Argomenti)**
+ `subQuery`: (*obbligatorio*) nome della sottoquery da valutare. La sottoquery viene resa in modo esplicito nell'output.
+ `solutionSet`: (*obbligatorio*) nome del set di soluzioni in cui archiviare il risultato della sottoquery.

## Operatore `PipelineJoin`
<a name="sparql-explain-operator-pipeline-join"></a>

Riceve come input l'output dell'operatore precedente ed esegue il join in base al modello di tupla definito dall'argomento `pattern`.

**Arguments (Argomenti)**
+ `pattern`— (*Obbligatorio*) Il pattern, che assume la forma di una tupla, e facoltativamente a grafo subject-predicate-object, che è alla base dell'unione. Se `distinct` viene specificato per il modello, il join estrae solo le soluzioni distinte dalle variabili di proiezione specificate dall'argomento `projectionVars`, piuttosto che tutte le soluzioni corrispondenti.
+ `inlineFilters`: (*facoltativo*) set di filtri da applicare alle variabili nel modello. Il modello viene valutato in combinazione con questi filtri.
+ `joinType`: (*obbligatorio*) tipo di join da eseguire.
  + `join`: join normale che richiede una corrispondenza esatta tra tutte le variabili condivise.
  + `optional`: join `optional` che usa la semantica dell'operatore SPARQL `OPTIONAL`.
  + `minus`: un'operazione `minus` conserva una mappatura per la quale non esiste alcun partner di join, utilizzando la semantica dell'operatore SPARQL `MINUS`.
  + `existence check`: verifica se c'è un partner di join o meno e associa la variabile `existenceCheckResultVar` al risultato di questo controllo.
+ `constraints`: (*facoltativo*) vincoli di join aggiuntivi considerati durante il join. I join che non soddisfano questi vincoli vengono eliminati.
+ `projectionVars`: (*facoltativo*) variabili della proiezione. Utilizzato in combinazione con `distinct := true` per applicare l'estrazione delle proiezioni distinte per un determinato set di variabili.
+ `cutoffLimit`: (*facoltativo*) limite massimo per il numero di partner di join estratti. Anche se non vi è alcun limite predefinito, è possibile impostare questo a 1 quando si eseguono join per implementare clausole `FILTER (NOT) EXISTS`, dove è sufficiente provare o smentire che c'è un partner di join.

## Operatore `PipelineCountJoin`
<a name="sparql-explain-operator-pipeline-count-join"></a>

Variante di `PipelineJoin`. Invece di eseguire il join, conteggia solo i partner di join corrispondenti e associa il conteggio alla variabile specificata dall'argomento `countVar`.

**Arguments (Argomenti)**
+ `countVar`: (*obbligatorio*) variabile a cui il risultato del conteggio, cioè il numero di partner di join, deve essere associato.
+ `pattern`— (*Obbligatorio*) Il pattern, che assume la forma di una tupla subject-predicate-object, e facoltativamente a grafo, che sta alla base dell'unione. Se `distinct` viene specificato per il modello, il join estrae solo le soluzioni distinte dalle variabili di proiezione specificate dall'argomento `projectionVars`, piuttosto che tutte le soluzioni corrispondenti.
+ `inlineFilters`: (*facoltativo*) set di filtri da applicare alle variabili nel modello. Il modello viene valutato in combinazione con questi filtri.
+ `joinType`: (*obbligatorio*) tipo di join da eseguire.
  + `join`: join normale che richiede una corrispondenza esatta tra tutte le variabili condivise.
  + `optional`: join `optional` che usa la semantica dell'operatore SPARQL `OPTIONAL`.
  + `minus`: un'operazione `minus` conserva una mappatura per la quale non esiste alcun partner di join, utilizzando la semantica dell'operatore SPARQL `MINUS`.
  + `existence check`: verifica se c'è un partner di join o meno e associa la variabile `existenceCheckResultVar` al risultato di questo controllo.
+ `constraints`: (*facoltativo*) vincoli di join aggiuntivi considerati durante il join. I join che non soddisfano questi vincoli vengono eliminati.
+ `projectionVars`: (*facoltativo*) variabili della proiezione. Utilizzato in combinazione con `distinct := true` per applicare l'estrazione delle proiezioni distinte per un determinato set di variabili.
+ `cutoffLimit`: (*facoltativo*) limite massimo per il numero di partner di join estratti. Anche se non vi è alcun limite predefinito, è possibile impostare questo a 1 quando si eseguono join per implementare clausole `FILTER (NOT) EXISTS`, dove è sufficiente provare o smentire che c'è un partner di join.

## Operatore `PipelinedHashIndexJoin`
<a name="sparql-explain-operator-pipeline-hash-index-join"></a>

Si tratta di un operatore di all-in-one build hash index e join. Accetta un elenco di associazioni, le elabora in un indice hash e quindi esegue il join delle soluzioni in entrata rispetto all'indice hash.

**Arguments (Argomenti)**
+ `sourceType`: (*obbligatorio*) tipo di origine da cui vengono ottenute le associazioni da archiviare nell'indice hash, uno tra:
  + `pipeline`: fa sì che `PipelinedHashIndexJoin` elabori le soluzioni in entrata dall'operatore downstream nella pipeline dell'operatore nell'indice hash.
  + `binding set`: fa sì che `PipelinedHashIndexJoin` elabori il set di associazioni fisse specificate dall'argomento `sourceBindingSet` nell'indice hash.
+ `sourceSubQuery `: (*facoltativo*) se il valore dell'argomento `sourceType` è `pipeline`, questo argomento specifica la sottoquery che viene valutata ed elaborata nell'indice hash.
+ `sourceBindingSet `: (*facoltativo*) se il valore dell'argomento `sourceType` è `binding set`, questo argomento specifica il set di associazioni statico da elaborare nell'indice hash.
+ `joinType`: (*obbligatorio*) tipo di join da eseguire:
  + `join`: join normale che richiede una corrispondenza esatta tra tutte le variabili condivise.
  + `optional`: join `optional` che usa la semantica dell'operatore SPARQL `OPTIONAL`.
  + `minus`: un'operazione `minus` conserva una mappatura per la quale non esiste alcun partner di join, utilizzando la semantica dell'operatore SPARQL `MINUS`.
  + `existence check`: verifica se c'è un partner di join o meno e associa la variabile `existenceCheckResultVar` al risultato di questo controllo.
+ `existenceCheckResultVar`: (*facoltativo*) usato solo per i join in cui `joinType` è uguale a `existence check` (vedi l'argomento joinType precedente).

## Operatore `Projection`
<a name="sparql-explain-operator-projection"></a>

Proietta su un sottoinsieme di variabili. Il numero di soluzioni in entrata è uguale al numero di soluzioni in uscita, ma la forma della soluzione varia in base all'impostazione della modalità.

**Modalità**
+ `retain`: conserva nelle soluzioni solo le variabili specificate dall'argomento `vars`.
+ `drop`: elimina tutte le variabili specificate dall'argomento `vars`.

**Arguments (Argomenti)**
+ `vars`: (*obbligatorio*) variabili da conservare o eliminare, a seconda dell'impostazione della modalità.

## Operatore `PropertyPath`
<a name="sparql-explain-operator-property-path"></a>

Abilita percorsi di proprietà ricorsivi come `+` o `*`. Neptune implementa un approccio di iterazione a virgola fissa in base a un modello specificato dall'argomento `iterationTemplate`. Le variabili lato destro o lato sinistro note sono vincolate nel modello per ogni iterazione a virgola fissa, fino a quando non vengono più trovate nuove soluzioni.

**Arguments (Argomenti)**
+ `iterationTemplate`: (*obbligatorio*) nome del modello di sottoquery utilizzato per implementare l'iterazione a virgola fissa.
+ `leftTerm`: (*obbligatorio*) termine (variabile o costante) sul lato sinistro del percorso di proprietà.
+ `rightTerm`: (*obbligatorio*) termine (variabile o costante) sul lato destro del percorso di proprietà.
+ `lowerBound`: (*obbligatorio*) limite inferiore per l'iterazione a virgola fissa (`0` per le query `*` oppure `1` per le query `+`).

## Operatore `TermResolution`
<a name="sparql-explain-operator-term-resolution"></a>

Traduce i valori dell'identificatore della stringa interna nelle stringhe esterni corrispondenti o traduce le stringhe esterne in valori dell'identificatore della stringa interna, in base alla modalità.

**Modalità**
+ `value2id`— Associa termini come valori letterali e URIs ai corrispondenti valori ID interni (codifica in valori interni).
+ `id2value`— Associa i valori ID interni ai termini corrispondenti, ad esempio letterali e URIs (decodifica dei valori interni).

**Arguments (Argomenti)**
+ `vars`— (*Obbligatorio*) Specificate le variabili le cui stringhe o stringhe interne devono essere mappate. IDs 

## Operatore `Slice`
<a name="sparql-explain-operator-slice"></a>

Implementa una sezione nel flusso di soluzioni in entrata, utilizzando la semantica delle clausole SPARQL `LIMIT` e `OFFSET`.

**Arguments (Argomenti)**
+ `limit`: (*facoltativo*) limite per le soluzioni da inoltrare.
+ `offset`: (*facoltativo*) offset a cui sono valutate le soluzioni per l'inoltro.

## Operatore `SolutionInjection`
<a name="sparql-explain-operator-solution-injection"></a>

Non riceve alcun input. Introduce staticamente le soluzioni nel piano di query e le registra nell'argomento `solutions`.

I piani di query iniziano sempre con questa introduzione statica. Se le soluzioni statiche da introdurre possono essere ricavate dalla query stessa combinando varie origini di associazioni statiche (ad esempio da clausole `VALUES` o `BIND`), l'operatore `SolutionInjection` introduce queste soluzioni statiche derivate. Nel caso più semplice, queste riflettono associazioni che sono implicite in una clausola `VALUES` esterna.

Se nessuna delle soluzioni statiche può essere ricavata dalla query, `SolutionInjection` introduce la soluzione vuota cosiddetta universale, che viene ampliata e moltiplicata durante tutto il processo di valutazione di query.

**Arguments (Argomenti)**
+ `solutions`: (*obbligatorio*) sequenza di soluzioni introdotte dall'operatore.

## Operatore `Sort`
<a name="sparql-explain-operator-sort"></a>

Ordina il set di soluzioni utilizzando le condizioni di ordinamento specificate.

**Arguments (Argomenti)**
+ `sortOrder`: (*obbligatorio*) elenco ordinato di variabili, ognuna contenente un identificatore `ASC` (crescente) o `DESC` (decrescente), utilizzate sequenzialmente per ordinare il set di soluzioni.

## Operatore `VariableAlignment`
<a name="sparql-explain-operator-variable-alignment"></a>

Analizza le soluzioni una ad una, eseguendo l'allineamento su ognuna in base a due variabili: un `sourceVar` specificato e un `targetVar` specificato.

Se `sourceVar` e `targetVar` in una soluzione hanno lo stesso valore, le variabili sono considerate allineate e la soluzione viene inoltrata, con il `sourceVar` ridondante proiettato in uscita.

Se le variabili sono associate a diversi valori, la soluzione viene completamente filtrata.

**Arguments (Argomenti)**
+ `sourceVar`: (*obbligatorio*) variabile di origine da confrontare con la variabile di destinazione. Se l'allineamento va a buon fine in una soluzione, il che significa che le due variabili hanno lo stesso valore, la variabile di origine viene proiettata in uscita.
+ `targetVar`: (*obbligatorio*) variabile di destinazione con la quale viene confrontata la variabile di origine. Viene conservata anche quando l'allineamento va a buon fine.

# Limitazioni di SPARQL `explain` in Neptune
<a name="sparql-explain-limitations"></a>

Il rilascio della funzionalità SPARQL `explain` in Neptune ha i seguenti limiti.

**Neptune attualmente supporta explain solo in query SPARQL SELECT**  
Per informazioni sul processo di valutazione per altri formati di query, ad esempio le query `ASK`, `CONSTRUCT`, `DESCRIBE` e `SPARQL UPDATE`, è possibile trasformare queste query in una query SELECT. Quindi utilizzare `explain` per controllare la query SELECT corrispondente.

Ad esempio, per ottenere informazioni di `explain` su una query `ASK WHERE {...}`, eseguire la query corrispondente `SELECT WHERE {...} LIMIT 1` con `explain`.

Analogamente, per una query `CONSTRUCT {...} WHERE {...}`, eliminare la parte `CONSTRUCT {...}` ed eseguire una query `SELECT` con `explain` nella seconda clausola `WHERE {...}`. La valutazione della seconda clausola `WHERE` generalmente rivela le principali sfide per l'elaborazione della query `CONSTRUCT` poiché le soluzioni in uscita dal secondo `WHERE` nel modello `CONSTRUCT` generalmente richiedono solo una semplice sostituzione.

**Gli operatori Explain possono cambiare nelle versioni future**  
Gli operatori SPARQL `explain` e i relativi parametri possono cambiare nelle versioni future

**L'output di Explain può cambiare nelle versioni future**  
Ad esempio, potrebbero essere modificate le intestazioni di colonna e altre colonne potrebbero essere aggiunte alle tabelle.

# Query federate SPARQL in Neptune che utilizzano l'estensione `SERVICE`
<a name="sparql-service"></a>

Amazon Neptune supporta completamente l'estensione delle query federate SPARQL che utilizza la parola chiave `SERVICE`. Per ulteriori informazioni, consulta [Query federate SPARQL 1.1](https://www.w3.org/TR/sparql11-federated-query/).

La parola chiave `SERVICE` indica al motore di query SPARQL di eseguire una parte della query rispetto a un endpoint SPARQL remoto e di comporre il risultato della query finale. Sono possibili solo le operazioni `READ`. Le operazioni `WRITE` e `DELETE` non sono supportate. Neptune può eseguire solo query federate su endpoint SPARQL accessibili all'interno del proprio cloud privato virtuale (VPC). Tuttavia, è anche possibile utilizzare un proxy inverso nel VPC per rendere accessibile un'origine dati esterna all'interno del VPC.

**Nota**  
Quando SPARQL `SERVICE` viene utilizzato per federare una query a due o più cluster Neptune nello stesso VPC, i gruppi di sicurezza devono essere configurati per consentire a tutti i cluster Neptune di parlare tra loro.

**Importante**  
La federazione SPARQL 1.1 effettua richieste di servizio per tuo conto quando trasferisci query e parametri a endpoint SPARQL esterni. È tua responsabilità verificare che gli endpoint SPARQL esterni soddisfino i requisiti di sicurezza e gestione dei dati dell'applicazione.

## Esempio di una query federata Neptune
<a name="sparql-service-example-1"></a>

Il seguente esempio semplice mostra il funzionamento di query federate SPARQL.

Supponiamo che un cliente invii la seguente query a *Neptune-1* all'indirizzo `http://neptune-1:8182/sparql`.

```
SELECT * WHERE {
   ?person rdf:type foaf:Person .
   SERVICE <http://neptune-2:8182/sparql> {
       ?person foaf:knows ?friend .
    }
}
```

1. *Neptune-1* valuta il primo modello di query (*Q-1*) che è `?person rdf:type foaf:Person`, utilizza i risultati per risolvere `?person` in *Q-2* (`?person foaf:knows ?friend`) e inoltra il modello risultante a *Neptune-2* all'indirizzo `http://neptune-2:8182/sparql`.

1. *Neptune-2* valuta *Q-2* e restituisce i risultati a *Neptune-1*.

1. *Neptune-1* unisce le soluzioni per entrambi i modelli e restituisce i risultati al cliente.

Questo flusso è mostrato nel seguente diagramma.

![\[Diagramma di flusso che mostra i modelli di query federate SPARQL in fase di valutazione e le risposte inviate al client.\]](http://docs.aws.amazon.com/it_it/neptune/latest/userguide/images/federated.png)


**Nota**  
Per impostazione predefinita, il sistema di ottimizzazione determina a che punto dell'esecuzione della query viene eseguita l'istruzione `SERVICE`. È possibile sostituire questo posizionamento utilizzando l'hint di query [joinOrder](sparql-query-hints-joinOrder.md).

## Controllo degli accessi per query federate in Neptune
<a name="sparql-service-auth"></a>

Neptune AWS Identity and Access Management utilizza (IAM) per l'autenticazione e l'autorizzazione. Il controllo degli accessi per una query federata può riguardare più istanze database Neptune. Queste istanze potrebbero avere requisiti diversi per il controllo degli accessi. In alcune circostanze, questo può limitare la possibilità di effettuare una query federata.

Consideriamo il semplice esempio presentato nella sezione precedente. *Neptune-1* chiama *Neptune-2* con le stesse credenziali con cui è stato chiamato.
+ Se *Neptune-1* richiede l'autenticazione e l'autorizzazione IAM, ma *Neptune-2* non le richiede, per effettuare la query federata occorrono solo le autorizzazioni IAM appropriate per *Neptune-1*.
+ Se *Neptune-1* e *Neptune-2* richiedono entrambi l'autenticazione e l'autorizzazione IAM, è necessario collegare le autorizzazioni IAM per entrambi i database per effettuare la query federata. Entrambi i cluster devono inoltre trovarsi nello stesso AWS account e nella stessa regione. Le architetture di query federate and/or tra più account non sono attualmente supportate.
+ Tuttavia, nel caso in cui *Neptune-1* non sia abilitato per IAM ma *Neptune-2* lo sia, non è possibile effettuare una query federata. Il motivo è che *Neptune-1* non può recuperare le credenziali IAM e passarle a *Neptune-2* per autorizzare la seconda parte della query.