

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

# Utilizzo di tabelle, elementi, query, scansioni e indici
<a name="WorkingWithDynamo"></a>

In questa sezione sono forniti i dettagli di utilizzo di tabelle, elementi, query e altri elementi in Amazon DynamoDB.

**Topics**
+ [Utilizzo di tabelle e dati in DynamoDB](WorkingWithTables.md)
+ [Tabelle globali: replica multi-attiva e multi-Regione](GlobalTables.md)
+ [Utilizzo di elementi e attributi in DynamoDB](WorkingWithItems.md)
+ [Miglioramento dell’accesso ai dati con gli indici secondari in DynamoDB](SecondaryIndexes.md)
+ [Gestione di flussi di lavoro complessi con transazioni DynamoDB](transactions.md)
+ [Change Data Capture con Amazon DynamoDB](streamsmain.md)

# Utilizzo di tabelle e dati in DynamoDB
<a name="WorkingWithTables"></a>

Questa sezione descrive come utilizzare AWS Command Line Interface (AWS CLI) e AWS SDKs per creare, aggiornare ed eliminare tabelle in Amazon DynamoDB.

**Nota**  
Puoi eseguire queste stesse attività utilizzando la Console di gestione AWS. Per ulteriori informazioni, consulta [Utilizzo della console](AccessingDynamoDB.md#ConsoleDynamoDB).

In questa sezione sono fornite inoltre ulteriori informazioni sulla capacità di throughput tramite l'uso della scalabilità automatica di DynamoDB o l'impostazione manuale della velocità effettiva assegnata.

**Topics**
+ [Operazioni di base sulle tabelle DynamoDB](WorkingWithTables.Basics.md)
+ [Considerazioni sulla scelta di una classe di tabella in DynamoDB](WorkingWithTables.tableclasses.md)
+ [Aggiunta di tag ed etichette alle risorse in DynamoDB](Tagging.md)

# Operazioni di base sulle tabelle DynamoDB
<a name="WorkingWithTables.Basics"></a>

Analogamente ad altri sistemi di database, Amazon DynamoDB archivia i dati in tabelle. Puoi gestire le tabelle utilizzando alcune operazioni di base.

**Topics**
+ [Creazione di una tabella](#WorkingWithTables.Basics.CreateTable)
+ [Descrizione di una tabella](#WorkingWithTables.Basics.DescribeTable)
+ [Aggiornamento di una tabella](#WorkingWithTables.Basics.UpdateTable)
+ [Eliminazione di una tabella](#WorkingWithTables.Basics.DeleteTable)
+ [Uso della protezione da eliminazione](#WorkingWithTables.Basics.DeletionProtection)
+ [Elenco dei nomi delle tabelle](#WorkingWithTables.Basics.ListTables)
+ [Descrizione delle quote di velocità di trasmissione effettiva assegnate](#WorkingWithTables.Basics.DescribeLimits)

## Creazione di una tabella
<a name="WorkingWithTables.Basics.CreateTable"></a>

Utilizza l'operazione `CreateTable` per creare una tabella in Amazon DynamoDB. Per creare la tabella, è necessario fornire le informazioni riportate di seguito:
+ **Nome tabella.** Il nome deve essere conforme alle regole di denominazione di DynamoDB e deve essere univoco per l'account corrente e la regione. AWS Ad esempio, è possibile creare una tabella `People` nella regione Stati Uniti orientali (Virginia settentrionale) e un'altra tabella `People` in Europa (Irlanda). Tuttavia, queste due tabelle sarebbero totalmente diverse l'una dall'altra. Per ulteriori informazioni, consulta [Tipi di dati e regole di denominazione supportati in Amazon DynamoDB](HowItWorks.NamingRulesDataTypes.md).
+ **Chiave primaria.** La chiave primaria può consistere di un attributo (chiave di partizione) o due attributi (chiave di partizione e chiave di ordinamento). Devi fornire i nomi e i tipi di dati degli attributi e il ruolo di ciascun attributo: `HASH` (per una chiave di partizione) e `RANGE` (per una chiave di ordinamento). Per ulteriori informazioni, consulta [Chiave primaria](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey).
+ **Impostazioni di throughput (per tabelle assegnate).** Se utilizzi la modalità assegnata, devi specificare le impostazioni iniziali di throughput di lettura e scrittura per la tabella. Queste impostazioni possono essere modificate successivamente oppure è possibile abilitare la scalabilità automatica di DynamoDB perché le impostazioni vengano gestite automaticamente. Per ulteriori informazioni, consultare [Modalità con capacità allocata di DynamoDB](provisioned-capacity-mode.md) e [Gestione automatica della capacità effettiva di trasmissione con il dimensionamento automatico di DynamoDB](AutoScaling.md).

### Esempio 1: creare una tabella su richiesta
<a name="create-payperrequest-example"></a>

Per creare la stessa tabella `Music` utilizzando la modalità on demand:

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode=PAY_PER_REQUEST
```

L'operazione `CreateTable` restituisce i metadati per la tabella, come illustrato di seguito:

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 0,
            "ReadCapacityUnits": 0
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "BillingModeSummary": {
            "BillingMode": "PAY_PER_REQUEST"
        },
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397468.348
    }
}
```

**Importante**  
 Quando si richiama `DescribeTable` su una tabella on demand, le unità di capacità in lettura e le unità di capacità in scrittura sono impostate su 0. 

### Esempio 2: creazione di una tabella predisposta
<a name="create-provisioned-example"></a>

L' AWS CLI esempio seguente mostra come creare una tabella (`Music`). La chiave primaria è costituita da `Artist` (chiave di partizione) e `SongTitle` (chiave di ordinamento), entrambe con tipo di dati `String`. Il throughput massimo per questa tabella è 10 unità di capacità di lettura e 5 unità di capacità di scrittura.

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5
```

L'operazione `CreateTable` restituisce i metadati per la tabella, come illustrato di seguito:

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 5,
            "ReadCapacityUnits": 10
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397215.37
    }
}
```

L'elemento `TableStatus` indica lo stato corrente della tabella (`CREATING`). La creazione della tabella potrebbe richiedere del tempo, in base ai valori specificati per `ReadCapacityUnits` e `WriteCapacityUnits`. Valori maggiori richiedono l'allocazione di più risorse per la tabella da parte di DynamoDB.

### Esempio 3: creazione di una tabella utilizzando la classe di tabella DynamoDB Standard (accesso infrequente)
<a name="create-infrequent-access-example"></a>

Crea la stessa tabella `Music` utilizzando la classe di tabella DynamoDB Standard (accesso infrequente).

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --table-class STANDARD_INFREQUENT_ACCESS
```

L'operazione `CreateTable` restituisce i metadati per la tabella, come illustrato di seguito:

```
{
    "TableDescription": {
        "TableArn": "arn:aws:dynamodb:us-east-1:123456789012:table/Music",
        "AttributeDefinitions": [
            {
                "AttributeName": "Artist",
                "AttributeType": "S"
            },
            {
                "AttributeName": "SongTitle",
                "AttributeType": "S"
            }
        ],
        "ProvisionedThroughput": {
            "NumberOfDecreasesToday": 0,
            "WriteCapacityUnits": 5,
            "ReadCapacityUnits": 10
        },
        "TableClassSummary": {
            "LastUpdateDateTime": 1542397215.37,
            "TableClass": "STANDARD_INFREQUENT_ACCESS"
        },
        "TableSizeBytes": 0,
        "TableName": "Music",
        "TableStatus": "CREATING",
        "TableId": "12345678-0123-4567-a123-abcdefghijkl",
        "KeySchema": [
            {
                "KeyType": "HASH",
                "AttributeName": "Artist"
            },
            {
                "KeyType": "RANGE",
                "AttributeName": "SongTitle"
            }
        ],
        "ItemCount": 0,
        "CreationDateTime": 1542397215.37
    }
}
```

## Descrizione di una tabella
<a name="WorkingWithTables.Basics.DescribeTable"></a>

Per visualizzare i dettagli su una tabella, utilizza l'operazione `DescribeTable`. Devi specificare il nome della tabella. Il formato dell'output da `DescribeTable` è identico a quello da `CreateTable`. Include il timestamp di creazione della tabella, lo schema delle chiavi, le impostazioni della velocità effettiva assegnata, le dimensioni stimate e gli eventuali indici secondari presenti.

**Importante**  
 Quando si richiama `DescribeTable` su una tabella on demand, le unità di capacità in lettura e le unità di capacità in scrittura sono impostate su 0. 

**Example**  

```
aws dynamodb describe-table --table-name Music
```

La tabella è pronta per l'uso quando `TableStatus` cambia da `CREATING` ad `ACTIVE`.

**Nota**  
Se si emette una richiesta `DescribeTable` subito dopo una richiesta `CreateTable`, DynamoDB potrebbe restituire un errore (`ResourceNotFoundException`). Questo accade perché `DescribeTable` utilizza una query consistente finale e i metadata della tabella potrebbero non essere disponibili in quel momento. Attendi qualche secondo e prova nuovamente la richiesta `DescribeTable`.  
A scopo di fatturazione, i costi di archiviazione di DynamoDB includono un costo per elemento di 100 byte. Per ulteriori informazioni, consulta [Prezzi di DynamoDB](https://aws.amazon.com/dynamodb/pricing/). Questi 100 byte extra per elemento non sono utilizzati nei calcoli delle unità di capacità o dall'operazione `DescribeTable`. 

## Aggiornamento di una tabella
<a name="WorkingWithTables.Basics.UpdateTable"></a>

L'operazione `UpdateTable` consente di effettuare una delle operazioni seguenti:
+ Modificare le impostazioni di throughput assegnate di una tabella (per tabelle con modalità assegnata).
+ Cambia la modalità di read/write capacità della tabella.
+ Utilizza gli indici secondari globali nella tabella (consulta [Utilizzo degli indici secondari globali in DynamoDB](GSI.md)).
+ Abilitare o disabilitare DynamoDB Streams sulla tabella (vedere [Acquisizione dei dati di modifica per DynamoDB Streams](Streams.md)).

**Example**  
L' AWS CLI esempio seguente mostra come modificare le impostazioni di throughput assegnate a una tabella.  

```
aws dynamodb update-table --table-name Music \
    --provisioned-throughput ReadCapacityUnits=20,WriteCapacityUnits=10
```

**Nota**  
Quando emetti una richiesta `UpdateTable`, lo stato della tabella cambia da `AVAILABLE` a `UPDATING`. La tabella rimane completamente disponibile mentre lo stato è `UPDATING`. Al termine del processo, lo stato cambia da `UPDATING` ad `AVAILABLE`.

**Example**  
L' AWS CLI esempio seguente mostra come modificare la modalità di read/write capacità di una tabella in modalità on-demand.  

```
aws dynamodb update-table --table-name Music \
    --billing-mode PAY_PER_REQUEST
```

## Eliminazione di una tabella
<a name="WorkingWithTables.Basics.DeleteTable"></a>

Puoi rimuovere una tabella inutilizzata con l'operazione `DeleteTable`. L'operazione di eliminazione di una tabella è irreversibile. Per eliminare una tabella utilizzando la Console di gestione AWS, consulta [Fase 6: (facoltativo) eliminare la tabella DynamoDB per eseguire la pulizia delle risorse](getting-started-step-6.md).

**Example**  
L' AWS CLI esempio seguente mostra come eliminare una tabella.  

```
aws dynamodb delete-table --table-name Music
```

Quando emetti una richiesta `DeleteTable`, lo stato della tabella cambia da `ACTIVE` a `DELETING`. L'eliminazione della tabella può richiedere del tempo, in base alle risorse che utilizza (come i dati archiviati e i flussi o gli indici presenti).

A conclusione dell'operazione `DeleteTable`, la tabella sarà più presente in DynamoDB.

## Uso della protezione da eliminazione
<a name="WorkingWithTables.Basics.DeletionProtection"></a>

È possibile proteggere una tabella dall'eliminazione accidentale con la proprietà di protezione da eliminazione. L'attivazione di questa proprietà per una tabella aiuta a garantire che non venga eliminata accidentalmente durante le normali operazioni di gestione delle tabelle degli amministratori. In tal modo si contribuisce anche a prevenire le interruzioni delle normali operazioni aziendali.

 Il proprietario della tabella o un amministratore autorizzato controlla la proprietà di protezione da eliminazione per ogni tabella che per impostazione predefinita è disattivata per tutte le tabelle, incluse le repliche globali e le tabelle ripristinate dai backup. Quando la protezione da eliminazione è disabilitata, la tabella può essere eliminata da qualsiasi utente autorizzato da una policy Identity and Access Management (IAM). Quando la protezione da eliminazione è abilitata, nessuno può eliminare la tabella. 

Per modificare questa impostazione, vai alle **Impostazioni aggiuntive** della tabella, apri il pannello **Protezione da eliminazione** e seleziona **Abilita la protezione da eliminazione**. 

La proprietà di protezione da eliminazione è supportata dalla console DynamoDB, dall'API, dalla CLI, dall'SDK e da CloudFormation. L'API `CreateTable` supporta la proprietà di protezione da eliminazione al momento della creazione della tabella e l'API `UpdateTable` supporta la modifica della proprietà di protezione da eliminazione per le tabelle esistenti.

**Nota**  
Se un AWS account viene eliminato, tutti i dati dell'account, incluse le tabelle, vengono comunque eliminati entro 90 giorni.
Se DynamoDB perde l'accesso a una chiave gestita dal cliente utilizzata per crittografare una tabella, archivia comunque la tabella. L'archiviazione comporta l'esecuzione di un backup della tabella e l'eliminazione dell'originale.

## Elenco dei nomi delle tabelle
<a name="WorkingWithTables.Basics.ListTables"></a>

L'`ListTables`operazione restituisce i nomi delle tabelle DynamoDB per l'account AWS corrente e la regione.

**Example**  
L' AWS CLI esempio seguente mostra come elencare i nomi delle tabelle DynamoDB.  

```
aws dynamodb list-tables
```

## Descrizione delle quote di velocità di trasmissione effettiva assegnate
<a name="WorkingWithTables.Basics.DescribeLimits"></a>

L'`DescribeLimits`operazione restituisce le quote di capacità di lettura e scrittura correnti per l' AWS account corrente e la regione.

**Example**  
L' AWS CLI esempio seguente mostra come descrivere le quote di throughput attualmente assegnate.  

```
aws dynamodb describe-limits
```
L'output mostra le quote superiori di unità di capacità di lettura e scrittura per il conto corrente AWS e la regione.

Per ulteriori informazioni sulle quote e su come richiedere un aumento delle quote, consulta [Quote predefinite della velocità di trasmissione effettiva](ServiceQuotas.md#default-limits-throughput).

# Considerazioni sulla scelta di una classe di tabella in DynamoDB
<a name="WorkingWithTables.tableclasses"></a>

DynamoDB offre due classi di tabelle progettate per aiutarti a ottimizzare i costi. La classe di tabella DynamoDB Standard è quella predefinita ed è consigliata per la maggior parte dei carichi di lavoro. La classe di tabella DynamoDB Standard-Infrequent Access (DynamoDB Standard (accesso infrequente)) è ottimizzata per le tabelle in cui l'archiviazione è il costo principale. Ad esempio, le tabelle che archiviano dati a cui si accede raramente, come i registri delle applicazioni, i vecchi post sui social media, la cronologia degli ordini di e-commerce e i risultati di gioco precedenti, sono buoni candidati per la classe di tabella Standard (accesso infrequente).

Ogni tabella DynamoDB è associata a una classe di tabella. Tutti gli indici secondari associati alla tabella utilizzano la stessa classe di tabella. È possibile impostare la classe di tabella durante la creazione della tabella (DynamoDB Standard per impostazione predefinita) e aggiornare la classe di tabella di una tabella esistente utilizzando la AWS CLI o l' Console di gestione AWS SDK. AWS DynamoDB supporta anche la gestione della classe di tabelle AWS CloudFormation utilizzando tabelle a regione singola (tabelle che non sono tabelle globali). Ogni classe di tabella offre prezzi diversi per l'archiviazione dati e le richieste di lettura e scrittura. Quando scegli una classe di tabella per la tua tabella, tieni presente quanto segue:
+ La classe di tabella DynamoDB Standard offre costi di throughput inferiori rispetto a DynamoDB Standard (accesso infrequente) ed è l'opzione più conveniente per le tabelle in cui il throughput è il costo dominante. 
+ La classe di tabella DynamoDB Standard (accesso infrequente) offre costi di storage inferiori rispetto a DynamoDB Standard ed è l'opzione più conveniente per le tabelle in cui l'archiviazione è il costo dominante. Quando l'archiviazione supera il 50% del costo del throughput (letture e scritture) di una tabella utilizzando la classe di tabella DynamoDB Standard, la classe di tabella DynamoDB Standard (accesso infrequente) può aiutare a ridurre il costo totale della tabella. 
+ Le tabelle DynamoDB Standard (accesso infrequente) offrono le stesse prestazioni, durata e disponibilità delle tabelle DynamoDB Standard. 
+ Il passaggio tra le classi di tabella DynamoDB Standard e Standard (accesso infrequente) non richiede la modifica del codice dell'applicazione. Utilizzi lo stesso APIs DynamoDB e gli stessi endpoint di servizio indipendentemente dalla classe di tabella utilizzata dalle tabelle. 
+ Le tabelle DynamoDB Standard-IA sono compatibili con tutte le funzionalità di DynamoDB esistenti come la scalabilità automatica, la time-to-live modalità on-demand (TTL), i backup su richiesta, il ripristino (PITR) e gli indici secondari globali. point-in-time

La classe di tabella più conveniente per la tabella dipende dai modelli di archiviazione e utilizzo del throughput previsti dalla tabella. Puoi esaminare lo storico dei costi e dell'utilizzo dello storage e del throughput della tabella con AWS Cost and Usage Reports e AWS Cost Explorer. Utilizza questi dati storici per determinare la classe di tabella più conveniente per la tua tabella. Per ulteriori informazioni sull'utilizzo dei report sui AWS costi e sull'utilizzo e del AWS Cost Explorer, consulta la documentazione di [AWS Billing and Cost Management](https://docs.aws.amazon.com/account-billing/index.html). Per dettagli sui prezzi della classe di tabella, consulta [Amazon DynamoDB Pricing](https://aws.amazon.com/dynamodb/pricing/on-demand/).

**Nota**  
Un aggiornamento della classe di tabella è un processo in background. Puoi comunque accedere normalmente alla tabella durante un aggiornamento della classe di tabella. Il tempo necessario per aggiornare la classe di tabella dipende dal traffico della tabella, dalle dimensioni di archiviazione e da altre variabili correlate. Non sono consentiti più di due aggiornamenti della classe di tabella in un periodo finale di 30 giorni.

# Aggiunta di tag ed etichette alle risorse in DynamoDB
<a name="Tagging"></a>

È possibile etichettare le risorse Amazon DynamoDB utilizzando i *tag*. I tag consentono di categorizzare le risorse in diversi modi, ad esempio, per scopo, proprietario, ambiente o altri criteri. I tag consentono di eseguire le seguenti operazioni:
+ identificare rapidamente una risorsa in base ai tag a questa assegnati.
+ Visualizza le AWS fatture suddivise per tag.
**Nota**  
Tutti gli indici secondari locali (LSI) e gli indici secondari globali (GSI) correlati alle tabelle con le etichette, sono etichettati con gli stessi tag in modo automatico. Attualmente, l'utilizzo di DynamoDB Streams non può essere taggato.

Il tagging è supportato da AWS servizi come Amazon EC2, Amazon S3, DynamoDB e altri. Un tagging efficiente può fornire informazioni dettagliate sui costi abilitando la creazione di report su servizi che recano tag specifici.

Per iniziare a utilizzare il tagging, procedi come segue:

1. comprendere [Limitazioni dell'assegnazione di tag in DynamoDB](#TaggingRestrictions);

1. creare tag utilizzando [Assegnazione di tag alle risorse in DynamoDB](Tagging.Operations.md);

1. Utilizzalo [Utilizzo dei tag DynamoDB per creare report di allocazione dei costi](#CostAllocationReports) per tenere traccia dei costi per tag attivo. AWS 

Infine, è buona norma seguire strategie di tagging ottimali. Per informazioni, consulta [Strategie di assegnazione di tag di AWS](https://d0.awsstatic.com/aws-answers/AWS_Tagging_Strategies.pdf).

## Limitazioni dell'assegnazione di tag in DynamoDB
<a name="TaggingRestrictions"></a>

 Ogni tag consiste di una chiave e di un valore, entrambi personalizzabili. Le restrizioni si applicano come segue: 
+  Ogni tabella DynamoDB può avere solo un tag con la stessa chiave. Se provi ad aggiungere un tag esistente (con la stessa chiave), il valore del tag esistente viene caricato al nuovo valore; 
+  I valori e le chiavi dei tag rispettano la distinzione tra maiuscole e minuscole. 
+  La lunghezza massima della chiave è di 128 caratteri Unicode. 
+ La lunghezza massima del valore è di 256 caratteri Unicode. 
+  i caratteri consentiti sono lettere, spazi vuoti, numeri e i seguenti caratteri speciali: `+ - = . _ : /` 
+  Il numero massimo di tag per risorsa è 50.
+ La dimensione massima supportata per tutti i tag in una tabella è 10 KB.
+ AWS-ai nomi e ai valori dei tag assegnati viene assegnato automaticamente il `aws:` prefisso, che non puoi assegnare. AWS-i nomi dei tag assegnati non vengono conteggiati ai fini del limite di tag di 50 o del limite di dimensione massima di 10 KB. I nomi dei tag assegnati dall'utente hanno il prefisso `user:` nel report di allocazione dei costi; 
+  Non puoi retrodatare l'applicazione di un tag. 

# Assegnazione di tag alle risorse in DynamoDB
<a name="Tagging.Operations"></a>

Puoi utilizzare la console Amazon DynamoDB o AWS Command Line Interface il AWS CLI() per aggiungere, elencare, modificare o eliminare tag. Puoi quindi attivare questi tag definiti dall'utente in modo che vengano visualizzati nella console Gestione dei costi e fatturazione AWS per il tracciamento dell'allocazione dei costi. Per ulteriori informazioni, consulta [Utilizzo dei tag DynamoDB per creare report di allocazione dei costi](Tagging.md#CostAllocationReports). 

 Per la modifica in blocco, puoi anche utilizzare l'editor di tag nella Console di gestione AWS. Per ulteriori informazioni, consulta [Utilizzo dell'editor di tag](https://docs.aws.amazon.com/awsconsolehelpdocs/latest/gsg/tag-editor.html).

 Per utilizzare l'API DynamoDB, consulta le seguenti operazioni nella [Documentazione di riferimento delle API di Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/):
+ [TagResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TagResource.html)
+ [UntagResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UntagResource.html)
+ [ListTagsOfResource](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTagsOfResource.html)

**Topics**
+ [Impostazione delle autorizzazioni per filtrare in base ai tag](#Tagging.Operations.permissions)
+ [Aggiunta di tag a tabelle nuove o esistenti (Console di gestione AWS)](#Tagging.Operations.using-console)
+ [Aggiunta di tag a tabelle nuove o esistenti (AWS CLI)](#Tagging.Operations.using-cli)

## Impostazione delle autorizzazioni per filtrare in base ai tag
<a name="Tagging.Operations.permissions"></a>

Per utilizzare i tag per filtrare l'elenco delle tabelle nella console DynamoDB, assicurati che le policy dell'utente includano l'accesso alle seguenti operazioni:
+ `tag:GetTagKeys`
+ `tag:GetTagValues`

È possibile accedere a queste operazioni collegando una nuova policy IAM all'utente attenendosi alla procedura riportata di seguito.

1. Accedi alla [Console IAM](https://console.aws.amazon.com/iam/) come utente amministratore.

1. Nel menu di navigazione a sinistra, seleziona "Policy".

1. Seleziona "Crea policy".

1. Incollare la seguente policy nell'editor JSON.

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "tag:GetTagKeys",
                   "tag:GetTagValues"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

------

1. Completare la procedura guidata e assegnare un nome alla policy, ad esempio `TagKeysAndValuesReadAccess`.

1. Dal menu di navigazione a sinistra, scegli "Utenti".

1. Dall'elenco, seleziona l'utente normalmente utilizzato per accedere alla console DynamoDB.

1. Seleziona "Aggiungi autorizzazioni".

1. Seleziona "Collega direttamente le policy esistenti".

1. Seleziona quindi la policy creata in precedenza.

1. Completa la procedura guidata.

## Aggiunta di tag a tabelle nuove o esistenti (Console di gestione AWS)
<a name="Tagging.Operations.using-console"></a>

È possibile utilizzare la console DynamoDB per aggiungere, tag a nuove tabelle durante la loro creazione oppure aggiungere, modificare o eliminare i tag di tabelle esistenti.

**Per assegnare tag alle risorse al momento della creazione (console)**

1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Nel pannello di navigazione, scegli **Tabelle**, quindi seleziona **Crea tabella**.

1. Nella pagina **Create DynamoDB table (Crea tabella DynamoDB)**, fornire un nome e una chiave primaria. Nella sezione **Tags (Tag)**, scegli **Add new tag (Aggiungi nuovo tag)** e inserisci i tag che vuoi utilizzare.

   Per informazioni sulla struttura dei tag, consulta [Limitazioni dell'assegnazione di tag in DynamoDB](Tagging.md#TaggingRestrictions). 

   Per ulteriori informazioni sulla creazione delle tabelle, consulta [Operazioni di base sulle tabelle DynamoDB](WorkingWithTables.Basics.md).

**Per assegnare tag alle risorse esistenti (console)**

Apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Nel pannello di navigazione, seleziona **Tabelle**.

1. Scegli una tabella nell'elenco, quindi scegli la scheda **Additional settings (Impostazioni aggiuntive)**. Puoi aggiungere, modificare o eliminare i tag nella sezione **Tags (Tag)** nella parte inferiore della pagina.

## Aggiunta di tag a tabelle nuove o esistenti (AWS CLI)
<a name="Tagging.Operations.using-cli"></a>

Gli esempi seguenti mostrano come utilizzare i tag AWS CLI per specificare quando si creano tabelle e indici e per etichettare le risorse esistenti.

**Per assegnare tag alle risorse al momento della creazione (AWS CLI)**
+ Il seguente esempio crea una nuova tabella `Movies` e aggiunge il tag `Owner` con un valore `blueTeam`: 

  ```
  aws dynamodb create-table \
      --table-name Movies \
      --attribute-definitions AttributeName=Title,AttributeType=S \
      --key-schema AttributeName=Title,KeyType=HASH \
      --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
      --tags Key=Owner,Value=blueTeam
  ```

**Per assegnare tag alle risorse esistenti (AWS CLI)**
+ L'esempio seguente aggiunge il tag `Owner` con un valore `blueTeam` della tabella `Movies`: 

  ```
  aws dynamodb tag-resource \
      --resource-arn arn:aws:dynamodb:us-east-1:123456789012:table/Movies \
      --tags Key=Owner,Value=blueTeam
  ```

**Per elencare tutti i tag di una tabella (AWS CLI)**
+ L'esempio seguente elenca tutti i tag associati alla tabella `Movies`:

  ```
  aws dynamodb list-tags-of-resource \
      --resource-arn arn:aws:dynamodb:us-east-1:123456789012:table/Movies
  ```

## Utilizzo dei tag DynamoDB per creare report di allocazione dei costi
<a name="CostAllocationReports"></a>

AWS utilizza i tag per organizzare i costi delle risorse nel rapporto di allocazione dei costi. AWS fornisce due tipi di tag di allocazione dei costi:
+ Un AWS tag generato. AWS definisce, crea e applica questo tag per te.
+ Tag definiti dall'utente. L'utente definisce, crea e applica questi tag.

È necessario attivare entrambi i tipi di tag separatamente per poterli visualizzare in Cost Explorer o in un report di allocazione dei costi. 

 Per attivare i tag AWS generati: 

1.  Accedi Console di gestione AWS e apri la console Billing and Cost Management [https://console.aws.amazon.com/billing/a](https://console.aws.amazon.com/billing/home#/.) casa\$1/. 

1.  Nel riquadro di navigazione scegli **Cost Allocation Tags (Tag per l'allocazione dei costi)**. 

1.  In **Tag per l'allocazione dei costi generati da AWS** scegli **Attiva**. 

 Per attivare i tag definiti dall'utente: 

1.  Accedi Console di gestione AWS e apri la console Billing and Cost Management [https://console.aws.amazon.com/billing/a](https://console.aws.amazon.com/billing/home#/.) casa\$1/. 

1.  Nel riquadro di navigazione scegli **Cost Allocation Tags (Tag per l'allocazione dei costi)**. 

1.  In **Tag per l'allocazione dei costi definiti dall'utente** scegli **Attiva**. 

 Dopo aver creato e attivato i tag, AWS genera un rapporto di allocazione dei costi con l'utilizzo e i costi raggruppati in base ai tag attivi. Il rapporto sull'allocazione dei costi include tutti i AWS costi per ogni periodo di fatturazione. Il report include sia le risorse taggate, sia quelle non taggate, per permetterti di organizzare in modo chiaro le spese per le risorse. 

**Nota**  
 Attualmente, tutti i dati trasferiti da DynamoDB non saranno suddivisi per tag nei report di allocazione dei costi. 

 Per ulteriori informazioni, consulta [Utilizzo dei tag per l'allocazione dei costi](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html). 

# Tabelle globali: replica multi-attiva e multi-Regione
<a name="GlobalTables"></a>

Le *tabelle globali Amazon DynamoDB* sono una funzionalità di database completamente gestito, multi-Regione e multi-attivo che offre replica dei dati e prestazioni di lettura e scrittura rapide e localizzate per applicazioni scalate a livello globale.

Le tabelle globali replicano automaticamente i dati delle tabelle DynamoDB su più account e, facoltativamente AWS , Regioni AWS su più account senza richiedere la creazione e la manutenzione della propria soluzione di replica. Le tabelle globali sono ideali per le applicazioni che richiedono continuità aziendale e alta disponibilità attraverso l’implementazione multi-Regione. Qualsiasi replica di tabella globale può essere utilizzata per operazioni di lettura e scrittura. Le applicazioni possono raggiungere un’elevata resilienza con un Obiettivo del punto di ripristino (RPO) basso o nullo spostando il traffico verso un’altra Regione se l’elaborazione delle applicazioni viene interrotta in una Regione. Le tabelle globali sono disponibili in tutte le Regioni in cui DynamoDB è disponibile.

## Modalità di coerenza
<a name="GlobalTables.consistency-modes"></a>

Quando si crea una tabella globale, è possibile configurarne la modalità di coerenza. Le tabelle globali supportano due modalità di coerenza: Multi-region Eventual Consistency (MREC) e Multi-region Strong Consistency (MRSC).

Se non si specifica una modalità di coerenza durante la creazione di una tabella globale, la tabella globale utilizza come impostazione predefinita la coerenza finale multi-Regione (MREC). Una tabella globale non può contenere repliche configurate con modalità di coerenza diverse. Non è possibile modificare la modalità di coerenza di una tabella globale dopo la creazione.

## Configurazioni dell'account
<a name="GlobalTables.account-configurations"></a>

DynamoDB ora supporta due modelli di tabelle globali, ciascuno progettato per diversi modelli architettonici:
+ **Tabelle globali dello stesso account**: tutte le repliche vengono create e gestite all'interno di un unico account. AWS 
+ **Tabelle globali con più account: le** repliche vengono distribuite su più AWS account mentre partecipano a un gruppo di replica condiviso.

Sia i modelli con lo stesso account che quelli con più account supportano scritture in più regioni, replica asincrona, risoluzione dei conflitti e lo stesso modello di fatturazione. last-writer-wins Tuttavia, differiscono nel modo in cui vengono gestiti gli account, le autorizzazioni, la crittografia e la governance delle tabelle.

Le tabelle globali configurate per MRSC supportano solo configurazioni dello stesso account.

È possibile configurare una tabella globale utilizzando la console di gestione. AWS Le tabelle globali utilizzano APIs DynamoDB esistente per leggere e scrivere dati nelle tabelle, quindi non sono necessarie modifiche all'applicazione. Il pagamento avviene solo in base alle risorse allocate o utilizzate, senza costi anticipati o impegni.


| **Proprietà** | **Tabelle globali per lo stesso account** | **Tabelle globali con più account** | 
| --- | --- | --- | 
| Caso d'uso principale | Resilienza multiregionale per le applicazioni all'interno di un singolo account AWS  | Replica multiregionale e multi-account per applicazioni di proprietà di team diversi, unità aziendali distinte o forti limiti di sicurezza tra gli account | 
| Modello di account | Tutte le repliche create e gestite in un unico account AWS  | Repliche create su più AWS account all'interno della stessa distribuzione | 
| Proprietà delle risorse | La tabella e tutte le repliche sono gestite da un solo account | Ogni account possiede la propria replica locale; il gruppo di replica si estende su più account | 
| Versione supportata | Tabelle globali versione 2019.11.21 (attuale) e versione 2017.11.29 (Legacy) | Tabelle globali versione 2019.11.21 (attuale) | 
| Operazioni del piano di controllo | Crea, modifica ed elimina le repliche tramite l'account del proprietario della tabella | Operazioni distribuite sul piano di controllo: gli account entrano o escono dal gruppo di replica | 
| Operazioni sul piano dati | Endpoint DynamoDB standard per regione | Accesso al piano dati per account/regione; instradamento attraverso il gruppo di replica | 
| Limite di sicurezza | Un unico limite IAM e KMS | IAM, KMS, fatturazione e governance distinti per CloudTrail account | 
| La soluzione migliore | Organizzazioni con proprietà centralizzata delle tabelle | Organizzazioni con team federati, confini di governance o configurazioni con più account | 

**Topics**
+ [Modalità di coerenza](#GlobalTables.consistency-modes)
+ [Configurazioni dell'account](#GlobalTables.account-configurations)
+ [Concetti fondamentali delle tabelle globali](globaltables-CoreConcepts.md)
+ [Tabella globale per lo stesso account DynamoDB](globaltables-SameAccount.md)
+ [Tabelle globali multi-account DynamoDB](globaltables-MultiAccount.md)
+ [Informazioni sulla fatturazione di Amazon DynamoDB per le tabelle globali](global-tables-billing.md)
+ [Versioni delle tabelle globali DynamoDB](V2globaltables_versions.md)
+ [Best practice per le tabelle globali](globaltables-bestpractices.md)

# Concetti fondamentali delle tabelle globali
<a name="globaltables-CoreConcepts"></a>

Le seguenti sezioni descrivono i concetti e i comportamenti delle tabelle globali in Amazon DynamoDB.

## Concetti
<a name="globaltables-CoreConcepts.KeyConcepts"></a>

*Le tabelle globali* sono una funzionalità di DynamoDB che replica i dati delle tabelle tra le regioni. AWS 

Una *tabella di replica* (o replica) è una singola tabella DynamoDB che funziona come parte di una tabella globale. Una tabella globale è composta da due o più tabelle di replica in diverse regioni. AWS Ciascuna tabella globale può avere una sola tabella di replica per Regione AWS . Tutte le repliche in una tabella globale condividono lo stesso nome di tabella, lo stesso schema di chiave primaria e gli stessi dati degli elementi.

Quando un’applicazione scrive dati in una replica in una Regione, DynamoDB replica automaticamente la scrittura in tutte le altre repliche nella tabella globale. Per ulteriori informazioni su come iniziare a utilizzare le tabelle globali, consulta [Tutorial: creazione di tabelle globali](V2globaltables.tutorial.md) o[Tutorial: Creazione di tabelle globali multi-account](V2globaltables_MA.tutorial.md).

## Versioni
<a name="globaltables-CoreConcepts.Versions"></a>

Sono disponibili due versioni delle tabelle globali DynamoDB: [Tabelle globali versione 2019.11.21 (Corrente)](GlobalTables.md) e [Tabelle globali versione 2017.11.29 (Legacy)](globaltables.V1.md). È necessario utilizzare la versione 2019.11.21 (corrente) di Global Tables ogni volta che è possibile. Le informazioni contenute in questa sezione della documentazione si riferiscono alla versione 2019.11.21 (Corrente). Per ulteriori informazioni, vedere Determinazione della versione di una tabella globale. [Determinare la versione di una tabella globale](V2globaltables_versions.md#globaltables.DetermineVersion)

## Disponibilità
<a name="globaltables-CoreConcepts.availability"></a>

Le tabelle globali aiutano a migliorare la continuità aziendale semplificando l’implementazione di un’architettura ad alta disponibilità multi-Regione. Se un carico di lavoro in una singola AWS regione viene compromesso, è possibile spostare il traffico delle applicazioni in una regione diversa ed eseguire letture e scritture su una tabella di replica diversa nella stessa tabella globale.

Ogni tabella di replica in una tabella globale offre la stessa durata e disponibilità di una tabella DynamoDB a Regione singola. Le tabelle globali offrono un [Accordo sul livello di servizio (SLA)](https://aws.amazon.com//dynamodb/sla/) con disponibilità del 99,999%, rispetto al 99,99% delle tabelle a Regione singola.

## Test di iniezione di guasti
<a name="fault-injection-testing"></a>

Entrambe le tabelle globali MREC e MRSC si integrano con [AWSAWS Fault Injection Service (FIS), un servizio](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) completamente gestito per l'esecuzione di esperimenti di iniezione di errori controllati per migliorare la resilienza di un'applicazione. Utilizzando AWS FIS, è possibile:
+ Creare modelli di esperimenti che definiscono scenari di fallimento specifici.
+ Inietta gli errori per convalidare la resilienza delle applicazioni simulando l'isolamento di una regione (ovvero, mettendo in pausa la replica da e verso una replica selezionata) per testare la gestione degli errori, i meccanismi di ripristino e il comportamento dello spostamento del traffico tra più regioni quando un'area subisce un'interruzione. AWS 

Ad esempio, in una tabella globale con repliche negli Stati Uniti orientali (Virginia settentrionale), negli Stati Uniti orientali (Ohio) e negli Stati Uniti occidentali (Oregon), è possibile eseguire un esperimento negli Stati Uniti orientali (Ohio) per testare l'isolamento della regione mentre Stati Uniti orientali (Virginia settentrionale) e Stati Uniti occidentali (Oregon) continuano le normali operazioni. Questo test controllato consente di identificare e risolvere potenziali problemi prima che influiscano sui carichi di lavoro di produzione. 

Consulta [Action targets](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) nella *guida per l'utente AWS FIS* per un elenco completo delle azioni supportate da AWS FIS e della [connettività interregionale per sospendere la replica di DynamoDB tra le regioni](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html).

*Per informazioni sulle azioni delle tabelle globali di Amazon DynamoDB disponibili AWS in FIS, [consulta il riferimento alle azioni delle tabelle globali di DynamoDB nella FIS User Guide](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference).AWS *

Per iniziare a eseguire esperimenti di fault injection, consulta [Planning your AWS FIS experiment (Pianificazione degli esperimenti FIS) nella guida per l'utente FIS](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html). AWS 

**Nota**  
Durante AWS FIS gli esperimenti in MRSC, alla fine sono consentite letture coerenti, ma gli aggiornamenti delle impostazioni delle tabelle, come la modifica della modalità di fatturazione o la configurazione del throughput della tabella, non sono consentiti, analogamente a MREC. Controlla la CloudWatch metrica per ulteriori dettagli sul codice [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors)di errore.

## Time to live (TTL)
<a name="global-tables-ttl"></a>

Le tabelle globali configurate per MREC supportano la configurazione dell’eliminazione [Time to Live](TTL.md) (TTL). Le impostazioni del TTL vengono sincronizzate automaticamente per tutte le repliche in una tabella globale. Quando il TTL elimina un elemento da una replica in una Regione, l’eliminazione viene replicata su tutte le altre repliche nella tabella globale. Il TTL non consuma capacità di scrittura, quindi non viene addebitato alcun costo per l’eliminazione TTL nella Regione in cui è avvenuta l’eliminazione. Tuttavia, viene addebitato il costo dell’eliminazione replicata in ogni altra Regione con una replica nella tabella globale.

La replica di eliminazione TTL consuma la capacità di scrittura sulle repliche in cui viene replicata l’eliminazione. Le repliche configurate per la capacità allocata possono limitare le richieste se la combinazione di throughput di scrittura e throughput di eliminazione TTL è superiore alla capacità di scrittura allocata.

Le tabelle globali configurate per MRSC (elevata consistenza multi-Regione) non supportano la configurazione dell’eliminazione TTL.

## Streams
<a name="global-tables-streams"></a>

Le tabelle globali configurate per coerenza finale multi-Regione (MREC) replicano le modifiche leggendo tali modifiche da un [flusso DynamoDB](Streams.md) su una tabella di replica e applicandole a tutte le altre tabelle di replica. I flussi sono quindi abilitati per impostazione predefinita su tutte le repliche in una tabella globale MREC e non possono essere disabilitati su tali repliche. Il processo di replica MREC può combinare più modifiche in un breve periodo di tempo in un’unica scrittura replicata, con il risultato che il flusso di ogni replica contiene record leggermente diversi. I record Streams sulle repliche MREC mantengono l'ordine per tutte le modifiche allo stesso elemento, ma l'ordine relativo delle modifiche ai diversi elementi può variare tra le repliche.

Se si desidera scrivere un’applicazione che elabori i record dei flussi per le modifiche avvenute in una particolare Regione ma non in altre Regioni in una tabella globale, è possibile aggiungere un attributo a ogni elemento che definisce in quale Regione è avvenuta la modifica per quell’elemento. È possibile utilizzare questo attributo per filtrare i record dei flussi in base alle modifiche apportate in altre Regioni, incluso l’uso dei filtri di eventi Lambda per invocare le funzioni Lambda solo per le modifiche in una Regione specifica.

Le tabelle globali configurate per elevata consistenza multi-Regione (MRSC) non utilizzano i flussi DynamoDB per la replica, pertanto i flussi non sono abilitati per impostazione predefinita sulle repliche MRSC. È possibile abilitare i flussi su una replica MRSC. I record dei flussi sulle repliche MRSC sono identici per ogni replica, incluso l’ordinamento dei record dei flussi.

## Transazioni
<a name="global-tables-transactions"></a>

In una tabella globale configurata per MREC, le operazioni di transazione DynamoDB ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) e [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) sono atomiche solo all’interno della Regione in cui è stata invocata l’operazione. Le scritture transazionali non vengono replicate come unità tra le Regioni, il che significa che solo alcune delle scritture di una transazione possono essere restituite dalle operazioni di lettura in altre repliche in un determinato momento.

Ad esempio, se è presente una tabella globale con repliche nelle Regioni Stati Uniti orientali (Ohio) e Stati Uniti occidentali (Oregon) e si esegue un’operazione `TransactWriteItems` nella Regione Stati Uniti orientali (Ohio), potrebbe essere possibile osservare transazioni parzialmente completate nella Regione Stati Uniti occidentali (Oregon) man mano che le modifiche vengono replicate. Le modifiche vengono replicate in altre Regioni solo dopo essere state confermate nella Regione di origine.

Le tabelle globali configurate per MRSC (elevata consistenza multi-Regione) non supportano le operazioni di transazione e restituiranno un errore se tali operazioni vengono invocate su una replica MRSC.

## Velocità di trasmissione effettiva di lettura e di scrittura
<a name="globaltables-CoreConcepts.Throughput"></a>

### Modalità provisioning
<a name="gt_throughput.provisioned"></a>

La replica consuma capacità di scrittura. Le repliche configurate per la capacità assegnata possono limitare le richieste se la combinazione del throughput di scrittura dell'applicazione e del throughput di scrittura della replica supera la capacità di scrittura assegnata. Per le tabelle globali che utilizzano la modalità provisioned, le impostazioni di ridimensionamento automatico per le capacità di lettura e scrittura sono sincronizzate tra le repliche.

È possibile configurare in modo indipendente le impostazioni della capacità di lettura per ogni replica in una tabella globale utilizzando il [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html)parametro a livello di replica. Per impostazione predefinita, le modifiche alla capacità di lettura assegnata vengono applicate a tutte le repliche nella tabella globale. Quando si aggiunge una nuova replica a una tabella globale, la capacità di lettura della tabella o della replica di origine viene utilizzata come valore iniziale, a meno che non venga specificata esplicitamente un'eccezione a livello di replica.

### Modalità on demand
<a name="gt_throughput.on-demand"></a>

Per le tabelle globali configurate per la modalità on demand, la capacità di scrittura viene sincronizzata automaticamente su tutte le repliche. DynamoDB regola automaticamente la capacità in base al traffico e non ci sono impostazioni di capacità di lettura o scrittura specifiche per la replica da gestire.

## Monitoraggio delle tabelle globali
<a name="monitoring-global-tables"></a>

Le tabelle globali configurate per la coerenza finale tra più regioni (MREC) pubblicano la metrica su. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Questa metrica tiene traccia del tempo trascorso tra la scrittura di un elemento in una tabella di replica e la visualizzazione di tale elemento in un’altra replica nella tabella globale. `ReplicationLatency` è espresso in millisecondi e viene emesso per ogni coppia di Regioni di origine e di destinazione in una tabella globale. 

`ReplicationLatency`I valori tipici dipendono dalla distanza tra le AWS regioni scelte e da altre variabili come il tipo di carico di lavoro e la velocità effettiva. Ad esempio, una replica di origine nella Regione Stati Uniti occidentali (California settentrionale) (us-west-1) ha un `ReplicationLatency` inferiore rispetto alla Regione Stati Uniti occidentali (Oregon) (us-west-2) rispetto alla Regione Africa (Città del Capo) (af-south-1).

Un valore crescente per `ReplicationLatency` potrebbe indicare che gli aggiornamenti da una replica non si propagano ad altre tabelle di replica in modo tempestivo. In questo caso, puoi reindirizzare temporaneamente l'attività di lettura e scrittura dell'applicazione verso un'altra regione. AWS 

Le tabelle globali configurate per l’elevata consistenza multi-Regione (MRSC) non pubblicano una metrica `ReplicationLatency`.

## Considerazioni sulla gestione delle tabelle globali
<a name="management-considerations"></a>

Non è possibile eliminare una tabella utilizzata per aggiungere una nuova replica globale della tabella prima che siano trascorse 24 ore dalla creazione della nuova replica.

Se si disabilita una AWS regione che contiene repliche di tabelle globali, tali repliche vengono convertite in modo permanente in tabelle a regione singola 20 ore dopo la disattivazione della regione.

# Tabella globale per lo stesso account DynamoDB
<a name="globaltables-SameAccount"></a>

Le tabelle globali dello stesso account replicano automaticamente i dati delle tabelle DynamoDB tra le regioni all'interno di un singolo account. AWS AWS Le tabelle globali con lo stesso account forniscono il modello più semplice per l'esecuzione di applicazioni multiregionali perché tutte le repliche condividono lo stesso limite di account, proprietà e modello di autorizzazioni. Quando si scelgono le AWS regioni per le tabelle di replica, le tabelle globali gestiscono automaticamente tutte le repliche. Le tabelle globali sono disponibili in tutte le Regioni in cui DynamoDB è disponibile.

Le tabelle globali dello stesso account offrono i seguenti vantaggi:
+ Replica automaticamente i dati delle tabelle DynamoDB nelle aree AWS di tua scelta per localizzare i dati più vicino agli utenti
+ Maggiore disponibilità delle applicazioni durante l’isolamento o la riduzione delle prestazioni Regionale
+ Utilizza la risoluzione dei conflitti integrata in modo da poterti concentrare sulla logica di business dell'applicazione
+ Quando si crea una tabella globale per lo stesso account, è possibile scegliere tra [Coerenza finale multi-Regione (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec) [Elevata consistenza multi-Regione (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc)

**Topics**
+ [Come funzionano le tabelle globali DynamoDB](V2globaltables_HowItWorks.md)
+ [Tutorial: creazione di tabelle globali](V2globaltables.tutorial.md)
+ [Sicurezza per tabelle globali DynamoDB](globaltables-security.md)

# Come funzionano le tabelle globali DynamoDB
<a name="V2globaltables_HowItWorks"></a>

Nelle sezioni seguenti sono riportate ulteriori informazioni sui concetti e i comportamenti delle tabelle globali in Amazon DynamoDB.

## Concetti
<a name="V2globaltables_HowItWorks.KeyConcepts"></a>

*Le tabelle globali* sono una funzionalità di DynamoDB che replica i dati delle tabelle tra le regioni. AWS 

Una *tabella di replica* (o replica) è una singola tabella DynamoDB che funziona come parte di una tabella globale. Una tabella globale è composta da due o più tabelle di replica in diverse regioni. AWS Ciascuna tabella globale può avere una sola tabella di replica per Regione AWS . Tutte le repliche in una tabella globale condividono lo stesso nome di tabella, lo stesso schema di chiave primaria e gli stessi dati degli elementi.

Quando un’applicazione scrive dati in una replica in una Regione, DynamoDB replica automaticamente la scrittura in tutte le altre repliche nella tabella globale. Per ulteriori informazioni su come iniziare a utilizzare le tabelle globali, consulta [Tutorial: creazione di tabelle globali](V2globaltables.tutorial.md).

## Versioni
<a name="V2globaltables_HowItWorks.versions"></a>

Sono disponibili due versioni delle tabelle globali DynamoDB: versione 2019.11.21 (Corrente) e [versione 2017.11.29 (Legacy).](globaltables.V1.md) Sarebbe opportuno utilizzare la versione 2019.11.21 (Corrente) ogni volta che è possibile. Le informazioni contenute in questa sezione della documentazione si riferiscono alla versione 2019.11.21 (Corrente). Per ulteriori informazioni, consulta [Determinare la versione di una tabella globale](V2globaltables_versions.md#globaltables.DetermineVersion).

## Disponibilità
<a name="V2globaltables_HowItWorks.availability"></a>

Le tabelle globali aiutano a migliorare la continuità aziendale semplificando l’implementazione di un’architettura ad alta disponibilità multi-Regione. Se un carico di lavoro in una singola AWS regione viene compromesso, è possibile spostare il traffico delle applicazioni in una regione diversa ed eseguire letture e scritture su una tabella di replica diversa nella stessa tabella globale.

Ogni tabella di replica in una tabella globale offre la stessa durata e disponibilità di una tabella DynamoDB a Regione singola. Le tabelle globali offrono un [Accordo sul livello di servizio (SLA)](https://aws.amazon.com//dynamodb/sla/) con disponibilità del 99,999%, rispetto al 99,99% delle tabelle a Regione singola.

## Modalità di coerenza
<a name="V2globaltables_HowItWorks.consistency-modes"></a>

Quando si crea una tabella globale, è possibile configurarne la modalità di coerenza. Le tabelle globali supportano due modalità di coerenza: coerenza finale multi-Regione (MREC, Multi-Region Eventual Consistency) e elevata consistenza multi-Regione (MRSC, Multi-Region Strong Consistency).

Se non si specifica una modalità di coerenza durante la creazione di una tabella globale, la tabella globale utilizza come impostazione predefinita la coerenza finale multi-Regione (MREC). Una tabella globale non può contenere repliche configurate con modalità di coerenza diverse. Non è possibile modificare la modalità di coerenza di una tabella globale dopo la creazione.

### Coerenza finale multi-Regione (MREC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrec"></a>

La coerenza finale multi-Regione (MREC) è la modalità di coerenza predefinita per le tabelle globali. Le modifiche agli elementi in una replica di tabella globale MREC vengono replicate in modo asincrono su tutte le altre repliche, in genere entro un secondo o meno. Nell’improbabile eventualità che una replica in una tabella globale MREC venga isolata o danneggiata, tutti i dati non ancora replicati in altre Regioni verranno replicati quando la replica diventa integra.

Se lo stesso elemento viene modificato in più Regioni contemporaneamente, DynamoDB risolverà il conflitto utilizzando la modifica con il timestamp interno più recente per elemento, denominato metodo di risoluzione dei conflitti basato sulla “priorità dell’ultima istanza di scrittura”. Un elemento alla fine convergerà in tutte le repliche alla versione creata dall’ultima scrittura.

Le [operazioni a elevata consistenza di lettura](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html#DDB-GetItem-request-ConsistentRead) restituiscono la versione più recente di un elemento se tale elemento è stato aggiornato l’ultima volta nella Regione in cui è avvenuta la lettura, ma possono restituire dati non aggiornati se l’elemento è stato aggiornato l’ultima volta in una Regione diversa. Le scritture condizionali valutano l’espressione della condizione rispetto alla versione dell’elemento nella Regione.

Si crea una tabella globale MREC aggiungendo una replica a una tabella DynamoDB esistente. L’aggiunta di una replica non ha alcun impatto sulle prestazioni sulle tabelle DynamoDB a Regione singola esistenti o sulle repliche di tabelle globali. È possibile aggiungere repliche a una tabella globale MREC per espandere il numero di Regioni in cui i dati vengono replicati o rimuovere le repliche da una tabella globale MREC se non sono più necessarie. Una tabella globale MREC può avere una replica in qualsiasi Regione in cui è disponibile DynamoDB e può avere tante repliche quante sono le Regioni nella [partizione AWS .](https://docs.aws.amazon.com/whitepapers/latest/aws-fault-isolation-boundaries/partitions.html)

### Elevata consistenza multi-Regione (MRSC)
<a name="V2globaltables_HowItWorks.consistency-modes.mrsc"></a>

È possibile configurare la modalità MRSC (Multi-region Strong Consistency) quando si crea una tabella globale. Le modifiche agli elementi in una replica di tabella globale MRSC vengono replicate in modo sincrono in almeno un’altra Regione prima che l’operazione di scrittura restituisca una risposta con esito positivo. Le operazioni a elevata consistenza di lettura su qualsiasi replica MRSC restituiscono sempre la versione più recente di un elemento. Le scritture condizionali valutano sempre l’espressione della condizione rispetto alla versione più recente di un elemento.

Una tabella globale MRSC deve essere implementata esattamente in tre Regioni. È possibile configurare una tabella globale MRSC con tre repliche o con due repliche e un testimone. Un witness è un componente di una tabella globale MRSC che contiene dati scritti su repliche di tabelle globali e fornisce un'alternativa opzionale a una replica completa, supportando al contempo l'architettura di disponibilità di MRSC. Non è possibile eseguire operazioni di lettura o scrittura su un testimone. Un testimone si trova in una Regione diversa rispetto alle due repliche. Quando si crea una tabella globale MRSC, si scelgono le Regioni sia per l’implementazione di replica che di testimone al momento della creazione della tabella MRSC. È possibile determinare se e in quale Regione una tabella globale MRSC ha un testimone configurato dall’output dell’API [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html). Il testimone è di proprietà e gestito da DynamoDB e non verrà visualizzato nel AWS tuo account nella regione in cui è configurato.

Le tabelle globali MRSC sono disponibili nei seguenti set di regioni: set di regioni Stati Uniti (Stati Uniti orientali Virginia, Stati Uniti orientali Ohio, Stati Uniti occidentali Oregon), set di regioni UE (Europa Irlanda, Europa Londra, Europa Parigi, Europa Francoforte) e set di regioni AP (Asia Pacifico Tokyo, Asia Pacifico Seul e Asia Pacifico Osaka). Le tabelle globali MRSC non possono estendersi a set di Regioni (ad esempio, una tabella globale MRSC non può contenere repliche di set di Regioni degli Stati Uniti e dell’Europa).

Si crea una tabella globale MRSC aggiungendo una replica e un testimone o due repliche a una tabella DynamoDB esistente che non contiene dati. Quando si converte una tabella a regione singola esistente in una tabella globale MRSC, è necessario assicurarsi che la tabella sia vuota. La conversione di una tabella a Regione singola in una tabella globale MRSC con elementi esistenti non è supportata. Assicurati che non venga scritto alcun dato nella tabella durante il processo di conversione. Non è possibile aggiungere repliche aggiuntive a una tabella globale MRSC esistente. Non è possibile eliminare una singola replica o un testimone da una tabella globale MRSC. È possibile eliminare due repliche o eliminare una replica e un testimone da una tabella globale MRSC, convertendo la replica rimanente in una tabella DynamoDB a Regione singola.

Un’operazione di scrittura ha esito negativo con una `ReplicatedWriteConflictException` quando tenta di modificare un elemento che è già stato modificato in un’altra Regione. Le scritture con esito negativo `ReplicatedWriteConflictException` possono essere ritentate e avranno esito positivo se l'elemento non viene più modificato in un'altra regione.

Le seguenti considerazioni si applicano alle tabelle globali MRSC:
+ Il valore Time to Live (TTL) non è supportato per le tabelle globali MRSC.
+ Gli indici secondari locali (LSIs) non sono supportati per le tabelle globali MRSC.
+ CloudWatch Le informazioni di Contributor Insights vengono riportate solo per la regione in cui si è verificata un'operazione.

## Scelta di una modalità di coerenza
<a name="V2globaltables_HowItWorks.choosing-consistency-mode"></a>

Il criterio chiave per la scelta di una modalità di coerenza multi-Regione è se l’applicazione dia priorità alle scritture a bassa latenza e alle operazioni a elevata consistenza di lettura o dia priorità alla elevata consistenza globale.

Le tabelle globali MREC avranno latenze per operazioni di scrittura e per operazioni a elevata consistenza di lettura inferiori rispetto alle tabelle globali MRSC. Le tabelle globali MREC hanno un Recovery Point Objective (RPO) pari al ritardo di replica tra le repliche, in genere di pochi secondi a seconda delle regioni di replica.

È necessario utilizzare la modalità MREC quando:
+ L’applicazione può tollerare la restituzione di dati obsoleti da operazioni a elevata consistenza di lettura se tali dati sono stati aggiornati in un’altra Regione.
+ Si dà la priorità a latenze per operazioni di e operazioni a elevata consistenza di lettura inferiori rispetto alla coerenza di lettura multi-Regione.
+ La strategia di alta disponibilità multi-Regione può tollerare un RPO superiore a zero.

Le tabelle globali MRSC avranno latenze superiori per operazioni di scrittura e operazioni a elevata consistenza di lettura rispetto alle tabelle globali MREC superiori. Le tabelle globali MRSC supportano un RPO pari a zero.

È necessario utilizzare la modalità MRSC quando:
+ Sono necessarie operazioni a elevata consistenza di lettura in più Regioni.
+ Si dà la priorità alla coerenza di lettura globale rispetto a una latenza di scrittura inferiore.
+ La strategia di alta disponibilità multi-Regione richiede un RPO pari a zero.

## Monitoraggio delle tabelle globali
<a name="monitoring-global-tables"></a>

Le tabelle globali configurate per la coerenza finale tra più regioni (MREC) pubblicano la metrica su. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Questa metrica tiene traccia del tempo trascorso tra la scrittura di un elemento in una tabella di replica e la visualizzazione di tale elemento in un’altra replica nella tabella globale. `ReplicationLatency` è espresso in millisecondi e viene emesso per ogni coppia di Regioni di origine e di destinazione in una tabella globale. 

`ReplicationLatency`I valori tipici dipendono dalla distanza tra le AWS regioni scelte e da altre variabili come il tipo di carico di lavoro e la velocità effettiva. Ad esempio, una replica di origine nella Regione Stati Uniti occidentali (California settentrionale) (us-west-1) ha un `ReplicationLatency` inferiore rispetto alla Regione Stati Uniti occidentali (Oregon) (us-west-2) rispetto alla Regione Africa (Città del Capo) (af-south-1).

Un valore crescente per `ReplicationLatency` potrebbe indicare che gli aggiornamenti da una replica non si propagano ad altre tabelle di replica in modo tempestivo. In questo caso, puoi reindirizzare temporaneamente l'attività di lettura e scrittura dell'applicazione verso un'altra regione. AWS 

Le tabelle globali configurate per l’elevata consistenza multi-Regione (MRSC) non pubblicano una metrica `ReplicationLatency`.

## Test di iniezione di guasti
<a name="fault-injection-testing"></a>

Entrambe le tabelle globali MREC e MRSC si integrano con [AWSAWS Fault Injection Service](https://docs.aws.amazon.com/resilience-hub/latest/userguide/testing.html) (FIS), un servizio completamente gestito per l'esecuzione di esperimenti di iniezione di guasti controllati per migliorare la resilienza di un'applicazione. Utilizzando AWS FIS, è possibile:
+ Creare modelli di esperimenti che definiscono scenari di fallimento specifici.
+ Inietta gli errori per convalidare la resilienza delle applicazioni simulando l'isolamento di una regione (ovvero, mettendo in pausa la replica da e verso una replica selezionata) per testare la gestione degli errori, i meccanismi di ripristino e il comportamento dello spostamento del traffico tra più regioni quando un'area subisce un'interruzione. AWS 

Ad esempio, in una tabella globale con repliche negli Stati Uniti orientali (Virginia settentrionale), negli Stati Uniti orientali (Ohio) e negli Stati Uniti occidentali (Oregon), è possibile eseguire un esperimento negli Stati Uniti orientali (Ohio) per testare l'isolamento della regione mentre Stati Uniti orientali (Virginia settentrionale) e Stati Uniti occidentali (Oregon) continuano le normali operazioni. Questo test controllato consente di identificare e risolvere potenziali problemi prima che influiscano sui carichi di lavoro di produzione. 

Consulta [Action targets](https://docs.aws.amazon.com/fis/latest/userguide/action-sequence.html#action-targets) nella *guida per l'utente AWS FIS* per un elenco completo delle azioni supportate da AWS FIS e della [connettività interregionale per sospendere la replica di DynamoDB tra le regioni](https://docs.aws.amazon.com/fis/latest/userguide/cross-region-scenario.html).

*Per informazioni sulle azioni delle tabelle globali di Amazon DynamoDB disponibili AWS in FIS, [consulta il riferimento alle azioni delle tabelle globali di DynamoDB nella FIS User Guide](https://docs.aws.amazon.com/fis/latest/userguide/fis-actions-reference.html#dynamodb-actions-reference).AWS *

Per iniziare a eseguire esperimenti di fault injection, consulta [Planning your AWS FIS experiment (Pianificazione degli esperimenti FIS) nella guida per l'utente FIS](https://docs.aws.amazon.com/fis/latest/userguide/getting-started-planning.html). AWS 

**Nota**  
Durante AWS FIS gli esperimenti in MRSC, alla fine sono consentite letture coerenti, ma gli aggiornamenti delle impostazioni delle tabelle, come la modifica della modalità di fatturazione o la configurazione del throughput della tabella, non sono consentiti, analogamente a MREC. Controlla la CloudWatch metrica per ulteriori dettagli sul codice [`FaultInjectionServiceInducedErrors`](metrics-dimensions.md#FaultInjectionServiceInducedErrors)di errore.

## Time to live (TTL)
<a name="global-tables-ttl"></a>

Le tabelle globali configurate per MREC supportano la configurazione dell’eliminazione [Time to Live](TTL.md) (TTL). Le impostazioni del TTL vengono sincronizzate automaticamente per tutte le repliche in una tabella globale. Quando il TTL elimina un elemento da una replica in una Regione, l’eliminazione viene replicata su tutte le altre repliche nella tabella globale. Il TTL non consuma capacità di scrittura, quindi non viene addebitato alcun costo per l’eliminazione TTL nella Regione in cui è avvenuta l’eliminazione. Tuttavia, viene addebitato il costo dell’eliminazione replicata in ogni altra Regione con una replica nella tabella globale.

La replica di eliminazione TTL consuma la capacità di scrittura sulle repliche in cui viene replicata l’eliminazione. Le repliche configurate per la capacità allocata possono limitare le richieste se la combinazione di throughput di scrittura e throughput di eliminazione TTL è superiore alla capacità di scrittura allocata.

Le tabelle globali configurate per MRSC (elevata consistenza multi-Regione) non supportano la configurazione dell’eliminazione TTL.

## Streams
<a name="global-tables-streams"></a>

Le tabelle globali configurate per coerenza finale multi-Regione (MREC) replicano le modifiche leggendo tali modifiche da un [flusso DynamoDB](Streams.md) su una tabella di replica e applicandole a tutte le altre tabelle di replica. I flussi sono quindi abilitati per impostazione predefinita su tutte le repliche in una tabella globale MREC e non possono essere disabilitati su tali repliche. Il processo di replica MREC può combinare più modifiche in un breve periodo di tempo in un’unica scrittura replicata, con il risultato che il flusso di ogni replica contiene record leggermente diversi. I record dei flussi sulle repliche MREC vengono sempre ordinati per elemento, ma l’ordinamento tra gli elementi può differire tra le repliche.

Le tabelle globali configurate per elevata consistenza multi-Regione (MRSC) non utilizzano i flussi DynamoDB per la replica, pertanto i flussi non sono abilitati per impostazione predefinita sulle repliche MRSC. È possibile abilitare i flussi su una replica MRSC. I record dei flussi sulle repliche MRSC sono identici per ogni replica, incluso l’ordinamento dei record dei flussi.

Se si desidera scrivere un’applicazione che elabori i record dei flussi per le modifiche avvenute in una particolare Regione ma non in altre Regioni in una tabella globale, è possibile aggiungere un attributo a ogni elemento che definisce in quale Regione è avvenuta la modifica per quell’elemento. È possibile utilizzare questo attributo per filtrare i record dei flussi in base alle modifiche apportate in altre Regioni, incluso l’uso dei filtri di eventi Lambda per invocare le funzioni Lambda solo per le modifiche in una Regione specifica.

## Transazioni
<a name="global-tables-transactions"></a>

In una tabella globale configurata per MREC, le operazioni di transazione DynamoDB ([https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) e [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html)) sono atomiche solo all’interno della Regione in cui è stata invocata l’operazione. Le scritture transazionali non vengono replicate come unità tra le Regioni, il che significa che solo alcune delle scritture di una transazione possono essere restituite dalle operazioni di lettura in altre repliche in un determinato momento.

Ad esempio, se è presente una tabella globale con repliche nelle Regioni Stati Uniti orientali (Ohio) e Stati Uniti occidentali (Oregon) e si esegue un’operazione `TransactWriteItems` nella Regione Stati Uniti orientali (Ohio), potrebbe essere possibile osservare transazioni parzialmente completate nella Regione Stati Uniti occidentali (Oregon) man mano che le modifiche vengono replicate. Le modifiche vengono replicate in altre Regioni solo dopo essere state confermate nella Regione di origine.

Le tabelle globali configurate per MRSC (elevata consistenza multi-Regione) non supportano le operazioni di transazione e restituiranno un errore se tali operazioni vengono invocate su una replica MRSC.

## Velocità di trasmissione effettiva di lettura e di scrittura
<a name="V2globaltables_HowItWorks.Throughput"></a>

### Modalità provisioning
<a name="gt_throughput.provisioned"></a>

La replica consuma capacità di scrittura. Le repliche configurate per la capacità assegnata possono limitare le richieste se la combinazione del throughput di scrittura dell'applicazione e del throughput di scrittura della replica supera la capacità di scrittura assegnata. Per le tabelle globali che utilizzano la modalità provisioned, le impostazioni di ridimensionamento automatico per le capacità di lettura e scrittura sono sincronizzate tra le repliche.

È possibile configurare in modo indipendente le impostazioni della capacità di lettura per ogni replica in una tabella globale utilizzando il [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ProvisionedThroughputOverride.html)parametro a livello di replica. Per impostazione predefinita, le modifiche alla capacità di lettura assegnata vengono applicate a tutte le repliche nella tabella globale. Quando si aggiunge una nuova replica a una tabella globale, la capacità di lettura della tabella o della replica di origine viene utilizzata come valore iniziale, a meno che non venga specificata esplicitamente un'eccezione a livello di replica.

### Modalità on demand
<a name="gt_throughput.on-demand"></a>

Per le tabelle globali configurate per la modalità on demand, la capacità di scrittura viene sincronizzata automaticamente su tutte le repliche. DynamoDB regola automaticamente la capacità in base al traffico e non ci sono impostazioni di capacità di lettura o scrittura specifiche per la replica da gestire.

## Sincronizzazione delle impostazioni
<a name="V2globaltables_HowItWorks.setting-synchronization"></a>

Le impostazioni nelle tabelle globali di DynamoDB sono parametri di configurazione che controllano vari aspetti del comportamento e della replica delle tabelle. Queste impostazioni sono gestite tramite il APIs piano di controllo di DynamoDB e possono essere configurate durante la creazione o la modifica di tabelle globali. Le tabelle globali sincronizzano automaticamente determinate impostazioni su tutte le repliche per mantenere la coerenza e consentire al contempo la flessibilità per le ottimizzazioni specifiche della Regione. Comprendere quali impostazioni si sincronizzano e come si comportano aiuta a configurare la tabella globale in modo efficace. Le impostazioni rientrano in tre categorie principali in base al modo in cui sono sincronizzate tra le repliche.

Le seguenti impostazioni sono sempre sincronizzate tra le repliche in una tabella globale:
+ Modalità di capacità (capacità allocata o on demand)
+ Capacità di scrittura allocata alla tabella
+ Dimensionamento automatico della tabella
+ Definizione degli attributi dello schema chiave
+ Definizione degli indici secondari globali (GSI)
+ Capacità di scrittura allocata ai GSI
+ Dimensionamento automatico in scrittura dei GSI
+ Tipo di crittografia lato server (SSE)
+ Definizione dei flussi in modalità MREC
+ Time to live (TTL)
+ Throughput a caldo
+ Throughput massimo on demand

Le seguenti impostazioni sono sincronizzate tra le repliche, ma possono essere sostituite per ogni singola replica:
+ Capacità di lettura allocata alla tabella
+ Dimensionamento automatico in lettura della tabella
+ Capacità di lettura allocata ai GSI
+ Dimensionamento automatico in lettura dei GSI
+ Classe di tabella
+ Throughput massimo on demand

**Nota**  
I valori delle impostazioni sostituibili vengono modificati se l’impostazione viene modificata su qualsiasi altra replica. Ad esempio, è disponibile una tabella globale MREC con repliche nelle Regioni Stati Uniti orientali (Virginia settentrionale) e Stati Uniti occidentali (Oregon). La replica degli Stati Uniti orientali (Virginia settentrionale) ha assegnato un throughput di lettura impostato su 200. RCUs Per la replica negli Stati Uniti occidentali (Oregon), la velocità effettiva di lettura assegnata è impostata su 100. RCUs Se si aggiorna l'impostazione della velocità effettiva di lettura assegnata sulla replica degli Stati Uniti orientali (Virginia settentrionale) da 200 RCUs a 300 RCUs, il nuovo valore della velocità effettiva di lettura assegnata verrà applicato anche alla replica negli Stati Uniti occidentali (Oregon). Ciò modifica l'impostazione della velocità effettiva di lettura assegnata per la replica degli Stati Uniti occidentali (Oregon) dal valore sovrascritto di 100 al nuovo valore di 300. RCUs RCUs

Le seguenti impostazioni non vengono mai sincronizzate tra le repliche:
+ Protezione da eliminazione
+ Point-in-time Recupero
+ Tag
+ Attivazione di Table CloudWatch Contributor Insights
+ Abilitazione di GSI Contributor Insights CloudWatch 
+ Definizione del flusso di dati Kinesis
+ Policy delle risorse
+ Definizione dei flussi in modalità MRSC

Tutte le altre impostazioni non vengono sincronizzate tra le repliche.

## DynamoDB Accelerator (DAX)
<a name="V2globaltables_HowItWorks.dax"></a>

Le scritture su repliche di tabelle globali ignorano DynamoDB Accelerator (DAX), aggiornando direttamente DynamoDB. Di conseguenza, le cache di DAX possono diventare obsolete poiché le scritture non le aggiornano. Le cache di DAX configurate per le repliche globali delle tabelle verranno aggiornate solo alla scadenza del TTL della cache.

## Considerazioni sulla gestione delle tabelle globali
<a name="management-considerations"></a>

Non è possibile eliminare una tabella utilizzata per aggiungere una nuova replica globale della tabella prima che siano trascorse 24 ore dalla creazione della nuova replica.

Se si disabilita una AWS regione che contiene repliche di tabelle globali, tali repliche vengono convertite in modo permanente in tabelle a regione singola 20 ore dopo la disattivazione della regione.

# Tutorial: creazione di tabelle globali
<a name="V2globaltables.tutorial"></a>

Questa sezione fornisce step-by-step istruzioni per creare tabelle globali DynamoDB configurate per la modalità di consistenza preferita. Seleziona la modalità a coerenza finale multi-Regione (MREC, Multi-Region Eventual Consistency) o elevata consistenza multi-Regione (MRSC, Multi-Region Strong Consistency) in base ai requisiti dell’applicazione.

Le tabelle globali MREC offrono una latenza di scrittura inferiore con una coerenza finale generale Regioni AWS. Le tabelle globali MRSC forniscono operazioni a elevata consistenza di lettura tra le Regioni con latenze di scrittura leggermente superiori rispetto a MREC. Sceglie la modalità di coerenza che meglio soddisfa le esigenze dell’applicazione in termini di coerenza, latenza e disponibilità dei dati.

**Topics**
+ [Creazione di una tabella globale configurata per MREC](#V2creategt_mrec)
+ [Creazione di una tabella globale configurata per MRSC](#create-gt-mrsc)

## Creazione di una tabella globale configurata per MREC
<a name="V2creategt_mrec"></a>

Questa sezione mostra come creare una tabella globale con la modalità a coerenza finale multi-Regione (MREC). MREC è la modalità di coerenza predefinita per le tabelle globali e fornisce scritture a bassa latenza con replica asincrona su tutte le Regioni AWS. Le modifiche apportate a un elemento in una Regione vengono in genere replicate in tutte le altre Regioni entro un secondo. Ciò rende la MREC ideale per le applicazioni che danno priorità a una bassa latenza di scrittura e possono tollerare brevi periodi in cui Regioni diverse possono restituire versioni di dati leggermente diverse.

È possibile creare tabelle globali MREC con repliche in qualsiasi regione in AWS cui è disponibile DynamoDB e aggiungere o rimuovere repliche in qualsiasi momento. Gli esempi seguenti mostrano come creare una tabella globale MREC con repliche in più Regioni.

### Creazione di una tabella globale MREC con la console DynamoDB
<a name="mrec-console"></a>

Completa questa procedura per creare una tabella globale utilizzando Console di gestione AWS. Il seguente esempio consente di creare una tabella globale con le tabelle di replica negli Stati Uniti e in Europa.

1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Per questo esempio, seleziona **Stati Uniti orientali (Ohio)** dal selettore delle Regioni nella barra di navigazione.

1. Nel riquadro di navigazione sul lato sinistro della console scegli **Tables (Tabelle)**.

1. Scegliere **Create Table (Crea tabella)**.

1. Nella pagina **Crea tabella**:

   1. Nel campo **Table name (Nome tabella)** immetti **Music**.

   1. In **Partition key** (Chiave di partizione), inserisci **Artist**.

   1. Per **Chiave di ordinamento**, immetti **SongTitle**.

   1. Mantieni le restanti impostazioni predefinite e seleziona **Crea tabella**.

      Questa nuova tabella funge da prima tabella di replica in una nuova tabella globale. È il prototipo per altre tabelle di replica che verranno aggiunte in seguito.

1. Dopo che la tabella è diventata attiva:

   1. Nell’elenco delle tabelle, seleziona la tabella **Musica**.

   1. Seleziona la scheda **Tabelle globali**.

   1. Scegliere **Crea replica**.

1. Dall’elenco a discesa **Regioni di replica disponibili**, seleziona **Stati Uniti occidentali (Oregon) us-west-2**.

   La console verifica che non esista una tabella con lo stesso nome nella Regione selezionata. Se esiste una tabella con lo stesso nome, è necessario eliminare la tabella esistente prima di poter creare una nuova tabella di replica in quella regione.

1. Scegliere **Crea replica**. Viene avviato il processo di creazione della tabella nella Regione Stati Uniti occidentali (Oregon) us-west-2.

   La scheda **Tabelle globali** per la tabella **Musica** (e per qualsiasi altra tabella di replica) mostra che la tabella è stata replicata in più Regioni.

1. Aggiungi un’altra Regione ripetendo le fasi precedenti, ma seleziona **Europa (Francoforte) eu-central-1** come Regione.

1. Per testare la replica:

   1. Assicurati di utilizzare la Console di gestione AWS regione Stati Uniti orientali (Ohio).

   1. Scegli **Explore table items** (Esplora elementi della tabella).

   1. Scegli **Crea elemento**.

   1. Entra **item\$11** per **Artista** e **Song Value 1** per **SongTitle**.

   1. Scegli **Crea elemento**.

1. Verifica la replica passando alle altre Regioni:

   1. Dal selettore delle Regioni in alto a destra, seleziona **Europa (Francoforte)**.

   1. Verifica che la tabella **Musica** contenga l’elemento creato.

   1. Ripeti la verifica per **Stati Uniti occidentali (Oregon)**.

### Creazione di una tabella globale MREC utilizzando o Java AWS CLI
<a name="mrec-cli-java"></a>

------
#### [ CLI ]

Gli esempi di codice seguenti mostrano come creare e gestire le tabelle DynamoDB globali con consistenza effettiva multi-Regione (MRSC).
+ Creare una tabella con replica multi-Regione (MREC).
+ Inserire e ottenere elementi dalle tabelle di replica.
+ Rimuovi le repliche. one-by-one
+ Eseguire la pulizia mediante l’eliminazione delle tabelle.

**AWS CLI con lo script Bash**  
Creare una tabella con replica multi-Regione.  

```
# Step 1: Create a new table (MusicTable) in US East (Ohio), with DynamoDB Streams enabled (NEW_AND_OLD_IMAGES)
aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
    --region us-east-2

# Step 2: Create an identical MusicTable table in US East (N. Virginia)
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Create": {
        "RegionName": "us-east-1"
      }
    }
  ]
}' \
--region us-east-2

# Step 3: Create a table in Europe (Ireland)
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Create": {
        "RegionName": "eu-west-1"
      }
    }
  ]
}' \
--region us-east-2
```
Descrivere la tabella multi-Regione.  

```
# Step 4: View the list of replicas created using describe-table
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*].{Region:RegionName,Status:ReplicaStatus}}'
```
Inserisce elementi in una tabella di replica.  

```
# Step 5: To verify that replication is working, add a new item to the Music table in US East (Ohio)
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2
```
Ottiene elementi dalle tabelle di replica.  

```
# Step 6: Wait for a few seconds, and then check to see whether the item has been 
# successfully replicated to US East (N. Virginia) and Europe (Ireland)
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-1

aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region eu-west-1
```
Rimuove le repliche.  

```
# Step 7: Delete the replica table in Europe (Ireland) Region
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Delete": {
        "RegionName": "eu-west-1"
      }
    }
  ]
}' \
--region us-east-2

# Delete the replica table in US East (N. Virginia) Region
aws dynamodb update-table --table-name MusicTable --cli-input-json \
'{
  "ReplicaUpdates":
  [
    {
      "Delete": {
        "RegionName": "us-east-1"
      }
    }
  ]
}' \
--region us-east-2
```
Eseguire la pulizia mediante l’eliminazione delle tabelle.  

```
# Clean up: Delete the primary table
aws dynamodb delete-table --table-name MusicTable --region us-east-2

echo "Global table demonstration complete."
```
+ Per informazioni dettagliate sull’API, consulta i seguenti argomenti nella *documentazione di riferimento dei comandi della AWS CLI *.
  + [CreateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/PutItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateTable)

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

L’esempio di codice seguente mostra come creare e gestire le tabelle globali DynamoDB con repliche tra più Regioni.
+ Creare una tabella con un indice secondario globale e flussi Amazon DynamoDB.
+ Aggiungere repliche in Regioni diverse per creare una tabella globale.
+ Rimuovere le repliche da una tabella globale.
+ Aggiungere elementi di test per verificare la replica tra Regioni.
+ Descrivere la configurazione della tabella globale e lo stato della replica.

**SDK per Java 2.x**  
Crea una tabella con Global Secondary Index e DynamoDB Streams utilizzando. AWS SDK for Java 2.x  

```
    public static CreateTableResponse createTableWithGSI(
        final DynamoDbClient dynamoDbClient, final String tableName, final String indexName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (indexName == null || indexName.trim().isEmpty()) {
            throw new IllegalArgumentException("Index name cannot be null or empty");
        }

        try {
            LOGGER.info("Creating table: " + tableName + " with GSI: " + indexName);

            CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(
                    AttributeDefinition.builder()
                        .attributeName("Artist")
                        .attributeType(ScalarAttributeType.S)
                        .build(),
                    AttributeDefinition.builder()
                        .attributeName("SongTitle")
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(
                    KeySchemaElement.builder()
                        .attributeName("Artist")
                        .keyType(KeyType.HASH)
                        .build(),
                    KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.RANGE)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .globalSecondaryIndexes(GlobalSecondaryIndex.builder()
                    .indexName(indexName)
                    .keySchema(KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.HASH)
                        .build())
                    .projection(
                        Projection.builder().projectionType(ProjectionType.ALL).build())
                    .build())
                .streamSpecification(StreamSpecification.builder()
                    .streamEnabled(true)
                    .streamViewType(StreamViewType.NEW_AND_OLD_IMAGES)
                    .build())
                .build();

            CreateTableResponse response = dynamoDbClient.createTable(createTableRequest);
            LOGGER.info("Table creation initiated. Status: "
                + response.tableDescription().tableStatus());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to create table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Attendi che una tabella diventi attiva utilizzando. AWS SDK for Java 2.x  

```
    public static void waitForTableActive(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Waiting for table to become active: " + tableName);

            try (DynamoDbWaiter waiter =
                DynamoDbWaiter.builder().client(dynamoDbClient).build()) {
                DescribeTableRequest request =
                    DescribeTableRequest.builder().tableName(tableName).build();

                waiter.waitUntilTableExists(request);
                LOGGER.info("Table is now active: " + tableName);
            }

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to wait for table to become active: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Aggiungi una replica per creare o estendere una tabella globale utilizzando AWS SDK for Java 2.x.  

```
    public static UpdateTableResponse addReplica(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final String indexName,
        final Long readCapacity) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (indexName == null || indexName.trim().isEmpty()) {
            throw new IllegalArgumentException("Index name cannot be null or empty");
        }
        if (readCapacity == null || readCapacity <= 0) {
            throw new IllegalArgumentException("Read capacity must be a positive number");
        }

        try {
            LOGGER.info("Adding replica in region: " + replicaRegion.id() + " for table: " + tableName);

            // Create a ReplicationGroupUpdate for adding a replica
            ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder()
                .create(builder -> builder.regionName(replicaRegion.id())
                    .globalSecondaryIndexes(ReplicaGlobalSecondaryIndex.builder()
                        .indexName(indexName)
                        .provisionedThroughputOverride(ProvisionedThroughputOverride.builder()
                            .readCapacityUnits(readCapacity)
                            .build())
                        .build())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(replicationGroupUpdate)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("Replica addition initiated in region: " + replicaRegion.id());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add replica in region: " + replicaRegion.id() + " - " + e.getMessage());
            throw e;
        }
    }
```
Rimuovi una replica da una tabella globale utilizzando. AWS SDK for Java 2.x  

```
    public static UpdateTableResponse removeReplica(
        final DynamoDbClient dynamoDbClient, final String tableName, final Region replicaRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }

        try {
            LOGGER.info("Removing replica in region: " + replicaRegion.id() + " for table: " + tableName);

            // Create a ReplicationGroupUpdate for removing a replica
            ReplicationGroupUpdate replicationGroupUpdate = ReplicationGroupUpdate.builder()
                .delete(builder -> builder.regionName(replicaRegion.id()).build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(replicationGroupUpdate)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("Replica removal initiated in region: " + replicaRegion.id());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to remove replica in region: " + replicaRegion.id() + " - " + e.getMessage());
            throw e;
        }
    }
```
Aggiungi elementi di test per verificare la replica utilizzando. AWS SDK for Java 2.x  

```
    public static PutItemResponse putTestItem(
        final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Adding test item to table: " + tableName);

            Map<String, software.amazon.awssdk.services.dynamodb.model.AttributeValue> item = new HashMap<>();
            item.put(
                "Artist",
                software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder()
                    .s(artist)
                    .build());
            item.put(
                "SongTitle",
                software.amazon.awssdk.services.dynamodb.model.AttributeValue.builder()
                    .s(songTitle)
                    .build());

            PutItemRequest putItemRequest =
                PutItemRequest.builder().tableName(tableName).item(item).build();

            PutItemResponse response = dynamoDbClient.putItem(putItemRequest);
            LOGGER.info("Test item added successfully");

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Descrivi la configurazione globale della tabella e le repliche utilizzando. AWS SDK for Java 2.x  

```
    public static DescribeTableResponse describeTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Describing table: " + tableName);

            DescribeTableRequest request =
                DescribeTableRequest.builder().tableName(tableName).build();

            DescribeTableResponse response = dynamoDbClient.describeTable(request);

            LOGGER.info("Table status: " + response.table().tableStatus());
            if (response.table().replicas() != null
                && !response.table().replicas().isEmpty()) {
                LOGGER.info("Number of replicas: " + response.table().replicas().size());
                response.table()
                    .replicas()
                    .forEach(replica -> LOGGER.info(
                        "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus()));
            }

            return response;

        } catch (ResourceNotFoundException e) {
            LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage());
            throw e;
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Esempio completo di operazioni su tabelle globali utilizzando AWS SDK for Java 2.x.  

```
    public static void exampleUsage(final Region sourceRegion, final Region replicaRegion) {

        String tableName = "Music";
        String indexName = "SongTitleIndex";
        Long readCapacity = 15L;

        // Create DynamoDB client for the source region
        try (DynamoDbClient dynamoDbClient =
            DynamoDbClient.builder().region(sourceRegion).build()) {

            try {
                // Step 1: Create the initial table with GSI and streams
                LOGGER.info("Step 1: Creating table in source region: " + sourceRegion.id());
                createTableWithGSI(dynamoDbClient, tableName, indexName);

                // Step 2: Wait for table to become active
                LOGGER.info("Step 2: Waiting for table to become active");
                waitForTableActive(dynamoDbClient, tableName);

                // Step 3: Add replica in destination region
                LOGGER.info("Step 3: Adding replica in region: " + replicaRegion.id());
                addReplica(dynamoDbClient, tableName, replicaRegion, indexName, readCapacity);

                // Step 4: Wait a moment for replica creation to start
                Thread.sleep(5000);

                // Step 5: Describe table to view replica information
                LOGGER.info("Step 5: Describing table to view replicas");
                describeTable(dynamoDbClient, tableName);

                // Step 6: Add a test item to verify replication
                LOGGER.info("Step 6: Adding test item to verify replication");
                putTestItem(dynamoDbClient, tableName, "TestArtist", "TestSong");

                LOGGER.info("Global table setup completed successfully!");
                LOGGER.info("You can verify replication by checking the item in region: " + replicaRegion.id());

                // Step 7: Remove replica and clean up table
                LOGGER.info("Step 7: Removing replica from region: " + replicaRegion.id());
                removeReplica(dynamoDbClient, tableName, replicaRegion);
                DeleteTableResponse deleteTableResponse = dynamoDbClient.deleteTable(
                    DeleteTableRequest.builder().tableName(tableName).build());
                LOGGER.info("MREC global table demonstration completed successfully!");

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Thread was interrupted", e);
            } catch (DynamoDbException e) {
                LOGGER.severe("DynamoDB operation failed: " + e.getMessage());
                throw e;
            }
        }
    }
```
+ Per informazioni dettagliate sull’API, consulta i seguenti argomenti nella *documentazione di riferimento dell’API AWS SDK for Java 2.x *.
  + [CreateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/CreateTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DescribeTable)
  + [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateTable)

------

## Creazione di una tabella globale configurata per MRSC
<a name="create-gt-mrsc"></a>

Questa sezione mostra come creare una tabella globale a elevata consistenza multi-Regione (MRSC). Le tabelle globali MRSC replicano in modo sincrono le modifiche agli elementi tra le Regioni, garantendo che le operazioni a elevata consistenza di lettura su qualsiasi replica restituiscano sempre la versione più recente di un elemento. Quando si converte una tabella a Regione singola in una tabella globale MRSC, è necessario assicurarsi che la tabella sia vuota. La conversione di una tabella a Regione singola in una tabella globale MRSC con elementi esistenti non è supportata. Assicurati che non venga scritto alcun dato nella tabella durante il processo di conversione.

È possibile configurare una tabella globale MRSC con tre repliche o con due repliche e un testimone. Quando si crea una tabella globale MRSC, si scelgono le Regioni in cui vengono distribuite le repliche e un testimone opzionale. L’esempio seguente crea una tabella globale MRSC con repliche nelle Regioni Stati Uniti orientali (Virginia settentrionale) e Stati Uniti orientali (Ohio), con un testimone nella Regione Stati Uniti occidentali (Oregon).

**Nota**  
Prima di creare una tabella globale, verifica che i limiti di throughput della quota di servizio siano coerenti in tutte le Regioni di destinazione, poiché ciò è necessario per creare una tabella globale. Per ulteriori informazioni sui limiti di throughput delle tabelle globali, consulta [Quote delle tabelle globali](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html#gt-limits-throughput).

### Creazione di una tabella globale MRSC con la console DynamoDB
<a name="mrsc_console"></a>

Completa questa procedura per creare una tabella globale MRSC utilizzando la Console di gestione AWS.

1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Dal selettore delle Regioni nella barra di navigazione, seleziona una Regione in cui sono [supportate](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes) le tabelle globali con MRSC, ad esempio **us-east-2**.

1. Nel pannello di navigazione, seleziona **Tabelle**.

1. Scegliere **Create table (Crea tabella)**.

1. Nella pagina **Crea tabella**:

   1. Nel campo **Table name (Nome tabella)** immetti **Music**.

   1. Per **Chiave di partizione** immetti **Artist** e mantieni il tipo di **Stringa** predefinito.

   1. Per **Chiave di ordinamento** immetti **SongTitle** e mantieni il tipo di **Stringa** predefinito.

   1. Mantieni le restanti impostazioni predefinite e seleziona **Crea tabella**.

      Questa nuova tabella funge da prima tabella di replica in una nuova tabella globale. È il prototipo per altre tabelle di replica che verranno aggiunte in seguito.

1. Attendi che la tabella diventi attiva, quindi selezionala dall’elenco delle tabelle.

1. Seleziona la scheda **Tabelle globali**, quindi seleziona **Crea replica**.

1. Nella pagina **Crea replica**:

   1. In **Coerenza multi-Regione**, seleziona **Coerenza forte**.

   1. Per **Regione di replica 1**, seleziona **US East (N. Virginia) us-east-1**.

   1. Per **Regione di replica 2**, seleziona **US West (Oregon) us-west-2**.

   1. Seleziona **Configura come testimone** per la Regione Stati Uniti occidentali (Oregon).

   1. Seleziona **Crea repliche**.

1. Attendi il completamento della replica e del processo di creazione del testimone. Lo stato della replica verrà visualizzato come **Attivo** quando la tabella sarà pronta per l’uso.

### Creazione di una tabella globale MRSC utilizzando o Java AWS CLI
<a name="mrsc-cli-java"></a>

Prima di iniziare, assicurati che il principale IAM disponga delle autorizzazioni necessarie per creare una tabella globale MRSC con una Regione testimone.

La seguente policy IAM di esempio consente di creare una tabella DynamoDB (`MusicTable`) negli Stati Uniti orientali (Ohio) con una replica nella Regione Stati Uniti orientali (Virginia settentrionale) e una Regione testimone negli Stati Uniti occidentali (Oregon):

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:CreateTableReplica",
                "dynamodb:CreateGlobalTableWitness",
                "dynamodb:DescribeTable",
                "dynamodb:UpdateTable",
                "dynamodb:DeleteTable",
                "dynamodb:DeleteTableReplica",
                "dynamodb:DeleteGlobalTableWitness",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:UpdateItem",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DeleteItem",
                "dynamodb:BatchWriteItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:123456789012:table/MusicTable",
                "arn:aws:dynamodb:us-east-2:123456789012:table/MusicTable",
                "arn:aws:dynamodb:us-west-2:123456789012:table/MusicTable"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "arn:aws:iam::*:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "replication.dynamodb.amazonaws.com"
                }
            }
        }
    ]
}
```

------

Gli esempi di codice seguenti mostrano come creare e gestire tabelle globali DynamoDB con elevata consistenza multi-Regione (MRSC).
+ Creare una tabella con consistenza avanzata multi-Regione.
+ Verificare la configurazione MRSC e lo stato della replica.
+ Verificare l’elevata consistenza tra Regioni con letture immediate.
+ Eseguire scritture condizionali con garanzie MRSC.
+ Eseguire la pulizia delle risorse della tabella globale MRSC.

------
#### [ Bash ]

**AWS CLI con lo script Bash**  
Creare una tabella con consistenza avanzata multi-Regione.  

```
# Step 1: Create a new table in us-east-2 (primary region for MRSC)
# Note: Table must be empty when enabling MRSC
aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --region us-east-2

# Wait for table to become active
aws dynamodb wait table-exists --table-name MusicTable --region us-east-2

# Step 2: Add replica and witness with Multi-Region Strong Consistency
# MRSC requires exactly three replicas in supported regions
aws dynamodb update-table \
    --table-name MusicTable \
    --replica-updates '[{"Create": {"RegionName": "us-east-1"}}]' \
    --global-table-witness-updates '[{"Create": {"RegionName": "us-west-2"}}]' \
    --multi-region-consistency STRONG \
    --region us-east-2
```
Verificare la configurazione MRSC e lo stato della replica.  

```
# Verify the global table configuration and MRSC setting
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*],GlobalTableWitnesses:GlobalTableWitnesses[*].{Region:RegionName,Status:ReplicaStatus}}'
```
Verifica l’elevata consistenza con letture immediate tra Regioni.  

```
# Write an item to the primary region
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"},"Album": {"S":"The Beatles 1967-1970"},"Year": {"N":"1968"}}' \
    --region us-east-2

# Read the item from replica region to verify strong consistency (cannot read or write to witness)
# No wait time needed - MRSC provides immediate consistency
echo "Reading from us-east-1 (immediate consistency):"
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \
    --consistent-read \
    --region us-east-1
```
Eseguire scritture condizionali con garanzie MRSC.  

```
# Perform a conditional update from a different region
# This demonstrates that conditions work consistently across all regions
aws dynamodb update-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"The Beatles"},"SongTitle": {"S":"Hey Jude"}}' \
    --update-expression "SET #rating = :rating" \
    --condition-expression "attribute_exists(Artist)" \
    --expression-attribute-names '{"#rating": "Rating"}' \
    --expression-attribute-values '{":rating": {"N":"5"}}' \
    --region us-east-1
```
Eseguire la pulizia delle risorse della tabella globale MRSC.  

```
# Remove replica tables (must be done before deleting the primary table)
aws dynamodb update-table \
    --table-name MusicTable \
    --replica-updates '[{"Delete": {"RegionName": "us-east-1"}}]' \
    --global-table-witness-updates '[{"Delete": {"RegionName": "us-west-2"}}]' \
    --region us-east-2

# Wait for replicas to be deleted
echo "Waiting for replicas to be deleted..."
sleep 30

# Delete the primary table
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-2
```
+ Per informazioni dettagliate sull’API, consulta i seguenti argomenti nella *documentazione di riferimento dei comandi della AWS CLI *.
  + [CreateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/PutItem)
  + [UpdateItem](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/aws-cli/dynamodb-2012-08-10/UpdateTable)

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

**SDK per Java 2.x**  
Crea una tabella regionale pronta per la conversione MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static CreateTableResponse createRegionalTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Creating regional table: " + tableName + " (must be empty for MRSC)");

            CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(
                    AttributeDefinition.builder()
                        .attributeName("Artist")
                        .attributeType(ScalarAttributeType.S)
                        .build(),
                    AttributeDefinition.builder()
                        .attributeName("SongTitle")
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(
                    KeySchemaElement.builder()
                        .attributeName("Artist")
                        .keyType(KeyType.HASH)
                        .build(),
                    KeySchemaElement.builder()
                        .attributeName("SongTitle")
                        .keyType(KeyType.RANGE)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .build();

            CreateTableResponse response = dynamoDbClient.createTable(createTableRequest);
            LOGGER.info("Regional table creation initiated. Status: "
                + response.tableDescription().tableStatus());

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to create regional table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to create regional table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Converti una tabella regionale in MRSC con repliche e verifica utilizzando. AWS SDK for Java 2.x  

```
    public static UpdateTableResponse convertToMRSCWithWitness(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("Converting table to MRSC with replica in " + replicaRegion.id() + " and witness in "
                + witnessRegion.id());

            // Create replica update using ReplicationGroupUpdate
            ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder()
                .create(CreateReplicationGroupMemberAction.builder()
                    .regionName(replicaRegion.id())
                    .build())
                .build();

            // Create witness update
            GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder()
                .create(CreateGlobalTableWitnessGroupMemberAction.builder()
                    .regionName(witnessRegion.id())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(List.of(replicaUpdate))
                .globalTableWitnessUpdates(List.of(witnessUpdate))
                .multiRegionConsistency(MultiRegionConsistency.STRONG)
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("MRSC conversion initiated. Status: "
                + response.tableDescription().tableStatus());
            LOGGER.info("UpdateTableResponse full object: " + response);
            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to convert table to MRSC: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to convert table to MRSC: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Descrivi una configurazione di tabella globale MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static DescribeTableResponse describeMRSCTable(final DynamoDbClient dynamoDbClient, final String tableName) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }

        try {
            LOGGER.info("Describing MRSC global table: " + tableName);

            DescribeTableRequest request =
                DescribeTableRequest.builder().tableName(tableName).build();

            DescribeTableResponse response = dynamoDbClient.describeTable(request);

            LOGGER.info("Table status: " + response.table().tableStatus());
            LOGGER.info("Multi-region consistency: " + response.table().multiRegionConsistency());

            if (response.table().replicas() != null
                && !response.table().replicas().isEmpty()) {
                LOGGER.info("Number of replicas: " + response.table().replicas().size());
                response.table()
                    .replicas()
                    .forEach(replica -> LOGGER.info(
                        "Replica region: " + replica.regionName() + ", Status: " + replica.replicaStatus()));
            }

            if (response.table().globalTableWitnesses() != null
                && !response.table().globalTableWitnesses().isEmpty()) {
                LOGGER.info("Number of witnesses: "
                    + response.table().globalTableWitnesses().size());
                response.table()
                    .globalTableWitnesses()
                    .forEach(witness -> LOGGER.info(
                        "Witness region: " + witness.regionName() + ", Status: " + witness.witnessStatus()));
            }

            return response;

        } catch (ResourceNotFoundException e) {
            LOGGER.severe("Table not found: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Table not found: " + tableName)
                .cause(e)
                .build();
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to describe table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to describe table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Aggiunge elementi di test per verificare l’elevata consistenza MRSC con AWS SDK for Java 2.x.  

```
    public static PutItemResponse putTestItem(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final String artist,
        final String songTitle,
        final String album,
        final String year) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Adding test item to MRSC global table: " + tableName);

            Map<String, AttributeValue> item = new HashMap<>();
            item.put("Artist", AttributeValue.builder().s(artist).build());
            item.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            if (album != null && !album.trim().isEmpty()) {
                item.put("Album", AttributeValue.builder().s(album).build());
            }
            if (year != null && !year.trim().isEmpty()) {
                item.put("Year", AttributeValue.builder().n(year).build());
            }

            PutItemRequest putItemRequest =
                PutItemRequest.builder().tableName(tableName).item(item).build();

            PutItemResponse response = dynamoDbClient.putItem(putItemRequest);
            LOGGER.info("Test item added successfully with strong consistency");

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to add test item to table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to add test item to table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Leggi gli elementi con letture coerenti dalle repliche MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static GetItemResponse getItemWithConsistentRead(
        final DynamoDbClient dynamoDbClient, final String tableName, final String artist, final String songTitle) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }

        try {
            LOGGER.info("Reading item from MRSC global table with consistent read: " + tableName);

            Map<String, AttributeValue> key = new HashMap<>();
            key.put("Artist", AttributeValue.builder().s(artist).build());
            key.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            GetItemRequest getItemRequest = GetItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .consistentRead(true)
                .build();

            GetItemResponse response = dynamoDbClient.getItem(getItemRequest);

            if (response.hasItem()) {
                LOGGER.info("Item found with strong consistency - no wait time needed");
            } else {
                LOGGER.info("Item not found");
            }

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to read item from table: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to read item from table: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Esegui aggiornamenti condizionali con garanzie MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static UpdateItemResponse performConditionalUpdate(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final String artist,
        final String songTitle,
        final String rating) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (artist == null || artist.trim().isEmpty()) {
            throw new IllegalArgumentException("Artist cannot be null or empty");
        }
        if (songTitle == null || songTitle.trim().isEmpty()) {
            throw new IllegalArgumentException("Song title cannot be null or empty");
        }
        if (rating == null || rating.trim().isEmpty()) {
            throw new IllegalArgumentException("Rating cannot be null or empty");
        }

        try {
            LOGGER.info("Performing conditional update on MRSC global table: " + tableName);

            Map<String, AttributeValue> key = new HashMap<>();
            key.put("Artist", AttributeValue.builder().s(artist).build());
            key.put("SongTitle", AttributeValue.builder().s(songTitle).build());

            Map<String, String> expressionAttributeNames = new HashMap<>();
            expressionAttributeNames.put("#rating", "Rating");

            Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
            expressionAttributeValues.put(
                ":rating", AttributeValue.builder().n(rating).build());

            UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .updateExpression("SET #rating = :rating")
                .conditionExpression("attribute_exists(Artist)")
                .expressionAttributeNames(expressionAttributeNames)
                .expressionAttributeValues(expressionAttributeValues)
                .build();

            UpdateItemResponse response = dynamoDbClient.updateItem(updateItemRequest);
            LOGGER.info("Conditional update successful - demonstrates strong consistency");

            return response;

        } catch (ConditionalCheckFailedException e) {
            LOGGER.warning("Conditional check failed: " + e.getMessage());
            throw e;
        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to perform conditional update: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to perform conditional update: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Attendi che le repliche e i testimoni MRSC diventino attivi utilizzando. AWS SDK for Java 2.x  

```
    public static void waitForMRSCReplicasActive(
        final DynamoDbClient dynamoDbClient, final String tableName, final int maxWaitTimeSeconds)
        throws InterruptedException {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (maxWaitTimeSeconds <= 0) {
            throw new IllegalArgumentException("Max wait time must be positive");
        }

        try {
            LOGGER.info("Waiting for MRSC replicas and witnesses to become active: " + tableName);

            final long startTime = System.currentTimeMillis();
            final long maxWaitTimeMillis = maxWaitTimeSeconds * 1000L;
            int backoffSeconds = 5; // Start with 5 second intervals
            final int maxBackoffSeconds = 30; // Cap at 30 seconds

            while (System.currentTimeMillis() - startTime < maxWaitTimeMillis) {
                DescribeTableResponse response = describeMRSCTable(dynamoDbClient, tableName);

                boolean allActive = true;
                StringBuilder statusReport = new StringBuilder();

                if (response.table().multiRegionConsistency() == null
                    || !MultiRegionConsistency.STRONG
                        .toString()
                        .equals(response.table().multiRegionConsistency().toString())) {
                    allActive = false;
                    statusReport
                        .append("MultiRegionConsistency: ")
                        .append(response.table().multiRegionConsistency())
                        .append(" ");
                }
                if (response.table().replicas() == null
                    || response.table().replicas().isEmpty()) {
                    allActive = false;
                    statusReport.append("No replicas found. ");
                }
                if (response.table().globalTableWitnesses() == null
                    || response.table().globalTableWitnesses().isEmpty()) {
                    allActive = false;
                    statusReport.append("No witnesses found. ");
                }

                // Check table status
                if (!"ACTIVE".equals(response.table().tableStatus().toString())) {
                    allActive = false;
                    statusReport
                        .append("Table: ")
                        .append(response.table().tableStatus())
                        .append(" ");
                }

                // Check replica status
                if (response.table().replicas() != null) {
                    for (var replica : response.table().replicas()) {
                        if (!"ACTIVE".equals(replica.replicaStatus().toString())) {
                            allActive = false;
                            statusReport
                                .append("Replica(")
                                .append(replica.regionName())
                                .append("): ")
                                .append(replica.replicaStatus())
                                .append(" ");
                        }
                    }
                }

                // Check witness status
                if (response.table().globalTableWitnesses() != null) {
                    for (var witness : response.table().globalTableWitnesses()) {
                        if (!"ACTIVE".equals(witness.witnessStatus().toString())) {
                            allActive = false;
                            statusReport
                                .append("Witness(")
                                .append(witness.regionName())
                                .append("): ")
                                .append(witness.witnessStatus())
                                .append(" ");
                        }
                    }
                }

                if (allActive) {
                    LOGGER.info("All MRSC replicas and witnesses are now active: " + tableName);
                    return;
                }

                LOGGER.info("Waiting for MRSC components to become active. Status: " + statusReport.toString());
                LOGGER.info("Next check in " + backoffSeconds + " seconds...");

                tempWait(backoffSeconds);

                // Exponential backoff with cap
                backoffSeconds = Math.min(backoffSeconds * 2, maxBackoffSeconds);
            }

            throw DynamoDbException.builder()
                .message("Timeout waiting for MRSC replicas to become active after " + maxWaitTimeSeconds + " seconds")
                .build();

        } catch (DynamoDbException | InterruptedException e) {
            LOGGER.severe("Failed to wait for MRSC replicas to become active: " + tableName + " - " + e.getMessage());
            throw e;
        }
    }
```
Pulisci le repliche e i testimoni MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static UpdateTableResponse cleanupMRSCReplicas(
        final DynamoDbClient dynamoDbClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion) {

        if (dynamoDbClient == null) {
            throw new IllegalArgumentException("DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("Cleaning up MRSC replicas and witnesses for table: " + tableName);

            // Remove replica using ReplicationGroupUpdate
            ReplicationGroupUpdate replicaUpdate = ReplicationGroupUpdate.builder()
                .delete(DeleteReplicationGroupMemberAction.builder()
                    .regionName(replicaRegion.id())
                    .build())
                .build();

            // Remove witness
            GlobalTableWitnessGroupUpdate witnessUpdate = GlobalTableWitnessGroupUpdate.builder()
                .delete(DeleteGlobalTableWitnessGroupMemberAction.builder()
                    .regionName(witnessRegion.id())
                    .build())
                .build();

            UpdateTableRequest updateTableRequest = UpdateTableRequest.builder()
                .tableName(tableName)
                .replicaUpdates(List.of(replicaUpdate))
                .globalTableWitnessUpdates(List.of(witnessUpdate))
                .build();

            UpdateTableResponse response = dynamoDbClient.updateTable(updateTableRequest);
            LOGGER.info("MRSC cleanup initiated - removing replica and witness. Response: " + response);

            return response;

        } catch (DynamoDbException e) {
            LOGGER.severe("Failed to cleanup MRSC replicas: " + tableName + " - " + e.getMessage());
            throw DynamoDbException.builder()
                .message("Failed to cleanup MRSC replicas: " + tableName)
                .cause(e)
                .build();
        }
    }
```
Dimostrazione completa del flusso di lavoro MRSC utilizzando. AWS SDK for Java 2.x  

```
    public static void demonstrateCompleteMRSCWorkflow(
        final DynamoDbClient primaryClient,
        final DynamoDbClient replicaClient,
        final String tableName,
        final Region replicaRegion,
        final Region witnessRegion)
        throws InterruptedException {

        if (primaryClient == null) {
            throw new IllegalArgumentException("Primary DynamoDB client cannot be null");
        }
        if (replicaClient == null) {
            throw new IllegalArgumentException("Replica DynamoDB client cannot be null");
        }
        if (tableName == null || tableName.trim().isEmpty()) {
            throw new IllegalArgumentException("Table name cannot be null or empty");
        }
        if (replicaRegion == null) {
            throw new IllegalArgumentException("Replica region cannot be null");
        }
        if (witnessRegion == null) {
            throw new IllegalArgumentException("Witness region cannot be null");
        }

        try {
            LOGGER.info("=== Starting Complete MRSC Workflow Demonstration ===");

            // Step 1: Create an empty single-Region table
            LOGGER.info("Step 1: Creating empty single-Region table");
            createRegionalTable(primaryClient, tableName);

            // Use the existing GlobalTableOperations method for basic table waiting
            LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // Step 2: Convert to MRSC with replica and witness
            LOGGER.info("Step 2: Converting to MRSC with replica and witness");
            convertToMRSCWithWitness(primaryClient, tableName, replicaRegion, witnessRegion);

            // Wait for MRSC conversion to complete using MRSC-specific waiter
            LOGGER.info("Waiting for MRSC conversion to complete...");
            waitForMRSCReplicasActive(primaryClient, tableName);

            LOGGER.info("Intermediate step: Waiting for table [" + tableName + "] to become active before continuing");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // Step 3: Verify MRSC configuration
            LOGGER.info("Step 3: Verifying MRSC configuration");
            describeMRSCTable(primaryClient, tableName);

            // Step 4: Test strong consistency with data operations
            LOGGER.info("Step 4: Testing strong consistency with data operations");

            // Add test item to primary region
            putTestItem(primaryClient, tableName, "The Beatles", "Hey Jude", "The Beatles 1967-1970", "1968");

            // Immediately read from replica region (no wait needed with MRSC)
            LOGGER.info("Reading from replica region immediately (strong consistency):");
            GetItemResponse getResponse =
                getItemWithConsistentRead(replicaClient, tableName, "The Beatles", "Hey Jude");

            if (getResponse.hasItem()) {
                LOGGER.info("✓ Strong consistency verified - item immediately available in replica region");
            } else {
                LOGGER.warning("✗ Item not found in replica region");
            }

            // Test conditional update from replica region
            LOGGER.info("Testing conditional update from replica region:");
            performConditionalUpdate(replicaClient, tableName, "The Beatles", "Hey Jude", "5");
            LOGGER.info("✓ Conditional update successful - demonstrates strong consistency");

            // Step 5: Cleanup
            LOGGER.info("Step 5: Cleaning up resources");
            cleanupMRSCReplicas(primaryClient, tableName, replicaRegion, witnessRegion);

            // Wait for cleanup to complete using basic table waiter
            LOGGER.info("Waiting for replica cleanup to complete...");
            GlobalTableOperations.waitForTableActive(primaryClient, tableName);

            // "Halt" until replica/witness cleanup is complete
            DescribeTableResponse cleanupVerification = describeMRSCTable(primaryClient, tableName);
            int backoffSeconds = 5; // Start with 5 second intervals
            while (cleanupVerification.table().multiRegionConsistency() != null) {
                LOGGER.info("Waiting additional time (" + backoffSeconds + " seconds) for MRSC cleanup to complete...");
                tempWait(backoffSeconds);

                // Exponential backoff with cap
                backoffSeconds = Math.min(backoffSeconds * 2, 30);
                cleanupVerification = describeMRSCTable(primaryClient, tableName);
            }

            // Delete the primary table
            deleteTable(primaryClient, tableName);

            LOGGER.info("=== MRSC Workflow Demonstration Complete ===");
            LOGGER.info("");
            LOGGER.info("Key benefits of Multi-Region Strong Consistency (MRSC):");
            LOGGER.info("- Immediate consistency across all regions (no eventual consistency delays)");
            LOGGER.info("- Simplified application logic (no need to handle eventual consistency)");
            LOGGER.info("- Support for conditional writes and transactions across regions");
            LOGGER.info("- Consistent read operations from any region without waiting");

        } catch (DynamoDbException | InterruptedException e) {
            LOGGER.severe("MRSC workflow failed: " + e.getMessage());
            throw e;
        }
    }
```
+ Per informazioni dettagliate sull’API, consulta i seguenti argomenti nella *documentazione di riferimento dell’API AWS SDK for Java 2.x *.
  + [CreateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/CreateTable)
  + [DeleteTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DeleteTable)
  + [DescribeTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/DescribeTable)
  + [GetItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/GetItem)
  + [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)
  + [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)
  + [UpdateTable](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateTable)

------

# Sicurezza per tabelle globali DynamoDB
<a name="globaltables-security"></a>

Le repliche delle tabelle globali sono tabelle DynamoDB, quindi si utilizzano gli stessi metodi per controllare l'accesso alle repliche utilizzati per le tabelle a regione singola, AWS Identity and Access Management incluse le politiche di identità (IAM) e le politiche basate sulle risorse.

Questo argomento spiega come proteggere le tabelle globali DynamoDB utilizzando le autorizzazioni AWS Key Management Service IAM e la crittografia ().AWS KMS Scopri i ruoli collegati ai servizi (SLR) che consentono la replica e l'auto-scaling tra regioni, le autorizzazioni IAM necessarie per creare, aggiornare ed eliminare tabelle globali e le differenze tra le tabelle MREC (Multi-region Eventual Consistency) e Multi-region Strong Consistency (MRSC). Scopri AWS KMS anche le chiavi di crittografia per gestire in modo sicuro la replica tra regioni.

## Ruoli collegati ai servizi per tabelle globali
<a name="globaltables-slr"></a>

Le tabelle globali DynamoDB si basano su ruoli collegati ai servizi SLRs () per gestire la replica tra regioni e le funzionalità di auto-scaling.

È sufficiente configurare questi ruoli una sola volta per account. AWS Una volta creati, gli stessi ruoli servono a tutte le tabelle globali del tuo account. Per ulteriori informazioni sui ruoli collegati al servizio, consulta [Utilizzo dei ruoli collegati al servizio](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) nella *Guida per l'utente IAM*.

### Ruolo collegato al servizio
<a name="globaltables-replication-slr"></a>

Amazon DynamoDB crea automaticamente il ruolo collegato `AWSServiceRoleForDynamoDBReplication` al servizio (SLR) quando crei la tua prima tabella globale. Questo ruolo gestisce la replica tra regioni per te.

Quando applichi politiche basate sulle risorse alle repliche, assicurati di non negare nessuna delle autorizzazioni definite nella scheda principale SLR, poiché ciò interromperebbe `AWSServiceRoleForDynamoDBReplicationPolicy` la replica. Se si negano le autorizzazioni SLR richieste, la replica da e verso le repliche interessate verrà interrotta e lo stato della tabella di replica cambierà in `REPLICATION_NOT_AUTHORIZED`.
+ Per le tabelle globali Multi-region Eventual Consistency (MREC), se una replica rimane nello `REPLICATION_NOT_AUTHORIZED` stato per più di 20 ore, viene convertita in modo irreversibile in una tabella DynamoDB a regione singola.
+ Per le tabelle globali MRSC (Multi-region Strong Consistency), la negazione delle autorizzazioni richieste comporta operazioni di scrittura e lettura fortemente coerenti. `AccessDeniedException` Se una replica rimane nello `REPLICATION_NOT_AUTHORIZED` stato per più di sette giorni, diventa definitivamente inaccessibile e le operazioni di scrittura e lettura fortemente coerenti continueranno a fallire con un errore. Alcune operazioni di gestione, come l’eliminazione delle repliche, avranno esito positivo.

### Dimensionamento automatico del ruolo collegato al servizio
<a name="globaltables-autoscaling-slr"></a>

Quando si configura una tabella globale per la modalità di capacità fornita, è necessario configurare la scalabilità automatica per la tabella globale. La scalabilità automatica di DynamoDB utilizza il servizio Application AWS Auto Scaling per regolare dinamicamente la capacità di throughput assegnata sulle repliche di tabelle globali. Il servizio Application Auto Scaling crea un ruolo collegato al servizio (SLR) denominato. [https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html) Questo ruolo collegato al servizio viene creato automaticamente nel tuo AWS account quando configuri per la prima volta la scalabilità automatica per una tabella DynamoDB. Consente ad Application Auto Scaling di gestire la capacità delle tabelle assegnate e di creare allarmi. CloudWatch 

 Quando applicate politiche basate sulle risorse alle repliche, assicuratevi di non negare alcuna autorizzazione definita nel principio di Application [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html)Auto Scaling SLR, poiché ciò interromperà la funzionalità di auto scaling.

### Esempi di politiche IAM per ruoli collegati ai servizi
<a name="globaltables-example-slr"></a>

Una policy IAM con la seguente condizione non influisce sulle autorizzazioni richieste per la SLR di replica DynamoDB e la Auto Scaling SLR. AWS Questa condizione può essere aggiunta a policy altrimenti ampiamente restrittive per evitare l'interruzione involontaria della replica o della scalabilità automatica.

#### Esclusione delle autorizzazioni SLR richieste dalle politiche di negazione
<a name="example-exclude-slr-policy"></a>

L'esempio seguente mostra come escludere i ruoli principali collegati ai servizi dalle dichiarazioni di negazione:

```
"Condition": {
    "StringNotEquals": {
        "aws:PrincipalArn": [
            "arn:aws::iam::111122223333:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication",
            "arn:aws::iam::111122223333:role/aws-service-role/dynamodb.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_DynamoDBTable"
        ]
    }
}
```

## In che modo le tabelle globali utilizzano IAM AWS
<a name="globaltables-iam"></a>

Le sezioni seguenti descrivono le autorizzazioni richieste per le diverse operazioni delle tabelle globali e forniscono esempi di policy per aiutarti a configurare l'accesso appropriato per utenti e applicazioni.

**Nota**  
Tutte le autorizzazioni descritte devono essere applicate alla risorsa della tabella ARN specifica nelle regioni interessate. La risorsa della tabella ARN segue il formato`arn:aws:dynamodb:region:account-id:table/table-name`, in cui è necessario specificare i valori effettivi della regione, dell'ID dell'account e del nome della tabella.

**Topics**
+ [Creazione di tabelle globali e aggiunta di repliche](#globaltables-creation-iam)
+ [Aggiornamento delle tabelle globali](#globaltables-update-iam)
+ [Eliminazione di tabelle globali e rimozione di repliche](#globaltables-delete-iam)

### Creazione di tabelle globali e aggiunta di repliche
<a name="globaltables-creation-iam"></a>

Le tabelle globali DynamoDB supportano due modalità di coerenza: Multi-region Eventual Consistency (MREC) e Multi-region Strong Consistency (MRSC). Le tabelle globali MREC possono avere più repliche in un numero qualsiasi di regioni e garantire la coerenza finale. Le tabelle globali MRSC richiedono esattamente tre regioni (tre repliche o due repliche e un testimone) e forniscono una forte coerenza con zero Recovery Point Objective (RPO).

Le autorizzazioni necessarie per creare tabelle globali dipendono dal fatto che si stia creando una tabella globale con o senza un testimone.

#### Autorizzazioni per la creazione di tabelle globali
<a name="globaltables-creation-iam-all-types"></a>

Le seguenti autorizzazioni sono necessarie sia per la creazione iniziale della tabella globale che per l'aggiunta di repliche in un secondo momento. Queste autorizzazioni si applicano alle tabelle globali Multi-Region Eventual Consistency (MREC) e Multi-Region Strong Consistency (MRSC).
+ Le tabelle globali richiedono la replica tra regioni, che DynamoDB gestisce tramite il ruolo collegato al servizio (SLR). [`AWSServiceRoleForDynamoDBReplication`](#globaltables-replication-slr) La seguente autorizzazione consente a DynamoDB di creare questo ruolo automaticamente quando si crea una tabella globale per la prima volta:
  + `iam:CreateServiceLinkedRole`
+ Per creare una tabella globale o aggiungere una replica utilizzando l'[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, è necessario disporre della seguente autorizzazione sulla risorsa della tabella di origine:
  + `dynamodb:UpdateTable`
+ È necessario disporre delle seguenti autorizzazioni sulla risorsa della tabella nelle Regioni per aggiungere le repliche:
  + `dynamodb:CreateTable`
  + `dynamodb:CreateTableReplica`
  + `dynamodb:Query`
  + `dynamodb:Scan`
  + `dynamodb:UpdateItem`
  + `dynamodb:PutItem`
  + `dynamodb:GetItem`
  + `dynamodb:DeleteItem`
  + `dynamodb:BatchWriteItem`

#### Autorizzazioni aggiuntive per le tabelle globali MRSC che utilizzano un testimone
<a name="globaltables-creation-iam-witness"></a>

Quando si crea una tabella globale MRSC (Multi-Region Strong Consistency) con una regione di riferimento, è necessario disporre della seguente autorizzazione sulla risorsa della tabella in tutte le regioni partecipanti (incluse sia le regioni di replica che la regione di riferimento):
+ `dynamodb:CreateGlobalTableWitness`

#### Esempi di politiche IAM per la creazione di tabelle globali
<a name="globaltables-creation-iam-example"></a>

##### Creazione di una tabella globale MREC o MRSC in tre regioni
<a name="globaltables-creation-iam-example-three-regions"></a>

La seguente politica basata sull'identità consente di creare una tabella globale MREC o MRSC denominata «users» in tre regioni, inclusa la creazione del ruolo collegato al servizio di replica DynamoDB richiesto.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingUsersGlobalTable",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users",
        "arn:aws:dynamodb:us-west-2:123456789012:table/users"
      ]
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Limitazione della creazione di tabelle globali MREC o MRSC a regioni specifiche
<a name="globaltables-creation-iam-example-restrict-regions"></a>

La seguente policy basata sull'identità consente di creare repliche di tabelle globali DynamoDB in regioni specifiche utilizzando la RequestedRegion chiave [aws:](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion) condition, inclusa la creazione del ruolo collegato al servizio di replica DynamoDB richiesto.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowAddingReplicasToSourceTable",
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-1"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingReplicas",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-2",
            "us-west-2"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Creazione di una tabella globale MRSC con testimone
<a name="globaltables-creation-iam-example-witness"></a>

La seguente policy basata sull'identità consente di creare una tabella globale DynamoDB MRSC denominata «users» con repliche in us-east-1 e us-east-2 e un testimone in us-west-2, inclusa la creazione del ruolo collegato al servizio di replica DynamoDB richiesto.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingUsersGlobalTableWithWitness",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:CreateGlobalTableWitness",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users"
      ]
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

##### Limitazione della creazione di testimoni MRSC a regioni specifiche
<a name="globaltables-creation-iam-example-restrict-witness-regions"></a>

Questa policy basata sull'identità consente di creare una tabella globale MRSC con repliche limitate a regioni specifiche utilizzando la chiave [aws: RequestedRegion](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html#condition-keys-requestedregion) condition e la creazione di testimoni senza restrizioni in tutte le regioni, inclusa la creazione del ruolo collegato al servizio di replica DynamoDB richiesto.

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCreatingReplicas",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateTable",
        "dynamodb:CreateTableReplica",
        "dynamodb:UpdateTable",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem",
        "dynamodb:PutItem",
        "dynamodb:GetItem",
        "dynamodb:DeleteItem",
        "dynamodb:BatchWriteItem"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "aws:RequestedRegion": [
            "us-east-1",
            "us-east-2"
          ]
        }
      }
    },
    {
      "Sid": "AllowCreatingWitness",
      "Effect": "Allow",
      "Action": [
        "dynamodb:CreateGlobalTableWitness"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AllowCreatingSLR",
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": [
        "arn:aws:iam::123456789012:role/aws-service-role/replication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBReplication"
      ]
    }
  ]
}
```

------

### Aggiornamento delle tabelle globali
<a name="globaltables-update-iam"></a>

Per modificare le impostazioni di replica per una tabella globale esistente utilizzando l'[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, è necessaria la seguente autorizzazione sulla risorsa della tabella nella regione in cui stai effettuando la chiamata API:
+ `dynamodb:UpdateTable`

È inoltre possibile aggiornare altre configurazioni di tabelle globali, come i criteri di ridimensionamento automatico e le impostazioni Time to Live. Per queste operazioni di aggiornamento aggiuntive sono necessarie le seguenti autorizzazioni:
+ Per aggiornare una politica di ridimensionamento automatico delle repliche con l'[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTableReplicaAutoScaling.html)API, è necessario disporre delle seguenti autorizzazioni sulla risorsa della tabella in tutte le regioni contenenti repliche:
  + `application-autoscaling:DeleteScalingPolicy`
  + `application-autoscaling:DeleteScheduledAction`
  + `application-autoscaling:DeregisterScalableTarget`
  + `application-autoscaling:DescribeScalableTargets`
  + `application-autoscaling:DescribeScalingActivities`
  + `application-autoscaling:DescribeScalingPolicies`
  + `application-autoscaling:DescribeScheduledActions`
  + `application-autoscaling:PutScalingPolicy`
  + `application-autoscaling:PutScheduledAction`
  + `application-autoscaling:RegisterScalableTarget`
+ Per aggiornare le impostazioni Time to Live con l'[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTimeToLive.html)API, è necessario disporre delle seguenti autorizzazioni sulla risorsa della tabella in tutte le regioni contenenti repliche:
  + `dynamodb:UpdateTimeToLive`

  Tieni presente che Time to Live (TTL) è supportato solo per le tabelle globali configurate con Multi-Region Eventual Consistency (MREC). Per ulteriori informazioni su come funzionano le tabelle globali con TTL, consulta [Come funzionano le tabelle globali DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/V2globaltables_HowItWorks.html).

### Eliminazione di tabelle globali e rimozione di repliche
<a name="globaltables-delete-iam"></a>

Per eliminare una tabella globale, è necessario rimuovere tutte le repliche. Le autorizzazioni richieste per questa operazione variano a seconda che si stia eliminando una tabella globale con o senza una regione di riferimento.

#### Autorizzazioni per l'eliminazione di tabelle globali e la rimozione di repliche
<a name="globaltables-delete-iam-all-types"></a>

Le seguenti autorizzazioni sono necessarie sia per rimuovere singole repliche sia per eliminare completamente le tabelle globali. L'eliminazione di una configurazione di tabella globale rimuove solo la relazione di replica tra tabelle in regioni diverse. Non elimina la tabella DynamoDB sottostante nell'ultima regione rimanente. La tabella nell'ultima regione continua a esistere come tabella DynamoDB standard con gli stessi dati e le stesse impostazioni. Queste autorizzazioni si applicano alle tabelle globali Multi-Region Eventual Consistency (MREC) e Multi-Region Strong Consistency (MRSC). 
+ Per rimuovere le repliche da una tabella globale utilizzando l'[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API, è necessaria la seguente autorizzazione sulla risorsa della tabella nella regione da cui si sta effettuando la chiamata API:
  + `dynamodb:UpdateTable`
+ Sono necessarie le seguenti autorizzazioni sulla risorsa della tabella in ogni regione in cui stai rimuovendo una replica:
  + `dynamodb:DeleteTable`
  + `dynamodb:DeleteTableReplica`

#### Autorizzazioni aggiuntive per le tabelle globali MRSC che utilizzano un testimone
<a name="globaltables-delete-iam-witness"></a>

Per eliminare una tabella globale MRSC (Multi-region Strong Consistency) con un testimone, devi disporre della seguente autorizzazione sulla risorsa della tabella in tutte le regioni partecipanti (incluse sia le regioni di replica che la regione di riferimento):
+ `dynamodb:DeleteGlobalTableWitness`

#### Esempi: politiche IAM per eliminare le repliche di una tabella globale
<a name="globaltables-delete-iam-example"></a>

##### Eliminazione di repliche di tabelle globali
<a name="globaltables-delete-replicas-iam-example"></a>

Questa policy basata sull'identità consente di eliminare una tabella globale DynamoDB denominata «users» e le relative repliche in tre regioni:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable",
        "dynamodb:DeleteTable",
        "dynamodb:DeleteTableReplica"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users",
        "arn:aws:dynamodb:us-west-2:123456789012:table/users"
      ]
    }
  ]
}
```

------

##### Eliminazione di una tabella globale MRSC con un testimone
<a name="globaltables-delete-witness-iam-example"></a>

Questa politica basata sull'identità consente di eliminare la replica e il testimone di una tabella globale MRSC denominata «users»:

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:UpdateTable",
        "dynamodb:DeleteTable",
        "dynamodb:DeleteTableReplica",
        "dynamodb:DeleteGlobalTableWitness"
      ],
      "Resource": [
        "arn:aws:dynamodb:us-east-1:123456789012:table/users",
        "arn:aws:dynamodb:us-east-2:123456789012:table/users"
      ]
    }
  ]
}
```

------

## Come vengono utilizzate le tabelle globali AWS KMS
<a name="globaltables-kms"></a>

Come tutte le tabelle DynamoDB, le repliche delle tabelle globali crittografano sempre i dati inattivi utilizzando chiavi di crittografia archiviate AWS in Key Management Service ().AWS KMS

Tutte le repliche in una tabella globale devono essere configurate con lo stesso tipo di chiave KMS (chiave di proprietà di AWS , chiave gestita da AWS o chiave gestita dal cliente).

**Importante**  
DynamoDB richiede l’accesso alla chiave di crittografia della replica per eliminare una replica. Se si desidera disabilitare o eliminare una chiave gestita dal cliente utilizzata per crittografare una replica perché si sta eliminando la replica, è necessario prima eliminare la replica, attendere che lo stato della tabella su una delle repliche rimanenti cambi in `ACTIVE`, quindi disabilitare o eliminare la chiave.

Per una tabella globale configurata per coerenza finale multi-Regione (MREC), se si disabilita o si revoca l’accesso di DynamoDB a una chiave gestita dal cliente utilizzata per crittografare una replica, la replica da e verso la replica verrà interrotta e lo stato della replica cambierà in `INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se una replica in una tabella globale MREC rimane nello stato `INACCESSIBLE_ENCRYPTION_CREDENTIALS` per più di 20 ore, viene convertita in modo irreversibile in una tabella DynamoDB a Regione singola.

Per una tabella globale configurata per elevata consistenza multi-Regione (MRSC), se si disabilita o si revoca l’accesso di DynamoDB a una chiave gestita dal cliente utilizzata per crittografare una replica, la replica da e verso la replica si interromperà, i tentativi di eseguire scritture oppure operazioni a elevata consistenza di lettura sulla replica restituiranno un errore e lo stato della replica cambierà in `INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se una replica in una tabella globale MRSC rimane nello stato `INACCESSIBLE_ENCRYPTION_CREDENTIALS` per più di sette giorni, a seconda delle autorizzazioni specifiche revocate, la replica verrà archiviata o diventerà definitivamente inaccessibile.

# Tabelle globali multi-account DynamoDB
<a name="globaltables-MultiAccount"></a>

Le tabelle globali multi-account replicano automaticamente i dati delle tabelle DynamoDB su più AWS regioni e più AWS account per migliorare la resilienza, isolare i carichi di lavoro a livello di account e applicare controlli di sicurezza e governance distinti. Ogni tabella di replica risiede in un AWS account distinto, che consente l'isolamento degli errori sia a livello di regione che di account. È inoltre possibile allineare le repliche alla struttura organizzativa. AWS Le tabelle globali con più account offrono ulteriori vantaggi in termini di isolamento, governance e sicurezza rispetto alle tabelle globali con lo stesso account.

Le tabelle globali con più account offrono i seguenti vantaggi:
+ Replica automaticamente i dati delle tabelle DynamoDB tra account e regioni a tua scelta AWS 
+ Migliora la sicurezza e la governance replicando i dati tra account con policy, barriere e limiti di conformità distinti
+ Migliora la resilienza operativa e l'isolamento degli errori a livello di account inserendo le repliche in account separati AWS 
+ Allinea i carichi di lavoro per unità aziendale o proprietà quando utilizzi una strategia multi-account
+ Semplifica l'attribuzione dei costi fatturando ogni replica sul rispettivo account AWS 

Per ulteriori informazioni, consulta [Vantaggi dell'utilizzo di](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html) più account. AWS Se i tuoi carichi di lavoro non richiedono la replica di più account o desideri una gestione delle repliche più semplice con sostituzioni locali, puoi continuare a utilizzare tabelle globali dello stesso account.

Puoi configurare tabelle globali con più account con. [Coerenza finale multi-Regione (MREC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrec) Le tabelle globali configurate per [Elevata consistenza multi-Regione (MRSC)](V2globaltables_HowItWorks.md#V2globaltables_HowItWorks.consistency-modes.mrsc) non supportano il modello multi-account.

**Topics**
+ [Come funzionano le tabelle globali DynamoDB](V2globaltables_MA_HowItWorks.md)
+ [Tutorial: Creazione di tabelle globali multi-account](V2globaltables_MA.tutorial.md)
+ [Sicurezza per tabelle globali DynamoDB](globaltables_MA_security.md)

# Come funzionano le tabelle globali DynamoDB
<a name="V2globaltables_MA_HowItWorks"></a>

Le tabelle globali multi-account estendono le funzionalità completamente gestite, serverless, multiregionali e multiattive di DynamoDB per più account. AWS Le tabelle globali con più account replicano i dati tra AWS regioni e account, fornendo la stessa funzionalità attiva-attiva delle tabelle globali con lo stesso account. Quando scrivi su qualsiasi replica, DynamoDB replica i dati su tutte le altre repliche.

Le principali differenze rispetto alle tabelle globali dello stesso account includono:
+ La replica multiaccount è supportata per le tabelle globali MREC (Multi-Region Eventual Consistency).
+ È possibile aggiungere repliche solo iniziando con una tabella a regione singola. La conversione di una tabella globale esistente con lo stesso account in una configurazione con più account non è supportata. Per eseguire la migrazione, è necessario eliminare le repliche esistenti per tornare a una tabella a regione singola prima di creare una nuova tabella globale con più account.
+ Ogni replica deve risiedere in un account separato. AWS *Per una tabella globale con più account con *N* repliche, è necessario disporre di N account.*
+ Per impostazione predefinita, le tabelle globali con più account utilizzano impostazioni di tabella unificate in tutte le repliche. Tutte le repliche condividono automaticamente la stessa configurazione (ad esempio la modalità di trasmissione e il TTL) e, a differenza delle tabelle globali dello stesso account, queste impostazioni non possono essere sostituite per replica.
+ I clienti devono fornire le autorizzazioni di replica al responsabile del servizio di tabelle globali DynamoDB nelle loro politiche delle risorse.

Le tabelle globali con più account utilizzano la stessa tecnologia di replica sottostante delle tabelle globali con lo stesso account. Le impostazioni delle tabelle vengono replicate automaticamente su tutte le repliche regionali e i clienti non possono sovrascrivere o personalizzare le impostazioni per replica. Ciò garantisce una configurazione coerente e un comportamento prevedibile tra più AWS account che partecipano alla stessa tabella globale.

Le impostazioni nelle tabelle globali di DynamoDB definiscono il comportamento di una tabella e il modo in cui i dati vengono replicati tra le regioni. Queste impostazioni vengono configurate tramite il APIs piano di controllo DynamoDB durante la creazione della tabella o quando si aggiunge una nuova replica regionale.

Quando creano una tabella globale con più account, i clienti devono impostarla `GlobalTableSettingsReplicationMode = ENABLED` per ogni replica regionale. Ciò garantisce che le modifiche alla configurazione apportate in una regione si propaghino automaticamente a tutte le altre regioni che partecipano alla tabella globale.

È possibile abilitare la replica delle impostazioni dopo la creazione della tabella. Ciò supporta lo scenario in cui una tabella viene originariamente creata come tabella regionale e successivamente aggiornata a una tabella globale con più account.

**Impostazioni sincronizzate**

Le seguenti impostazioni della tabella sono sempre sincronizzate tra tutte le repliche in una tabella globale con più account:

**Nota**  
A differenza delle tabelle globali con lo stesso account, le tabelle globali con più account non consentono sostituzioni per regione per queste impostazioni. L'unica eccezione è che le sostituzioni per le politiche di auto-scaling di lettura (tabelle e GSIs) sono consentite in quanto si tratta di risorse esterne separate.
+ Modalità di capacità (capacità allocata o on demand)
+ Capacità di lettura e scrittura fornita dalla tabella
+ Scalabilità automatica di lettura e scrittura delle tabelle
+ Definizione dell'indice secondario locale (LSI)
+ Definizione degli indici secondari globali (GSI)
+ GSI ha fornito capacità di lettura e scrittura
+ Scalabilità automatica di lettura e scrittura GSI
+ Definizione dei flussi in modalità MREC
+ Time to live (TTL)
+ Throughput a caldo
+ Velocità massima di lettura e scrittura su richiesta

**Impostazioni non sincronizzate**

Le seguenti impostazioni non sono sincronizzate tra le repliche e devono essere configurate indipendentemente per ogni tabella di replica in ogni regione.
+ Classe di tabella
+ Tipo di crittografia lato server (SSE)
+ Point-in-time Ripristino
+ ID chiave KMS con crittografia lato server (SSE)
+ Protezione dall'eliminazione
+ Kinesis Data Streams (KDSD)
+ Tag
+ Policy delle risorse
+ Tabella Cloudwatch-Contributor Insights (CCI)
+ GSI Cloudwatch-Contributor Insights (CCI)

## Monitoraggio
<a name="V2globaltables_MA_HowItWorks.monitoring"></a>

Le tabelle globali configurate per la coerenza finale multiregionale (MREC) pubblicano la metrica su. [`ReplicationLatency`](metrics-dimensions.md#ReplicationLatency) CloudWatch Questa metrica tiene traccia del tempo trascorso tra la scrittura di un elemento in una tabella di replica e la visualizzazione di tale elemento in un’altra replica nella tabella globale. `ReplicationLatency` è espresso in millisecondi e viene emesso per ogni coppia di Regioni di origine e di destinazione in una tabella globale.

`ReplicationLatency`I valori tipici dipendono dalla distanza tra le AWS regioni scelte e da altre variabili come il tipo di carico di lavoro e la velocità effettiva. Ad esempio, una replica di origine nella Regione Stati Uniti occidentali (California settentrionale) (us-west-1) ha un `ReplicationLatency` inferiore rispetto alla Regione Stati Uniti occidentali (Oregon) (us-west-2) rispetto alla Regione Africa (Città del Capo) (af-south-1).

Un valore crescente per `ReplicationLatency` potrebbe indicare che gli aggiornamenti da una replica non si propagano ad altre tabelle di replica in modo tempestivo. In questo caso, puoi reindirizzare temporaneamente l'attività di lettura e scrittura dell'applicazione verso un'altra regione. AWS 

**Gestione dei problemi di latenza di replica nelle tabelle globali con più account**

Se si `ReplicationLatency` superano le 3 ore a causa di problemi causati dal cliente su una tabella di replica, DynamoDB invia una notifica richiedendo al cliente di risolvere il problema sottostante. I problemi più comuni causati dal cliente che possono impedire la replica includono:
+ Rimozione delle autorizzazioni richieste dalla politica delle risorse della tabella di replica
+ Disattivazione di una AWS regione che ospita una replica della tabella globale con più account
+ Negazione delle autorizzazioni della chiave AWS KMS della tabella necessarie per decrittografare i dati

DynamoDB invia una notifica iniziale entro 3 ore dall'elevata latenza di replica, seguita da una seconda notifica dopo 20 ore se il problema rimane irrisolto. Se il problema non viene corretto entro la finestra temporale richiesta, DynamoDB dissocierà automaticamente la replica dalla tabella globale. La replica interessata verrà quindi convertita in una tabella regionale.

# Tutorial: Creazione di tabelle globali multi-account
<a name="V2globaltables_MA.tutorial"></a>

Questa sezione fornisce step-by-step istruzioni per creare tabelle globali DynamoDB che si estendono su più account. AWS 

## Creare una tabella globale multi-account utilizzando la console DynamoDB
<a name="create-ma-gt-console"></a>

Segui questi passaggi per creare una tabella globale multi-account utilizzando. Console di gestione AWS L'esempio seguente crea una tabella globale con tabelle di replica negli Stati Uniti d'America.

1. Accedi Console di gestione AWS e apri la console DynamoDB [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)all'indirizzo per il primo account (ad esempio). *111122223333*

1. Per questo esempio, seleziona **Stati Uniti orientali (Ohio)** dal selettore delle Regioni nella barra di navigazione.

1. Nel riquadro di navigazione sul lato sinistro della console scegli **Tables (Tabelle)**.

1. Scegliere **Create Table (Crea tabella)**.

1. Nella pagina **Crea tabella**:

   1. Nel campo **Table name (Nome tabella)** immetti **MusicTable**.

   1. In **Partition key** (Chiave di partizione), inserisci **Artist**.

   1. Per **Chiave di ordinamento**, immetti **SongTitle**.

   1. Mantieni le restanti impostazioni predefinite e seleziona **Crea tabella**.

1. Aggiungi la seguente politica delle risorse alla tabella

------
#### [ JSON ]

****  

   ```
   {
   "Version":"2012-10-17",		 	 	 
   "Statement": [
       {
           "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
           "Effect": "Allow",
           "Action": [
               "dynamodb:ReadDataForReplication",
               "dynamodb:WriteDataForReplication",
               "dynamodb:ReplicateSettings"
           ],
           "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
           "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
           "Condition": {
               "StringEquals": {
                   "aws:SourceAccount": ["444455556666","111122223333"],
                   "aws:SourceArn": [
                       "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                       "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                   ]
               }
           }
       },
       {
           "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
           "Effect": "Allow",
           "Action": [
               "dynamodb:AssociateTableReplica"
           ],
           "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
           "Principal": {"AWS": ["444455556666"]}
       }
   ]
   }
   ```

------

1. Questa nuova tabella funge da prima tabella di replica in una nuova tabella globale. È il prototipo per altre tabelle di replica che verranno aggiunte in seguito.

1. Attendi che la tabella diventi **attiva**. Per la tabella appena creata, dalla scheda **Tabelle globali**, accedi a **Replica delle impostazioni** e fai clic su **Abilita.**

1. Esci da questo account (*111122223333*qui).

1. Accedi Console di gestione AWS e apri la console DynamoDB [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)all'indirizzo per il secondo account (ad esempio). *444455556666*

1. Per questo esempio, scegli **Stati Uniti orientali (Virginia settentrionale) dal selettore Regione nella barra di navigazione.**

1. La console verifica che non esista una tabella con lo stesso nome nella Regione selezionata. Se esiste una tabella con lo stesso nome, è necessario eliminare la tabella esistente prima di poter creare una nuova tabella di replica in quella regione.

1. Nel menu a discesa vicino a **Crea tabella**, scegli **Crea da un altro account**

1. Nella pagina **Crea tabella da un altro account**:

   1. Aggiungi **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** come tabella arn per la tabella di origine.

   1. Nella **tabella di replica ARNs**, aggiungi nuovamente l'ARN della tabella di origine. **arn:aws:dynamodb:us-east-2:*111122223333*:table/MusicTable** Se esistono già più repliche come parte di una tabella globale multiaccount, è necessario aggiungere tutte le repliche esistenti all'ARN. ReplicaTable

   1. **Mantieni le altre impostazioni predefinite e scegli Invia.**

1. La scheda **Tabelle globali** per la tabella Music (e per qualsiasi altra tabella di replica) mostra che la tabella è stata replicata in più regioni.

1. Per testare la replica:

   1. È possibile utilizzare qualsiasi regione in cui esiste una replica per questa tabella

   1. Scegli **Explore table items** (Esplora elementi della tabella).

   1. Scegli **Crea elemento**.

   1. Inserisci **item\$11** per **Artista** e **Song Value 1** per **SongTitle**.

   1. Scegli **Crea elemento**.

   1. Verifica la replica passando alle altre Regioni:

   1. Verifica che la tabella Musica contenga l’elemento creato.

## Crea una tabella globale multi-account utilizzando il AWS CLI
<a name="ma-gt-cli"></a>

Negli esempi seguenti viene illustrato come creare una tabella globale con più account utilizzando. AWS CLI Questi esempi illustrano il flusso di lavoro completo per l'impostazione della replica tra account.

------
#### [ CLI ]

Utilizza i seguenti AWS CLI comandi per creare una tabella globale multi-account con replica tra account.

```
# STEP 1: Setting resource policy for the table in account 111122223333

cat > /tmp/source-resource-policy.json << 'EOF'
{
    "Version": "2012-10-17", 		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": ["444455556666","111122223333"],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                        "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable",
            "Principal": {"AWS": ["444455556666"]}
        }
    ]
}
EOF

# Step 2: Create a new table (MusicTable) in US East (Ohio), 
#   with DynamoDB Streams enabled (NEW_AND_OLD_IMAGES),
#   and Settings Replication ENABLED on the account 111122223333

aws dynamodb create-table \
    --table-name MusicTable \
    --attribute-definitions \
        AttributeName=Artist,AttributeType=S \
        AttributeName=SongTitle,AttributeType=S \
    --key-schema \
        AttributeName=Artist,KeyType=HASH \
        AttributeName=SongTitle,KeyType=RANGE \
    --billing-mode PAY_PER_REQUEST \
    --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES \
    --global-table-settings-replication-mode ENABLED \
    --resource-policy file:///tmp/source-resource-policy.json \
    --region us-east-2 


# Step 3: Creating replica table in account 444455556666

# Resource policy for account 444455556666
cat > /tmp/dest-resource-policy.json << 'EOF'
{
    "Version": "2012-10-17", 		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": ["444455556666","111122223333"],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:us-east-1:444455556666:table/MusicTable",
                        "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable"
                    ]
                }
            }
        }
    ]
}
EOF

# Execute the replica table creation
aws dynamodb create-table \
    --table-name MusicTable \
    --global-table-source-arn "arn:aws:dynamodb:us-east-2:111122223333:table/MusicTable" \
    --resource-policy file:///tmp/dest-resource-policy.json \
    --global-table-settings-replication-mode ENABLED \
    --region us-east-1

# Step 4: View the list of replicas created using describe-table
aws dynamodb describe-table \
    --table-name MusicTable \
    --region us-east-2 \
    --query 'Table.{TableName:TableName,TableStatus:TableStatus,MultiRegionConsistency:MultiRegionConsistency,Replicas:Replicas[*].{Region:RegionName,Status:ReplicaStatus}}'

# Step 5: To verify that replication is working, add a new item to the Music table in US East (Ohio)
aws dynamodb put-item \
    --table-name MusicTable \
    --item '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2

# Step 6: Wait for a few seconds, and then check to see whether the item has been 
# successfully replicated to US East (N. Virginia) and Europe (Ireland)
aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-1

aws dynamodb get-item \
    --table-name MusicTable \
    --key '{"Artist": {"S":"item_1"},"SongTitle": {"S":"Song Value 1"}}' \
    --region us-east-2

# Step 7: Delete the replica table in US East (N. Virginia) Region
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-1

# Clean up: Delete the primary table
aws dynamodb delete-table \
    --table-name MusicTable \
    --region us-east-2
```

------

# Sicurezza per tabelle globali DynamoDB
<a name="globaltables_MA_security"></a>

Le repliche delle tabelle globali sono tabelle DynamoDB, quindi si utilizzano gli stessi metodi per controllare l'accesso alle repliche utilizzati per le tabelle a regione singola, AWS Identity and Access Management incluse le politiche di identità (IAM) e le politiche basate sulle risorse. Questo argomento spiega come proteggere le tabelle globali multi-account DynamoDB utilizzando le autorizzazioni AWS Key Management Service IAM e la crittografia ().AWS KMS Scopri le politiche basate sulle risorse e i ruoli collegati ai servizi (SLR) che consentono la replica e l'auto-scaling tra account tra più regioni, le autorizzazioni IAM necessarie per creare, aggiornare ed eliminare tabelle globali, per le tabelle MREC (Multi-Region Eventual Consistency). Scopri anche le chiavi di crittografia per gestire la replica tra regioni in modo sicuro. AWS KMS 

Fornisce informazioni dettagliate sulle politiche e le autorizzazioni basate sulle risorse necessarie per stabilire la replica delle tabelle tra account e regioni. La comprensione di questo modello di sicurezza è fondamentale per i clienti che devono implementare soluzioni di replica dei dati sicure e tra più account.

## Autorizzazione principale del servizio per la replica
<a name="globaltables_MA_service_principal"></a>

Le tabelle globali multi-account di DynamoDB utilizzano un approccio di autorizzazione distinto perché la replica viene eseguita oltre i confini degli account. Questa operazione viene eseguita utilizzando il principio del servizio di replica di DynamoDB:. `replication.dynamodb.amazonaws.com` [Ogni account partecipante deve consentire esplicitamente tale principale nella politica delle risorse della tabella di replica, assegnandole autorizzazioni che possono essere limitate a repliche specifiche in base alle condizioni del contesto di origine su chiavi come `aws:SourceAccount``aws:SourceArn`, ecc. — vedi le chiavi di condizione globali per maggiori dettagli.AWS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html) Le autorizzazioni sono bidirezionali, il che significa che tutte le repliche devono concedersi esplicitamente le autorizzazioni reciproche prima di poter stabilire la replica su una particolare coppia di repliche.

Le seguenti autorizzazioni principali del servizio sono essenziali per la replica tra account:
+ `dynamodb:ReadDataForReplication`garantisce la capacità di leggere i dati per scopi di replica. Questa autorizzazione consente di leggere e propagare le modifiche in una replica ad altre repliche.
+ `dynamodb:WriteDataForReplication`consente la scrittura di dati replicati nelle tabelle di destinazione. Questa autorizzazione consente di sincronizzare le modifiche su tutte le repliche nella tabella globale.
+ `dynamodb:ReplicateSettings`consente la sincronizzazione delle impostazioni delle tabelle tra le repliche, fornendo una configurazione coerente su tutte le tabelle partecipanti.

Ogni replica deve concedere le autorizzazioni di cui sopra a tutte le altre repliche e a se stessa, ovvero le condizioni del contesto di origine devono includere l'intero set di repliche che comprende la tabella globale. Queste autorizzazioni vengono verificate per ogni nuova replica quando viene aggiunta a una tabella globale con più account. Ciò verifica che le operazioni di replica vengano eseguite solo dal servizio DynamoDB autorizzato e solo tra le tabelle previste.

## Ruoli collegati ai servizi per tabelle globali con più account
<a name="globaltables_MA_service_linked_roles"></a>

Le tabelle globali multi-account di DynamoDB replicano le impostazioni su tutte le repliche in modo che ogni replica sia configurata in modo identico con un throughput costante e offra un'esperienza di failover senza interruzioni. La replica delle impostazioni è controllata tramite l'`ReplicateSettings`autorizzazione del responsabile del servizio, ma ci affidiamo anche ai ruoli collegati al servizio (SLRs) per gestire determinate funzionalità di replica e di auto-scaling tra account. Questi ruoli vengono configurati solo una volta per account. AWS Una volta creati, gli stessi ruoli servono a tutte le tabelle globali del tuo account. Per ulteriori informazioni sui ruoli collegati ai servizi, consulta [Using service-linked roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create-service-linked-role.html) nella IAM User Guide.

### Ruolo collegato al servizio di gestione delle impostazioni
<a name="globaltables_MA_settings_management_slr"></a>

Amazon DynamoDB crea automaticamente il ruolo collegato AWSService RoleForDynamo DBGlobal TableSettingsManagement al servizio (SLR) quando crei la prima replica di tabella globale multi-account nell'account. Questo ruolo gestisce automaticamente la replica delle impostazioni tra account e regioni diverse.

Quando applicate politiche basate sulle risorse alle repliche, verificate di non negare nessuna delle autorizzazioni definite nel principio SLR, poiché ciò potrebbe interferire con la `AWSServiceRoleForDynamoDBGlobalTableSettingsManagement` gestione delle impostazioni e compromettere la replica se il throughput non corrisponde tra le repliche o. GSIs Se negate le autorizzazioni SLR richieste, la replica da e verso le repliche interessate potrebbe interrompersi e lo stato della tabella di replica cambierà in. `REPLICATION_NOT_AUTHORIZED` Per le tabelle globali con più account, se una replica rimane nello `REPLICATION_NOT_AUTHORIZED` stato per più di 20 ore, viene convertita in modo irreversibile in una tabella DynamoDB a regione singola. La SLR dispone delle seguenti autorizzazioni:
+ `application-autoscaling:DeleteScalingPolicy`
+ `application-autoscaling:DescribeScalableTargets`
+ `application-autoscaling:DescribeScalingPolicies`
+ `application-autoscaling:DeregisterScalableTarget`
+ `application-autoscaling:PutScalingPolicy`
+ `application-autoscaling:RegisterScalableTarget`

### Dimensionamento automatico del ruolo collegato al servizio
<a name="globaltables_MA_autoscaling_slr"></a>

Quando si configura una tabella globale per la modalità di capacità fornita, è necessario configurare la scalabilità automatica per la tabella globale. La scalabilità automatica di DynamoDB utilizza il servizio Application AWS Auto Scaling per regolare dinamicamente la capacità di throughput assegnata sulle repliche di tabelle globali. Il servizio Application Auto Scaling crea un ruolo collegato al servizio (SLR) denominato. [AWSServiceRoleForApplicationAutoScaling\$1DynamoDBTable](https://docs.aws.amazon.com/autoscaling/application/userguide/application-auto-scaling-service-linked-roles.html) Questo ruolo collegato al servizio viene creato automaticamente nel tuo AWS account quando configuri per la prima volta la scalabilità automatica per una tabella DynamoDB. Consente ad Application Auto Scaling di gestire la capacità delle tabelle assegnata e creare allarmi. CloudWatch 

Quando si applicano politiche basate sulle risorse alle repliche, verificate di non negare alcuna autorizzazione definita nella Policy al principale [AWSApplicationAutoscalingDynamoDBTableApplication](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AWSApplicationAutoscalingDynamoDBTablePolicy.html) Auto Scaling SLR, poiché ciò interromperà la funzionalità di auto-scaling.

## In che modo le tabelle globali utilizzano IAM AWS
<a name="globaltables_MA_iam"></a>

Le sezioni seguenti descrivono le autorizzazioni richieste per le diverse operazioni sulle tabelle globali e forniscono esempi di policy per aiutarti a configurare l'accesso appropriato per utenti e applicazioni.

**Nota**  
Tutte le autorizzazioni descritte devono essere applicate alla risorsa della tabella ARN specifica nelle regioni interessate. La risorsa della tabella ARN segue il formato`arn:aws:dynamodb:region:account-id:table/table-name`, in cui è necessario specificare i valori effettivi della regione, dell'ID dell'account e del nome della tabella.

Di seguito sono riportati gli step-by-step argomenti trattati nelle sezioni seguenti:
+ Creazione di tabelle globali multi-account e aggiunta di repliche
+ Aggiornamento di una tabella globale con più account
+ Eliminazione di tabelle globali e rimozione di repliche

### Creazione di tabelle globali e aggiunta di repliche
<a name="globaltables_MA_creating"></a>

#### Autorizzazioni per la creazione di tabelle globali
<a name="globaltables_MA_creating_permissions"></a>

Quando una nuova replica viene aggiunta a una tabella regionale per formare una tabella globale multi-account o a una tabella globale multi-account esistente, il principale IAM che esegue l'azione deve essere autorizzato da tutti i membri esistenti. Affinché l'aggiunta della replica abbia esito positivo, tutti i membri esistenti devono fornire la seguente autorizzazione nella politica della tabella:
+ `dynamodb:AssociateTableReplica`- Questa autorizzazione consente di unire le tabelle in una configurazione di tabella globale. Questa è l'autorizzazione fondamentale che consente la creazione iniziale della relazione di replica.

Questo controllo preciso consente solo agli account autorizzati di partecipare alla configurazione globale della tabella.

#### Esempi di politiche IAM per la creazione di tabelle globali
<a name="globaltables_MA_creating_examples"></a>

##### Esempi di politiche IAM per una configurazione a 2 repliche
<a name="globaltables_MA_2replica_example"></a>

La configurazione delle tabelle globali multi-account segue un flusso di autorizzazione specifico che fornisce una replica sicura. Esaminiamo come funziona in pratica descrivendo uno scenario pratico in cui un cliente desidera creare una tabella globale con due repliche. La prima replica (replicaA) risiede nell'account A nella regione ap-east-1, mentre la seconda replica (replicaB) si trova nell'account B nella regione eu-south-1.
+ Nell'account di origine (Account A), il processo inizia con la creazione della tabella di replica primaria. L'amministratore dell'account deve allegare a questa tabella una politica basata sulle risorse che conceda esplicitamente le autorizzazioni necessarie all'account di destinazione (account B) per eseguire l'associazione. Questa policy autorizza inoltre il servizio di replica DynamoDB a eseguire azioni di replica essenziali.
+ L'account di destinazione (Account B) segue un processo simile allegando una politica corrispondente basata sulle risorse durante la creazione della replica e facendo riferimento all'ARN della tabella di origine da utilizzare per creare la replica. Questa politica rispecchia le autorizzazioni concesse dall'Account A, creando una relazione bidirezionale affidabile. Prima di stabilire la replica, DynamoDB convalida queste autorizzazioni tra account per verificare che l'autorizzazione sia corretta.

Per stabilire questa configurazione:
+ L'amministratore dell'Account A deve prima allegare la policy basata sulle risorse a ReplicaA. Questa policy concede esplicitamente le autorizzazioni necessarie all'Account B e al servizio di replica DynamoDB.
+ Analogamente, l'amministratore dell'Account B deve allegare una policy corrispondente a ReplicaB, invertendo i riferimenti agli account per concedere le autorizzazioni corrispondenti all'Account A, nella chiamata di creazione della tabella per creare la replica B facendo riferimento alla replica A come tabella di origine.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"AWS": ["444455556666"]}
        }
    ]
}
```

------

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        }
    ]
}
```

------

##### Esempi di politiche IAM per una configurazione a 3 repliche
<a name="globaltables_MA_3replica_example"></a>

In questa configurazione, abbiamo 3 repliche ReplicA, ReplicaB e ReplicaC nell'Account A, Account B e Account C, rispettivamente. La replica A è la prima replica, che inizia come tabella regionale, quindi vengono aggiunti ReplicaB e ReplicaC.
+ L'amministratore dell'Account A deve innanzitutto collegare la policy basata sulle risorse a ReplicaA, consentendone la replica con tutti i membri e permettendo ai principali IAM dell'Account B e dell'Account C di aggiungere repliche.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666", "123456789012" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
                        "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
            "Principal": { "AWS": [ "444455556666", "123456789012" ] }
        }
    ]
}
```

------
+ L'amministratore dell'Account B deve aggiungere una replica (Replica B) che punti a ReplicaA come origine. La replica B ha la seguente politica che consente la replica tra tutti i membri e consente all'account C di aggiungere una replica:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666", "123456789012" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
                        "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC"
                    ]
                }
            }
        },
        {
            "Sid": "AllowTrustedAccountsToJoinThisGlobalTable",
            "Effect": "Allow",
            "Action": [
                "dynamodb:AssociateTableReplica"
            ],
            "Resource": "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB",
            "Principal": { "AWS": [ "123456789012" ] }
        }
    ]
}
```

------
+ Infine, l'amministratore dell'Account C crea una replica con la seguente politica che consente le autorizzazioni di replica tra tutti i membri. La politica non consente l'aggiunta di ulteriori repliche.

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DynamoDBActionsNeededForSteadyStateReplication",
            "Effect": "Allow",
            "Action": [
                "dynamodb:ReadDataForReplication",
                "dynamodb:WriteDataForReplication",
                "dynamodb:ReplicateSettings"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/ReplicaC",
            "Principal": {"Service": ["replication.dynamodb.amazonaws.com"]},
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": [ "111122223333", "444455556666" ],
                    "aws:SourceArn": [
                        "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                        "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                    ]
                }
            }
        }
    ]
}
```

------

### Aggiornamento di una tabella globale con più account
<a name="globaltables_MA_updating"></a>

Per modificare le impostazioni di replica per una tabella globale esistente utilizzando l' UpdateTable API, è necessaria la seguente autorizzazione sulla risorsa della tabella nella regione in cui si sta effettuando la chiamata API: `dynamodb:UpdateTable`

È inoltre possibile aggiornare altre configurazioni di tabelle globali, come i criteri di ridimensionamento automatico e le impostazioni Time to Live. Per queste operazioni di aggiornamento aggiuntive sono necessarie le seguenti autorizzazioni:

Per aggiornare le impostazioni Time to Live con l'`UpdateTimeToLive`API, è necessario disporre della seguente autorizzazione sulla risorsa della tabella in tutte le regioni contenenti repliche: `dynamodb:UpdateTimeToLive`

Per aggiornare una politica di ridimensionamento automatico delle repliche con l'`UpdateTableReplicaAutoScaling`API, è necessario disporre delle seguenti autorizzazioni sulla risorsa della tabella in tutte le regioni contenenti repliche:
+ `application-autoscaling:DeleteScalingPolicy`
+ `application-autoscaling:DeleteScheduledAction`
+ `application-autoscaling:DeregisterScalableTarget`
+ `application-autoscaling:DescribeScalableTargets`
+ `application-autoscaling:DescribeScalingActivities`
+ `application-autoscaling:DescribeScalingPolicies`
+ `application-autoscaling:DescribeScheduledActions`
+ `application-autoscaling:PutScalingPolicy`
+ `application-autoscaling:PutScheduledAction`
+ `application-autoscaling:RegisterScalableTarget`

**Nota**  
È necessario fornire le `dynamodb:ReplicateSettings` autorizzazioni per tutte le aree e gli account di replica affinché la tabella di aggiornamento abbia esito positivo. Se una replica non fornisce le autorizzazioni per replicare le impostazioni su nessuna replica nella tabella globale con più account, tutte le operazioni di aggiornamento su tutte le repliche avranno esito negativo fino a quando le autorizzazioni non verranno corrette. `AccessDeniedException`

### Eliminazione delle tabelle globali e rimozione delle repliche
<a name="globaltables_MA_deleting"></a>

Per eliminare una tabella globale, è necessario rimuovere tutte le repliche. A differenza di Global Table con lo stesso account, non è possibile `UpdateTable` eliminare una tabella di replica in una regione remota e ogni replica deve essere eliminata tramite l'`DeleteTable`API dall'account che la controlla.

#### Autorizzazioni per l'eliminazione di tabelle globali e la rimozione di repliche
<a name="globaltables_MA_deleting_permissions"></a>

Le seguenti autorizzazioni sono necessarie sia per rimuovere singole repliche sia per eliminare completamente le tabelle globali. L'eliminazione di una configurazione di tabella globale rimuove solo la relazione di replica tra tabelle in regioni diverse. Non elimina la tabella DynamoDB sottostante nell'ultima regione rimanente. La tabella nell'ultima regione continua a esistere come tabella DynamoDB standard con gli stessi dati e le stesse impostazioni.

Sono necessarie le seguenti autorizzazioni sulla risorsa della tabella in ogni regione in cui stai rimuovendo una replica:
+ `dynamodb:DeleteTable`
+ `dynamodb:DeleteTableReplica`

## Come vengono utilizzate le tabelle globali AWS KMS
<a name="globaltables_MA_kms"></a>

Come tutte le tabelle DynamoDB, le repliche globali delle tabelle crittografano sempre i dati inattivi utilizzando le chiavi di crittografia archiviate AWS in Key Management Service ().AWS KMS

**Nota**  
A differenza della tabella globale con lo stesso account, diverse repliche in una tabella globale con più account possono essere configurate con il diverso tipo di AWS KMS chiave (chiave AWS proprietaria o chiave gestita dal cliente). Le tabelle globali con più account non supportano le chiavi gestite. AWS 

Le tabelle globali multi-account che utilizzano CMKs richiedono la policy delle chiavi di ogni replica per concedere le autorizzazioni al servizio di replica DynamoDB principal (`replication.dynamodb.amazonaws.com`) per accedere alla chiave per la replica e la gestione delle impostazioni. Sono richieste le seguenti autorizzazioni:
+ `kms:Decrypt`
+ `kms:ReEncrypt*`
+ `kms:GenerateDataKey*`
+ `kms:DescribeKey`

**Importante**

DynamoDB richiede l’accesso alla chiave di crittografia della replica per eliminare una replica. Se desideri disabilitare o eliminare una chiave gestita dal cliente utilizzata per crittografare una replica perché stai eliminando la replica, devi prima eliminare la replica, attendere che la tabella venga rimossa dal gruppo di replica chiamando describe in una delle altre repliche, quindi disabilitare o eliminare la chiave.

Se disabiliti o revochi l'accesso di DynamoDB a una chiave gestita dal cliente utilizzata per crittografare una replica, la replica da e verso la replica verrà interrotta e lo stato della replica cambierà in`INACCESSIBLE_ENCRYPTION_CREDENTIALS`. Se una replica rimane nello `INACCESSIBLE_ENCRYPTION_CREDENTIALS` stato per più di 20 ore, viene convertita in modo irreversibile in una tabella DynamoDB a regione singola.

### Politica di esempio AWS KMS
<a name="globaltables_MA_kms_example"></a>

La AWS KMS policy consente a DynamoDB di accedere a AWS KMS entrambe le chiavi per la replica tra le repliche A e B. AWS KMS Le chiavi allegate alla replica DynamoDB in ogni account devono essere aggiornate con la seguente policy:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": { "Service": "replication.dynamodb.amazonaws.com" },
        "Action": [
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:DescribeKey"
        ],
        "Resource": "*",
        "Condition": {
            "StringEquals": {
                "aws:SourceAccount": [ "111122223333", "444455556666" ],
                "aws:SourceArn": [
                    "arn:aws:dynamodb:ap-east-1:111122223333:table/ReplicaA",
                    "arn:aws:dynamodb:eu-south-1:444455556666:table/ReplicaB"
                ]
            }
        }
      }
   ]
 }
```

------

# Informazioni sulla fatturazione di Amazon DynamoDB per le tabelle globali
<a name="global-tables-billing"></a>

Questa guida descrive come funziona la fatturazione di DynamoDB per le tabelle globali, identificando i componenti che contribuiscono al costo delle tabelle globali, incluso un esempio pratico. 

Le [tabelle globali Amazon DynamoDB](GlobalTables.md) sono un database completamente gestito, serverless, multi-Regione e multi-attivo. Le tabelle globali sono progettate per una [disponibilità del 99,999%](https://aws.amazon.com/dynamodb/sla/), offrendo una maggiore resilienza delle applicazioni e una migliore continuità aziendale. Le tabelle globali replicano automaticamente le tabelle DynamoDB tra le regioni AWS di tua scelta in modo da ottenere prestazioni di lettura e scrittura locali rapide. 

## Come funziona
<a name="global-tables-billing-how-it-works"></a>

Il modello di fatturazione per le tabelle globali è diverso dalle tabelle DynamoDB a Regione singola. Le operazioni di scrittura per le tabelle DynamoDB a Regione singola vengono fatturate utilizzando le seguenti unità:
+ Write Request Units (WRUs) per la modalità di capacità su richiesta, in cui viene addebitata una WRU per ogni scrittura fino a 1 KB
+ Unità di capacità di scrittura (WCUs) per la modalità di capacità fornita, in cui una WCU fornisce una scrittura al secondo per un massimo di 1 KB

Quando si crea una tabella globale aggiungendo una tabella di replica a una tabella a Regione singola esistente, tale tabella a Regione singola diventa una tabella di replica, il che significa che cambiano anche le unità utilizzate per fatturare le scritture sulla tabella. Le operazioni di scrittura per le tabelle di replica vengono fatturate utilizzando le seguenti unità: 
+ Unità di richiesta di scrittura replicate (rWRUs) per la modalità di capacità su richiesta, in cui viene addebitata una RWRu per tabella di replica per ogni scrittura fino a 1 KB
+ Unità di capacità di scrittura replicate (rWCUs) per la modalità di capacità fornita, in cui una WCU per tabella di replica fornisce una scrittura al secondo per un massimo di 1 KB

Gli aggiornamenti agli indici secondari globali (GSIs) vengono fatturati utilizzando le stesse unità delle tabelle DynamoDB a regione singola, anche se la tabella di base per il GSI è una tabella di replica. Le operazioni di aggiornamento di vengono fatturate utilizzando le seguenti unità: GSIs 
+ Write Request Units (WRUs) per la modalità di capacità su richiesta, in cui viene addebitata una WRU per ogni scrittura fino a 1 KB
+ Unità di capacità di scrittura (WCUs) per la modalità di capacità fornita, in cui una WCU fornisce una scrittura al secondo per un massimo di 1 KB

Le unità di scrittura replicate (r WCUs e rWRUs) hanno lo stesso prezzo delle unità di scrittura a regione singola (and). WCUs WRUs I costi per il trasferimento di dati tra Regioni vengono applicati per le tabelle globali poiché i dati vengono replicati tra Regioni. I costi di scrittura replicata (rWCU o rWRU) sono previsti in ogni Regione che contiene una tabella di replica per la tabella globale.

Le operazioni di lettura dalle tabelle a Regione singola e dalle tabelle di replica utilizzano le seguenti unità:
+ Read Request Units (RRUs) per la modalità di capacità on demand, in cui viene addebitata una RRU per ogni lettura altamente coerente fino a 4 KB
+ Unità di capacità di lettura (RCUs) per le tabelle assegnate, in cui una RCU fornisce una lettura estremamente coerente al secondo per un massimo di 4 KB

## Modalità di coerenza e fatturazione
<a name="global-tables-billing-consistency-modes"></a>

Le unità di scrittura replicate (r WCUs e rWRUs) utilizzate per la fatturazione delle operazioni di scrittura sono identiche sia per le modalità Multi-region Strong Consistency (MRSC) che Multi-region Eventual Consistency (MREC). Le tabelle globali che utilizzano la modalità MRSC (Multi-region Strong Consistency) configurate con un testimone non comportano costi di unità di scrittura replicati (r WCUs e rWRUs), costi di archiviazione o costi di trasferimento dei dati per la replica al witness.

## Esempio di fatturazione per tabelle globali DynamoDB
<a name="global-tables-billing-example"></a>

Si esamina uno scenario di esempio di più giorni per vedere come funziona in pratica la fatturazione globale delle richieste di scrittura su tabelle (si noti che questo esempio considera solo le richieste di scrittura e non include i costi di ripristino della tabella e di trasferimento dati tra Regioni diverse che sarebbero sostenuti nell’esempio):

**Giorno 1 – Tabella a Regione singola:** si dispone di una tabella DynamoDB on demand a Regione singola denominata Tabella\$1A nella Regione us-west-2. Vengono scritti 100 elementi da 1 KB su Tabella\$1A. Per queste operazioni di scrittura a Regione singola, viene addebitata 1 unità di richiesta di scrittura (WRU) per 1 KB scritto. Le spese del giorno 1 sono:
+ 100 WRUs nella regione us-west-2 per le scritture su una singola regione

**Il totale delle unità di richiesta addebitate il giorno 1:100. WRUs**

**Giorno 2 – Creazione di una tabella globale: **si crea una tabella globale aggiungendo una replica a Tabella\$1A nella Regione us-east-2. La Tabella\$1A è ora una tabella globale con due tabelle di replica: una nella Regione us-west-2 e una nella Regione us-east-2. Si scrivono 150 elementi da 1 KB nella tabella di replica nella Regione us-west-2. Le spese del giorno 2 sono:
+ 150 r WRUs nella regione us-west-2 per le scritture replicate
+ 150 r WRUs nella regione us-east-2 per le scritture replicate

**Il totale delle unità di richiesta addebitate il giorno 2:300 r. WRUs**

**Giorno 3 – Aggiunta di un indice secondario globale:** si aggiunge un GSI alla tabella di replica nella Regione us-east-2 che proietta tutti gli attributi dalla tabella di base (replica). La tabella globale crea automaticamente il GSI sulla tabella di replica nella Regione us-west-2 per l’utente. Si scrivono 200 nuovi record da 1 KB nella tabella di replica nella Regione us-west-2. Le spese del giorno 3 sono:
+ • 200 r WRUs nella regione us-west-2 per le scritture replicate
+ • 200 WRUs nella regione us-west-2 per gli aggiornamenti GSI
+ • 200 r WRUs nella regione us-east-2 per le scritture replicate
+ • 200 WRUs nella regione us-east-2 per gli aggiornamenti GSI

Il totale delle unità di richiesta di scrittura addebitate il giorno 3: **400 WRUs e 400 r**. WRUs

I costi totali per unità di scrittura per tutti e tre i giorni sono 500 WRUs (100 WRU il giorno 1 \$1 400 il WRUs giorno 3) e 700 r WRUs (300 r il WRUs giorno 2 \$1 400 r il WRUs giorno 3).

In sintesi, le operazioni di scrittura delle tabelle di replica vengono fatturate in unità di scrittura replicate in tutte le Regioni che contengono una tabella di replica. Se disponi di indici secondari globali, ti vengono addebitate le unità di scrittura per gli aggiornamenti GSIs in tutte le aree che contengono un GSI (che in una tabella globale sono tutte le regioni che contengono una tabella di replica). 

# Versioni delle tabelle globali DynamoDB
<a name="V2globaltables_versions"></a>

Sono disponibili due versioni delle tabelle globali DynamoDB: Tabelle globali versione 2019.11.21 (Corrente) e Tabelle globali versione 2017.11.29 (Legacy). Si consiglia di utilizzare la versione 2019.11.21 (Corrente) poiché è più facile da usare, è supportata in più Regioni e ha un costo inferiore per la maggior parte dei carichi di lavoro rispetto alla versione 2017.11.29 (Legacy).

## Determinare la versione di una tabella globale
<a name="globaltables.DetermineVersion"></a>

### Determinazione della versione utilizzando il AWS CLI
<a name="globaltables.CLI"></a>

#### Identificazione di una replica di una tabella globale versione 2019.11.21 (Corrente)
<a name="globaltables.CLI.current"></a>

Per determinare se una tabella è una replica delle tabelle globali versione 2019.11.21 (Corrente), invoca il comando `describe-table` per la tabella. Se l’output contiene l’attributo `GlobalTableVersion`con il valore “2019.11.21”, allora la tabella è una replica della tabella globale versione 2019.11.21 (Corrente).

Un comando CLI di esempio per `describe-table`:

```
aws dynamodb describe-table \
--table-name users \
--region us-east-2
```

L’output (abbreviato) contiene l’attributo `GlobalTableVersion` con il valore “2019.11.21”, quindi questa tabella è una replica della tabella globale versione 2019.11.21 (Corrente).

```
{
    "Table": {
        "AttributeDefinitions": [
            {
                "AttributeName": "id",
                "AttributeType": "S"
            },
            {
                "AttributeName": "name",
                "AttributeType": "S"
            }
        ],
        "TableName": "users",
        ...
        "GlobalTableVersion": "2019.11.21",
        "Replicas": [
            {
                "RegionName": "us-west-2",
                "ReplicaStatus": "ACTIVE",
            }
        ],
        ...
    }
}
```

#### Identificazione di una replica di una tabella globale versione 2017.11.29 (Corrente)
<a name="globaltables.CLI.legacy"></a>

La versione 2017.11.29 (Legacy) utilizza un set di comandi dedicato per la gestione delle tabelle globali. Per determinare se una tabella è una replica delle tabelle globali 2017.11.29 (Legacy), invoca il comando `describe-global-table` per la tabella. Se si riceve una risposta positiva, la tabella è una replica di tabella globale versione 2017.11.29 (Legacy). Se il comando `describe-global-table` restituisce un errore `GlobalTableNotFoundException`, la tabella non è una replica della versione 2017.11.29 (Legacy).

Un comando CLI di esempio per `describe-global-table`:

```
aws dynamodb describe-global-table \
--table-name users \
--region us-east-2
```

Il comando restituisce una risposta positiva, pertanto la tabella è una replica di tabella globale versione 2017.11.29 (Legacy).

```
{
    "GlobalTableDescription": {
        "ReplicationGroup": [
            {
                "RegionName": "us-west-2"
            },
            {
                "RegionName": "us-east-2"
            }
        ],
        "GlobalTableArn": "arn:aws:dynamodb::123456789012:global-table/users",
        "CreationDateTime": "2025-06-10T13:55:53.630000-04:00",
        "GlobalTableStatus": "ACTIVE",
        "GlobalTableName": "users"
    }
}
```

### Determinare la versione utilizzando la console DynamoDB
<a name="globaltables.console"></a>

Per identificare la versione di una replica di una tabella globale, procedi come segue:

1. [Apri la console DynamoDB a casa. https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home)

1. Nel riquadro di navigazione sul lato sinistro della console scegli **Tables (Tabelle)**.

1. Seleziona la tabella per la quale desideri identificare la versione delle tabelle globali.

1. Scegliere la scheda **Global Tables (Tabelle globali)**.

   La sezione *Riepilogo* mostra la versione delle tabelle globali in uso.

## Differenze di comportamento tra le versioni Legacy e Corrente
<a name="DiffLegacyVsCurrent"></a>

L’elenco seguente descrive le differenze di comportamento tra le versioni Legacy e Corrente delle tabelle globali.
+ La versione 2019.11.21 (Corrente) utilizza meno capacità di scrittura per diverse operazioni DynamoDB rispetto alla versione 2017.11.29 (Legacy) e pertanto è più conveniente per la maggior parte dei clienti. Le differenze per queste operazioni DynamoDB sono le seguenti:
  + [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html)Per richiamare un elemento da 1 KB in una regione e replicarlo in altre regioni sono necessarie 2 r WRUs per regione per la versione 2017.11.29 (versione precedente), ma solo 1 RWRu per la versione 2019.11.21 (versione corrente).
  + L'invocazione [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html)di un elemento da 1 KB richiede 2 r WRUs nella regione di origine e 1 RWRu per regione di destinazione per 2017.11.29 (Legacy), ma solo 1 RWRu per entrambe le regioni di origine e di destinazione per la versione 2019.11.21 (corrente).
  + L'invocazione [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html)di un elemento da 1 KB richiede 1 RWRu nella regione di origine e 2 r WRUs per regione di destinazione per il 2017.11.29 (Legacy), ma solo 1 RWRu sia per la regione di origine che per la regione di destinazione per la versione 2019.11.21 (corrente).

  La tabella seguente mostra l’utilizzo di rWRU delle tabelle 2017.11.29 (Legacy) e 2019.11.21 (Corrente) per un elemento da 1 KB in due Regioni.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/V2globaltables_versions.html)
+ la versione 2017.11.29 (Legacy) è disponibile solo in 11. Regioni AWS Tuttavia, la versione 2019.11.21 (Corrente) è disponibile in tutte le Regioni AWS.
+ È possibile creare tabelle globali nella versione 2017.11.29 (Legacy) creando prima un set di tabelle regionali vuote, quindi richiamando l'API per formare la [CreateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateGlobalTable.html)tabella globale. Puoi creare tabelle globali nella versione 2019.11.21 (Current) richiamando l'[UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)API per aggiungere una replica a una tabella regionale esistente.
+ La versione 2017.11.29 (Legacy) richiede di svuotare tutte le repliche nella tabella prima di aggiungere una replica in una nuova Regione (anche durante la creazione). La versione 2019.11.21 (Corrente) supporta l’aggiunta e la rimozione di repliche nelle Regioni su una tabella che contiene già dati.
+ la versione 2017.11.29 (Legacy) utilizza il seguente set di piani di controllo dedicato per la gestione delle repliche: APIs 
  + [CreateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateGlobalTable.html)
  + [DescribeGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeGlobalTable.html)
  + [DescribeGlobalTableSettings](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeGlobalTableSettings.html)
  + [ListGlobalTables](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListGlobalTables.html)
  + [UpdateGlobalTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateGlobalTable.html)
  + [UpdateGlobalTableSettings](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateGlobalTableSettings.html)

  la versione 2019.11.21 (Current) utilizza and per gestire le repliche. [DescribeTable[UpdateTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html)](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html) APIs 
+ La versione 2017.11.29 (Legacy) pubblica due record dei flussi DynamoDB per ogni scrittura. La versione 2019.11.21 (Corrente) pubblica solo un record dei flussi DynamoDB per ogni scrittura.
+ La versione 2017.11.29 (Legacy) compila e aggiorna gli attributi `aws:rep:deleting`, `aws:rep:updateregion` e `aws:rep:updatetime`. La versione 2019.11.21 (Corrente) non compila né aggiorna questi attributi.
+ La versione 2017.11.29 (Legacy) non sincronizza le impostazioni [Utilizzo del Time to Live in DynamoDB](TTL.md) tra le repliche. La versione 2019.11.21 (Corrente) sincronizza le impostazioni del TTL tra le repliche.
+ La versione 2017.11.29 (Legacy) non replica le eliminazioni TTL su altre repliche. La versione 2019.11.21 (Corrente) replica le eliminazioni TTL su tutte le repliche.
+ La versione 2017.11.29 (Legacy) non sincronizza le impostazioni di [dimensionamento automatico](AutoScaling.md) tra le repliche. La versione 2019.11.21 (Corrente) sincronizza le impostazioni di dimensionamento automatico tra le repliche.
+ La versione 2017.11.29 (Legacy) non sincronizza le impostazioni degli [indici secondari globali (GSI)](GSI.md) tra le repliche. La versione 2019.11.21 (Corrente) sincronizza le impostazioni degli indici secondari globali tra le repliche.
+ La versione 2017.11.29 (Legacy) non sincronizza le impostazioni di [crittografia dei dati a riposo](encryption.usagenotes.md) tra le repliche. La versione 2019.11.21 (Corrente) sincronizza le impostazioni di crittografia dei dati a riposo tra le repliche.
+ La versione 2017.11.29 (Legacy) pubblica la metrica `PendingReplicationCount`. La versione 2019.11.21 (Corrente) non pubblica questa metrica.

## Aggiornamento alla versione corrente
<a name="upgrading-to-current-version"></a>

### Autorizzazioni richieste per l’aggiornamento delle tabelle globali
<a name="V2globaltables_versions.Notes-permissions"></a>

Per eseguire l’aggiornamento alla versione 2019.11.21 (Corrente), è necessario disporre delle autorizzazioni `dynamodb:UpdateGlobalTableversion` in tutte le Regioni con repliche. Queste autorizzazioni richieste si aggiungono alle autorizzazioni necessarie per accedere alla console DynamoDB e visualizzare le tabelle.

La seguente policy IAM concede le autorizzazioni per aggiornare qualsiasi tabella globale alla versione 2019.11.21 (Corrente).

```
{
    "version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "dynamodb:UpdateGlobalTableversion",
            "Resource": "*"
        }
    ]
}
```

La seguente policy IAM concede le autorizzazioni per aggiornare solo la tabella globale `Music`, con repliche in due Regioni, alla versione 2019.11.21 (Corrente).

```
{
    "version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "dynamodb:UpdateGlobalTableversion",
            "Resource": [
                "arn:aws:dynamodb::123456789012:global-table/Music",
                "arn:aws:dynamodb:ap-southeast-1:123456789012:table/Music",
                "arn:aws:dynamodb:us-east-2:123456789012:table/Music"
            ]
        }
    ]
}
```

### Cosa aspettarsi durante l’aggiornamento
<a name="V2GlobalTablesUpgradeExpectations"></a>
+ Tutte le repliche di tabelle globali continueranno a elaborare il traffico di lettura e scrittura durante l’aggiornamento.
+ Il processo di aggiornamento richiede da pochi minuti a diverse ore a seconda delle dimensioni della tabella e del numero di repliche.
+ Durante il processo di aggiornamento, il valore di [TableStatus](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TableDescription.html#DDB-Type-TableDescription-TableStatus)cambierà da a. `ACTIVE` `UPDATING` È possibile visualizzare lo stato della tabella richiamando l'[DescribeTable](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DescribeTable.html)API o con la vista **Tabelle nella console** DynamoDB.
+ Il dimensionamento automatico non modificherà le impostazioni di capacità allocata per una tabella globale durante l’aggiornamento della tabella. Si consiglia vivamente di impostare la tabella sulla modalità con capacità [on demand](capacity-mode.md#capacity-mode-on-demand) durante l’aggiornamento.
+ Se si sceglie di utilizzare la modalità con capacità [allocata](provisioned-capacity-mode.md) con il dimensionamento automatico durante l’aggiornamento, è necessario aumentare il throughput minimo di lettura e scrittura nelle policy per soddisfare eventuali aumenti previsti di traffico per evitare la limitazione (della larghezza di banda della rete) durante l’aggiornamento.
+ La metrica `ReplicationLatency` può segnalare temporaneamente i picchi di latenza o interrompere la segnalazione dei dati delle metriche durante il processo di aggiornamento. Per ulteriori informazioni, consulta [ReplicationLatency](metrics-dimensions.md#ReplicationLatency). 
+ Al termine del processo di aggiornamento, lo stato della tabella torna su `ACTIVE`.

### Comportamento dei flussi DynamoDB prima, durante e dopo l’aggiornamento
<a name="V2GlobalTablesUpgradeDDBStreamsBehavior"></a>

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/V2globaltables_versions.html)

### Aggiornamento alla versione 2019.11.21 (Corrente)
<a name="V2globaltables_versions.upgrade"></a>

Attieniti alla seguente procedura per aggiornare la versione delle tabelle globali DynamoDB utilizzando la Console di gestione AWS.

**Come eseguire l’aggiornamento delle tabelle globali alla versione 2019.11.21 (Corrente)**

1. [Apri la console DynamoDB a casa. https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/home) 

1. Nel pannello di navigazione sul lato sinistro della console, seleziona **Tabelle** e quindi seleziona la tabella globale che desideri aggiornare alla versione 2019.11.21 (Corrente). 

1. Scegliere la scheda **Global Tables (Tabelle globali)**.

1. Scegli **Aggiorna versione**.  
![\[Screenshot della console che mostra il pulsante Update version (Aggiorna versione).\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GlobalTables-upgrade.png)

1. Leggi e accetta i nuovi requisiti, quindi scegli **Update version (Aggiorna versione)**.

1. Al termine del processo di aggiornamento, la versione delle tabelle globali visualizzata sulla console cambia in **2019.11.21**.

# Best practice per le tabelle globali
<a name="globaltables-bestpractices"></a>

Le sezioni seguenti descrivono le best practice per l’implementazione e l’utilizzo di tabelle globali.

## Versione
<a name="globaltables-bestpractices-version"></a>

Sono disponibili due versioni delle tabelle globali DynamoDB: versione 2019.11.21 (Corrente) e [versione 2017.11.29 (Legacy)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/globaltables.V1.html). Sarebbe opportuno utilizzare la versione 2019.11.21 (Corrente) ogni volta che è possibile. 

## Protezione da eliminazione
<a name="globaltables-bestpractices-deletionprotection"></a>

È necessario abilitare la protezione dall’eliminazione sulle repliche globali di tabelle che si desidera proteggere dall’eliminazione accidentale. È necessario abilitare la protezione dall’eliminazione su ogni replica.

## Usando AWS CloudFormation
<a name="globaltables-bestpractices-cloudformation"></a>

CloudFormation attualmente non supporta il coordinamento di risorse multiregionali come le tabelle globali tra gli stack. Se si definisce ogni replica di una tabella globale in uno stack Regionale separato, si verificheranno errori dovuti alla deviazione rilevata tra gli stack durante l’esecuzione degli aggiornamenti delle repliche. Per evitare questo problema, è necessario scegliere una Regione come Regione di riferimento per l’implementazione delle tabelle globali e definire tutte le repliche della tabella globale nello stack di quella Regione.

**Importante**  
Non è possibile convertire una risorsa di tipo `AWS::DynamoDB::Table` in una risorsa di tipo `AWS::DynamoDB::GlobalTable` modificandone il tipo nel modello. Il tentativo di convertire una tabella a regione singola in una tabella globale modificandone il tipo di CloudFormation risorsa può comportare l'eliminazione della tabella DynamoDB.

È possibile utilizzare la risorsa `AWS::DynamoDB::GlobalTable` per creare una tabella in una singola Regione. Questa tabella verrà implementata come qualsiasi altra tabella a Regione singola. Se successivamente si aggiorna lo stack per aggiungere altre Regioni a una risorsa, le repliche verranno aggiunte alla tabella e questa verrà convertita in modo sicuro in una tabella globale.

Se si dispone di una risorsa `AWS::DynamoDB::Table` esistente che desideri convertire in risorsa `AWS::DynamoDB::GlobalTable`, le fasi consigliate per convertire il tipo di risorsa sono:

1. Impostare la policy di eliminazione `AWS::DynamoDB::Table` da mantenere.

1. Rimuovere la tabella dalla definizione degli stack.

1. Aggiungi repliche alla tabella a regione singola nella AWS console, convertendola in una tabella globale.

1. Importare la nuova tabella globale come una nuova risorsa `AWS::DynamoDB::GlobalTable` nello stack.

## Backup e ripristino Point-in-Time
<a name="globaltables-bestpractices-backups"></a>

L'abilitazione dei backup e del Point-in-Time ripristino automatizzati (PITR) per una replica in una tabella globale può essere sufficiente per soddisfare gli obiettivi di disaster recovery. I backup di replica creati con AWS-Backup possono essere replicati automaticamente tra le regioni per una maggiore resilienza. Per la scelta della strategia di backup e abilitazione del PITR, considera gli obiettivi del piano di disaster recovery nel contesto della disponibilità elevata in più Regioni.

## Progettazione per un’elevata disponibilità multi-Regione
<a name="globaltables-bestpractices-multiregion"></a>

Per un prontuario sull’implementazione di tabelle globali, consulta [Best practice per la progettazione di tabelle DynamoDB globali](bp-global-table-design.md).

# Utilizzo di elementi e attributi in DynamoDB
<a name="WorkingWithItems"></a>

In Amazon DynamoDB, un *elemento* è una raccolta di attributi. Ogni attributo ha un nome e un valore. Il valore di un attributo può essere un tipo scalare, un set o un tipo di documento. Per ulteriori informazioni, consulta [Amazon DynamoDB: come funziona](HowItWorks.md).

DynamoDB fornisce quattro operazioni per le funzionalità di creazione, lettura, aggiornamento ed eliminazione CRUD (create/read/update/delete) di base. Tutte queste operazioni sono atomiche.
+ `PutItem`: crea un elemento.
+ `GetItem`: legge un elemento.
+ `UpdateItem`: aggiorna un elemento.
+ `DeleteItem`: elimina un elemento.

Ognuna di queste operazioni richiede di specificare la chiave primaria dell'elemento da usare. Per leggere, ad esempio, un elemento con `GetItem`, devi specificare la chiave di partizione e la chiave di ordinamento (se applicabile) per l'elemento.

Oltre alle quattro operazioni CRUD di base, DynamoDB fornisce anche le seguenti funzionalità:
+ `BatchGetItem`: legge fino a 100 elementi da una o più tabelle.
+ `BatchWriteItem`: crea o elimina fino a 25 elementi in una o più tabelle.

Queste operazioni batch combinano diverse operazioni CRUD in una singola richiesta. Le operazioni batch, inoltre, leggono e scrivono gli elementi in parallelo, per ridurre al minimo la latenza delle risposte.

In questa sezione viene descritto come usare queste operazioni e sono inclusi argomenti correlati, come gli aggiornamenti condizionali e i contatori atomici. Questa sezione include anche un codice di esempio che utilizza il AWS SDKs. 

**Topics**
+ [Dimensioni e formati degli elementi di DynamoDB](CapacityUnitCalculations.md)
+ [Lettura di un elemento](#WorkingWithItems.ReadingData)
+ [Scrittura di un elemento](#WorkingWithItems.WritingData)
+ [Valori restituiti](#WorkingWithItems.ReturnValues)
+ [Operazioni batch](#WorkingWithItems.BatchOperations)
+ [Contatori atomici](#WorkingWithItems.AtomicCounters)
+ [Scritture condizionali](#WorkingWithItems.ConditionalUpdate)
+ [Utilizzo di espressioni in DynamoDB](Expressions.md)
+ [Utilizzo del Time to Live in DynamoDB](TTL.md)
+ [Esecuzione di query in DynamoDB](Query.md)
+ [Scansione di tabelle in DynamoDB](Scan.md)
+ [PartiQL: un linguaggio di query compatibile con SQL per Amazon DynamoDB](ql-reference.md)
+ [Utilizzo degli elementi: Java](JavaDocumentAPIItemCRUD.md)
+ [Uso di elementi: .NET](LowLevelDotNetItemCRUD.md)

# Dimensioni e formati degli elementi di DynamoDB
<a name="CapacityUnitCalculations"></a>

Le tabelle DynamoDB non hanno uno schema, tranne per la chiave primaria, pertanto gli elementi in una tabella possono avere attributi, dimensioni e tipi di dati diversi.

La dimensione totale di un elemento è data dalla somma delle lunghezze dei nomi e dei valori dei relativi attributi, più eventuali overhead applicabili come descritto di seguito. Per stimare le dimensioni degli attributi, puoi utilizzare le linee guida seguenti:
+ Le stringhe sono Unicode con codifica binaria UTF-8. La dimensione di una stringa è *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 (numero di byte con codifica UTF-8)*.
+ I numeri hanno lunghezza variabile, con un massimo di 38 cifre significative. Gli zero iniziali e finali vengono tagliati. La dimensione di un numero è circa *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 (1 byte ogni due cifre significative) \$1 (1 byte)*.
+ Un valore binario deve essere codificato in formato base64 per essere inviato a DynamoDB, ma per il calcolo della dimensione viene utilizzata la lunghezza dei byte in formato RAW del valore. La dimensione di un attributo di tipo binario è *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 (numero di byte in formato RAW).*
+ La dimensione di un attributo null o booleano è *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 (1 byte)*.
+ Un attributo di tipo `List` o `Map` richiede 3 byte di overhead, indipendentemente dal contenuto. La dimensione di un `List` o di una `Map` è *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 somma (dimensione degli elementi annidati) \$1 (3 byte)*. La dimensione di un `List` o di una `Map` vuoti è *(numero di byte con codifica UTF-8 del nome dell’attributo) \$1 (3 byte)*.
+ Ogni elemento `List` o `Map` richiede anche un byte di sovraccarico.

**Nota**  
È consigliabile preferire nomi di attributo brevi piuttosto che lunghi. Ciò consente di ridurre la quantità di spazio di archiviazione richiesta, ma può anche ridurre la quantità RCU/WCUs di spazio utilizzato.

Ai fini della fatturazione dell'archiviazione, ogni elemento include un overhead di archiviazione per elemento che dipende dalle funzionalità abilitate.
+ Tutti gli elementi in DynamoDB richiedono 100 byte di overhead di archiviazione per l'indicizzazione.
+ Alcune funzionalità DynamoDB (tabelle globali, transazioni, acquisizione dei dati di modifica per Kinesis Data Streams con DynamoDB) richiedono un overhead di archiviazione aggiuntivo per tenere conto degli attributi creati dal sistema derivanti dall'abilitazione di tali funzionalità. Ad esempio, le tabelle globali richiedono un overhead aggiuntivo di 48 byte di archiviazione.

## Lettura di un elemento
<a name="WorkingWithItems.ReadingData"></a>

Per leggere un elemento da una tabella DynamoDB, utilizza l'operazione `GetItem`. Devi fornire il nome della tabella e la chiave primaria dell'elemento desiderato.

**Example**  
L' AWS CLI esempio seguente mostra come leggere un elemento dalla `ProductCatalog` tabella.  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}'
```

**Nota**  
Con `GetItem`, devi specificare l'*intera* chiave primaria, non una parte di essa. Se, ad esempio, una tabella ha una chiave primaria composita (chiave di partizione e chiave di ordinamento), devi fornire un valore per la chiave di partizione e uno per la chiave di ordinamento.

Una richiesta `GetItem` esegue una lettura consistente finale per impostazione predefinita. Puoi usare il parametro `ConsistentRead` per richiedere invece una lettura consistente assoluta. (Ciò consuma unità di capacità di lettura aggiuntive, ma restituisce la maggior parte delle up-to-date versioni dell'articolo.)

`GetItem` restituisce tutti gli attributi dell'elemento. Puoi usare un'*espressione di proiezione* per restituire solo alcuni degli attributi. Per ulteriori informazioni, consulta [Utilizzo di espressioni di proiezione in DynamoDB](Expressions.ProjectionExpressions.md).

Per restituire il numero di unità di capacità di lettura utilizzate da `GetItem`, imposta il parametro `ReturnConsumedCapacity` su `TOTAL`.

**Example**  
L'esempio seguente AWS Command Line Interface (AWS CLI) mostra alcuni `GetItem` parametri opzionali.  

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --consistent-read \
    --projection-expression "Description, Price, RelatedItems" \
    --return-consumed-capacity TOTAL
```

## Scrittura di un elemento
<a name="WorkingWithItems.WritingData"></a>

Per creare, aggiornare o eliminare un elemento in una tabella DynamoDB, utilizza una delle operazioni seguenti:
+ `PutItem`
+ `UpdateItem`
+ `DeleteItem`

Per ognuna di queste operazioni, devi specificare l'intera chiave primaria e non solo una parte di essa. Se, ad esempio, una tabella ha una chiave primaria composita (chiave di partizione e chiave di ordinamento), devi fornire un valore per la chiave di partizione e uno per la chiave di ordinamento.

Per restituire il numero di unità di capacità di scrittura utilizzate da queste operazioni, imposta il parametro `ReturnConsumedCapacity` su uno dei valori seguenti: 
+ `TOTAL`: restituisce il numero totale di unità di capacità di scrittura totali consumate.
+ `INDEXES`: restituisce il numero totale di unità di capacità di scrittura consumate, con i subtotali per la tabella e gli eventuali indici secondari interessati dall'operazione.
+ `NONE`: non vengono restituiti dettagli sulla capacità di scrittura. Questa è l'impostazione predefinita.

### PutItem
<a name="WorkingWithItems.WritingData.PutItem"></a>

`PutItem` crea un nuovo elemento. Se nella tabella esiste già un elemento con la stessa chiave, il nuovo elemento sostituisce quello esistente.

**Example**  
Scrivi un nuovo elemento nella tabella `Thread`. La chiave primaria per `Thread` è costituita da `ForumName` (chiave di partizione) e `Subject` (chiave di ordinamento).  

```
aws dynamodb put-item \
    --table-name Thread \
    --item file://item.json
```
Gli argomenti per `--item` sono memorizzati nel file `item.json`:  

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"},
    "Message": {"S": "First post in this thread"},
    "LastPostedBy": {"S": "fred@example.com"},
    "LastPostDateTime": {"S": "201603190422"}
}
```

### UpdateItem
<a name="WorkingWithItems.WritingData.UpdateItem"></a>

Se non esiste un elemento con la chiave specificata, `UpdateItem` crea un nuovo elemento. In caso contrario, modifica gli attributi di un elemento esistente.

Puoi usare un'*espressione di aggiornamento* per specificare gli attributi che desideri modificare e i loro nuovi valori. Per ulteriori informazioni, consulta [Utilizzo di espressioni di aggiornamento in DynamoDB](Expressions.UpdateExpressions.md). 

Nell'espressione di aggiornamento usi i valori degli attributi di espressione come segnaposto per i valori effettivi. Per ulteriori informazioni, consulta [Utilizzo dei valori degli attributi di espressione in DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Modifica i diversi attributi nell'elemento `Thread`. Il parametro `ReturnValues` facoltativo mostra l'elemento dopo l'aggiornamento. Per ulteriori informazioni, consulta [Valori restituiti](#WorkingWithItems.ReturnValues).  

```
aws dynamodb update-item \
    --table-name Thread \
    --key file://key.json \
    --update-expression "SET Answered = :zero, Replies = :zero, LastPostedBy = :lastpostedby" \
    --expression-attribute-values file://expression-attribute-values.json \
    --return-values ALL_NEW
```

Gli argomenti per `--key` sono memorizzati nel file `key.json`:

```
{
    "ForumName": {"S": "Amazon DynamoDB"},
    "Subject": {"S": "New discussion thread"}
}
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `expression-attribute-values.json`:

```
{
    ":zero": {"N":"0"},
    ":lastpostedby": {"S":"barney@example.com"}
}
```

### DeleteItem
<a name="WorkingWithItems.WritingData.DeleteItem"></a>

`DeleteItem` elimina l'elemento con la chiave specificata.

**Example**  
L' AWS CLI esempio seguente mostra come eliminare l'`Thread`elemento.  

```
aws dynamodb delete-item \
    --table-name Thread \
    --key file://key.json
```

## Valori restituiti
<a name="WorkingWithItems.ReturnValues"></a>

In alcuni casi potrebbe essere necessario che DynamoDB restituisca determinati valori degli attributi nello stato in cui si trovano prima o dopo la modifica. Le operazioni `PutItem`, `UpdateItem` e `DeleteItem` hanno un parametro `ReturnValues` che è possibile usare per restituire i valori degli attributi prima o dopo la modifica.

Il valore predefinito per `ReturnValues` è `NONE`, il che significa che DynamoDB non restituisce informazioni sugli attributi che sono stati modificati. 

Di seguito sono illustrate le altre impostazioni valide per `ReturnValues`, organizzate in base all'operazione API di DynamoDB.

### PutItem
<a name="WorkingWithItems.ReturnValues.PutItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Se sovrascrivi un elemento esistente, `ALL_OLD` restituisce l'intero elemento precedente alla sovrascrittura.
  + Se scrivi un elemento che non esiste, `ALL_OLD` non ha alcun effetto.

### UpdateItem
<a name="WorkingWithItems.ReturnValues.UpdateItem"></a>

L'uso più comune di `UpdateItem` è quello di aggiornare un elemento esistente. `UpdateItem` esegue tuttavia un'operazione *upsert*, ovvero crea automaticamente l'elemento, se non esiste già.
+ `ReturnValues`: `ALL_OLD`
  + Se aggiorni un elemento esistente, `ALL_OLD` restituisce l'intero elemento precedente all'aggiornamento.
  + Se aggiorni un item che non esiste (upsert), `ALL_OLD` non ha alcun effetto.
+ `ReturnValues`: `ALL_NEW`
  + Se aggiorni un elemento esistente, `ALL_NEW` restituisce l'intero elemento successivo all'aggiornamento.
  + Se aggiorni un elemento che non esiste (upsert), `ALL_NEW` restituisce l'intero elemento.
+ `ReturnValues`: `UPDATED_OLD`
  + Se aggiorni un elemento esistente, `UPDATED_OLD` restituisce solo gli attributi aggiornati, nello stato precedente all'aggiornamento.
  + Se aggiorni un item che non esiste (upsert), `UPDATED_OLD` non ha alcun effetto.
+ `ReturnValues`: `UPDATED_NEW`
  + Se aggiorni un elemento esistente, `UPDATED_NEW` restituisce solo gli attributi interessati, nello stato successivo all'aggiornamento.
  + Se aggiorni un elemento che non esiste (upsert), `UPDATED_NEW` restituisce solo gli attributi aggiornati, nello stato successivo all'aggiornamento.

### DeleteItem
<a name="WorkingWithItems.ReturnValues.DeleteItem"></a>
+ `ReturnValues`: `ALL_OLD`
  + Se elimini un elemento esistente, `ALL_OLD` restituisce l'intero elemento precedente all'eliminazione.
  + Se elimini un elemento che non esiste, `ALL_OLD` non restituisce alcun dato.

## Operazioni batch
<a name="WorkingWithItems.BatchOperations"></a>

Per le applicazioni che devono leggere o scrivere più elementi, DynamoDB fornisce le operazioni `BatchGetItem` e `BatchWriteItem`. L'uso di queste operazioni permette di ridurre il numero di viaggi di andata e ritorno di rete dall'applicazione a DynamoDB. Inoltre, DynamoDB esegue le singole operazioni di lettura o scrittura in parallelo. Le applicazioni possono ottenere un vantaggio da questo parallelismo, senza dover gestire la concorrenza o il threading.

Le operazioni batch sono essenzialmente una combinazione di più richieste di lettura o di scrittura. Se, ad esempio, una richiesta `BatchGetItem` contiene cinque elementi, DynamoDB esegue cinque operazioni `GetItem` per conto tuo. Analogamente, se una richiesta `BatchWriteItem` contiene due richieste put e quattro richieste delete, DynamoDB esegue due richieste `PutItem` e quattro richieste `DeleteItem`.

In generale, un'operazione batch non ha esito negativo a meno che *tutte* le richieste nel batch non abbiano esito negativo. Supponi, ad esempio, di eseguire un'operazione `BatchGetItem`, ma una delle singole richieste `GetItem` nel batch ha esito negativo. In questo caso, `BatchGetItem` restituisce le chiavi e i dati della richiesta `GetItem` che ha avuto esito negativo. Le altre richieste `GetItem` nel batch non sono interessate.

### BatchGetItem
<a name="WorkingWithItems.BatchOperations.BatchGetItem"></a>

Una singola operazione `BatchGetItem` può contenere fino a 100 singole richieste `GetItem` e può recuperare fino a 16 MB di dati. Un'operazione `BatchGetItem` può inoltre recuperare elementi da più tabelle.

**Example**  
Recupera due elementi dalla tabella `Thread` usando un'espressione di proiezione per restituire solo alcuni degli attributi.  

```
aws dynamodb batch-get-item \
    --request-items file://request-items.json
```
Gli argomenti per `--request-items` sono memorizzati nel file `request-items.json`:  

```
{
    "Thread": {
        "Keys": [
            {
                "ForumName":{"S": "Amazon DynamoDB"},
                "Subject":{"S": "DynamoDB Thread 1"}
            },
            {
                "ForumName":{"S": "Amazon S3"},
                "Subject":{"S": "S3 Thread 1"}
            }
        ],
        "ProjectionExpression":"ForumName, Subject, LastPostedDateTime, Replies"
    }
}
```

### BatchWriteItem
<a name="WorkingWithItems.BatchOperations.BatchWriteItem"></a>

L'operazione `BatchWriteItem` può contenere fino a 25 singole richieste `PutItem` e `DeleteItem` e può scrivere fino a 16 MB di dati. La dimensione massima di un singolo elemento è 400 KB. Un'operazione `BatchWriteItem` può inoltre inserire o eliminare elementi in più tabelle. 

**Nota**  
`BatchWriteItem` non supporta le richieste `UpdateItem`.

**Example**  
Scrivi due elementi nella tabella `ProductCatalog`.  

```
aws dynamodb batch-write-item \
    --request-items file://request-items.json
```
Gli argomenti per `--request-items` sono memorizzati nel file `request-items.json`:  

```
{
    "ProductCatalog": [
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "601" },
                    "Description": { "S": "Snowboard" },
                    "QuantityOnHand": { "N": "5" },
                    "Price": { "N": "100" }
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "Id": { "N": "602" },
                    "Description": { "S": "Snow shovel" }
                }
            }
        }
    ]
}
```

## Contatori atomici
<a name="WorkingWithItems.AtomicCounters"></a>

È possibile utilizzare l'operazione `UpdateItem` per implementare un *contatore atomico*: un attributo numerico che viene incrementato, incondizionatamente, senza interferire con altre richieste di scrittura. Tutte le richieste di scrittura vengono applicate in base all'ordine di ricezione. Con un contatore atomico, gli aggiornamenti non sono idempotenti. In altre parole, il valore numerico aumenta o diminuisce a ogni chiamata di `UpdateItem`. Se il valore di incremento utilizzato per aggiornare il contatore atomico è positivo, può causare un conteggio in eccesso. Se il valore dell'incremento è negativo, può causare un conteggio in difetto.

Puoi usare un contatore atomico per tenere traccia del numero di visitatori di un sito Web. In questo caso, l'applicazione incrementa un valore numerico, indipendentemente dal valore corrente. Se un'operazione `UpdateItem` non va a buon fine, l'applicazione può semplicemente provare a ripetere l'operazione. Ciò rischierebbe di aggiornare il contatore due volte, anche se probabilmente un lieve discostamento in eccesso o in difetto nel numero di visitatori del sito Web può essere tollerato.

Un contatore atomico non è appropriato quando un conteggio maggiore o minore di quello effettivo non può essere tollerato (ad esempio, in un'applicazione bancaria). In questo caso, è preferibile usare un aggiornamento condizionale al posto di un contatore atomico.

Per ulteriori informazioni, consulta [Incremento e decremento di attributi numerici](Expressions.UpdateExpressions.md#Expressions.UpdateExpressions.SET.IncrementAndDecrement).

**Example**  
L' AWS CLI esempio seguente incrementa il valore `Price` di un prodotto di 5. In questo esempio, l’elemento esisteva già prima dell’aggiornamento del contatore. Poiché `UpdateItem` non è idempotente, il valore di `Price` aumenta ogni volta che si esegue il codice.   

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": { "N": "601" }}' \
    --update-expression "SET Price = Price + :incr" \
    --expression-attribute-values '{":incr":{"N":"5"}}' \
    --return-values UPDATED_NEW
```

## Scritture condizionali
<a name="WorkingWithItems.ConditionalUpdate"></a>

Per impostazione predefinita, le operazioni di scrittura di DynamoDB `PutItem` (`DeleteItem`,) *sono* incondizionate: ogni operazione sovrascrive un elemento esistente con la chiave primaria specificata.

Facoltativamente, per queste operazioni DynamoDB supporta le scritture condizionali. Una scrittura condizionale ha esito positivo solo se gli attributi dell'elemento soddisfano una o più condizioni. In caso contrario, restituisce un errore.

Le scritture condizionali controllano le condizioni rispetto alla versione aggiornata più recente dell’elemento. Se l’elemento non esisteva in precedenza o se l’ultima operazione completata su quell’elemento è stata un’eliminazione, la scrittura condizionale non troverà alcun elemento precedente.

 Le operazioni di scrittura condizionali sono utili in molte situazioni. Potrebbe ad esempio essere necessario fare in modo che un'operazione `PutItem` abbia esito positivo solo se non è già presente un elemento con la stessa chiave primaria. In alternativa, si potrebbe impedire a un'operazione `UpdateItem` di modificare un elemento se uno o più dei relativi attributi ha un determinato valore.

Le scritture condizionali sono utili nei casi in cui più utenti tentano di modificare lo stesso elemento. Si consideri il diagramma seguente, in cui due utenti (Alice e Bob) stanno lavorando con lo stesso elemento in una tabella DynamoDB.

![\[Gli utenti Alice e Bob tentano di modificare un elemento con Id 1, dimostrando la necessità di scritture condizionali.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/update-no-condition.png)


Supponiamo che Alice utilizzi l'attributo to per aggiornare l' AWS CLI attributo a 8. `Price`

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `expression-attribute-values.json`:

```
{
    ":newval":{"N":"8"}
}
```

Supponi ora che Bob esegua una richiesta `UpdateItem` simile in un secondo momento, modificando però il valore di `Price` in 12. Per Bob, l'aspetto del parametro `--expression-attribute-values` è simile al seguente.

```
{
    ":newval":{"N":"12"}
}
```

La richiesta di Bob ha esito positivo, ma l'aggiornamento precedente di Alice viene perso.

Per richiedere un'operazione `PutItem`, `DeleteItem` o `UpdateItem` condizionale, specifichi un'espressione di condizione. Un'*espressione condizionale* è una stringa contenente nomi di attributi, operatori condizionali e funzioni predefinite. L'intera espressione deve essere vera. In caso contrario, l'operazione non va a buon fine.

Considera ora il diagramma seguente, che mostra in che modo le scritture condizionali impedirebbero la sovrascrittura dell'aggiornamento di Alice.

![\[Scrittura condizionale che impedisce all’aggiornamento dell’utente Bob di sovrascrivere le modifiche dell’utente Alice allo stesso elemento.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/update-yes-condition.png)


Alice prova innanzitutto ad aggiornare il valore di `Price` a 8, ma solo se il valore di `Price` corrente è 10.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"1"}}' \
    --update-expression "SET Price = :newval" \
    --condition-expression "Price = :currval" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `expression-attribute-values.json`:

```
{
    ":newval":{"N":"8"},
    ":currval":{"N":"10"}
}
```

L'aggiornamento di Alice riesce perché la condizione è vera.

Bob cerca quindi di aggiornare il valore di `Price` a 12, ma solo se il valore di `Price` corrente è 10. Per Bob, l'aspetto del parametro `--expression-attribute-values` è simile al seguente.

```
{
    ":newval":{"N":"12"},
    ":currval":{"N":"10"}
}
```

Poiché in precedenza Alice ha modificato il valore di `Price` in 8, l'espressione condizionale è falsa e l'aggiornamento di Bob non riesce.

Per ulteriori informazioni, consulta [Esempio di CLI di espressione condizionale in DynamoDB](Expressions.ConditionExpressions.md).

### Idempotenza delle scritture condizionali
<a name="WorkingWithItems.ConditionalWrites.Idempotence"></a>

Le scritture condizionali possono essere *idempotenti* se la verifica condizionale è sullo stesso attributo in fase di aggiornamento. Ciò significa che DynamoDB esegue una certa richiesta di scrittura solo se determinati valori degli attributi nell'elemento corrispondono a quanto previsto al momento della richiesta. 

Supponi, ad esempio, di eseguire una richiesta `UpdateItem` per aumentare il valore di `Price` per un elemento di 3, ma solo se il valore di `Price` corrente è 20. Dopo che hai inviato la richiesta, ma prima di ricevere i risultati, si verifica un errore di rete e non sai se la richiesta ha avuto esito positivo. Poiché la scrittura condizionale è idempotente, è possibile eseguire di nuovo la stessa richiesta `UpdateItem` e DynamoDB aggiornerà l'elemento solo se il valore di `Price` corrente è 20.

### Unità di capacità utilizzate dalle scritture condizionali
<a name="WorkingWithItems.ConditionalWrites.ReturnConsumedCapacity"></a>

Se `ConditionExpression` restituisce false durante una scrittura condizionale, DynamoDB utilizza comunque la capacità di scrittura della tabella. La quantità consumata dipende dalla dimensione dell'elemento esistente (o almeno 1). Ad esempio, se un elemento esistente è di 300 KB e il nuovo elemento che si sta cercando di creare o aggiornare è 310 KB, le unità di capacità di scrittura consumate saranno 300 se la condizione restituisce un errore o 310 se la condizione riesce. Se si tratta di un elemento nuovo (non un elemento esistente), le unità di capacità di scrittura consumate saranno 1 se la condizione restituisce un errore e 310 se la condizione riesce.

**Nota**  
Le operazioni di scrittura utilizzano solo unità di capacità in *scrittura*. Non utilizzano mai unità di capacità in *lettura*.

Una scrittura condizionale non riuscita restituisce `ConditionalCheckFailedException`. In questo caso, non vengono inviate informazioni nella risposta sulla capacità di scrittura utilizzata.

Per restituire il numero di unità di capacità di scrittura utilizzate durante una scrittura condizionale, usa il parametro `ReturnConsumedCapacity`:
+ `TOTAL`: restituisce il numero totale di unità di capacità di scrittura totali consumate.
+ `INDEXES`: restituisce il numero totale di unità di capacità di scrittura consumate, con i subtotali per la tabella e gli eventuali indici secondari interessati dall'operazione.
+ `NONE`: non vengono restituiti dettagli sulla capacità di scrittura. Questa è l'impostazione predefinita.

  

**Nota**  
A differenza di un indice secondario globale, un indice secondario locale condivide la capacità di throughput assegnata con la relativa tabella. L'attività di lettura e scrittura su un indice secondario locale utilizza la capacità di throughput assegnata della tabella.

# Utilizzo di espressioni in DynamoDB
<a name="Expressions"></a>

In Amazon DynamoDB è possibile *utilizzare* le espressioni per specificare quali attributi leggere da un elemento, per scrivere dati quando viene soddisfatta una condizione, per specificare come aggiornare un elemento, per definire query e filtrare i risultati di una query.

Questa tabella descrive la grammatica delle espressioni di base e i tipi di espressioni disponibili.


| Tipo di espressione | Description | 
| --- | --- | 
| Espressioni di proiezione | Un'espressione di proiezione identifica gli attributi che si desidera recuperare da un elemento quando si utilizzano operazioni come Query o GetItem Scan. | 
| Espressione condizionale | Un'espressione di condizione determina quali elementi devono essere modificati quando si utilizzano le operazioni PutItem UpdateItem, e. DeleteItem  | 
| Espressione di aggiornamento | Un'espressione di aggiornamento specifica come UpdateItem verranno modificati gli attributi di un elemento, ad esempio l'impostazione di un valore scalare o la rimozione di elementi da un elenco o da una mappa. | 
| Espressione di condizione della chiave | Un’espressione di condizione della chiave determina gli elementi che una query leggerà da una tabella o da un indice. | 
| Espressione filtro | Un’espressione di filtro determina quali elementi all’interno dei risultati di Query devono essere restituiti. Tutti gli altri risultati vengono scartati. | 

Per ulteriori informazioni sulla sintassi delle espressioni e informazioni più dettagliate su ciascun tipo di espressione, consulta le sezioni riportate di seguito.

**Topics**
+ [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](Expressions.Attributes.md)
+ [Nomi di attributi di espressione (alias) in DynamoDB](Expressions.ExpressionAttributeNames.md)
+ [Utilizzo dei valori degli attributi di espressione in DynamoDB](Expressions.ExpressionAttributeValues.md)
+ [Utilizzo di espressioni di proiezione in DynamoDB](Expressions.ProjectionExpressions.md)
+ [Utilizzo di espressioni di aggiornamento in DynamoDB](Expressions.UpdateExpressions.md)
+ [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md)
+ [Esempio di CLI di espressione condizionale in DynamoDB](Expressions.ConditionExpressions.md)

**Nota**  
Per la compatibilità con le versioni precedenti, DynamoDB supporta anche parametri condizionali che non usano espressioni. Per ulteriori informazioni, consulta [Parametri condizionali legacy di DynamoDB](LegacyConditionalParameters.md).  
Le nuove applicazioni dovrebbero utilizzare le espressioni al posto dei parametri legacy.

# Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB
<a name="Expressions.Attributes"></a>

In questa sezione viene descritto come fare riferimento agli attributi degli elementi in una espressione in Amazon DynamoDB. Puoi utilizzare qualsiasi attributo, anche se è nidificato all'interno di più elenchi e mappe.

**Topics**
+ [Attributi di primo livello](#Expressions.Attributes.TopLevelAttributes)
+ [Attributi nidificati](#Expressions.Attributes.NestedAttributes)
+ [Percorsi dei documenti](#Expressions.Attributes.NestedElements.DocumentPathExamples)

**Un articolo di esempio: ProductCatalog**  
Gli esempi presenti in questa pagina utilizzano il seguente elemento di esempio presente nella tabella `ProductCatalog`. (Questa tabella è descritta in [Tabelle e dati di esempio da utilizzare in DynamoDB](AppendixSampleTables.md)).

```
{
    "Id": 123,
    "Title": "Bicycle 123",
    "Description": "123 description",
    "BicycleType": "Hybrid",
    "Brand": "Brand-Company C",
    "Price": 500,
    "Color": ["Red", "Black"],
    "ProductCategory": "Bicycle",
    "InStock": true,
    "QuantityOnHand": null,
    "RelatedItems": [
        341,
        472,
        649
    ],
    "Pictures": {
        "FrontView": "http://example.com/products/123_front.jpg",
        "RearView": "http://example.com/products/123_rear.jpg",
        "SideView": "http://example.com/products/123_left_side.jpg"
    },
    "ProductReviews": {
	    "FiveStar": [
	    		"Excellent! Can't recommend it highly enough! Buy it!",
	    		"Do yourself a favor and buy this."
	    ],
	    "OneStar": [
	    		"Terrible product! Do not buy this."
	    ]
    },
    "Comment": "This product sells out quickly during the summer",
    "Safety.Warning": "Always wear a helmet"
 }
```

Tenere presente quanto segue:
+ il valore della chiave di partizione (`Id`) è `123`. Non vi è chiave di ordinamento;
+ la maggior parte degli attributi dispone di tipi di dati scalari, come `String`, `Number`, `Boolean` e `Null`;
+ un attributo (`Color`) è di tipo `String Set`;
+ i seguenti attributi sono tipi di dati dei documenti:
  + elenco di `RelatedItems`. Ogni elemento è un `Id` per un prodotto correlato;
  + una mappa di `Pictures`. Ogni elemento rappresenta una breve descrizione di un'immagine insieme all'URL del file dell'immagine corrispondente;
  + una mappa di `ProductReviews`. Ogni elemento rappresenta una classificazione e un elenco delle valutazioni corrispondenti a quella classificazione. Inizialmente, questa mappa viene popolata con valutazioni di cinque stelle e di una stella.

## Attributi di primo livello
<a name="Expressions.Attributes.TopLevelAttributes"></a>

Un attributo si definisce di *primo livello* se non è incorporato in un altro attributo. Per gli elementi `ProductCatalog`, gli attributi di primo livello sono:
+ `Id`
+ `Title`
+ `Description`
+ `BicycleType`
+ `Brand`
+ `Price`
+ `Color`
+ `ProductCategory`
+ `InStock`
+ `QuantityOnHand`
+ `RelatedItems`
+ `Pictures`
+ `ProductReviews`
+ `Comment`
+ `Safety.Warning`

Tutti questi attributi di primo livello sono scalari, eccetto `Color` (elenco), `RelatedItems` (elenco), `Pictures` (mappa) e `ProductReviews` (mappa).

## Attributi nidificati
<a name="Expressions.Attributes.NestedAttributes"></a>

Un attributo si definisce *nidificato* se è incorporato in un altro attributo. Per ottenere l'accesso a un attributo nidificato, usa gli *operatori di deferenziazione*:
+ `[n]`: per gli elementi list
+ `.` (punto): per gli elementi map

### Accesso agli elementi dell'elenco
<a name="Expressions.Attributes.NestedElements.AccessingListElements"></a>

L'operatore di deferenziazione per un elemento dell'elenco è **[*N*]**, dove *n* è il numero dell'elemento. Gli elementi dell'elenco sono a base zero, ovvero [0] rappresenta il primo elemento nell'elenco, [1] il secondo e così via. Ecco alcuni esempi:
+ `MyList[0]`
+ `AnotherList[12]`
+ `ThisList[5][11]`

L'elemento `ThisList[5]` è esso stesso un elenco nidificato. Pertanto, `ThisList[5][11]` si riferisce al dodicesimo elemento in quell'elenco.

Il numero all'interno delle parentesi quadre deve essere un numero intero non negativo. Pertanto, le espressioni seguenti non sono valide:
+ `MyList[-1]`
+ `MyList[0.4]`

### Accesso agli elementi della mappa
<a name="Expressions.Attributes.NestedElements.AccessingMapElements"></a>

L'operatore di deferenziazione per una mappa è **.** (un punto). Usa un punto come separatore tra gli elementi in una mappa:
+ `MyMap.nestedField`
+ `MyMap.nestedField.deeplyNestedField`

## Percorsi dei documenti
<a name="Expressions.Attributes.NestedElements.DocumentPathExamples"></a>

In un espressione si utilizza un *percorso del documento* per comunicare a DynamoDB dove trovare un attributo. Per gli attributi di primo livello, il percorso del documento è semplicemente il nome dell'attributo. Per un attributo nidificato, costruisci il percorso del documento usando gli operatori di deferenziazione.

Di seguito sono riportati alcuni esempi di percorsi di documenti. (Fai riferimento all'elemento mostrato in [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](#Expressions.Attributes)).
+ Un attributo scalare di primo livello:

   `Description`
+ Un attributo dell'elenco di primo livello. (Questo restituisce l'intero elenco, non solo alcuni elementi).

  `RelatedItems`
+ Il terzo elemento dall'elenco `RelatedItems`. (Ricorda che gli elementi dell'elenco sono a base zero).

  `RelatedItems[2]`
+ L'immagine di vista frontale del prodotto.

  `Pictures.FrontView`
+ Tutte le valutazioni da cinque stelle.

  `ProductReviews.FiveStar`
+ La prima delle valutazioni da cinque stelle.

  `ProductReviews.FiveStar[0]`

**Nota**  
La profondità massima per un percorso del documento è 32. Pertanto, il numero di operatori di deferenziazione in un percorso non può eccedere questo limite.

È possibile utilizzare qualsiasi nome di attributo nel percorso di un documento purché soddisfi i seguenti requisiti:
+ Il primo carattere è una lettera (`a-z` o `A-Z`) o un numero (`0-9`)
+ Il secondo carattere (se presente) è una lettera (`a-z` o `A-Z`)

**Nota**  
Se un nome di attributo non soddisfa questo requisito, devi definire un nome di attributo dell'espressione come un segnaposto.

Per ulteriori informazioni, consulta [Nomi di attributi di espressione (alias) in DynamoDB](Expressions.ExpressionAttributeNames.md).

# Nomi di attributi di espressione (alias) in DynamoDB
<a name="Expressions.ExpressionAttributeNames"></a>

Un *nome di attributo di espressione* è un alias (o segnaposto) utilizzato in un’espressione Amazon DynamoDB in alternativa a un nome di attributo effettivo. Un nome di attributo di espressione deve iniziare con un simbolo di cancelletto (`#`) ed essere seguito da uno o più caratteri alfanumerici. È consentito anche il carattere trattino basso (`_`).

In questa sezione vengono descritte diverse situazioni in cui è necessario utilizzare i nomi di attributi di espressione.

**Nota**  
Gli esempi in questa sezione utilizzano il AWS Command Line Interface (AWS CLI). 

**Topics**
+ [Parole riservate](#Expressions.ExpressionAttributeNames.ReservedWords)
+ [Nomi di attributi contenenti caratteri speciali](#Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters)
+ [Attributi nidificati](#Expressions.ExpressionAttributeNames.NestedAttributes)
+ [Riferimento ripetuto ai nomi di attributo](#Expressions.ExpressionAttributeNames.RepeatingAttributeNames)

## Parole riservate
<a name="Expressions.ExpressionAttributeNames.ReservedWords"></a>

A volte potrebbe essere necessario scrivere un'espressione contenente un nome di attributo in conflitto con una parola riservata di DynamoDB. Per un elenco completo delle parole riservate, consulta [Parole riservate in DynamoDB](ReservedWords.md).)

Ad esempio, l' AWS CLI esempio seguente non riuscirà perché `COMMENT` è una parola riservata.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Comment"
```

Come soluzione alternativa, puoi sostituire `Comment` con un nome di attributo di espressione come `#c`. Il simbolo `#` (cancelletto) è obbligatorio e indica che si tratta di un segnaposto per un nome di attributo. L' AWS CLI esempio sarebbe ora simile al seguente.

```
aws dynamodb get-item \
     --table-name ProductCatalog \
     --key '{"Id":{"N":"123"}}' \
     --projection-expression "#c" \
     --expression-attribute-names '{"#c":"Comment"}'
```

**Nota**  
Se un nome di attributo inizia con un numero, contiene uno spazio o una parola riservata, è *necessario* utilizzare un nome di attributo di espressione per sostituire il nome di tale attributo nell'espressione.

## Nomi di attributi contenenti caratteri speciali
<a name="Expressions.ExpressionAttributeNames.AttributeNamesContainingSpecialCharacters"></a>

Un punto (".") in un'espressione viene interpretato come carattere separatore in un percorso di un documento. Tuttavia, DynamoDB consente anche di utilizzare un punto e altri caratteri speciali, ad esempio, un trattino ("-") come parte di un nome di attributo. In alcuni casi questo può portare ad ambiguità. A titolo illustrativo, supponi di voler recuperare l'attributo `Safety.Warning` da un elemento `ProductCatalog` (consulta [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](Expressions.Attributes.md)).

Supponi di voler accedere a `Safety.Warning` utilizzando un'espressione di proiezione.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "Safety.Warning"
```

DynamoDB restituisce un risultato vuoto, anziché la stringa prevista ("`Always wear a helmet`"). Ciò accade poiché DynamoDB interpreta un punto in un'espressione come separatore del percorso di un documento. In questo caso, occorre definire un nome di attributo di espressione (ad esempio `#sw`) come sostituto di `Safety.Warning`. Puoi quindi utilizzare l'espressione di proiezione seguente.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#sw" \
    --expression-attribute-names '{"#sw":"Safety.Warning"}'
```

DynamoDB restituirebbe quindi il risultato corretto.

**Nota**  
Se il nome di un attributo contiene un punto (".") o un trattino ("-"), è *necessario* utilizzare un nome di attributo di espressione per sostituire il nome di tale attributo nell'espressione.

## Attributi nidificati
<a name="Expressions.ExpressionAttributeNames.NestedAttributes"></a>

Si supponga di voler accedere all’attributo annidato `ProductReviews.OneStar`. In un nome di attributo di espressione, DynamoDB considera il punto (“.”) come carattere all’interno di un nome di attributo. Per fare riferimento all’attributo annidato, definisci un nome di attributo di espressione per ogni elemento nel percorso del documento:
+ `#pr — ProductReviews`
+ `#1star — OneStar`

Puoi quindi utilizzare `#pr.#1star` per l'espressione di proiezione.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.#1star"  \
    --expression-attribute-names '{"#pr":"ProductReviews", "#1star":"OneStar"}'
```

DynamoDB restituirebbe quindi il risultato corretto.

## Riferimento ripetuto ai nomi di attributo
<a name="Expressions.ExpressionAttributeNames.RepeatingAttributeNames"></a>

I nomi di attributo di espressione sono utili quando si vuole fare riferimento ripetutamente allo stesso nome di attributo. Ad esempio, considera la seguente espressione per recuperare alcune valutazioni da un elemento di `ProductCatalog`.

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "ProductReviews.FiveStar, ProductReviews.ThreeStar, ProductReviews.OneStar"
```

Per renderlo più conciso, puoi sostituire `ProductReviews` con un nome di attributo di espressione come `#pr`. L'aspetto dell'espressione rivista è ora simile al seguente.
+  `#pr.FiveStar, #pr.ThreeStar, #pr.OneStar` 

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"123"}}' \
    --projection-expression "#pr.FiveStar, #pr.ThreeStar, #pr.OneStar" \
    --expression-attribute-names '{"#pr":"ProductReviews"}'
```

Se definisci un nome di attributo di espressione, è necessario usarlo in maniera uniforme nell'intera espressione. Inoltre, non puoi omettere il simbolo `#`. 

# Utilizzo dei valori degli attributi di espressione in DynamoDB
<a name="Expressions.ExpressionAttributeValues"></a>

I *valori degli attributi di espressione* in Amazon DynamoDB agiscono come variabili. Sostituiscono i valori effettivi che si desidera confrontare, valori che potrebbero non essere noti fino al runtime. Un valore dell'attributo dell'espressione deve iniziare con un carattere di due punti (`:`) ed essere seguito da uno o più caratteri alfanumerici.

Per esempio, supponi di voler restituire tutti gli elementi `ProductCatalog` che sono disponibili in `Black` e che costano `500` o meno. Puoi utilizzare un'operazione `Scan` con un'espressione di filtro, come in questo esempio di AWS Command Line Interface (AWS CLI).

```
aws dynamodb scan \
    --table-name ProductCatalog \
    --filter-expression "contains(Color, :c) and Price <= :p" \
    --expression-attribute-values file://values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:

```
{
    ":c": { "S": "Black" },
    ":p": { "N": "500" }
}
```

Se definisci un valore dell'attributo dell'espressione, è necessario usarlo in maniera uniforme nell'intera espressione. Inoltre, non puoi omettere il simbolo `:`. 

I valori degli attributi dell'espressione sono usati con espressioni di condizione della chiave, espressioni di condizioni, espressioni di aggiornamento ed espressioni di filtro.

# Utilizzo di espressioni di proiezione in DynamoDB
<a name="Expressions.ProjectionExpressions"></a>

Per leggere i dati da una tabella, vengono utilizzate operazioni quali `GetItem`, `Query` oppure `Scan`. Amazon DynamoDB restituisce tutti gli attributi dell'elemento per impostazione predefinita. Per ottenerne solo alcuni degli attributi e non tutti, usa un'espressione di proiezione.

Un'*espressione di proiezione* è una stringa che identifica gli attributi che desideri. Per recuperare un singolo attributo, specificane il nome. Per più attributi, i nomi devono essere separati da una virgola.

Di seguito sono riportati alcuni esempi di espressioni di proiezione basate sull'elemento `ProductCatalog` da [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](Expressions.Attributes.md):
+ Un singolo attributo di primo livello.

  `Title `
+ Tre attributi di livello superiore DynamoDB recupera l'intero set `Color`.

  `Title, Price, Color`
+ Quattro attributi di livello superiore. DynamoDB restituisce l'intero contenuto di `RelatedItems` e `ProductReviews`.

  `Title, Description, RelatedItems, ProductReviews`

**Nota**  
L’espressione di proiezione non ha alcun effetto sul consumo di throughput allocato. DynamoDB determina le unità di capacità utilizzate in base alla dimensione dell’elemento anziché alla quantità di dati restituiti a un’applicazione.

**Parole riservate e caratteri speciali**

DynamoDB dispone di parole riservate e caratteri speciali. DynamoDB consente di utilizzare le parole riservate e i caratteri speciali per i nomi, ma si consiglia di evitare questa opzione perché comporta l’utilizzo di alias per i nomi ogni volta che questi vengono utilizzati in un’espressione. Per un elenco completo, consulta [Parole riservate in DynamoDB](ReservedWords.md).

Sarà necessario utilizzare i nomi degli attributi di espressione al posto del nome effettivo se: 
+ Il nome di attributo è nell’elenco di parole riservate in DynamoDB.
+ Il nome dell’attributo non soddisfa il requisito che il primo carattere sia `a-z` o `A-Z` e che il secondo carattere (se presente) sia `a-Z`, `A-Z` o`0-9`.
+ Il nome dell’attributo contiene un **\$1** (cancelletto) o **:** (due punti).

L' AWS CLI esempio seguente mostra come utilizzare un'espressione di proiezione con un'`GetItem`operazione. Questa espressione di proiezione recupera un attributo scalare di primo livello (`Description`), il primo elemento in un elenco (`RelatedItems[0]`) e un elenco nidificato in una mappa (`ProductReviews.FiveStar`).

```
aws dynamodb get-item \
    --table-name ProductCatalog \
    --key '"Id": { "N": "123" } \
    --projection-expression "Description, RelatedItems[0], ProductReviews.FiveStar"
```

Per questo esempio viene restituito il seguente JSON.

```
{
    "Item": {
        "Description": {
            "S": "123 description"
        },
        "ProductReviews": {
            "M": {
                "FiveStar": {
                    "L": [
                        {
                            "S": "Excellent! Can't recommend it highly enough! Buy it!"
                        },
                        {
                            "S": "Do yourself a favor and buy this."
                        }
                    ]
                }
            }
        },
        "RelatedItems": {
            "L": [
                {
                    "N": "341"
                }
            ]
        }
    }
}
```

# Utilizzo di espressioni di aggiornamento in DynamoDB
<a name="Expressions.UpdateExpressions"></a>

L'operazione `UpdateItem` aggiorna una voce esistente o aggiunge una nuova voce alla tabella, se non è già presente. È necessario fornire la chiave dell'elemento che intendi aggiornare. È necessario fornire inoltre un'espressione di aggiornamento che indica gli attributi che intendi modificare e i valori che intendi assegnargli. 

Una *espressione di aggiornamento* specifica come `UpdateItem` modificherà gli attributi di un elemento, ad esempio impostando un valore scalare o rimuovendo elementi da un elenco o da una mappa.

Di seguito è riportato un riepilogo della sintassi delle espressioni di aggiornamento.

```
update-expression ::=
    [ SET action [, action] ... ]
    [ REMOVE action [, action] ...]
    [ ADD action [, action] ... ]
    [ DELETE action [, action] ...]
```

Un'espressione di aggiornamento comprende una o più clausole. Ogni clausola inizia con una parola chiave `SET`, `REMOVE`, `ADD` o `DELETE`. Puoi includere qualsiasi di queste clausole in un'espressione di aggiornamento, in qualsiasi ordine. Tuttavia, ciascuna parola chiave dell'operazione può comparire una sola volta.

All'interno di ogni clausola esistono una o più operazioni separate da virgole. Ciascuna operazione rappresenta una modifica di dati.

Gli esempi in questa sezione si basano sull'elemento `ProductCatalog` illustrato in [Utilizzo di espressioni di proiezione in DynamoDB](Expressions.ProjectionExpressions.md).

Gli argomenti seguenti illustrano diversi casi d'uso dell'operazione `SET`.

**Topics**
+ [SET: modifica o aggiunta di attributi dell'elemento](#Expressions.UpdateExpressions.SET)
+ [REMOVE: eliminazione degli attributi da un elemento](#Expressions.UpdateExpressions.REMOVE)
+ [ADD: aggiornamento di numeri e set](#Expressions.UpdateExpressions.ADD)
+ [DELETE: rimozione di elementi da un set](#Expressions.UpdateExpressions.DELETE)
+ [Utilizzo di più espressioni di aggiornamento](#Expressions.UpdateExpressions.Multiple)

## SET: modifica o aggiunta di attributi dell'elemento
<a name="Expressions.UpdateExpressions.SET"></a>

Utilizza l'operazione `SET` in un'espressione di aggiornamento per aggiungere uno o più attributi a un elemento. Se alcuni di questi attributi esistono già, vengono sovrascritti dai nuovi valori. Se intendi evitare la sovrascrittura di un attributo esistente, puoi utilizzare `SET` con la funzione `if_not_exists`. La funzione `if_not_exists` è specifica dell'operazione `SET` e può essere utilizzata solo in un'espressione di aggiornamento.

Quando utilizzi `SET` per aggiornare un elemento dell'elenco, i contenuti dell'elemento vengono sostituiti con i nuovi dati specificati. Se l'elemento non esiste ancora, `SET` aggiunge il nuovo elemento alla fine dell'elenco.

Se aggiungi più elementi in un'unica operazione `SET`, gli elementi verranno ordinati per numero di elemento.

Puoi inoltre utilizzare `SET` per aggiungere o sottrarre un attributo di tipo `Number`. Per eseguire più operazioni `SET`, separarle con virgole.

Nel riepilogo della sintassi seguente:
+ L'*path*elemento è il percorso del documento verso l'elemento.
+ Un **operand**elemento può essere il percorso del documento verso un elemento o una funzione.

```
set-action ::=
    path = value

value ::=
    operand
    | operand '+' operand
    | operand '-' operand

operand ::=
    path | function

function ::=
    if_not_exists (path, value)
```

Se l’elemento non contiene un attributo nel percorso specificato, `if_not_exists` restituisce `value`. Altrimenti, restituisce `path`.

L'operazione `PutItem` seguente crea un elemento di esempio a cui gli esempi fanno riferimento.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Gli argomenti per `--item` sono memorizzati nel file `item.json`: (Per semplicità, vengono utilizzati solo pochi attributi dell'item).

```
{
    "Id": {"N": "789"},
    "ProductCategory": {"S": "Home Improvement"},
    "Price": {"N": "52"},
    "InStock": {"BOOL": true},
    "Brand": {"S": "Acme"}
}
```

**Topics**
+ [Modifica degli attributi](#Expressions.UpdateExpressions.SET.ModifyingAttributes)
+ [Aggiunta di elenchi e mappe](#Expressions.UpdateExpressions.SET.AddingListsAndMaps)
+ [Aggiunta di elementi a un elenco](#Expressions.UpdateExpressions.SET.AddingListElements)
+ [Aggiunta di attributi di mappa nidificati](#Expressions.UpdateExpressions.SET.AddingNestedMapAttributes)
+ [Incremento e decremento di attributi numerici](#Expressions.UpdateExpressions.SET.IncrementAndDecrement)
+ [Aggiunta di elementi a un elenco](#Expressions.UpdateExpressions.SET.UpdatingListElements)
+ [Prevenzione delle sovrascritture di un attributo esistente](#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites)

### Modifica degli attributi
<a name="Expressions.UpdateExpressions.SET.ModifyingAttributes"></a>

**Example**  
Aggiorna gli attributi `ProductCategory` e `Price`.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET ProductCategory = :c, Price = :p" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":c": { "S": "Hardware" },
    ":p": { "N": "60" }
}
```

**Nota**  
Nell'operazione `UpdateItem`, `--return-values ALL_NEW` fa in modo che DynamoDB restituisca l'elemento come compare dopo l'aggiornamento.

### Aggiunta di elenchi e mappe
<a name="Expressions.UpdateExpressions.SET.AddingListsAndMaps"></a>

**Example**  
Aggiungi un nuovo elenco e una nuova mappa.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems = :ri, ProductReviews = :pr" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":ri": {
        "L": [
            { "S": "Hammer" }
        ]
    },
    ":pr": {
        "M": {
            "FiveStar": {
                "L": [
                    { "S": "Best product ever!" }
                ]
            }
        }
    }
}
```

### Aggiunta di elementi a un elenco
<a name="Expressions.UpdateExpressions.SET.AddingListElements"></a>

**Example**  
Aggiungi un nuovo attributo all'elenco `RelatedItems`. Ricorda che gli elementi dell'elenco sono a base zero, ovvero [0] rappresenta il primo elemento nell'elenco, [1] il secondo e così via.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :ri" \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":ri": { "S": "Nails" }
}
```

**Nota**  
Quando utilizzi `SET` per aggiornare un elemento dell'elenco, i contenuti dell'elemento vengono sostituiti con i nuovi dati specificati. Se l'elemento non esiste ancora, `SET` aggiunge il nuovo elemento alla fine dell'elenco.  
Se aggiungi più elementi in un'unica operazione `SET`, gli elementi verranno ordinati per numero di elemento.

### Aggiunta di attributi di mappa nidificati
<a name="Expressions.UpdateExpressions.SET.AddingNestedMapAttributes"></a>

**Example**  
Aggiungi alcuni attributi di mappa nidificati.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #pr.#5star[1] = :r5, #pr.#3star = :r3" \
    --expression-attribute-names file://names.json \
    --expression-attribute-values file://values.json \
    --return-values ALL_NEW
```
Gli argomenti per `--expression-attribute-names` sono memorizzati nel file `names.json`:  

```
{
    "#pr": "ProductReviews",
    "#5star": "FiveStar",
    "#3star": "ThreeStar"
}
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":r5": { "S": "Very happy with my purchase" },
    ":r3": {
        "L": [
            { "S": "Just OK - not that great" }
        ]
    }
}
```

**Importante**  
Non è possibile aggiornare gli attributi della mappa annidata se la mappa principale non esiste. Se si tenta di aggiornare un attributo annidato (ad esempio,`ProductReviews.FiveStar`) quando la mappa principale (`ProductReviews`) non esiste, DynamoDB restituisce `ValidationException` un con il *messaggio «Il percorso del documento fornito nell'espressione di aggiornamento non è valido per l'aggiornamento*».  
Quando crei elementi che avranno gli attributi della mappa nidificata aggiornati in un secondo momento, inizializza mappe vuote per gli attributi principali. Esempio:  

```
{
    "Id": {"N": "789"},
    "ProductReviews": {"M": {}},
    "Metadata": {"M": {}}
}
```
Ciò consente di aggiornare gli attributi annidati senza errori. `ProductReviews.FiveStar`

### Incremento e decremento di attributi numerici
<a name="Expressions.UpdateExpressions.SET.IncrementAndDecrement"></a>

Puoi eseguire aggiunte o sottrazioni da un attributo numerico esistente. A questo scopo, utilizza gli operatori `+` (più) e `-` (meno).

**Example**  
Riduci il valore `Price` di un elemento.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```
Per aumentare il valore `Price`, puoi utilizzare l'operatore `+` nell'espressione di aggiornamento.

### Aggiunta di elementi a un elenco
<a name="Expressions.UpdateExpressions.SET.UpdatingListElements"></a>

Puoi aggiungere elementi alla fine di un elenco. A tale scopo, utilizza `SET` con la funzione `list_append`. Il nome funzione rileva la distinzione tra maiuscole e minuscole. La funzione `list_append` è specifica dell'operazione `SET` e può essere utilizzata solo in un'espressione di aggiornamento. La sintassi è esposta di seguito.
+ `list_append (list1, list2)`

La funzione prende due liste come input e aggiunge tutti gli elementi da `list2` a ` list1`.

**Example**  
In [Aggiunta di elementi a un elenco](#Expressions.UpdateExpressions.SET.AddingListElements), viene creato l'elenco `RelatedItems` e popolato con due elementi: `Hammer` e `Nails`. Vengono quindi aggiunti due altri elementi alla fine di `RelatedItems`.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(#ri, :vals)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values file://values.json  \
    --return-values ALL_NEW
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":vals": {
        "L": [
            { "S": "Screwdriver" },
            {"S": "Hacksaw" }
        ]
    }
}
```
Infine, viene aggiunto un ulteriore elemento all'*inizio* di `RelatedItems`. A questo scopo, scambia l'ordine degli elementi `list_append`. Ricorda che `list_append` accetta due elenchi come input e aggiunge il secondo elenco al primo.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET #ri = list_append(:vals, #ri)" \
    --expression-attribute-names '{"#ri": "RelatedItems"}' \
    --expression-attribute-values '{":vals": {"L": [ { "S": "Chisel" }]}}' \
    --return-values ALL_NEW
```
L'attributo `RelatedItems` risultante contiene ora cinque elementi nell'ordine seguente: `Chisel`, `Hammer`, `Nails`, `Screwdriver`, `Hacksaw`.

### Prevenzione delle sovrascritture di un attributo esistente
<a name="Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites"></a>

**Example**  
Imposta l'attributo `Price` di un elemento, ma solo se l'elemento non dispone già di un attributo `Price`. Se l'attributo `Price` esiste già, non accade nulla.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = if_not_exists(Price, :p)" \
    --expression-attribute-values '{":p": {"N": "100"}}' \
    --return-values ALL_NEW
```

## REMOVE: eliminazione degli attributi da un elemento
<a name="Expressions.UpdateExpressions.REMOVE"></a>

Utilizza l'operazione `REMOVE` in una espressione di aggiornamento per rimuovere uno o più attributi di un elemento in Amazon DynamoDB. Per eseguire più operazioni `REMOVE`, separarle con virgole.

Di seguito è riportato un riepilogo della sintassi di `REMOVE` in un'espressione di aggiornamento. L'unico operando è il percorso di documento dell'attributo che intendi rimuovere.

```
remove-action ::=
    path
```

**Example**  
Rimuovi alcuni attributi di un elemento. Se gli attributi non esistono, non accade nulla.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE Brand, InStock, QuantityOnHand" \
    --return-values ALL_NEW
```

### Rimozione di elementi da un elenco
<a name="Expressions.UpdateExpressions.REMOVE.RemovingListElements"></a>

Puoi utilizzare `REMOVE` per eliminare singoli elementi da un elenco.

**Example**  
In [Aggiunta di elementi a un elenco](#Expressions.UpdateExpressions.SET.UpdatingListElements), modifica un attributo di elenco (`RelatedItems`) in modo che contenga cinque elementi:   
+ `[0]`—`Chisel`
+ `[1]`—`Hammer`
+ `[2]`—`Nails`
+ `[3]`—`Screwdriver`
+ `[4]`—`Hacksaw`
L'esempio seguente AWS Command Line Interface (AWS CLI) elimina `Hammer` e `Nails` dall'elenco.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "REMOVE RelatedItems[1], RelatedItems[2]" \
    --return-values ALL_NEW
```
Dopo che `Hammer` e `Nails` sono stati rimossi, gli elementi rimanenti vengono spostati. Ora l'elenco contiene quanto segue:  
+ `[0]`—`Chisel`
+ `[1]`—`Screwdriver`
+ `[2]`—`Hacksaw`

## ADD: aggiornamento di numeri e set
<a name="Expressions.UpdateExpressions.ADD"></a>

**Nota**  
In generale, consigliamo di utilizzare `SET` piuttosto che `ADD` garantire operazioni idempotenti.

Utilizza l'operazione `ADD` in un'espressione di aggiornamento per aggiungere un nuovo attributo e i suoi valori a un elemento.

Se l'attributo esiste già, il comportamento di `ADD` dipende dal tipo di dati dell'attributo:
+ Se l'attributo è un numero e anche il valore da aggiungere è un numero, il valore viene aggiunto matematicamente all'attributo esistente. Se il valore è un numero negativo, viene sottratto dall'attributo esistente.
+ Se l'attributo è un set e anche il valore da aggiungere è un set, il valore viene aggiunto matematicamente al set esistente.

**Nota**  
L'operazione `ADD` supporta solo i tipi di dati Number e Set.

Per eseguire più operazioni `ADD`, separarle con virgole.

Nel riepilogo della sintassi seguente:
+ L'*path*elemento è il percorso del documento verso un attributo. L'attributo deve essere un tipo di dati `Number` o Set. 
+ L'*value*elemento è un numero che si desidera aggiungere all'attributo (per `Number` i tipi di dati) o un set da aggiungere all'attributo (per i tipi di set).

```
add-action ::=
    path value
```

Gli argomenti seguenti illustrano diversi casi d'uso dell'operazione `ADD`.

**Topics**
+ [Aggiunta di un numero](#Expressions.UpdateExpressions.ADD.Number)
+ [Aggiunta di elementi a un set](#Expressions.UpdateExpressions.ADD.Set)

### Aggiunta di un numero
<a name="Expressions.UpdateExpressions.ADD.Number"></a>

Supponiamo che l'attributo `QuantityOnHand` non esista. L' AWS CLI esempio seguente è impostato `QuantityOnHand` su 5.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD QuantityOnHand :q" \
    --expression-attribute-values '{":q": {"N": "5"}}' \
    --return-values ALL_NEW
```

Ora che `QuantityOnHand` esiste, puoi eseguire nuovamente l'esempio per incrementare `QuantityOnHand` ogni volta di 5.

### Aggiunta di elementi a un set
<a name="Expressions.UpdateExpressions.ADD.Set"></a>

Supponiamo che l'attributo `Color` non esista. L'esempio AWS CLI seguente imposta `Color` su un set di stringhe con due elementi.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Orange", "Purple"]}}' \
    --return-values ALL_NEW
```

Ora che `Color` esiste, puoi aggiungergli più elementi:

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "ADD Color :c" \
    --expression-attribute-values '{":c": {"SS":["Yellow", "Green", "Blue"]}}' \
    --return-values ALL_NEW
```

## DELETE: rimozione di elementi da un set
<a name="Expressions.UpdateExpressions.DELETE"></a>

**Importante**  
L'operazione `DELETE` supporta solo i tipi di dati `Set`.

Utilizza l'operazione `DELETE` in un'espressione di aggiornamento per rimuovere uno o più elementi da un set. Per eseguire più operazioni `DELETE`, separarle con virgole.

Nel riepilogo della sintassi seguente:
+ L'*path*elemento è il percorso del documento verso un attributo. L'attributo deve essere un tipo di dati Set.
+ *subset*È uno o più elementi da cui si desidera eliminare*path*. È necessario specificare *subset* come tipo di set.

```
delete-action ::=
    path subset
```

**Example**  
In [Aggiunta di elementi a un set](#Expressions.UpdateExpressions.ADD.Set), crea lo String Set `Color`. In questo esempio vengono rimossi alcuni elementi di tale set.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "DELETE Color :p" \
    --expression-attribute-values '{":p": {"SS": ["Yellow", "Purple"]}}' \
    --return-values ALL_NEW
```

## Utilizzo di più espressioni di aggiornamento
<a name="Expressions.UpdateExpressions.Multiple"></a>

È possibile utilizzare più azioni in una singola espressione di aggiornamento. Tutti i riferimenti agli attributi vengono risolti in base allo stato dell'elemento prima dell'applicazione di qualsiasi azione.

**Example**  
Dato un elemento`{"id": "1", "a": 1, "b": 2, "c": 3}`, l'espressione seguente rimuove `a` e sposta i valori di `b` e`c`:  

```
aws dynamodb update-item \
    --table-name test \
    --key '{"id":{"S":"1"}}' \
    --update-expression "REMOVE a SET b = a, c = b" \
    --return-values ALL_NEW
```
Il risultato è`{"id": "1", "b": 1, "c": 2}`. Anche se `a` viene rimosso e `b` riassegnato nella stessa espressione, entrambi i riferimenti tornano ai valori originali.

**Example**  
Se vuoi modificare il valore di un attributo e rimuovere completamente un altro attributo, puoi utilizzare le operazioni SET e REMOVE in una singola istruzione. Questa operazione imposta il valore di `Price` su 15 e rimuove l'attributo `InStock` dall'elemento.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET Price = Price - :p REMOVE InStock" \
    --expression-attribute-values '{":p": {"N":"15"}}' \
    --return-values ALL_NEW
```

**Example**  
Se desideri aggiungere una voce a un elenco modificando anche il valore di un attributo, puoi utilizzare due operazioni SET in una singola istruzione. Questa operazione aggiunge "Nails" all'attributo di elenco `RelatedItems` e imposta il valore di `Price` su 21.  

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"789"}}' \
    --update-expression "SET RelatedItems[1] = :newValue, Price = :newPrice" \
    --expression-attribute-values '{":newValue": {"S":"Nails"}, ":newPrice": {"N":"21"}}'  \
    --return-values ALL_NEW
```

# Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB
<a name="Expressions.OperatorsAndFunctions"></a>

Per manipolare i dati in una tabella DynamoDB, è possibile utilizzare le operazioni `PutItem`, `UpdateItem` e `DeleteItem`. Per le operazioni di manipolazione dei dati, puoi specificare un'espressione di condizione per determinare quale elemento deve essere modificato. Se l’espressione condizionale restituisce true, l’operazione ha esito positivo. In caso contrario, l'operazione non va a buon fine.

In questa sezione sono descritte le funzioni e le parole chiave integrate per scrivere espressioni di condizione ed espressioni di filtro in Amazon DynamoDB. Per informazioni più dettagliate sulle funzioni e sulla programmazione con DynamoDB, consulta [Programmazione con DynamoDB e AWS SDKs](Programming.md) e [DynamoDB API Reference](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/).

**Topics**
+ [Sintassi per le espressioni di filtro e condizioni](#Expressions.OperatorsAndFunctions.Syntax)
+ [Realizzazione di confronti](#Expressions.OperatorsAndFunctions.Comparators)
+ [Funzioni](#Expressions.OperatorsAndFunctions.Functions)
+ [Valutazioni logiche](#Expressions.OperatorsAndFunctions.LogicalEvaluations)
+ [Parentesi](#Expressions.OperatorsAndFunctions.Parentheses)
+ [Priorità nelle condizioni](#Expressions.OperatorsAndFunctions.Precedence)

## Sintassi per le espressioni di filtro e condizioni
<a name="Expressions.OperatorsAndFunctions.Syntax"></a>

Nel seguente riepilogo della sintassi, an *operand* può essere il seguente: 
+ Un nome di attributo di primo livello, ad esempio `Id`, `Title`, `Description` o `ProductCategory`
+ Un percorso di documento che fa riferimento a un attributo nidificato

```
condition-expression ::=
      operand comparator operand
    | operand BETWEEN operand AND operand
    | operand IN ( operand (',' operand (, ...) ))
    | function
    | condition AND condition
    | condition OR condition
    | NOT condition
    | ( condition )

comparator ::=
    =
    | <>
    | <
    | <=
    | >
    | >=

function ::=
    attribute_exists (path)
    | attribute_not_exists (path)
    | attribute_type (path, type)
    | begins_with (path, substr)
    | contains (path, operand)
    | size (path)
```

## Realizzazione di confronti
<a name="Expressions.OperatorsAndFunctions.Comparators"></a>

Utilizza questi comparatori per confrontare un operando con un singolo valore:
+ `a = b`— Vero se *a* è uguale a. *b*
+ `a <> b`— Vero se non *a* è uguale a*b*.
+ `a < b`— Vero se *a* è minore di*b*.
+ `a <= b`— Vero se *a* è minore o uguale a*b*.
+ `a > b`— Vero se *a* è maggiore di*b*.
+ `a >= b`— Vero se *a* è maggiore o uguale a*b*.

Utilizza le parole chiave `BETWEEN` e `IN` per confrontare un operando con un intervallo di valori o con un elenco enumerato di valori:
+ `a BETWEEN b AND c`— Vero se *a* è maggiore o uguale a *b* e minore o uguale a*c*.
+ `a IN (b, c, d) `— Vero se *a* è uguale a qualsiasi valore nell'elenco, ad esempio qualsiasi di *b**c*, o. *d* L'elenco può contenere fino a 100 valori separati da virgole.

## Funzioni
<a name="Expressions.OperatorsAndFunctions.Functions"></a>

Utilizza le seguenti funzioni per determinare se un attributo è presente in un elemento o per valutare il valore di un attributo. I nomi di funzione rispettano la distinzione tra lettere maiuscole e minuscole. Per un attributo nidificato, è necessario fornire l'intero percorso del documento.


****  

| Funzione | Description | 
| --- | --- | 
|  `attribute_exists (path)`  | True se l'elemento contiene l'attributo specificato da `path`. Esempio: Verifica se un elemento nella tabella `Product` ha un'immagine di vista laterale. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_not_exists (path)`  | True se l'attributo specificato da `path` non è presente nell'elemento. Esempio: Verifica se un elemento ha un attributo `Manufacturer`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 
|  `attribute_type (path, type)`  |  True se l'attributo del percorso specificato è di un particolare tipo di dato. Il parametro `type` deve essere uno dei seguenti: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) È necessario utilizzare un valore di attributo di espressione per il parametro `type`. Esempio: Verifica se l'attributo `QuantityOnHand` è del tipo List. In questo esempio, `:v_sub` è un segnaposto per la stringa `L`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) È necessario utilizzare un valore di attributo di espressione per il parametro `type`.   | 
|  `begins_with (path, substr)`  |  True se l'attributo specificato da `path` inizia con una particolare sottostringa. Esempio: Verifica se i primi caratteri dell'URL dell'immagine di vista frontale sono `http://`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Il valore di attributo di espressione `:v_sub` è un segnaposto per `http://`.  | 
|  `contains (path, operand)`  | True se l'attributo specificato da `path` è uno dei seguenti: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Se l'attributo specificato da `path` è `String`, `operand` deve essere `String`. Se l'attributo specificato da `path` è un `Set`, l'`operand` deve essere il tipo di elemento del set. Il percorso e l'operando devono essere distinti. Vale a dire, `contains (a, a)` restituisce un errore. Esempio: Verifica se l'attributo `Brand` contiene la sottostringa `Company`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Il valore di attributo di espressione `:v_sub` è un segnaposto per `Company`. Esempio: Verifica se il prodotto è disponibile in rosso. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) Il valore di attributo di espressione `:v_sub` è un segnaposto per `Red`. | 
|  `size (path)`  | Restituisce un numero che rappresenta le dimensioni di un attributo. I seguenti sono tipi di dati validi per l'utilizzo con `size`.  Se l'attributo è di tipo `String`, `size`restituisce la lunghezza della stringa. Esempio: Verifica se la stringa `Brand` è inferiore o uguale a 20 caratteri. Il valore di attributo di espressione `:v_sub` è un segnaposto per `20`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se l'attributo è di tipo `Binary`, `size` restituisce il numero di byte nel valore attributo. Esempio: supponi che l'elemento `ProductCatalog` abbia un attributo di tipo binario denominato `VideoClip`, che contiene un breve video del prodotto in uso. L'espressione seguente verifica se `VideoClip` supera i 64.000 byte. Il valore di attributo di espressione `:v_sub` è un segnaposto per `64000`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se il tipo di dati dell'attributo è `Set`, `size` restituisce il numero di elementi nell'insieme.  Esempio: Verifica se il prodotto è disponibile in più di un colore. Il valore di attributo di espressione `:v_sub` è un segnaposto per `1`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  Se il tipo dell'attributo è `List` o `Map`, `size` restituisce il numero di elementi figlio. Esempio: Verifica se il numero di revisioni `OneStar` ha superato una certa soglia. Il valore di attributo di espressione `:v_sub` è un segnaposto per `3`. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html)  | 

## Valutazioni logiche
<a name="Expressions.OperatorsAndFunctions.LogicalEvaluations"></a>

Utilizza le parole chiave `AND`, `OR` e `NOT` per eseguire valutazioni logiche. Nell'elenco seguente, *a* e *b* rappresentano le condizioni da valutare.
+ `a AND b`— Vero se *a* e *b* sono entrambi veri.
+ `a OR b`— Vero se una delle due *a* o *b* (o entrambe) sono vere.
+ `NOT a`— Vero se *a* è falso. Falso se *a* è vero.

Di seguito è riportato un esempio di codice di AND in un'operazione.

`dynamodb-local (*)> select * from exprtest where a > 3 and a < 5;`

## Parentesi
<a name="Expressions.OperatorsAndFunctions.Parentheses"></a>

Utilizza le parentesi per modificare la priorità di una valutazione logica. Ad esempio, supponiamo che le condizioni *a* e *b* siano vere e che tale condizione *c* sia falsa. La seguente espressione restituisce true:
+ `a OR b AND c`

Tuttavia, se racchiudi una condizione tra parentesi, verrà valutata per prima. Ad esempio, la seguente espressione restituisce false:
+  `(a OR b) AND c`

**Nota**  
Puoi annidare le parentesi in un'espressione: quelle più interne saranno valutate per prime.

Di seguito è riportato un esempio di codice con parentesi in una valutazione logica.

`dynamodb-local (*)> select * from exprtest where attribute_type(b, string) or ( a = 5 and c = “coffee”);`

## Priorità nelle condizioni
<a name="Expressions.OperatorsAndFunctions.Precedence"></a>

 DynamoDB valuta le condizioni da sinistra a destra utilizzando le seguenti regole di precedenza:
+ `= <> < <= > >=`
+ `IN`
+ `BETWEEN`
+ `attribute_exists attribute_not_exists begins_with contains`
+ Parentesi
+ `NOT`
+ `AND`
+ `OR`

# Esempio di CLI di espressione condizionale in DynamoDB
<a name="Expressions.ConditionExpressions"></a>

Di seguito sono riportati alcuni AWS Command Line Interface (AWS CLI) esempi di utilizzo delle espressioni condizionali. Questo esempi sono basati sulla tabella `ProductCatalog`, che è stata introdotta in [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](Expressions.Attributes.md). La chiave di partizione di questa tabella è `Id`; non è presente una chiave di ordinamento. L'operazione `PutItem` seguente crea un elemento `ProductCatalog` di esempio a cui gli esempi fanno riferimento.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json
```

Gli argomenti per `--item` sono memorizzati nel file `item.json`: (Per semplicità, vengono utilizzati solo pochi attributi dell'item).

```
{
    "Id": {"N": "456" },
    "ProductCategory": {"S": "Sporting Goods" },
    "Price": {"N": "650" }
}
```

**Topics**
+ [Put condizionale](#Expressions.ConditionExpressions.PreventingOverwrites)
+ [Eliminazioni condizionali](#Expressions.ConditionExpressions.AdvancedComparisons)
+ [Aggiornamenti condizionali](#Expressions.ConditionExpressions.SimpleComparisons)
+ [Esempi di espressioni condizionali](#Expressions.ConditionExpressions.ConditionalExamples)

## Put condizionale
<a name="Expressions.ConditionExpressions.PreventingOverwrites"></a>

L'operazione `PutItem` sovrascrive un elemento con la stessa chiave primaria (se esiste). Se vuoi evitare che ciò accada, utilizza un'espressione di condizione. Ciò consente alla scrittura di procedere solo se l'elemento in questione non possiede già la stessa chiave primaria.

L'esempio seguente utilizza `attribute_not_exists()` per verificare se la chiave primaria esiste nella tabella prima di tentare l'operazione di scrittura. 

**Nota**  
Se la chiave primaria è composta sia da una chiave di partizione (PK) che da una chiave di ordinamento (SK), il parametro controllerà se `attribute_not_exists(pk)` E `attribute_not_exists(sk)` vengono considerati true o false come intera istruzione prima di tentare l’operazione di scrittura.

```
aws dynamodb put-item \
    --table-name ProductCatalog \
    --item file://item.json \
    --condition-expression "attribute_not_exists(Id)"
```

Se l'espressione di condizione viene valutata false, D restituisce il seguente messaggio di errore: The conditional request failed (La richiesta condizionale ha avuto esito negativo).

**Nota**  
Per ulteriori informazioni su `attribute_not_exists` e altre funzioni, consulta [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md).

## Eliminazioni condizionali
<a name="Expressions.ConditionExpressions.AdvancedComparisons"></a>

Per eseguire un'eliminazione condizionale, utilizza un'operazione `DeleteItem` con un'espressione di condizione. L'espressione di condizione deve restituire true affinché l'operazione abbia esito positivo; in caso contrario, ha esito negativo.

Si consideri l’elemento sopra definito.

Supponiamo che tu voglia eliminare l'elemento, ma solo alle seguenti condizioni:
+  il valore `ProductCategory` è "Sporting Goods" o "Gardening Supplies";
+  il valore `Price` è compreso tra 500 e 600.

Nell'esempio seguente si tenta di eliminare l'elemento:

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id":{"N":"456"}}' \
    --condition-expression "(ProductCategory IN (:cat1, :cat2)) and (Price between :lo and :hi)" \
    --expression-attribute-values file://values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:

```
{
    ":cat1": {"S": "Sporting Goods"},
    ":cat2": {"S": "Gardening Supplies"},
    ":lo": {"N": "500"},
    ":hi": {"N": "600"}
}
```

**Nota**  
Nell'espressione di condizione, `:` (due punti) indica un *valore di attributo dell'espressione*, ovvero un segnaposto per un valore effettivo. Per ulteriori informazioni, consulta [Utilizzo dei valori degli attributi di espressione in DynamoDB](Expressions.ExpressionAttributeValues.md).  
Per ulteriori informazioni su `IN`, `AND` e altre parole chiave, consulta [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md).

In questo esempio, il confronto `ProductCategory` viene valutato come true, ma il confronto `Price` viene valutato come false. Ciò fa sì che l'espressione di condizione venga valutata come false e che l'operazione `DeleteItem` abbia esito negativo.

## Aggiornamenti condizionali
<a name="Expressions.ConditionExpressions.SimpleComparisons"></a>

Per eseguire un aggiornamento condizionale, utilizza un'operazione `UpdateItem` con un'espressione di condizione. L'espressione di condizione deve restituire true affinché l'operazione abbia esito positivo; in caso contrario, ha esito negativo.

**Nota**  
`UpdateItem` supporta anche *espressioni di aggiornamento*, in cui si specificano le modifiche che intendi apportare a una voce. Per ulteriori informazioni, consulta [Utilizzo di espressioni di aggiornamento in DynamoDB](Expressions.UpdateExpressions.md).

Si supponga di iniziare con l’elemento mostrato sopra.

Nel seguente esempio viene eseguita un'operazione `UpdateItem`. Prova a ridurre il `Price` di un prodotto di 75, ma l'espressione della condizione impedisce l'aggiornamento se `Price` è minore o uguale a 500.

```
aws dynamodb update-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --update-expression "SET Price = Price - :discount" \
    --condition-expression "Price > :limit" \
    --expression-attribute-values file://values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:

```
{
    ":discount": { "N": "75"},
    ":limit": {"N": "500"}
}
```

Se l'attributo `Price` iniziale è 650, l'operazione `UpdateItem` riduce `Price` a 575. Se esegui nuovamente l'operazione `UpdateItem`, il valore `Price` viene ridotto a 500. Se esegui l'operazione una terza volta, l'espressione di condizione restituisce false e l'aggiornamento ha esito negativo.

**Nota**  
Nell'espressione di condizione, `:` (due punti) indica un *valore di attributo dell'espressione*, ovvero un segnaposto per un valore effettivo. Per ulteriori informazioni, consulta [Utilizzo dei valori degli attributi di espressione in DynamoDB](Expressions.ExpressionAttributeValues.md).  
Per ulteriori informazioni su "*>*" e altri operatori, consulta [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md).

## Esempi di espressioni condizionali
<a name="Expressions.ConditionExpressions.ConditionalExamples"></a>

Per ulteriori informazioni sulle funzioni utilizzate negli esempi seguenti, consulta [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md). Per ulteriori informazioni su come specificare diversi tipi di attributo in un'espressione, consulta [Riferimento agli attributi degli elementi quando si utilizzano le espressioni in DynamoDB](Expressions.Attributes.md). 

### Verifica degli attributi in un elemento
<a name="Expressions.ConditionExpressions.CheckingForAttributes"></a>

Puoi verificare la presenza o l'assenza di qualsiasi attributo. Se l'espressione condizionale viene valutata a true, l'operazione ha esito positivo, altrimenti ha esito negativo.

Nel seguente esempio si utilizza `attribute_not_exists` per eliminare un prodotto solo se non possiede un attributo `Price`.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_not_exists(Price)"
```

DynamoDB fornisce anche una funzione `attribute_exists`. Nel seguente esempio un prodotto viene eliminato solo se ha ricevuto recensioni negative.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_exists(ProductReviews.OneStar)"
```

### Verifica del tipo di attributo
<a name="Expressions.ConditionExpressions.CheckingForAttributeType"></a>

Puoi controllare il tipo di dati di un valore di attributo utilizzando la funzione `attribute_type`. Se l'espressione condizionale viene valutata a true, l'operazione ha esito positivo, altrimenti ha esito negativo.

Nell'esempio seguente viene utilizzato `attribute_type` per eliminare un prodotto solo se ha un attributo `Color` di tipo String Set. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "attribute_type(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel expression-attribute-values file.json.

```
{
    ":v_sub":{"S":"SS"}
}
```

### Verifica del valore iniziale della stringa
<a name="Expressions.ConditionExpressions.CheckingBeginsWith"></a>

Puoi verificare se un valore di attributo String inizia con una particolare sottostringa utilizzando la funzione `begins_with`. Se l'espressione condizionale viene valutata a true, l'operazione ha esito positivo, altrimenti ha esito negativo. 

Nell'esempio seguente viene utilizzato `begins_with` per eliminare un prodotto solo se l'elemento `FrontView` della mappa `Pictures` inizia con un valore specifico.

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "begins_with(Pictures.FrontView, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file expression-attribute-values .json.

```
{
    ":v_sub":{"S":"http://"}
}
```

### Controllo di un elemento in un set
<a name="Expressions.ConditionExpressions.CheckingForContains"></a>

Puoi verificare la presenza di un elemento in un set o cercare una sottostringa all'interno di una stringa utilizzando la funzione `contains`. Se l'espressione condizionale viene valutata a true, l'operazione ha esito positivo, altrimenti ha esito negativo. 

Nell'esempio seguente viene utilizzato `contains` per eliminare un prodotto solo se il String Set `Color` ha un elemento con un valore specifico. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "contains(Color, :v_sub)" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file expression-attribute-values .json.

```
{
    ":v_sub":{"S":"Red"}
}
```

### Controllo della dimensione di un valore di attributo
<a name="Expressions.ConditionExpressions.CheckingForSize"></a>

Puoi verificare la dimensione di un valore di attributo utilizzando la funzione `size`. Se l'espressione condizionale viene valutata a true, l'operazione ha esito positivo, altrimenti ha esito negativo. 

Nell'esempio seguente viene utilizzato `size` per eliminare un prodotto solo se la dimensione dell'attributo `VideoClip` Binary è maggiore di `64000` byte. 

```
aws dynamodb delete-item \
    --table-name ProductCatalog \
    --key '{"Id": {"N": "456"}}' \
    --condition-expression "size(VideoClip) > :v_sub" \
    --expression-attribute-values file://expression-attribute-values.json
```

Gli argomenti per `--expression-attribute-values` sono memorizzati nel file expression-attribute-values .json.

```
{
    ":v_sub":{"N":"64000"}
}
```

# Utilizzo del Time to Live in DynamoDB
<a name="TTL"></a>

Il Time to Live (TTL) per DynamoDB è un metodo conveniente per eliminare elementi che non sono più pertinenti. Il TTL consente di definire un timestamp per elemento in modo da indicare quando un elemento non è più necessario. DynamoDB elimina automaticamente gli elementi scaduti entro pochi giorni dalla data di scadenza, senza utilizzare il throughput di scrittura. 

Per utilizzare il TTL, è necessario prima abilitarlo su una tabella e poi definire un attributo specifico per archiviare il timestamp di scadenza del TTL. Il timestamp deve essere archiviato come tipo [di dati Number](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes) nel [formato Unix epoch time](https://en.wikipedia.org/wiki/Unix_time) con la granularità dei secondi. Gli elementi con un attributo TTL diverso da un tipo Number vengono ignorati dal processo TTL. Ogni volta che un elemento viene creato o aggiornato, è possibile calcolare l’ora di scadenza e salvarla nell’attributo TTL.

Gli articoli con attributi TTL validi e scaduti possono essere eliminati dal sistema in qualsiasi momento, in genere entro pochi giorni dalla scadenza. È comunque possibile aggiornare gli elementi scaduti in attesa di eliminazione, come anche modificare o rimuovere i relativi attributi TTL. Durante l’aggiornamento di un elemento scaduto, si consiglia di utilizzare un’espressione condizionale per assicurarsi che l’elemento non sia stato successivamente eliminato. Utilizza le espressioni di filtro per rimuovere gli elementi scaduti dai risultati di [Scan](Scan.md#Scan.FilterExpression) e [Query](Query.FilterExpression.md).

Gli elementi eliminati funzionano in modo simile a quelli eliminati tramite le tipiche operazioni di eliminazione. Una volta eliminati, gli elementi entrano nei flussi DynamoDB come eliminazioni da parte del servizio anziché degli utenti e vengono rimossi dagli indici secondari locali e dagli indici secondari globali proprio come con le altre operazioni di eliminazione. 

Se si utilizzano le [Tabelle globali versione 2019.11.21 (Corrente)](GlobalTables.md) e si utilizza anche la funzionalità TTL, DynamoDB replica le eliminazioni TTL in tutte le tabelle di replica. L’eliminazione TTL iniziale non consuma unità di capacità di scrittura (WCU, Write Capacity Units) nella Regione in cui si verifica la scadenza del TTL. Tuttavia, l’eliminazione TTL replicata nelle tabelle di replica consuma una WCU replicata quando si utilizza la capacità con provisioning o la scrittura replicata quando si utilizza la modalità con capacità on demand in ciascuna delle Regioni di replica e verranno addebitati i costi applicabili.

Per ulteriori informazioni su TTL, consulta i seguenti argomenti:

**Topics**
+ [Abilitazione del Time to Live in DynamoDB](time-to-live-ttl-how-to.md)
+ [Calcolo del Time to Live (TTL) in DynamoDB](time-to-live-ttl-before-you-start.md)
+ [Utilizzo di elementi scaduti e Time to Live](ttl-expired-items.md)

# Abilitazione del Time to Live in DynamoDB
<a name="time-to-live-ttl-how-to"></a>

**Nota**  
Per facilitare il debug e la verifica del corretto funzionamento della funzionalità del TTL, i valori forniti per l’elemento TTL vengono registrati in testo semplice nei log di diagnostica di DynamoDB.

Puoi abilitare il TTL nella console Amazon DynamoDB AWS Command Line Interface ,AWS CLI in () o utilizzando Amazon [DynamoDB API Reference con uno qualsiasi dei presunti](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/). AWS SDKs È necessaria circa un’ora per abilitare il TTL su tutte le partizioni.

## Abilita DynamoDB TTL utilizzando la console AWS
<a name="time-to-live-ttl-how-to-enable-console"></a>

1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Scegli **Tables (Tabelle)** e quindi seleziona la tabella da modificare.

1. Nella scheda **Impostazioni aggiuntive**, nella sezione **Time to Live (TTL)** seleziona **Attiva**.

1. Quando abiliti TTL su una tabella, DynamoDB richiede di indicare un determinato nome attributo ricercato dal servizio per determinare se un item è idoneo per la scadenza. Il nome dell’attributo TTL, mostrato di seguito, fa distinzione tra maiuscole e minuscole e deve corrispondere all’attributo definito nelle operazioni di lettura e scrittura. In caso di mancata corrispondenza, gli elementi scaduti non verranno eliminati. La ridenominazione dell’attributo TTL richiede di disabilitare il TTL, per poi riabilitarlo con il nuovo attributo. Una volta disabilitato, il TTL continuerà a elaborare le eliminazioni per circa 30 minuti. Il TTL deve essere riconfigurato sulle tabelle ripristinate.  
![\[Nome dell’attributo TTL con distinzione tra maiuscole e minuscole utilizzato da DynamoDB per determinare l’idoneità di un elemento alla scadenza.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/EnableTTL-Settings.png)

1. (Facoltativo) È possibile eseguire un test simulando la data e l’ora della scadenza con la corrispondenza di alcuni elementi. Questo fornisce un elenco di esempio di elementi e conferma che esistono elementi contenenti il nome dell’attributo TTL fornito insieme alla scadenza.

Una volta abilitato il TTL, l’attributo TTL viene contrassegnato come **TTL** quando si visualizzano gli elementi nella console DynamoDB. Puoi visualizzare la data e l'ora di scadenza di un item passando il puntatore del mouse sull'attributo. 

## Abilitazione del TTL di DynamoDB tramite l’API
<a name="time-to-live-ttl-how-to-enable-api"></a>

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

È possibile abilitare il TTL con codice, utilizzando l'operazione. [UpdateTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/update_time_to_live.html)

```
import boto3


def enable_ttl(table_name, ttl_attribute_name):
    """
    Enables TTL on DynamoDB table for a given attribute name
        on success, returns a status code of 200
        on error, throws an exception

    :param table_name: Name of the DynamoDB table
    :param ttl_attribute_name: The name of the TTL attribute being provided to the table.
    """
    try:
        dynamodb = boto3.client('dynamodb')

        # Enable TTL on an existing DynamoDB table
        response = dynamodb.update_time_to_live(
            TableName=table_name,
            TimeToLiveSpecification={
                'Enabled': True,
                'AttributeName': ttl_attribute_name
            }
        )

        # In the returned response, check for a successful status code.
        if response['ResponseMetadata']['HTTPStatusCode'] == 200:
            print("TTL has been enabled successfully.")
        else:
            print(f"Failed to enable TTL, status code {response['ResponseMetadata']['HTTPStatusCode']}")
    except Exception as ex:
        print("Couldn't enable TTL in table %s. Here's why: %s" % (table_name, ex))
        raise


# your values
enable_ttl('your-table-name', 'expirationDate')
```

È possibile confermare che il TTL è abilitato utilizzando l'[DescribeTimeToLive](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/describe_time_to_live.html)operazione, che descrive lo stato TTL su una tabella. Lo stato di `TimeToLive` è `ENABLED` o `DISABLED`.

```
# create a DynamoDB client
dynamodb = boto3.client('dynamodb')

# set the table name
table_name = 'YourTable'

# describe TTL
response = dynamodb.describe_time_to_live(TableName=table_name)
```

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

È possibile abilitare il TTL con codice utilizzando l'operazione. [UpdateTimeToLiveCommand](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-dynamodb/Class/UpdateTimeToLiveCommand/)

```
import { DynamoDBClient, UpdateTimeToLiveCommand } from "@aws-sdk/client-dynamodb";

const enableTTL = async (tableName, ttlAttribute) => {

    const client = new DynamoDBClient({});

    const params = {
        TableName: tableName,
        TimeToLiveSpecification: {
            Enabled: true,
            AttributeName: ttlAttribute
        }
    };

    try {
        const response = await client.send(new UpdateTimeToLiveCommand(params));
        if (response.$metadata.httpStatusCode === 200) {
            console.log(`TTL enabled successfully for table ${tableName}, using attribute name ${ttlAttribute}.`);
        } else {
            console.log(`Failed to enable TTL for table ${tableName}, response object: ${response}`);
        }
        return response;
    } catch (e) {
        console.error(`Error enabling TTL: ${e}`);
        throw e;
    }
};

// call with your own values
enableTTL('ExampleTable', 'exampleTtlAttribute');
```

------

## Abilita Time to Live utilizzando il AWS CLI
<a name="time-to-live-ttl-how-to-enable-cli-sdk"></a>

1. Abilita TTL nella tabella `TTLExample`.

   ```
   aws dynamodb update-time-to-live --table-name TTLExample --time-to-live-specification "Enabled=true, AttributeName=ttl"
   ```

1. Descrivi TTL nella tabella `TTLExample`.

   ```
   aws dynamodb describe-time-to-live --table-name TTLExample
   {
       "TimeToLiveDescription": {
           "AttributeName": "ttl",
           "TimeToLiveStatus": "ENABLED"
       }
   }
   ```

1. Aggiungi un elemento alla tabella `TTLExample` con l'attributo Time to Live (TTL) impostato usando la shell BASH e la AWS CLI. 

   ```
   EXP=`date -d '+5 days' +%s`
   aws dynamodb put-item --table-name "TTLExample" --item '{"id": {"N": "1"}, "ttl": {"N": "'$EXP'"}}'
   ```

Questo esempio inizia con la data corrente e aggiunge 5 giorni per creare un periodo di scadenza. Il periodo di scadenza viene quindi convertito nel formato temporale epoch Unix per aggiungere infine un item nella tabella `TTLExample`. 

**Nota**  
 Un modo per impostare i valori di scadenza per il Time to Live (TTL) consiste nel calcolare il numero di secondi da aggiungere al periodo di scadenza. Ad esempio, 5 giorni sono 432.000 secondi. È tuttavia in genere preferibile scegliere come punto di partenza una data.

Ottenere l'ora corrente in formato epoch Unix è piuttosto semplice, come negli esempi seguenti.
+ Terminale Linux: `date +%s`
+ Python: `import time; int(time.time())`
+ Java: `System.currentTimeMillis() / 1000L`
+ JavaScript: `Math.floor(Date.now() / 1000)`

## Abilita DynamoDB TTL utilizzando CloudFormation
<a name="time-to-live-ttl-how-to-enable-cf"></a>

```
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  TTLExampleTable:
    Type: AWS::DynamoDB::Table
    Description: "A DynamoDB table with TTL Specification enabled"
    Properties:
      AttributeDefinitions:
        - AttributeName: "Album"
          AttributeType: "S"
        - AttributeName: "Artist"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "Album"
          KeyType: "HASH"
        - AttributeName: "Artist"
          KeyType: "RANGE"
      ProvisionedThroughput:
        ReadCapacityUnits: "5"
        WriteCapacityUnits: "5"
      TimeToLiveSpecification:
        AttributeName: "TTLExampleAttribute"
        Enabled: true
```

[Ulteriori dettagli sull'utilizzo del TTL all'interno dei CloudFormation modelli sono disponibili qui.](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html)

# Calcolo del Time to Live (TTL) in DynamoDB
<a name="time-to-live-ttl-before-you-start"></a>

Un modo comune per implementare il TTL consiste nell’impostare una scadenza per gli elementi in base a quando sono stati creati o aggiornati l’ultima volta. Questa operazione è fattibile aggiungendo la scadenza ai timestamp `createdAt` e `updatedAt`. Ad esempio, il TTL per gli elementi appena creati può essere impostato su `createdAt` \$1 90 giorni. Quando l’elemento viene aggiornato, il TTL può essere ricalcolato a `updatedAt` \$1 90 giorni.

La scadenza calcolata deve essere in formato epoch, in secondi. Per essere considerato valido per la scadenza e l’eliminazione, il TTL non può essere passato da più di cinque anni. Se si utilizza un altro formato, i processi TTL ignorano l'item. Se imposti l'ora di scadenza su un periodo futuro in cui desideri che l'articolo scada, l'articolo scadrà dopo tale periodo. Ad esempio, supponiamo di aver impostato l'ora di scadenza su 1724241326 (ovvero lunedì 21 agosto 2024 11:55:26 (UTC)). L'articolo scade dopo l'ora specificata. Non esiste una durata TTL minima. È possibile impostare l'ora di scadenza su qualsiasi ora futura, ad esempio a 5 minuti dall'ora corrente. Tuttavia, DynamoDB in genere elimina gli articoli scaduti entro 48 ore dalla data di scadenza, non immediatamente dopo la scadenza dell'articolo.

**Topics**
+ [Creazione di un oggetto e impostazione del Time to Live](#time-to-live-ttl-before-you-start-create)
+ [Aggiornamento di un elemento e del Time to Live](#time-to-live-ttl-before-you-start-update)

## Creazione di un oggetto e impostazione del Time to Live
<a name="time-to-live-ttl-before-you-start-create"></a>

L’esempio seguente mostra come calcolare la scadenza durante la creazione di un nuovo elemento, utilizzando `expireAt` come nome dell’attributo TTL. Un’istruzione di assegnazione ottiene il momento corrente come variabile. Nell’esempio, la scadenza viene calcolata come a 90 giorni dal momento corrente. La scadenza viene quindi convertita in formato epoch e salvata come tipo di dati intero nell’attributo TTL.

Gli esempi di codice seguenti mostrano come creare un elemento con un valore TTL.

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

**SDK per Java 2.x**  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * Creates an item in a DynamoDB table with TTL attributes.
 * This class demonstrates how to add TTL expiration timestamps to DynamoDB items.
 */
public class CreateTTL {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String CREATION_DATE_ATTR = "creationDate";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String SUCCESS_MESSAGE = "%s PutItem operation with TTL successful.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs a CreateTTL instance with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public CreateTTL(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Constructs a CreateTTL with a default DynamoDB client.
     */
    public CreateTTL() {
        this.dynamoDbClient = null;
    }

    /**
     * Main method to demonstrate creating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new CreateTTL().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and create an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final CreateTTL createTTL = new CreateTTL(ddb);
            createTTL.createItemWithTTL(tableName, primaryKey, sortKey);
            return 0;
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * Creates an item in the specified table with TTL attributes.
     *
     * @param tableName The name of the table
     * @param primaryKeyValue The value for the primary key
     * @param sortKeyValue The value for the sort key
     * @return The response from the PutItem operation
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     */
    public PutItemResponse createItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long createDate = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = createDate + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        final Map<String, AttributeValue> itemMap = new HashMap<>();
        itemMap.put(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        itemMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());
        itemMap.put(
            CREATION_DATE_ATTR,
            AttributeValue.builder().n(String.valueOf(createDate)).build());
        itemMap.put(
            EXPIRE_AT_ATTR,
            AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final PutItemRequest request =
            PutItemRequest.builder().tableName(tableName).item(itemMap).build();

        try {
            final PutItemResponse response = dynamoDbClient.putItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  *Per i dettagli sull'API, consulta la sezione API Reference. [PutItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/PutItem)AWS SDK for Java 2.x * 

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

**SDK per JavaScript (v3)**  

```
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";

export function createDynamoDBItem(table_name, region, partition_key, sort_key) {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    // Get the current time in epoch second format
    const current_time = Math.floor(new Date().getTime() / 1000);

    // Calculate the expireAt time (90 days from now) in epoch second format
    const expire_at = Math.floor((new Date().getTime() + 90 * 24 * 60 * 60 * 1000) / 1000);

    // Create DynamoDB item
    const item = {
        'partitionKey': {'S': partition_key},
        'sortKey': {'S': sort_key},
        'createdAt': {'N': current_time.toString()},
        'expireAt': {'N': expire_at.toString()}
    };

    const putItemCommand = new PutItemCommand({
        TableName: table_name,
        Item: item,
        ProvisionedThroughput: {
            ReadCapacityUnits: 1,
            WriteCapacityUnits: 1,
        },
    });

    client.send(putItemCommand, function(err, data) {
        if (err) {
            console.log("Exception encountered when creating item %s, here's what happened: ", data, err);
            throw err;
        } else {
            console.log("Item created successfully: %s.", data);
            return data;
        }
    });
}

// Example usage (commented out for testing)
// createDynamoDBItem('your-table-name', 'us-east-1', 'your-partition-key-value', 'your-sort-key-value');
```
+  Per i dettagli sull'API, consulta la sezione *AWS SDK per JavaScript API [PutItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/PutItemCommand)Reference*. 

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

**SDK per Python (Boto3)**  

```
from datetime import datetime, timedelta

import boto3


def create_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Creates a DynamoDB item with an attached expiry attribute.

    :param table_name: Table name for the boto3 resource to target when creating an item
    :param region: string representing the AWS region. Example: `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expiration time (90 days from now) in epoch second format
        expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        item = {
            "primaryKey": primary_key,
            "sortKey": sort_key,
            "creationDate": current_time,
            "expireAt": expiration_time,
        }
        response = table.put_item(Item=item)

        print("Item created successfully.")
        return response
    except Exception as e:
        print(f"Error creating item: {e}")
        raise e


# Use your own values
create_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  Per i dettagli sull'API, consulta [PutItem AWS](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/PutItem)*SDK for Python (Boto3) API Reference*. 

------

## Aggiornamento di un elemento e del Time to Live
<a name="time-to-live-ttl-before-you-start-update"></a>

Questo esempio è una continuazione di quello della sezione [precedente](#time-to-live-ttl-before-you-start-create). La scadenza può essere ricalcolata se l’elemento viene aggiornato. L’esempio seguente ricalcola il timestamp `expireAt` in modo che corrisponda a 90 giorni dal momento corrente.

Gli esempi di codice seguenti mostrano come aggiornare il valore TTL di un elemento.

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

**SDK per Java 2.x**  
Aggiorna il TTL di un elemento DynamoDB esistente in una tabella.  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

    public UpdateItemResponse updateItemWithTTL(
        final String tableName, final String primaryKeyValue, final String sortKeyValue) {
        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = new HashMap<>();
        keyMap.put(PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKeyValue).build());
        keyMap.put(SORT_KEY_ATTR, AttributeValue.builder().s(sortKeyValue).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build());
        expressionAttributeValues.put(
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try {
            final UpdateItemResponse response = dynamoDbClient.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return response;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
```
+  *Per i dettagli sulle API, consulta [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)la sezione API Reference.AWS SDK for Java 2.x * 

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

**SDK per JavaScript (v3)**  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItem = async (tableName, partitionKey, sortKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);
    const expireAt = Math.floor((Date.now() + 90 * 24 * 60 * 60 * 1000) / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            partitionKey: partitionKey,
            sortKey: sortKey
        }),
        UpdateExpression: "SET updatedAt = :c, expireAt = :e",
        ExpressionAttributeValues: marshall({
            ":c": currentTime,
            ":e": expireAt
        }),
    };

    try {
        const data = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(data.Attributes);
        console.log("Item updated successfully: %s", responseData);
        return responseData;
    } catch (err) {
        console.error("Error updating item:", err);
        throw err;
    }
}

// Example usage (commented out for testing)
// updateItem('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  Per i dettagli sull'API, consulta la sezione *AWS SDK per JavaScript API [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)Reference*. 

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

**SDK per Python (Boto3)**  

```
from datetime import datetime, timedelta

import boto3


def update_dynamodb_item(table_name, region, primary_key, sort_key):
    """
    Update an existing DynamoDB item with a TTL.
    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :return: Void (nothing)
    """
    try:
        # Create the DynamoDB resource.
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Get the current time in epoch second format
        current_time = int(datetime.now().timestamp())

        # Calculate the expireAt time (90 days from now) in epoch second format
        expire_at = int((datetime.now() + timedelta(days=90)).timestamp())

        table.update_item(
            Key={"partitionKey": primary_key, "sortKey": sort_key},
            UpdateExpression="set updatedAt=:c, expireAt=:e",
            ExpressionAttributeValues={":c": current_time, ":e": expire_at},
        )

        print("Item updated successfully.")
    except Exception as e:
        print(f"Error updating item: {e}")


# Replace with your own values
update_dynamodb_item(
    "your-table-name", "us-west-2", "your-partition-key-value", "your-sort-key-value"
)
```
+  Per i dettagli sull'API, consulta [UpdateItem AWS](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)*SDK for Python (Boto3) API Reference*. 

------

Gli esempi del TTL discussi in questa introduzione dimostrano un metodo per garantire che in una tabella vengano conservati solo gli elementi aggiornati di recente. Gli elementi aggiornati hanno una durata prolungata, mentre gli elementi non aggiornati dopo la creazione scadono e vengono eliminati gratuitamente, liberando spazio di archiviazione e mantenendo le tabelle pulite.

# Utilizzo di elementi scaduti e Time to Live
<a name="ttl-expired-items"></a>

Gli elementi scaduti in attesa di eliminazione possono essere filtrati dalle operazioni di lettura e scrittura. Ciò è utile negli scenari in cui i dati scaduti non sono più validi e non devono essere utilizzati. Se non vengono filtrati, continueranno a essere visualizzati nelle operazioni di lettura e scrittura finché non verranno eliminati dal processo in background.

**Nota**  
Questi elementi continuano a essere conteggiati ai fini dei costi di archiviazione e lettura fino a quando non vengono eliminati.

Le eliminazioni TTL possono essere identificate nei flussi DynamoDB, ma solo nella Regione in cui è avvenuta l’eliminazione. Le eliminazioni TTL che vengono replicate nelle aree della tabella globale non sono identificabili nei flussi DynamoDB nelle aree in cui viene replicata l’eliminazione.

## Filtraggio di elementi scaduti dalle operazioni di lettura
<a name="ttl-expired-items-filter"></a>

Per operazioni di lettura come [Scan](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) e [Query](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html), un’espressione di filtro può filtrare gli elementi scaduti in attesa di eliminazione. Come illustrato nel seguente frammento di codice, l’espressione di filtro può filtrare gli elementi in cui il TTL è uguale o inferiore al momento corrente. Ad esempio, il codice dell’SDK per Python include un’istruzione di assegnazione che ottiene il momento corrente come variabile (`now`) e la converte in `int` per il formato ora epoch.

Gli esempi di codice seguenti mostrano come eseguire query su elementi TTL.

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

**SDK per Java 2.x**  
Interroga l'espressione filtrata per raccogliere elementi TTL in una tabella DynamoDB utilizzando. AWS SDK for Java 2.x  

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.QueryRequest;
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;

import java.util.Map;
import java.util.Optional;

        final QueryRequest request = QueryRequest.builder()
            .tableName(tableName)
            .keyConditionExpression(KEY_CONDITION_EXPRESSION)
            .filterExpression(FILTER_EXPRESSION)
            .expressionAttributeNames(expressionAttributeNames)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final QueryResponse response = ddb.query(request);
            System.out.println("Query successful. Found " + response.count() + " items that have not expired yet.");

            // Print each item
            response.items().forEach(item -> {
                System.out.println("Item: " + item);
            });

            return 0;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
```
+  Per informazioni dettagliate sull’API, consulta [Query](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/Query) nella *documentazione di riferimento dell’API AWS SDK for Java 2.x *. 

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

**SDK per (v3) JavaScript **  
Interroga l'espressione filtrata per raccogliere elementi TTL in una tabella DynamoDB utilizzando. AWS SDK per JavaScript  

```
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const queryFiltered = async (tableName, primaryKey, region = 'us-east-1') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        KeyConditionExpression: "#pk = :pk",
        FilterExpression: "#ea > :ea",
        ExpressionAttributeNames: {
            "#pk": "primaryKey",
            "#ea": "expireAt"
        },
        ExpressionAttributeValues: marshall({
            ":pk": primaryKey,
            ":ea": currentTime
        })
    };

    try {
        const { Items } = await client.send(new QueryCommand(params));
        Items.forEach(item => {
            console.log(unmarshall(item))
        });
        return Items;
    } catch (err) {
        console.error(`Error querying items: ${err}`);
        throw err;
    }
}

// Example usage (commented out for testing)
// queryFiltered('your-table-name', 'your-partition-key-value');
```
+  Per informazioni dettagliate sull’API, consulta [Query](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/QueryCommand) nella *documentazione di riferimento dell’API AWS SDK per JavaScript *. 

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

**SDK per Python (Boto3)**  
Interroga l'espressione filtrata per raccogliere elementi TTL in una tabella DynamoDB utilizzando. AWS SDK per Python (Boto3)  

```
from datetime import datetime

import boto3


def query_dynamodb_items(table_name, partition_key):
    """

    :param table_name: Name of the DynamoDB table
    :param partition_key:
    :return:
    """
    try:
        # Initialize a DynamoDB resource
        dynamodb = boto3.resource("dynamodb", region_name="us-east-1")

        # Specify your table
        table = dynamodb.Table(table_name)

        # Get the current time in epoch format
        current_time = int(datetime.now().timestamp())

        # Perform the query operation with a filter expression to exclude expired items
        # response = table.query(
        #    KeyConditionExpression=boto3.dynamodb.conditions.Key('partitionKey').eq(partition_key),
        #    FilterExpression=boto3.dynamodb.conditions.Attr('expireAt').gt(current_time)
        # )
        response = table.query(
            KeyConditionExpression=dynamodb.conditions.Key("partitionKey").eq(partition_key),
            FilterExpression=dynamodb.conditions.Attr("expireAt").gt(current_time),
        )

        # Print the items that are not expired
        for item in response["Items"]:
            print(item)

    except Exception as e:
        print(f"Error querying items: {e}")


# Call the function with your values
query_dynamodb_items("Music", "your-partition-key-value")
```
+  Per informazioni dettagliate sull’API, consulta [Query](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/Query) nella *documentazione di riferimento dell’API SDK for Python (Boto3)AWS *. 

------

## Scrittura in base a una condizione su elementi scaduti
<a name="ttl-expired-items-conditional-write"></a>

È possibile utilizzare un’espressione condizionale per evitare scritture su elementi scaduti. Il frammento di codice riportato di seguito è un aggiornamento condizionale che verifica se la scadenza è posteriore al momento corrente. Se true, l’operazione di scrittura continuerà.

Gli esempi di codice seguenti mostrano come aggiornare in modo condizionale il valore TTL di un elemento.

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

**SDK per Java 2.x**  
Aggiorna il TTL di un elemento DynamoDB esistente in una tabella con una condizione.  

```
package com.amazon.samplelib.ttl;

import com.amazon.samplelib.CodeSampleUtils;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemResponse;

import java.util.Map;
import java.util.Optional;

/**
 * Updates an item in a DynamoDB table with TTL attributes using a conditional expression.
 * This class demonstrates how to conditionally update TTL expiration timestamps.
 */
public class UpdateTTLConditional {

    private static final String USAGE =
        """
            Usage:
                <tableName> <primaryKey> <sortKey> <region>
            Where:
                tableName - The Amazon DynamoDB table being queried.
                primaryKey - The name of the primary key. Also known as the hash or partition key.
                sortKey - The name of the sort key. Also known as the range attribute.
                region (optional) - The AWS region that the Amazon DynamoDB table is located in. (Default: us-east-1)
            """;
    private static final int DAYS_TO_EXPIRE = 90;
    private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    private static final String PRIMARY_KEY_ATTR = "primaryKey";
    private static final String SORT_KEY_ATTR = "sortKey";
    private static final String UPDATED_AT_ATTR = "updatedAt";
    private static final String EXPIRE_AT_ATTR = "expireAt";
    private static final String UPDATE_EXPRESSION = "SET " + UPDATED_AT_ATTR + "=:c, " + EXPIRE_AT_ATTR + "=:e";
    private static final String CONDITION_EXPRESSION = "attribute_exists(" + PRIMARY_KEY_ATTR + ")";
    private static final String SUCCESS_MESSAGE = "%s UpdateItem operation with TTL successful.";
    private static final String CONDITION_FAILED_MESSAGE = "Condition check failed. Item does not exist.";
    private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";

    private final DynamoDbClient dynamoDbClient;

    /**
     * Constructs an UpdateTTLConditional with a default DynamoDB client.
     */
    public UpdateTTLConditional() {
        this.dynamoDbClient = null;
    }

    /**
     * Constructs an UpdateTTLConditional with the specified DynamoDB client.
     *
     * @param dynamoDbClient The DynamoDB client to use
     */
    public UpdateTTLConditional(final DynamoDbClient dynamoDbClient) {
        this.dynamoDbClient = dynamoDbClient;
    }

    /**
     * Main method to demonstrate conditionally updating an item with TTL.
     *
     * @param args Command line arguments
     */
    public static void main(final String[] args) {
        try {
            int result = new UpdateTTLConditional().processArgs(args);
            System.exit(result);
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }

    /**
     * Process command line arguments and conditionally update an item with TTL.
     *
     * @param args Command line arguments
     * @return 0 if successful, non-zero otherwise
     * @throws ResourceNotFoundException If the table doesn't exist
     * @throws DynamoDbException If an error occurs during the operation
     * @throws IllegalArgumentException If arguments are invalid
     */
    public int processArgs(final String[] args) {
        // Argument validation (remove or replace this line when reusing this code)
        CodeSampleUtils.validateArgs(args, new int[] {3, 4}, USAGE);

        final String tableName = args[0];
        final String primaryKey = args[1];
        final String sortKey = args[2];
        final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
            .map(Region::of)
            .orElse(Region.US_EAST_1);

        // Get current time in epoch second format
        final long currentTime = System.currentTimeMillis() / 1000;

        // Calculate expiration time 90 days from now in epoch second format
        final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);

        // Create the key map for the item to update
        final Map<String, AttributeValue> keyMap = Map.of(
            PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKey).build(),
            SORT_KEY_ATTR, AttributeValue.builder().s(sortKey).build());

        // Create the expression attribute values
        final Map<String, AttributeValue> expressionAttributeValues = Map.of(
            ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build(),
            ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build());

        final UpdateItemRequest request = UpdateItemRequest.builder()
            .tableName(tableName)
            .key(keyMap)
            .updateExpression(UPDATE_EXPRESSION)
            .conditionExpression(CONDITION_EXPRESSION)
            .expressionAttributeValues(expressionAttributeValues)
            .build();

        try (DynamoDbClient ddb = dynamoDbClient != null
            ? dynamoDbClient
            : DynamoDbClient.builder().region(region).build()) {
            final UpdateItemResponse response = ddb.updateItem(request);
            System.out.println(String.format(SUCCESS_MESSAGE, tableName));
            return 0;
        } catch (ConditionalCheckFailedException e) {
            System.err.println(CONDITION_FAILED_MESSAGE);
            throw e;
        } catch (ResourceNotFoundException e) {
            System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
            throw e;
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            throw e;
        }
    }
}
```
+  *Per i dettagli sulle API, consulta [UpdateItem](https://docs.aws.amazon.com/goto/SdkForJavaV2/dynamodb-2012-08-10/UpdateItem)la sezione API Reference.AWS SDK for Java 2.x * 

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

**SDK per JavaScript (v3)**  
Aggiorna il TTL di un elemento DynamoDB esistente in una tabella con una condizione.  

```
import { DynamoDBClient, UpdateItemCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";

export const updateItemConditional = async (tableName, partitionKey, sortKey, region = 'us-east-1', newAttribute = 'default-value') => {
    const client = new DynamoDBClient({
        region: region,
        endpoint: `https://dynamodb.${region}.amazonaws.com`
    });

    const currentTime = Math.floor(Date.now() / 1000);

    const params = {
        TableName: tableName,
        Key: marshall({
            artist: partitionKey,
            album: sortKey
        }),
        UpdateExpression: "SET newAttribute = :newAttribute",
        ConditionExpression: "expireAt > :expiration",
        ExpressionAttributeValues: marshall({
            ':newAttribute': newAttribute,
            ':expiration': currentTime
        }),
        ReturnValues: "ALL_NEW"
    };

    try {
        const response = await client.send(new UpdateItemCommand(params));
        const responseData = unmarshall(response.Attributes);
        console.log("Item updated successfully: ", responseData);
        return responseData;
    } catch (error) {
        if (error.name === "ConditionalCheckFailedException") {
            console.log("Condition check failed: Item's 'expireAt' is expired.");
        } else {
            console.error("Error updating item: ", error);
        }
        throw error;
    }
};

// Example usage (commented out for testing)
// updateItemConditional('your-table-name', 'your-partition-key-value', 'your-sort-key-value');
```
+  Per i dettagli sull'API, consulta la sezione *AWS SDK per JavaScript API [UpdateItem](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/dynamodb/command/UpdateItemCommand)Reference*. 

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

**SDK per Python (Boto3)**  
Aggiorna il TTL di un elemento DynamoDB esistente in una tabella con una condizione.  

```
from datetime import datetime, timedelta

import boto3
from botocore.exceptions import ClientError


def update_dynamodb_item_ttl(table_name, region, primary_key, sort_key, ttl_attribute):
    """
    Updates an existing record in a DynamoDB table with a new or updated TTL attribute.

    :param table_name: Name of the DynamoDB table
    :param region: AWS Region of the table - example `us-east-1`
    :param primary_key: one attribute known as the partition key.
    :param sort_key: Also known as a range attribute.
    :param ttl_attribute: name of the TTL attribute in the target DynamoDB table
    :return:
    """
    try:
        dynamodb = boto3.resource("dynamodb", region_name=region)
        table = dynamodb.Table(table_name)

        # Generate updated TTL in epoch second format
        updated_expiration_time = int((datetime.now() + timedelta(days=90)).timestamp())

        # Define the update expression for adding/updating a new attribute
        update_expression = "SET newAttribute = :val1"

        # Define the condition expression for checking if 'expireAt' is not expired
        condition_expression = "expireAt > :val2"

        # Define the expression attribute values
        expression_attribute_values = {":val1": ttl_attribute, ":val2": updated_expiration_time}

        response = table.update_item(
            Key={"primaryKey": primary_key, "sortKey": sort_key},
            UpdateExpression=update_expression,
            ConditionExpression=condition_expression,
            ExpressionAttributeValues=expression_attribute_values,
        )

        print("Item updated successfully.")
        return response["ResponseMetadata"]["HTTPStatusCode"]  # Ideally a 200 OK
    except ClientError as e:
        if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
            print("Condition check failed: Item's 'expireAt' is expired.")
        else:
            print(f"Error updating item: {e}")
    except Exception as e:
        print(f"Error updating item: {e}")


# replace with your values
update_dynamodb_item_ttl(
    "your-table-name",
    "us-east-1",
    "your-partition-key-value",
    "your-sort-key-value",
    "your-ttl-attribute-value",
)
```
+  Per i dettagli sull'API, consulta [UpdateItem AWS](https://docs.aws.amazon.com/goto/boto3/dynamodb-2012-08-10/UpdateItem)*SDK for Python (Boto3) API Reference*. 

------

## Identificazione degli elementi eliminati nei flussi DynamoDB
<a name="ttl-expired-items-identifying"></a>

Il record Streams contiene un campo di identità utente `Records[<index>].userIdentity`. Gli elementi eliminati dal processo TTL hanno i seguenti campi:

```
Records[<index>].userIdentity.type
"Service"

Records[<index>].userIdentity.principalId
"dynamodb.amazonaws.com"
```

Il JSON seguente mostra la porzione rilevante di un singolo record di flussi:

```
"Records": [ 
  { 
	... 
		"userIdentity": {
		"type": "Service", 
      	"principalId": "dynamodb.amazonaws.com" 
   	} 
   ... 
	} 
]
```

# Esecuzione di query in DynamoDB
<a name="Query"></a>

Puoi usare l'operazione API `Query` in Amazon DynamoDB per trovare gli elementi in base ai valori delle chiavi primarie.

È necessario fornire il nome dell'attributo della chiave di partizione e un singolo valore per tale attributo. `Query` restituisce tutti gli elementi con lo stesso valore della chiave di partizione. Facoltativamente, puoi fornire un attributo della chiave di ordinamento e utilizzare un operatore di confronto per perfezionare i risultati della ricerca.

Per ulteriori informazioni su come usare `Query`, come la sintassi della richiesta, i parametri di risposta e altri esempi, vedere [Query](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) nella *Documentazione di riferimento dell'API Amazon DynamoDB*.

**Topics**
+ [Espressioni di condizione della chiave per l’operazione Query in DynamoDB](Query.KeyConditionExpressions.md)
+ [Espressioni di filtro per l’operazione Query in DynamoDB](Query.FilterExpression.md)
+ [Impaginazione dei risultati delle query sulle tabelle in DynamoDB](Query.Pagination.md)
+ [Altri aspetti dell’utilizzo dell’operazione Query in DynamoDB](Query.Other.md)

# Espressioni di condizione della chiave per l’operazione Query in DynamoDB
<a name="Query.KeyConditionExpressions"></a>

Puoi utilizzare qualsiasi nome di attributo in un'espressione condizionale della chiave, a condizione che il primo carattere sia `a-z` o `A-Z` e che il resto dei caratteri (a iniziare dal secondo carattere, se presente) sia `a-z`, `A-Z` o `0-9`. Inoltre, il nome dell'attributo non deve essere una parola riservata di DynamoDB. Per l'elenco completo delle parole riservate, consulta [Parole riservate in DynamoDB](ReservedWords.md). Se un nome di attributo non soddisfa questi requisiti, devi definire un nome di attributo dell'espressione come un segnaposto. Per ulteriori informazioni, consulta [Nomi di attributi di espressione (alias) in DynamoDB](Expressions.ExpressionAttributeNames.md).

Per gli elementi con un determinato valore di chiave di partizione, DynamoDB li memorizza tutti insieme, ordinati in base al valore della chiave di ordinamento. In un'operazione `Query`, DynamoDB recupera gli elementi nell'ordine stabilito e quindi li elabora utilizzando `KeyConditionExpression` e qualsiasi `FilterExpression` eventualmente presente. Solo allora i risultati della `Query` vengono restituiti al client.

Un'operazione `Query` restituisce sempre un set di risultati. Se non vengono trovati item corrispondenti, il set di risultati è vuoto.

I risultati della `Query` sono sempre ordinati per il valore della chiave di ordinamento. Se il tipo di dati della chiave di ordinamento è `Number`, i risultati vengono restituiti in ordine numerico. In caso contrario, i risultati vengono restituiti nell'ordine di byte UTF-8. Per impostazione predefinita, l'ordinamento è crescente. Per invertire l'ordine, imposta il parametro `ScanIndexForward` su `false`.

Una singola operazione `Query` può recuperare un massimo di 1 MB di dati. Questo limite si applica prima che ai risultati venga applicato `FilterExpression` o `ProjectionExpression`. Se `LastEvaluatedKey` è presente nella risposta ed è non null, devi eseguire la paginazione del set di risultati (consulta [Impaginazione dei risultati delle query sulle tabelle in DynamoDB](Query.Pagination.md)).

## Esempi di espressioni di condizione della chiave
<a name="Query.KeyConditionExpressions-example"></a>

Per specificare i criteri di ricerca, è possibile utilizzare una *espressione di condizione chiave*, ovvero una stringa che determina gli elementi da leggere dalla tabella o dall'indice.

Devi specificare il nome e il valore della chiave di partizione come condizione di uguaglianza. Non puoi utilizzare un attributo non chiave in un'espressione di condizione chiave.

Facoltativamente puoi fornire una seconda condizione per la chiave di ordinamento (se presente). La condizione della chiave di ordinamento deve utilizzare uno dei seguenti operatori di confronto:
+ `a = b`— true se l'attributo *a* è uguale al valore *b*
+ `a < b`— vero se *a* è minore di *b*
+ `a <= b`— vero se *a* è minore o uguale a *b*
+ `a > b`— vero se *a* è maggiore di *b*
+ `a >= b`— vero se *a* è maggiore o uguale a *b*
+ `a BETWEEN b AND c`— vero se *a* è maggiore o uguale a *b* e minore o uguale a*c*.

È supportata anche la seguente funzione:
+ `begins_with (a, substr)`: true se il valore dell'attributo `a` inizia con una determinata sottostringa.

I seguenti esempi AWS Command Line Interface (AWS CLI) illustrano l'uso delle espressioni delle condizioni chiave. Queste espressioni usano segnaposti (come ad esempio `:name` e `:sub`) anziché i valori effettivi. Per ulteriori informazioni, consultare [Nomi di attributi di espressione (alias) in DynamoDB](Expressions.ExpressionAttributeNames.md) e [Utilizzo dei valori degli attributi di espressione in DynamoDB](Expressions.ExpressionAttributeValues.md).

**Example**  
Esegui la query sulla tabella `Thread` per un particolare `ForumName` (chiave di partizione). Tutti gli elementi con quel valore di `ForumName` vengono letti dalla query, perché la chiave di ordinamento (`Subject`) non è inclusa in `KeyConditionExpression`.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name" \
    --expression-attribute-values  '{":name":{"S":"Amazon DynamoDB"}}'
```

**Example**  
Esegui la query sulla tabella `Thread` per un particolare `ForumName` (chiave di partizione); questa volta vengono restituiti solo gli elementi con uno specifico `Subject` (chiave di ordinamento).  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":name":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"}
}
```

**Example**  
Esegui la query sulla tabella `Reply` per un particolare `Id` (chiave di partizione); vengono restituiti solo gli elementi il cui `ReplyDateTime` (chiave di ordinamento) inizia con determinati caratteri.  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":id":{"S":"Amazon DynamoDB#DynamoDB Thread 1"},
    ":dt":{"S":"2015-09"}
}
```

# Espressioni di filtro per l’operazione Query in DynamoDB
<a name="Query.FilterExpression"></a>

Se devi perfezionare ulteriormente i risultati di `Query`, opzionalmente puoi fornire un'espressione filtro. Un'*espressione di filtro* determina quali item all'interno dei risultati di `Query` devono essere restituiti. Tutti gli altri risultati vengono scartati.

Un'espressione di filtro viene applicata al termine di un'operazione `Query`, ma prima che i risultati vengano restituiti. Pertanto, un'operazione `Query` consuma la stessa quantità di capacità in lettura, a prescindere dal fatto che sia presente un'espressione di filtro.

Un'operazione `Query` può recuperare un massimo di 1 MB di dati. Questo limite si applica prima che l'espressione di filtro venga valutata.

Un'espressione di filtro non può contenere attributi di chiave di partizione o chiave di ordinamento. Devi specificare quegli attributi nell'espressione della condizione di chiave e non nell'espressione di filtro.

La sintassi per un'espressione di filtro è simile a quella di un'espressione di condizione chiave. Le espressioni di filtro possono utilizzare gli stessi comparatori, funzioni e operatori logici come espressione di condizione chiave. Inoltre, le espressioni di filtro possono utilizzare l'operatore non uguale (`<>`), l’operatore `OR`, l’operatore `CONTAINS`, l’operatore `IN`, l’operatore `BEGINS_WITH`, l’operatore `BETWEEN`, l’operatore `EXISTS` e l’operatore `SIZE`. Per ulteriori informazioni, consultare [Espressioni di condizione della chiave per l’operazione Query in DynamoDB](Query.KeyConditionExpressions.md) e [Sintassi per le espressioni di filtro e condizioni](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax).

**Example**  
L' AWS CLI esempio seguente interroga la `Thread` tabella per un particolare `ForumName` (chiave di partizione) e `Subject` (chiave di ordinamento). Tra gli elementi trovati, vengono restituiti solo i thread di discussione più popolari, in altre parole solo i thread con più di un certo numero di `Views`.  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :fn and Subject begins_with :sub" \
    --filter-expression "#v >= :num" \
    --expression-attribute-names '{"#v": "Views"}' \
    --expression-attribute-values file://values.json
```
Gli argomenti per `--expression-attribute-values` sono memorizzati nel file `values.json`:  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
Tenere presente che `Views` è una parola riservata in DynamoDB (vedere [Parole riservate in DynamoDB](ReservedWords.md)), quindi in questo esempio si usa `#v` come segnaposto. Per ulteriori informazioni, consulta [Nomi di attributi di espressione (alias) in DynamoDB](Expressions.ExpressionAttributeNames.md).

**Nota**  
Un'espressione filtro rimuove gli elementi dal set di risultati della `Query`. Se possibile, evita di utilizzare `Query` dove ti aspetti di recuperare un gran numero di item, ma sai che devi anche scartare la maggior parte di questi item.

# Impaginazione dei risultati delle query sulle tabelle in DynamoDB
<a name="Query.Pagination"></a>

DynamoDB esegue la *paginazione* dei risultati delle operazioni `Query`. Con la paginazione, i risultati della `Query` vengono divisi in "pagine" di dati la cui dimensione è al massimo 1 MB. Un'applicazione può elaborare la prima pagina dei risultati, quindi la seconda pagina e così via.

Una singola operazione `Query` restituisce solo un set di risultati che rientra nel limite di dimensione di 1 MB. Per determinare se ci sono più risultati e recuperarli una pagina alla volta, le applicazioni devono fare quanto segue: 

1. Esamina i risultati della `Query` di livello inferiore:
   + Se il risultato contiene un elemento `LastEvaluatedKey` che non è null, passa alla fase 2.
   + Se nel risultato *non* è presente un `LastEvaluatedKey`, allora non ci sono altri elementi da recuperare.

1. Costruzione di una `Query` con la stessa `KeyConditionExpression`. Tuttavia, questa volta, accettare il valore `LastEvaluatedKey` della fase 1 e usarlo come parametro `ExclusiveStartKey` nella nuova richiesta di `Query`.

1. Eseguire la nuova richiesta di `Query`.

1. Passa alla fase 1.

In altre parole, l'item `LastEvaluatedKey` della risposta di uno `Query` deve essere usato come item `ExclusiveStartKey` per la successiva richiesta di `Query`. Se non è presente un elemento `LastEvaluatedKey` nella risposta di uno `Query`, vuol dire che hai recuperato la pagina finale dei risultati. Se `LastEvaluatedKey` non è vuoto, non significa necessariamente che esistano più dati nel set di risultati. L'unico modo per sapere che hai raggiunto la fine del set di risultati è quando `LastEvaluatedKey` è vuoto.

È possibile utilizzare il AWS CLI per visualizzare questo comportamento. AWS CLI Invia ripetutamente `Query` richieste di basso livello a DynamoDB, `LastEvaluatedKey` finché non sono più presenti nei risultati. Considerate il seguente AWS CLI esempio che recupera i titoli dei film di un determinato anno.

```
aws dynamodb query --table-name Movies \
    --projection-expression "title" \
    --key-condition-expression "#y = :yyyy" \
    --expression-attribute-names '{"#y":"year"}' \
    --expression-attribute-values '{":yyyy":{"N":"1993"}}' \
    --page-size 5 \
    --debug
```

Normalmente, AWS CLI gestisce l'impaginazione automaticamente. Tuttavia, in questo esempio, il AWS CLI `--page-size` parametro limita il numero di elementi per pagina. Il parametro `--debug` consente di stampare le informazioni di livello inferiore relative alle richieste e alle risposte.

Se si esegue l'esempio, l'aspetto della prima risposta da DynamoDB sarà simile al seguente.

```
2017-07-07 11:13:15,603 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":5,"Items":[{"title":{"S":"A Bronx Tale"}},
{"title":{"S":"A Perfect World"}},{"title":{"S":"Addams Family Values"}},
{"title":{"S":"Alive"}},{"title":{"S":"Benny & Joon"}}],
"LastEvaluatedKey":{"year":{"N":"1993"},"title":{"S":"Benny & Joon"}},
"ScannedCount":5}'
```

L'item `LastEvaluatedKey` nella risposta indica che non tutti gli elementi sono stati recuperati. AWS CLI Quindi invia un'altra `Query` richiesta a DynamoDB. Questo modello di richiesta e risposta continua fino alla risposta finale.

```
2017-07-07 11:13:16,291 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"What\'s Eating Gilbert Grape"}}],"ScannedCount":1}'
```

L'assenza di `LastEvaluatedKey` indica che non ci sono più item da recuperare.

**Nota**  
 AWS SDKs Gestiscono le risposte DynamoDB di basso livello (inclusa la presenza o l'assenza di) e forniscono varie astrazioni per l'impaginazione `LastEvaluatedKey` dei risultati. `Query` Ad esempio, l'interfaccia del documento SDK per Java fornisce il supporto `java.util.Iterator` per poter esaminare i risultati uno alla volta.  
Per esempi di codice in vari linguaggi di programmazione, consulta la [Guida alle operazioni di base di Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) e la documentazione dell'SDK AWS per il linguaggio in uso.

È inoltre possibile ridurre la dimensione della pagina limitando il numero di elementi nel set di risultati, con il parametro `Limit` dell’operazione `Query`.

Per ulteriori informazioni sull'esecuzione di query con DynamoDB, consulta [Esecuzione di query in DynamoDB](Query.md).

# Altri aspetti dell’utilizzo dell’operazione Query in DynamoDB
<a name="Query.Other"></a>

Questa sezione tratta aspetti aggiuntivi dell’operazione Query in DynamoDB, tra cui la limitazione delle dimensioni dei risultati, il conteggio degli elementi scansionati rispetto a quelli restituiti, il monitoraggio dell’utilizzo della capacità di lettura e il controllo della coerenza di lettura.

## Limitazione del numero di elementi nel set di risultati
<a name="Query.Limit"></a>

Con l'operazione `Query` puoi limitare il numero di elementi che vengono letti. A tale scopo, imposta il parametro `Limit` sul numero massimo di item desiderati.

Ad esempio, supponi di eseguire un'operazione `Query` su una tabella, con un valore `Limit` di `6` e senza un'espressione di filtro. Il risultato dell'operazione `Query` contiene i primi sei item della tabella che corrispondono all'espressione di condizione della chiave della richiesta.

Supponi ora di aggiungere un'espressione di filtro a `Query`. In questo caso, DynamoDB legge fino a sei elementi e restituisce solo quelli che corrispondono all'espressione di filtro. Il risultato `Query` finale contiene sei elementi o meno, anche se, se DynamoDB avesse continuato la lettura, più elementi avrebbero trovato la corrispondenza con l'espressione del filtro.

## Conteggio degli elementi nei risultati
<a name="Query.Count"></a>

Oltre agli elementi che corrispondono ai tuoi criteri, la risposta `Query` contiene i seguenti elementi:
+ `ScannedCount`: il numero di voci corrispondenti all'espressione di condizione della query *prima* dell'applicazione di un'espressione di filtro (se presente).
+ `Count`: il numero di elementi che rimangono *dopo* aver applicato un'espressione di filtro.

**Nota**  
Se non si utilizza un'espressione di filtro `ScannedCount` e `Count` hanno lo stesso valore.

Se la dimensione del set di risultati di `Query` è maggiore di 1 MB, `ScannedCount` e `Count` rappresentano solo un conteggio parziale degli elementi totali. Devi eseguire più operazioni `Query` per recuperare tutti i risultati (consulta [Impaginazione dei risultati delle query sulle tabelle in DynamoDB](Query.Pagination.md)).

Ogni risposta di `Query` contiene `ScannedCount` e `Count` per gli elementi che sono stati elaborati da quella particolare richiesta `Query`. Per ottenere i totali generali per tutte le richieste di `Query`, puoi mantenere in esecuzione il conteggio per entrambi gli elementi `ScannedCount` e `Count`.

## Unità di capacità utilizzate dalla query
<a name="Query.CapacityUnits"></a>

Puoi eseguire `Query` su qualsiasi tabella o indice secondario, purché tu fornisca il nome dell'attributo della chiave di partizione e un singolo valore per tale attributo. `Query` restituisce tutti gli elementi con tale valore di chiave di partizione. Facoltativamente, puoi fornire un attributo della chiave di ordinamento e utilizzare un operatore di confronto per perfezionare i risultati della ricerca. `Query` Le operazioni API consumano unità di capacità in lettura, come segue.


****  

| Se si esegue `Query` per un... | DynamoDB utilizza le unità di capacità in lettura da... | 
| --- | --- | 
| Tabella | La capacità di lettura assegnata della tabella. | 
| Indice secondario globale | La capacità di lettura assegnata dell'indice. | 
| Indice secondario locale | La capacità di lettura assegnata della tabella di base. | 

Per impostazione predefinita, un'operazione `Query` non restituisce alcun dato sulla capacità di lettura che consuma. Tuttavia, puoi specificare il parametro `ReturnConsumedCapacity` in una richiesta di `Query` per ottenere queste informazioni. Le seguenti sono le impostazioni valide per `ReturnConsumedCapacity`:
+ `NONE`: non vengono restituiti dati relativi alla capacità utilizzata. Questa è l'impostazione predefinita.
+ `TOTAL`: la risposta include il numero aggregato di unità di capacità di lettura utilizzate.
+ `INDEXES`: la risposta mostra il numero aggregato di unità di capacità di lettura utilizzate, insieme alla capacità utilizzata per ogni tabella e indice a cui è stato effettuato l'accesso.

DynamoDB calcola il numero di unità di capacità di lettura utilizzate in base al numero di elementi e alla dimensione di quegli elementi, non alla quantità di dati restituiti a un’applicazione. Per questo motivo, il numero di unità di capacità consumate è lo stesso sia che tu richieda tutti gli attributi (il comportamento predefinito) o solo alcuni di essi (usando un'espressione di proiezione). Il numero è lo stesso anche indipendentemente dal fatto che si utilizzi o meno un’espressione di filtro. `Query` utilizza un’unità di capacità di lettura minima per eseguire un’operazione a elevata consistenza di lettura al secondo o due letture a coerenza finale al secondo per un elemento di un massimo di 4 KB. Se è necessario leggere un elemento che è più grande di 4 KB, DynamoDB necessità di unità di richiesta di lettura aggiuntive. Le tabelle vuote e le tabelle molto grandi che hanno una quantità limitata di chiavi di partizione potrebbero comportare costi aggiuntivi RCUs oltre alla quantità di dati richiesti. Ciò copre il costo di evasione della richiesta `Query` anche in assenza di dati.

## Consistenza di lettura per la query
<a name="Query.ReadConsistency"></a>

Un'operazione `Query` esegue letture consistenti finali per impostazione predefinita. Ciò significa che i risultati di `Query` potrebbero non riflettere le modifiche dovute alle operazioni `PutItem` o `UpdateItem` completate di recente. Per ulteriori informazioni, consulta [Coerenza di lettura di DynamoDB](HowItWorks.ReadConsistency.md).

Se hai bisogno di elevata coerenza di lettura, imposta il parametro `ConsistentRead` su `true` nella richiesta di `Query`.

# Scansione di tabelle in DynamoDB
<a name="Scan"></a>

Un'operazione `Scan` in Amazon DynamoDB legge ogni elemento in una tabella o in un indice secondario. Per impostazione predefinita, un'operazione `Scan` restituisce tutti gli attributi dei dati per ogni item nella tabella o nell'indice. Puoi usare il parametro `ProjectionExpression` in modo che `Scan` restituisca solo alcuni attributi, piuttosto che tutti.

`Scan` restituisce sempre un set di risultati. Se non vengono trovati item corrispondenti, il set di risultati è vuoto.

Una singola richiesta `Scan` può recuperare un massimo di 1 MB di dati. Facoltativamente, DynamoDB può applicare un'espressione di filtro a questi dati, limitando i risultati prima che vengano restituiti all'utente.

**Topics**
+ [Espressioni di filtro per la scansione](#Scan.FilterExpression)
+ [Limitazione del numero di elementi nel set di risultati](#Scan.Limit)
+ [Paginazione dei risultati](#Scan.Pagination)
+ [Conteggio degli elementi nei risultati](#Scan.Count)
+ [Unità di capacità utilizzate dalla scansione](#Scan.CapacityUnits)
+ [Consistenza di lettura per la scansione](#Scan.ReadConsistency)
+ [Scansione parallela](#Scan.ParallelScan)

## Espressioni di filtro per la scansione
<a name="Scan.FilterExpression"></a>

Se devi perfezionare ulteriormente i risultati di `Scan`, opzionalmente puoi fornire un'espressione filtro. Un'*espressione di filtro* determina quali item all'interno dei risultati di `Scan` devono essere restituiti. Tutti gli altri risultati vengono scartati.

Un'espressione di filtro viene applicata al termine di un'operazione `Scan`, ma prima che i risultati vengano restituiti. Pertanto, un'operazione `Scan` consuma la stessa quantità di capacità in lettura, a prescindere dal fatto che sia presente un'espressione di filtro.

Un'operazione `Scan` può recuperare un massimo di 1 MB di dati. Questo limite si applica prima che l'espressione di filtro venga valutata.

Con `Scan`, è possibile specificare qualsiasi attributo in un'espressione filtro, inclusi gli attributi di chiave di partizione e chiave di ordinamento.

La sintassi per un'espressione di filtro è identica a quella di un'espressione di condizione. Le espressioni di filtro possono utilizzare gli stessi comparatori, funzioni e operatori logici come espressione di condizione. Per ulteriori informazioni sugli operatori logici, consulta [Espressioni, operatori e funzioni di condizione e di filtro in DynamoDB](Expressions.OperatorsAndFunctions.md).

**Example**  
L'esempio seguente AWS Command Line Interface (AWS CLI) analizza la `Thread` tabella e restituisce solo gli ultimi elementi inviati da un determinato utente.  

```
aws dynamodb scan \
     --table-name Thread \
     --filter-expression "LastPostedBy = :name" \
     --expression-attribute-values '{":name":{"S":"User A"}}'
```

## Limitazione del numero di elementi nel set di risultati
<a name="Scan.Limit"></a>

L'operazione `Scan` consente di limitare il numero di item restituiti nel risultato. A questo scopo, imposta il parametro `Limit` sul numero massimo di item che devono essere restituiti dall'operazione `Scan`, prima di filtrare la valutazione dell'espressione.

Ad esempio, supponi di eseguire un'operazione `Scan` su una tabella con un valore `Limit` di `6` e senza un'espressione di filtro. Il risultato `Scan` contiene i primi sei elementi della tabella.

Supponi ora di aggiungere un'espressione di filtro a `Scan`. In questo caso, DynamoDB applica l'espressione di filtro ai sei elementi che sono stati restituiti, eliminando quelli che non corrispondono. Il risultato finale dell'operazione `Scan` contiene al massimo 6 item, a seconda del numero di quelli che sono stati filtrati.

## Paginazione dei risultati
<a name="Scan.Pagination"></a>

DynamoDB esegue la *paginazione* dei risultati delle operazioni `Scan`. Con la paginazione, i risultati della `Scan` vengono divisi in "pagine" di dati la cui dimensione è al massimo 1 MB. Un'applicazione può elaborare la prima pagina dei risultati, quindi la seconda pagina e così via.

Una singola operazione `Scan` restituisce solo un set di risultati che rientra nel limite di dimensione di 1 MB. 

Per determinare se ci sono più risultati e recuperarli una pagina alla volta, le applicazioni devono fare quanto segue:

1. Esamina i risultati della `Scan` di livello inferiore:
   + Se il risultato contiene un elemento `LastEvaluatedKey`, passa alla fase 2.
   + Se *non* è presente un item `LastEvaluatedKey` nel risultato non ci sono altri item da recuperare.

1. Costruire una nuova richiesta `Scan`, con gli stessi parametri della precedente. Tuttavia, questa volta, accettare il valore `LastEvaluatedKey` della fase 1 e usarlo come parametro `ExclusiveStartKey` nella nuova richiesta di `Scan`.

1. Eseguire la nuova richiesta di `Scan`.

1. Passa alla fase 1.

In altre parole, l'item `LastEvaluatedKey` della risposta di uno `Scan` deve essere usato come item `ExclusiveStartKey` per la successiva richiesta di `Scan`. Se non è presente un elemento `LastEvaluatedKey` nella risposta `Scan`, è stata recuperata la pagina finale dei risultati. L'assenza di `LastEvaluatedKey` è l'unico modo per sapere che hai raggiunto la fine del set di risultati.

È possibile utilizzare il AWS CLI per visualizzare questo comportamento. AWS CLI Invia `Scan` richieste di basso livello a DynamoDB, ripetutamente, `LastEvaluatedKey` fino a quando non è più presente nei risultati. Considerate l' AWS CLI esempio seguente che analizza l'intera `Movies` tabella ma restituisce solo i film di un genere particolare.

```
aws dynamodb scan \
    --table-name Movies \
    --projection-expression "title" \
    --filter-expression 'contains(info.genres,:gen)' \
    --expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \
    --page-size 100  \
    --debug
```

Normalmente, AWS CLI gestisce l'impaginazione automaticamente. Tuttavia, in questo esempio, il AWS CLI `--page-size` parametro limita il numero di elementi per pagina. Il parametro `--debug` consente di stampare le informazioni di livello inferiore relative alle richieste e alle risposte.

**Nota**  
I risultati dell'impaginazione varieranno anche in base ai parametri di input che vengono passati.   
L’utilizzo di `aws dynamodb scan --table-name Prices --max-items 1` restituisce un `NextToken`
L’utilizzo di `aws dynamodb scan --table-name Prices --limit 1` restituisce un `LastEvaluatedKey`.
Inoltre, tieni presente che l'uso di `--starting-token` in particolare richiede il valore `NextToken`. 

Se si esegue l'esempio, l'aspetto della prima risposta da DynamoDB sarà simile al seguente.

```
2017-07-07 12:19:14,389 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":7,"Items":[{"title":{"S":"Monster on the Campus"}},{"title":{"S":"+1"}},
{"title":{"S":"100 Degrees Below Zero"}},{"title":{"S":"About Time"}},{"title":{"S":"After Earth"}},
{"title":{"S":"Age of Dinosaurs"}},{"title":{"S":"Cloudy with a Chance of Meatballs 2"}}],
"LastEvaluatedKey":{"year":{"N":"2013"},"title":{"S":"Curse of Chucky"}},"ScannedCount":100}'
```

L'item `LastEvaluatedKey` nella risposta indica che non tutti gli elementi sono stati recuperati. AWS CLI Quindi invia un'altra `Scan` richiesta a DynamoDB. Questo modello di richiesta e risposta continua fino alla risposta finale.

```
2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'
```

L'assenza di `LastEvaluatedKey` indica che non ci sono più item da recuperare.

**Nota**  
 AWS SDKs Gestiscono le risposte DynamoDB di basso livello (inclusa la presenza o l'assenza di) e forniscono varie astrazioni per l'impaginazione `LastEvaluatedKey` dei risultati. `Scan` Ad esempio, l'interfaccia del documento SDK per Java fornisce il supporto `java.util.Iterator` per poter esaminare i risultati uno alla volta.  
Per esempi di codice in vari linguaggi di programmazione, consulta la [Guida alle operazioni di base di Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/) e la documentazione dell'SDK AWS per il linguaggio in uso.

## Conteggio degli elementi nei risultati
<a name="Scan.Count"></a>

Oltre agli elementi che corrispondono ai tuoi criteri, la risposta `Scan` contiene i seguenti elementi:
+ `ScannedCount`: il numero di elementi valutati, prima di qualsiasi `ScanFilter`applicato. Un valore `ScannedCount` elevato con pochi o nessun risultato `Count` indica un'operazione `Scan` inefficiente. Se non hai utilizzato un filtro nella richiesta, allora `ScannedCount` e `Count` avranno lo stesso valore. 
+ `Count`: il numero di elementi che rimangono *dopo* aver applicato un'espressione di filtro (se presente).

**Nota**  
Se non si utilizza un'espressione di filtro, `ScannedCount` e `Count` hanno lo stesso valore.

Se la dimensione del set di risultati di `Scan` è maggiore di 1 MB, `ScannedCount` e `Count` rappresentano solo un conteggio parziale degli elementi totali. Devi eseguire più operazioni `Scan` per recuperare tutti i risultati (consulta [Paginazione dei risultati](#Scan.Pagination)).

Ogni risposta di `Scan` contiene `ScannedCount` e `Count` per gli elementi che sono stati elaborati da quella particolare richiesta `Scan`. Per ottenere i totali generali per tutte le richieste `Scan`, puoi mantenere in esecuzione il conteggio per entrambi gli elementi `ScannedCount` e `Count`.

## Unità di capacità utilizzate dalla scansione
<a name="Scan.CapacityUnits"></a>

È possibile effettuare la `Scan` di qualsiasi tabella o indice secondario. Le operazioni `Scan` consumano le unità di capacità di lettura come riportato di seguito:


****  

| Se si esegue `Scan` per un... | DynamoDB utilizza le unità di capacità in lettura da... | 
| --- | --- | 
| Tabella | La capacità di lettura assegnata della tabella. | 
| Indice secondario globale | La capacità di lettura assegnata dell'indice. | 
| Indice secondario locale | La capacità di lettura assegnata della tabella di base. | 

**Nota**  
L’accesso multi-account per le operazioni di scansione degli indici secondari non è attualmente supportato dalle [policy basate su risorse](access-control-resource-based.md).

Per impostazione predefinita, un'operazione `Scan` non restituisce alcun dato sulla capacità di lettura che consuma. Tuttavia, puoi specificare il parametro `ReturnConsumedCapacity` in una richiesta di `Scan` per ottenere queste informazioni. Le seguenti sono le impostazioni valide per `ReturnConsumedCapacity`:
+ `NONE`: non vengono restituiti dati relativi alla capacità utilizzata. Questa è l'impostazione predefinita.
+ `TOTAL`: la risposta include il numero aggregato di unità di capacità di lettura utilizzate.
+ `INDEXES`: la risposta mostra il numero aggregato di unità di capacità di lettura utilizzate, insieme alla capacità utilizzata per ogni tabella e indice a cui è stato effettuato l'accesso.

DynamoDB calcola il numero di unità di capacità di lettura utilizzate in base al numero di elementi e alla dimensione di quegli elementi, non alla quantità di dati restituiti a un’applicazione. Per questo motivo, il numero di unità di capacità consumate è lo stesso sia che tu richieda tutti gli attributi (il comportamento predefinito) o solo alcuni di essi (usando un'espressione di proiezione). Il numero è lo stesso anche indipendentemente dal fatto che si utilizzi o meno un’espressione di filtro. `Scan` utilizza un’unità di capacità di lettura minima per eseguire un’operazione a elevata consistenza di lettura al secondo o due letture a coerenza finale al secondo per un elemento di un massimo di 4 KB. Se è necessario leggere un elemento che è più grande di 4 KB, DynamoDB necessità di unità di richiesta di lettura aggiuntive. Le tabelle vuote e le tabelle molto grandi che hanno una quantità limitata di chiavi di partizione potrebbero comportare costi aggiuntivi RCUs oltre alla quantità di dati scansionati. Ciò copre il costo di evasione della richiesta `Scan` anche in assenza di dati.

## Consistenza di lettura per la scansione
<a name="Scan.ReadConsistency"></a>

Un'operazione `Scan` esegue letture consistenti finali per impostazione predefinita. Ciò significa che i risultati di `Scan` potrebbero non riflettere le modifiche dovute alle operazioni `PutItem` o `UpdateItem` completate di recente. Per ulteriori informazioni, consulta [Coerenza di lettura di DynamoDB](HowItWorks.ReadConsistency.md).

Se hai bisogno di letture fortemente consistenti, dal momento in cui inizia lo `Scan`, imposta il parametro `ConsistentRead` su `true` nella richiesta di `Scan`. Ciò garantisce che tutte le operazioni di scrittura completate prima dell'inizio dell'operazione `Scan` sono incluse nella risposta `Scan`. 

L'impostazione di `ConsistentRead` su `true` può essere utile negli scenari di backup o replica delle tabelle, insieme a [DynamoDB Streams](./Streams.html). Per prima cosa, usa `Scan` con `ConsistentRead` impostato su true, per ottenere una copia coerente dei dati nella tabella. Durante l'operazione `Scan`, DynamoDB Streams registra qualsiasi attività di scrittura aggiuntiva che si verifica sulla tabella. Al termine dell'operazione `Scan`, puoi applicare l'attività di scrittura dal flusso alla tabella.

**Nota**  
Un'operazione `Scan` con `ConsistentRead` impostato su `true` consuma il doppio delle unità di capacità in lettura, rispetto a lasciare `ConsistentRead` sul valore predefinito (`false`).

## Scansione parallela
<a name="Scan.ParallelScan"></a>

Per impostazione predefinita, l'operazione `Scan` elabora i dati in sequenza. Amazon DynamoDB restituisce i dati all'applicazione in incrementi di 1 MB e un'applicazione esegue ulteriori operazioni `Scan` per recuperare il successivo 1 MB di dati. 

Più grande è la tabella o l'indice da sottoporre a scansione, più tempo richiederà `Scan` per il completamento. Inoltre, un'operazione `Scan` sequenziale potrebbe non essere sempre in grado di utilizzare completamente la capacità effettiva di trasmissione di lettura assegnata: anche se DynamoDB distribuisce i dati di una tabella di grandi dimensioni su più partizioni fisiche, un'operazione `Scan` può leggere solo una partizione alla volta. Per questo motivo, la velocità effettiva di una `Scan` è vincolata dalla velocità effettiva massima di una singola partizione.

Per risolvere questi problemi, l'operazione `Scan` può dividere in modo logico una tabella o un indice secondario in più *segmenti*, con più worker dell'applicazione che eseguono la scansione dei segmenti in parallelo. Ogni worker può essere un thread (in linguaggi di programmazione che supportano il multithreading) o un processo del sistema operativo. Per eseguire una scansione parallela, ogni worker emette la propria richiesta `Scan` con i seguenti parametri:
+ `Segment`: un segmento che deve essere sottoposto a scansione da un particolare worker. Ogni worker deve utilizzare un valore diverso per `Segment`.
+ `TotalSegments`: il numero totale dei segmenti per la scansione parallela. Il valore deve essere identico al numero di worker che saranno utilizzati dall'applicazione.

Nel diagramma riportato di seguito viene illustrato come un'applicazione multithread esegue una `Scan` parallela con tre gradi di parallelismo.

![\[Un’applicazione multi-thread che esegue una scansione parallela dividendo una tabella in tre segmenti.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/ParallelScan.png)




In questo diagramma, l'applicazione genera tre thread e assegna a ogni thread un numero. (Il primo numero dei segmenti è sempre 0.) Ogni thread emette una richiesta `Scan`, impostando `Segment` sul suo numero designato e `TotalSegments` su 3. Ogni thread esegue la scansione del segmento designato, recuperando i dati 1 MB alla volta e restituisce i dati al thread principale dell'applicazione.

DynamoDB *assegna gli elementi ai* segmenti applicando una funzione hash alla chiave di partizione di ciascun elemento. Per un determinato `TotalSegments` valore, tutti gli elementi con la stessa chiave di partizione vengono sempre assegnati allo stesso valore. `Segment` Ciò significa che in una tabella in cui *Item 1*, *Item 2* e *Item 3* condividono tutti `pk="account#123"` (ma hanno chiavi di ordinamento diverse), questi elementi verranno elaborati dallo stesso lavoratore, indipendentemente dai valori delle chiavi di ordinamento o dalla dimensione della *raccolta di elementi*.

Poiché l'assegnazione dei *segmenti* si basa esclusivamente sull'hash della chiave di partizione, i segmenti possono essere distribuiti in modo non uniforme. Alcuni segmenti potrebbero non contenere elementi, mentre altri potrebbero contenere molte chiavi di partizione con raccolte di elementi di grandi dimensioni. Di conseguenza, l'aumento del numero totale di segmenti non garantisce prestazioni di scansione più rapide, in particolare quando le chiavi di partizione non sono distribuite uniformemente nello spazio delle chiavi.

I valori per `Segment` e `TotalSegments` si applicano alle singole richieste `Scan` ed è possibile usare valori diversi in qualsiasi momento. Potrebbe essere necessario fare diverse prove con questi valori e il numero di worker utilizzati fino a quando l'applicazione non raggiunge le prestazioni migliori.

**Nota**  
Una scansione parallela con un numero elevato di worker può facilmente utilizzare tutta la velocità effettiva assegnata per la tabella o l'indice da sottoporre a scansione. È preferibile evitare tali scansioni se la tabella o l'indice subiscono anche un'intensa attività di lettura o scrittura da altre applicazioni.  
Per controllare la quantità di dati restituiti per ogni richiesta, utilizza il parametro `Limit`. Ciò consente di evitare situazioni in cui un worker utilizza tutta la velocità effettiva assegnata a spese di tutti gli altri worker.

# PartiQL: un linguaggio di query compatibile con SQL per Amazon DynamoDB
<a name="ql-reference"></a>

Amazon DynamoDB supporta [PartiQL](https://partiql.org/), un linguaggio di query compatibile con SQL, per selezionare, inserire, aggiornare ed eliminare i dati in Amazon DynamoDB. Utilizzando PartiQL, è possibile interagire facilmente con le tabelle DynamoDB ed eseguire query ad hoc utilizzando NoSQL Workbench e Console di gestione AWS DynamoDB for PartiQL. AWS Command Line Interface APIs 

Le operazioni PartiQL forniscono la stessa disponibilità, latenza e prestazioni delle altre operazioni del piano dati di DynamoDB.

Nelle sezioni seguenti viene descritta l'implementazione DynamoDB di PartiQL.

**Topics**
+ [Che cos'è PartiQL?](#ql-reference.what-is)
+ [PartiQL in Amazon DynamoDB](#ql-reference.what-is)
+ [Nozioni di base](ql-gettingstarted.md)
+ [Tipi di dati](ql-reference.data-types.md)
+ [Istruzioni](ql-reference.statements.md)
+ [Funzioni](ql-functions.md)
+ [Operatori](ql-operators.md)
+ [Transazioni](ql-reference.multiplestatements.transactions.md)
+ [Operazioni batch](ql-reference.multiplestatements.batching.md)
+ [Policy IAM](ql-iam.md)

## Che cos'è PartiQL?
<a name="ql-reference.what-is"></a>

*PartiQL* consente l'accesso alle query compatibile con SQL su più archivi dati contenenti dati strutturati, semistrutturati e nidificati. È ampiamente utilizzato in Amazon ed è ora disponibile come parte di molti AWS servizi, incluso DynamoDB.

Per la specifica PartiQL e un tutorial sul linguaggio delle query di base, consulta la [Documentazione di PartiQL](https://partiql.org/docs.html).

**Nota**  
Amazon DynamoDB supporta un *sottoinsieme* del linguaggio di query [PartiQL](https://partiql.org/).
Amazon DynamoDB non supporta il formato dati [Amazon Ion](http://amzn.github.io/ion-docs/) o i letterali Amazon Ion.

## PartiQL in Amazon DynamoDB
<a name="ql-reference.what-is"></a>

Per eseguire query PartiQL in DynamoDB, è possibile utilizzare:
+ La console DynamoDB
+ NoSQL Workbench
+ Il AWS Command Line Interface ()AWS CLI
+ Il DynamoDB APIs

Per informazioni sull'utilizzo di questi metodi per accedere a DynamoDB, consulta [Accesso a DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html).

# Nozioni di base su PartiQL per DynamoDB
<a name="ql-gettingstarted"></a>

Questa sezione descrive come utilizzare PartiQL per DynamoDB dalla console Amazon DynamoDB, the () e DynamoDB. AWS Command Line Interface AWS CLI APIs

Nei seguenti esempi, la tabella DynamoDB definita nel tutorial [Nozioni di base su DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html) è un prerequisito.

[Per informazioni sull'utilizzo della console DynamoDB o DynamoDB per accedere a DynamoDB AWS Command Line Interface, vedere Accesso a APIs DynamoDB.](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/AccessingDynamoDB.html)

Per [scaricare](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html) e utilizzare [NoSQL Workbench](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html) per creare istruzioni [PartiQL per DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html), seleziona **Operazioni PartiQL** nell'angolo in alto a destra dell'[Operation builder](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.querybuilder.operationbuilder.html) di NoSQL Workbench per DynamoDB.

------
#### [ Console ]

![\[Interfaccia dell’editor PartiQL che mostra il risultato dell’esecuzione dell’operazione Query sulla tabella Musica.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/partiqlgettingstarted.png)


1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Nel pannello di navigazione sul lato sinistro della console seleziona **Editor PartiQL**.

1. Seleziona la tabella **Music**.

1. Scegli **Esegui query sulla tabella**. Questa azione genera una query che non determinerà una scansione completa della tabella.

1. Sostituisci `partitionKeyValue` con il valore stringa `Acme Band`. Sostituisci `sortKeyValue` con il valore stringa `Happy Day`.

1. Scegli il pulsante **Esegui**. 

1. È possibile visualizzare i risultati della query scegliendo i pulsanti **Vista tabella** o **Vista JSON**. 

------
#### [ NoSQL workbench ]

![\[Interfaccia NoSQL Workbench. Mostra un’istruzione PartiQL SELECT che è possibile eseguire sulla tabella Musica.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/workbench/partiql.single.png)


1. Scegli **Istruzione PartiQL**.

1. Specifica la seguente [istruzione SELECT (SELEZIONA)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html) PartiQL. 

   ```
   SELECT *                                         
   FROM Music  
   WHERE Artist=? and SongTitle=?
   ```

1. Per specificare un valore per i parametri `Artist` e `SongTitle`:

   1. Scegli **Parametri di richiesta facoltativi**.

   1. Scegli **Aggiungi nuovi parametri**.

   1. Scegli il tipo di attributo **string** e il valore `Acme Band`.

   1. Ripeti i passaggi b e c, quindi scegli il tipo **string** e il valore `PartiQL Rocks`. 

1. Per generare codice, selezionare **Generate code (Genera codice)**.

   Selezionare la lingua desiderata dalle schede visualizzate. È possibile copiare questo codice e utilizzarlo nell'applicazione.

1. Per eseguire l'operazione immediatamente, seleziona **Esegui**.

------
#### [ AWS CLI ]

1. Crea un elemento nella tabella `Music` utilizzando l'istruzione INSERT (INSERISCI) PartiQL. 

   ```
   aws dynamodb execute-statement --statement "INSERT INTO Music  \
   					    VALUE  \
   					    {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"
   ```

1. Recupera un elemento dalla tabella Music utilizzando l'istruzione SELECT (SELEZIONA) PartiQL.

   ```
   aws dynamodb execute-statement --statement "SELECT * FROM Music   \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Aggiorna un elemento nella tabella `Music` utilizzando l'istruzione UPDATE (AGGIORNA) PartiQL.

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardsWon=1  \
                                               SET AwardDetail={'Grammys':[2020, 2018]}  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Aggiungi un valore di elenco per un elemento nella tabella `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Rimuovi un valore di elenco per un elemento nella tabella `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               REMOVE AwardDetail.Grammys[2]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Aggiungi un nuovo membro della mappa per un elemento nella tabella `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET AwardDetail.BillBoard=[2020]  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Aggiungi un nuovo attributo del set di stringhe per un elemento nella tabella `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =<<'member1', 'member2'>>  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

   Aggiungi un attributo del set di stringhe per un elemento nella tabella `Music`. 

   ```
   aws dynamodb execute-statement --statement "UPDATE Music  \
                                               SET BandMembers =set_add(BandMembers, <<'newmember'>>)  \
                                               WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

1. Elimina un elemento dalla tabella `Music` utilizzando l'istruzione DELETE (ELIMINA) PartiQL.

   ```
   aws dynamodb execute-statement --statement "DELETE  FROM Music  \
       WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
   ```

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

```
import java.util.ArrayList;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import software.amazon.dynamodb.AmazonDynamoDB;
import software.amazon.dynamodb.AmazonDynamoDBClientBuilder;
import software.amazon.dynamodb.model.AttributeValue;
import software.amazon.dynamodb.model.ConditionalCheckFailedException;
import software.amazon.dynamodb.model.ExecuteStatementRequest;
import software.amazon.dynamodb.model.ExecuteStatementResult;
import software.amazon.dynamodb.model.InternalServerErrorException;
import software.amazon.dynamodb.model.ItemCollectionSizeLimitExceededException;
import software.amazon.dynamodb.model.ProvisionedThroughputExceededException;
import software.amazon.dynamodb.model.RequestLimitExceededException;
import software.amazon.dynamodb.model.ResourceNotFoundException;
import software.amazon.dynamodb.model.TransactionConflictException;

public class DynamoDBPartiQGettingStarted {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-1");

        try {
            // Create ExecuteStatementRequest
            ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
            List<AttributeValue> parameters= getPartiQLParameters();

            //Create an item in the Music table using the INSERT PartiQL statement
            processResults(executeStatementRequest(dynamoDB, "INSERT INTO Music value {'Artist':?,'SongTitle':?}", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //Update an item in the Music table using the UPDATE PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist=? and SongTitle=?", parameters));

            //Add a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  where Artist=? and SongTitle=?", parameters));

            //Remove a list value for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music REMOVE AwardDetail.Grammys[2]   where Artist=? and SongTitle=?", parameters));

            //Add a new map member for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music set AwardDetail.BillBoard=[2020] where Artist=? and SongTitle=?", parameters));

            //Add a new string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =<<'member1', 'member2'>> where Artist=? and SongTitle=?", parameters));

            //update a string set attribute for an item in the Music table.
            processResults(executeStatementRequest(dynamoDB, "UPDATE Music SET BandMembers =set_add(BandMembers, <<'newmember'>>) where Artist=? and SongTitle=?", parameters));

            //Retrieve an item from the Music table using the SELECT PartiQL statement.
            processResults(executeStatementRequest(dynamoDB, "SELECT * FROM Music  where Artist=? and SongTitle=?", parameters));

            //delete an item from the Music Table
            processResults(executeStatementRequest(dynamoDB, "DELETE  FROM Music  where Artist=? and SongTitle=?", parameters));
        } catch (Exception e) {
            handleExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static List<AttributeValue> getPartiQLParameters() {
        List<AttributeValue> parameters = new ArrayList<AttributeValue>();
        parameters.add(new AttributeValue("Acme Band"));
        parameters.add(new AttributeValue("PartiQL Rocks"));
        return parameters;
    }

    private static ExecuteStatementResult executeStatementRequest(AmazonDynamoDB client, String statement, List<AttributeValue> parameters ) {
        ExecuteStatementRequest request = new ExecuteStatementRequest();
        request.setStatement(statement);
        request.setParameters(parameters);
        return client.executeStatement(request);
    }

    private static void processResults(ExecuteStatementResult executeStatementResult) {
        System.out.println("ExecuteStatement successful: "+ executeStatementResult.toString());

    }

    // Handles errors during ExecuteStatement execution. Use recommendations in error messages below to add error handling specific to
    // your application use-case.
    private static void handleExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (ConditionalCheckFailedException ccfe) {
            System.out.println("Condition check specified in the operation failed, review and update the condition " +
                                       "check before retrying. Error: " + ccfe.getErrorMessage());
        } catch (TransactionConflictException tce) {
            System.out.println("Operation was rejected because there is an ongoing transaction for the item, generally " +
                                       "safe to retry with exponential back-off. Error: " + tce.getErrorMessage());
        } catch (ItemCollectionSizeLimitExceededException icslee) {
            System.out.println("An item collection is too large, you\'re using Local Secondary Index and exceeded " +
                                       "size limit of items per partition key. Consider using Global Secondary Index instead. Error: " + icslee.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " +
                                       "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                                       "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " +
                                       ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " +
                                       "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                                       "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                                       "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                                       "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

## Utilizzo di istruzioni parametrizzate
<a name="ql-gettingstarted.parameterized"></a>

Invece di incorporare i valori direttamente in una stringa di istruzioni PartiQL, è possibile utilizzare i segnaposto con punto interrogativo `?` () e fornire i valori separatamente nel campo. `Parameters` Ciascuno `?` viene sostituito dal valore del parametro corrispondente, nell'ordine in cui vengono forniti.

L'uso di istruzioni con parametri è una buona pratica perché separa la struttura delle istruzioni dai valori dei dati, semplificando la lettura e il riutilizzo delle istruzioni. Inoltre, evita la necessità di formattare manualmente ed eliminare i valori degli attributi nella stringa dell'istruzione.

Le istruzioni con parametri sono supportate nelle operazioni `ExecuteStatement` e`BatchExecuteStatement`. `ExecuteTransaction`

Gli esempi seguenti recuperano un elemento dalla `Music` tabella utilizzando valori parametrizzati per la chiave di partizione e la chiave di ordinamento.

------
#### [ AWS CLI parameterized ]

```
aws dynamodb execute-statement \
    --statement "SELECT * FROM \"Music\" WHERE Artist=? AND SongTitle=?" \
    --parameters '[{"S": "Acme Band"}, {"S": "PartiQL Rocks"}]'
```

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

```
List<AttributeValue> parameters = new ArrayList<>();
parameters.add(new AttributeValue("Acme Band"));
parameters.add(new AttributeValue("PartiQL Rocks"));

ExecuteStatementRequest request = new ExecuteStatementRequest()
    .withStatement("SELECT * FROM Music WHERE Artist=? AND SongTitle=?")
    .withParameters(parameters);

ExecuteStatementResult result = dynamoDB.executeStatement(request);
```

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

```
response = dynamodb_client.execute_statement(
    Statement="SELECT * FROM Music WHERE Artist=? AND SongTitle=?",
    Parameters=[
        {'S': 'Acme Band'},
        {'S': 'PartiQL Rocks'}
    ]
)
```

------

**Nota**  
L'esempio Java nella precedente sezione introduttiva utilizza dappertutto istruzioni con parametri. Il `getPartiQLParameters()` metodo crea l'elenco dei parametri e ogni istruzione utilizza `?` segnaposto anziché valori in linea.

# Tipi di dati PartiQL per DynamoDB
<a name="ql-reference.data-types"></a>

Nella tabella seguente sono elencati i tipi di dati che è possibile utilizzare con PartiQL per DynamoDB.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/ql-reference.data-types.html)

## Esempi
<a name="ql-reference.data-types"></a>

Nell'istruzione seguente viene illustrato come inserire i seguenti tipi di dati: `String`, `Number`, `Map`, `List`, `Number Set` e `String Set`.

```
INSERT INTO TypesTable value {'primarykey':'1', 
'NumberType':1,
'MapType' : {'entryname1': 'value', 'entryname2': 4}, 
'ListType': [1,'stringval'], 
'NumberSetType':<<1,34,32,4.5>>, 
'StringSetType':<<'stringval','stringval2'>>
}
```

La seguente istruzione illustra come inserire nuovi elementi nei tipi `Map`, `List`, `Number Set` e `String Set` e come modificare il valore di un tipo `Number`.

```
UPDATE TypesTable 
SET NumberType=NumberType + 100 
SET MapType.NewMapEntry=[2020, 'stringvalue', 2.4]
SET ListType = LIST_APPEND(ListType, [4, <<'string1', 'string2'>>])
SET NumberSetType= SET_ADD(NumberSetType, <<345, 48.4>>)
SET StringSetType = SET_ADD(StringSetType, <<'stringsetvalue1', 'stringsetvalue2'>>)
WHERE primarykey='1'
```

La seguente istruzione illustra come rimuovere gli elementi dai tipi `Map`, `List`, `Number Set` e `String Set` e come modificare il valore di un tipo `Number`.

```
UPDATE TypesTable 
SET NumberType=NumberType - 1
REMOVE ListType[1]
REMOVE MapType.NewMapEntry
SET NumberSetType = SET_DELETE( NumberSetType, <<345>>)
SET StringSetType = SET_DELETE( StringSetType, <<'stringsetvalue1'>>)
WHERE primarykey='1'
```

Per ulteriori informazioni, consulta [Tipi di dati di DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes).

# Istruzioni PartiQL per DynamoDB
<a name="ql-reference.statements"></a>

Amazon DynamoDB supporta le seguenti istruzioni PartiQL.

**Nota**  
DynamoDB non supporta tutte le istruzioni PartiQL.  
Questo riferimento fornisce esempi di sintassi di base ed esempi di utilizzo delle istruzioni PartiQL eseguite manualmente utilizzando AWS CLI o. APIs

Il *linguaggio di manipolazione dei dati* (DML, Data Manipulation Language) è l'insieme di istruzioni PartiQL utilizzate per gestire i dati nelle tabelle DynamoDB. Le istruzioni DML vengono utilizzate per aggiungere, modificare o eliminare i dati in una tabella.

Sono supportate le seguenti istruzioni DML e del linguaggio di query:
+ [Istruzioni SELECT PartiQL per DynamoDB](ql-reference.select.md)
+ [Istruzioni UPDATE PartiQL per DynamoDB](ql-reference.update.md)
+ [Istruzioni INSERT PartiQL per DynamoDB](ql-reference.insert.md)
+ [Istruzioni DELETE PartiQL per DynamoDB](ql-reference.delete.md)

Anche [Esecuzione di transazioni con PartiQL per DynamoDB](ql-reference.multiplestatements.transactions.md) e [Esecuzione di operazioni in batch con PartiQL per DynamoDB](ql-reference.multiplestatements.batching.md) sono supportati da PartiQL per DynamoDB.

# Istruzioni SELECT PartiQL per DynamoDB
<a name="ql-reference.select"></a>

Utilizza l'istruzione `SELECT` per recuperare i dati da una tabella in Amazon DynamoDB.

L’uso di un’istruzione `SELECT` può comportare una scansione completa della tabella se non si fornisce una condizione di uguaglianza o IN con una chiave di partizione nella clausola WHERE. L'operazione di scansione esamina ogni elemento per i valori richiesti e può utilizzare la velocità effettiva assegnata per una tabella o un indice di grandi dimensioni in un'unica operazione. 

Se desideri evitare la scansione completa della tabella in PartiQL, è possibile:
+ Crea le tue istruzioni `SELECT` per non provocare scansioni complete della tabella assicurandoti che la [condizione della clausola WHERE (DOVE)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html#ql-reference.select.parameters) sia configurata di conseguenza.
+ Disabilitare le scansioni di tabelle complete utilizzando la policy IAM specificata in [Esempio: Consentire le istruzioni Select e rifiutare le istruzioni di scansione completa della tabella in PartiQL per DynamoDB](ql-iam.md#access-policy-ql-iam-example6), nella Guida per gli sviluppatori di DynamoDB.

Per ulteriori informazioni, consulta la sezione [Best practice per eseguire query e scansioni di dati](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html) nella Guida per gli sviluppatori di DynamoDB.

**Topics**
+ [Sintassi](#ql-reference.select.syntax)
+ [Parameters](#ql-reference.select.parameters)
+ [Esempi](#ql-reference.select.examples)

## Sintassi
<a name="ql-reference.select.syntax"></a>

```
SELECT expression  [, ...] 
FROM table[.index]
[ WHERE condition ] [ [ORDER BY key [DESC|ASC] , ...]
```

## Parameters
<a name="ql-reference.select.parameters"></a>

***expression***  
(Obbligatorio) Una proiezione formata dal carattere jolly `*` o un elenco di proiezione di uno o più nomi di attributi o percorsi di documento dal set di risultati. Un'espressione può essere costituita da chiamate a [Utilizzo delle funzioni PartiQL con DynamoDB](ql-functions.md) o da campi modificati da [Operatori PartiQL aritmetici, di confronto e logici per DynamoDB](ql-operators.md).

***table***  
(Obbligatorio) Il nome della tabella per cui eseguire la query.

***index***  
(Facoltativo) Il nome dell'indice su cui eseguire una query.  
È necessario aggiungere virgolette doppie al nome della tabella e al nome dell'indice quando si esegue una query su un indice.  

```
SELECT * 
FROM "TableName"."IndexName"
```

***condition***  
(Facoltativo) I criteri di selezione per la query.  
Per garantire che una istruzione `SELECT` non comporti una scansione completa della tabella, la condizione della clausola `WHERE` deve specificare una chiave di partizione. Utilizza l'operatore di uguaglianza o IN.  
Ad esempio, in presenza di una tabella `Orders` con una chiave di partizione `OrderID` e altri attributi non chiave, tra cui `Address`, le istruzioni seguenti non comportano una scansione completa della tabella:  

```
SELECT * 
FROM "Orders" 
WHERE OrderID = 100

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 and Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 or OrderID = 200

SELECT * 
FROM "Orders" 
WHERE OrderID IN [100, 300, 234]
```
Le seguenti istruzioni `SELECT`, tuttavia, provocheranno una scansione completa della tabella:  

```
SELECT * 
FROM "Orders" 
WHERE OrderID > 1

SELECT * 
FROM "Orders" 
WHERE Address='some address'

SELECT * 
FROM "Orders" 
WHERE OrderID = 100 OR Address='some address'
```

***key***  
(Facoltativo) Una chiave hash o una chiave di ordinamento da utilizzare per ordinare i risultati restituiti. L'ordine di default è crescente (`ASC`); specifica `DESC` se desideri che i risultati vengano rigenerati in ordine decrescente.

**Nota**  
Se si omette la clausola `WHERE`, saranno recuperati tutti gli elementi della tabella.

## Esempi
<a name="ql-reference.select.examples"></a>

La seguente query restituisce un elemento, se esistente, dalla tabella `Orders` specificando la chiave di partizione, `OrderID`, e utilizzando l'operatore di uguaglianza.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1
```

La seguente query restituisce tutti gli elementi nella tabella `Orders` che hanno una chiave di partizione specifica, `OrderID`, i valori che utilizzano l'operatore OR.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID = 1 OR OrderID = 2
```

La seguente query restituisce tutti gli elementi nella tabella `Orders` che hanno una chiave di partizione specifica, `OrderID`, i valori che utilizzano l'operatore IN. I risultati restituiti sono in ordine decrescente, in base al valore dell'attributo della chiave `OrderID`.

```
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC
```

La seguente query mostra una scansione completa della tabella che restituisce tutti gli elementi dalla tabella `Orders` che hanno un `Total` maggiore di 500, dove `Total` è un attributo non chiave.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total > 500
```

La seguente query mostra una scansione completa della tabella che restituisce tutti gli elementi dalla tabella `Orders` in un intervallo di ordinamento `Total` specifico, utilizzando l'operatore IN e un attributo non chiave `Total`.

```
SELECT OrderID, Total 
FROM "Orders"
WHERE Total IN [500, 600]
```

La seguente query mostra una scansione completa della tabella che restituisce tutti gli elementi dalla tabella `Orders` in un intervallo di ordinamento `Total` specifico, utilizzando l'operatore BETWEEN e un attributo non chiave `Total`.

```
SELECT OrderID, Total 
FROM "Orders" 
WHERE Total BETWEEN 500 AND 600
```

La seguente query restituisce la prima data in cui è stato utilizzato un dispositivo firestick specificando la chiave di partizione `CustomerID` e la chiave di ordinamento `MovieID` nella condizione clausola WHERE (DOVE) e utilizzando percorsi documento nella clausola SELECT (SELEZIONA).

```
SELECT Devices.FireStick.DateWatched[0] 
FROM WatchList 
WHERE CustomerID= 'C1' AND MovieID= 'M1'
```

La seguente query mostra una scansione completa della tabella che restituisce l'elenco degli elementi in cui un dispositivo firestick è stato utilizzato per la prima volta dopo il 12/12/19 utilizzando percorsi di documento nella condizione della clausola WHERE (DOVE).

```
SELECT Devices 
FROM WatchList 
WHERE Devices.FireStick.DateWatched[0] >= '12/24/19'
```

# Istruzioni UPDATE PartiQL per DynamoDB
<a name="ql-reference.update"></a>

Utilizza l'istruzione `UPDATE` per modificare il valore di uno o più attributi all'interno di un elemento in una tabella Amazon DynamoDB. 

**Nota**  
È possibile aggiornare solo un elemento alla volta; non è possibile emettere una singola istruzione PartiQL DynamoDB che aggiorna più elementi. Per informazioni sull'aggiornamento di più elementi, consulta [Esecuzione di transazioni con PartiQL per DynamoDB](ql-reference.multiplestatements.transactions.md) o [Esecuzione di operazioni in batch con PartiQL per DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintassi](#ql-reference.update.syntax)
+ [Parameters](#ql-reference.update.parameters)
+ [Valore restituito](#ql-reference.update.return)
+ [Esempi](#ql-reference.update.examples)

## Sintassi
<a name="ql-reference.update.syntax"></a>

```
UPDATE  table  
[SET | REMOVE]  path  [=  data] […]
WHERE condition [RETURNING returnvalues]
<returnvalues>  ::= [ALL OLD | MODIFIED OLD | ALL NEW | MODIFIED NEW] *
```

## Parameters
<a name="ql-reference.update.parameters"></a>

***table***  
(Obbligatorio) La tabella contenente i dati da modificare.

***path***  
(Obbligatorio) Un nome attributo o un percorso di documento da creare o modificare.

***data***  
(Obbligatorio) Un valore di attributo o il risultato di un'operazione.  
Le operazioni supportate da utilizzare con SET sono:  
+ LIST\$1APPEND: aggiunge un valore a un tipo di elenco.
+ SET\$1ADD: aggiunge un valore a un numero o un set di stringhe.
+ SET\$1DELETE: rimuove un valore da un numero o un set di stringhe.

***condition***  
(Obbligatorio) I criteri di selezione per l'elemento da modificare. Questa condizione deve essere risolta in un singolo valore di chiave primaria.

***returnvalues***  
(Facoltativo) Utilizza `returnvalues` se desideri ottenere gli attributi dell'elemento come appaiono prima o dopo l'aggiornamento. I valori validi sono:   
+ `ALL OLD *`: restituisce tutti gli attributi dell'elemento come apparivano prima dell'operazione di aggiornamento.
+ `MODIFIED OLD *`: restituisce solo gli attributi aggiornati come apparivano prima dell'operazione di aggiornamento.
+ `ALL NEW *`: restituisce tutti gli attributi dell'elemento come appaiono dopo l'operazione di aggiornamento.
+ `MODIFIED NEW *`: restituisce solo gli attributi aggiornati come appaiono dopo l'operazione `UpdateItem`.

## Valore restituito
<a name="ql-reference.update.return"></a>

Questa istruzione non restituisce un valore a meno che non sia stato specificato il parametro `returnvalues`.

**Nota**  
Se la clausola WHERE (DOVE) dell'istruzione UPDATE (AGGIORNA) non restituisce true per alcun elemento nella tabella DynamoDB, viene restituito `ConditionalCheckFailedException`.

## Esempi
<a name="ql-reference.update.examples"></a>

Aggiorna un valore dell'attributo in un elemento esistente. Se l'attributo non esiste, ne verrà creato uno.

La seguente query aggiorna un elemento nella tabella `"Music"` aggiungendo un attributo di tipo number (`AwardsWon`) e un attributo di tipo map (`AwardDetail`).

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

È possibile aggiungere `RETURNING ALL OLD *` per riportare gli attributi così come apparivano prima dell'operazione `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL OLD *
```

Restituisce quanto segue:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

È possibile aggiungere `RETURNING ALL NEW *` per riportare gli attributi così come apparivano dopo l'operazione `Update`.

```
UPDATE "Music" 
SET AwardsWon=1 
SET AwardDetail={'Grammys':[2020, 2018]}  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
RETURNING ALL NEW *
```

Restituisce quanto segue:

```
{
    "Items": [
        {
            "AwardDetail": {
                "M": {
                    "Grammys": {
                        "L": [
                            {
                                "N": "2020"
                            },
                            {
                                "N": "2018"
                            }
                        ]
                    }
                }
            },
            "AwardsWon": {
                "N": "1"
            }
        }
    ]
}
```

La seguente query aggiorna un elemento nella tabella `"Music"` aggiungendolo a un elenco `AwardDetail.Grammys`.

```
UPDATE "Music" 
SET AwardDetail.Grammys =list_append(AwardDetail.Grammys,[2016])  
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

La seguente query aggiorna un elemento nella tabella `"Music"` rimuovendolo da un elenco `AwardDetail.Grammys`.

```
UPDATE "Music" 
REMOVE AwardDetail.Grammys[2]   
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

La seguente query aggiorna un elemento nella tabella `"Music"` aggiungendo `BillBoard` alla mappa `AwardDetail`.

```
UPDATE "Music" 
SET AwardDetail.BillBoard=[2020] 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

La seguente query aggiorna un elemento nella tabella `"Music"` aggiungendo l'attributo del set di stringhe `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =<<'member1', 'member2'>> 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

La seguente query aggiorna un elemento nella tabella `"Music"` aggiungendo `newbandmember` al set di stringhe `BandMembers`.

```
UPDATE "Music" 
SET BandMembers =set_add(BandMembers, <<'newbandmember'>>) 
WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'
```

# Istruzioni DELETE PartiQL per DynamoDB
<a name="ql-reference.delete"></a>

Utilizza l'istruzione `DELETE` per eliminare un elemento esistente dalla tabella Amazon DynamoDB.

**Nota**  
È possibile eliminare un solo elemento alla volta. Non è possibile emettere una singola istruzione DynamoDB PartiQL che elimina più elementi. Per informazioni sull'aggiornamento di più elementi, consulta [Esecuzione di transazioni con PartiQL per DynamoDB](ql-reference.multiplestatements.transactions.md) o [Esecuzione di operazioni in batch con PartiQL per DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintassi](#ql-reference.delete.syntax)
+ [Parameters](#ql-reference.delete.parameters)
+ [Valore restituito](#ql-reference.delete.return)
+ [Esempi](#ql-reference.delete.examples)

## Sintassi
<a name="ql-reference.delete.syntax"></a>

```
DELETE FROM table 
 WHERE condition [RETURNING returnvalues]
 <returnvalues>  ::= ALL OLD *
```

## Parameters
<a name="ql-reference.delete.parameters"></a>

***table***  
(Obbligatorio) La tabella DynamoDB contenente l'elemento da eliminare.

***condition***  
(Obbligatorio) I criteri di selezione per l'elemento da eliminare. Questa condizione deve essere risolta in un singolo valore di chiave primaria.

***returnvalues***  
(Facoltativo) Utilizza `returnvalues` se desideri ottenere gli attributi dell'elemento come apparivano prima dell'eliminazione. I valori validi sono:   
+ `ALL OLD *`: viene restituito il contenuto del vecchio elemento.

## Valore restituito
<a name="ql-reference.delete.return"></a>

Questa istruzione non restituisce un valore a meno che non sia stato specificato il parametro `returnvalues`.

**Nota**  
Se la tabella DynamoDB non dispone di alcun elemento con la stessa chiave primaria di quella dell'elemento per il quale viene emessa l'istruzione DELETE (ELIMINA), viene restituito SUCCESS (ESITO POSITIVO) con 0 elementi eliminati. Se la tabella ha un elemento con la stessa chiave primaria, ma la condizione nella clausola WHERE (DOVE) dell'istruzione DELETE (ELIMINA) restituisce valore false, viene restituito il parametro `ConditionalCheckFailedException`.

## Esempi
<a name="ql-reference.delete.examples"></a>

La query seguente elimina un elemento nella tabella `"Music"`.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks'
```

È possibile aggiungere il parametro `RETURNING ALL OLD *` per restituire i dati che sono stati eliminati.

```
DELETE FROM "Music" WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks' RETURNING ALL OLD *
```

L'istruzione `Delete` ora restituisce quanto segue:

```
{
    "Items": [
        {
            "Artist": {
                "S": "Acme Band"
            },
            "SongTitle": {
                "S": "PartiQL Rocks"
            }
        }
    ]
}
```

# Istruzioni INSERT PartiQL per DynamoDB
<a name="ql-reference.insert"></a>

Utilizza l'istruzione `INSERT` per aggiungere un elemento a una tabella in Amazon DynamoDB.

**Nota**  
È possibile inserire un solo elemento alla volta; non è possibile emettere una singola istruzione PartiQL DynamoDB che inserisce più elementi. Per informazioni sull'inserimento di più elementi, consulta [Esecuzione di transazioni con PartiQL per DynamoDB](ql-reference.multiplestatements.transactions.md) o [Esecuzione di operazioni in batch con PartiQL per DynamoDB](ql-reference.multiplestatements.batching.md).

**Topics**
+ [Sintassi](#ql-reference.insert.syntax)
+ [Parameters](#ql-reference.insert.parameters)
+ [Valore restituito](#ql-reference.insert.return)
+ [Esempi](#ql-reference.insert.examples)

## Sintassi
<a name="ql-reference.insert.syntax"></a>

Inserisci un singolo elemento.

```
INSERT INTO table VALUE item
```

## Parameters
<a name="ql-reference.insert.parameters"></a>

***table***  
(Obbligatorio) La tabella in cui si desidera inserire i dati. La tabella deve già essere presente.

***item***  
(Obbligatorio) Un elemento DynamoDB valido rappresentato come [tupla PartiQL](https://partiql.org/docs.html). È necessario specificare solo *un* elemento e tenere presente che ciascun nome di attributo nell'elemento fa distinzione tra maiuscole e minuscole e può essere riportato con virgolette *singole* (`'...'`) in PartiQL.  
Anche i valori stringa sono riportati con virgolette *singole* (`'...'`) in PartiQL.

## Valore restituito
<a name="ql-reference.insert.return"></a>

Questa istruzione non restituisce alcun valore.

**Nota**  
Se nella tabella DynamoDB è già presente un elemento con la stessa chiave primaria della chiave primaria dell'elemento da inserire, viene restituito `DuplicateItemException`.

## Esempi
<a name="ql-reference.insert.examples"></a>

```
INSERT INTO "Music" value {'Artist' : 'Acme Band','SongTitle' : 'PartiQL Rocks'}
```

# Utilizzo delle funzioni PartiQL con DynamoDB
<a name="ql-functions"></a>

PartiQL in Amazon DynamoDB supporta le seguenti varianti incorporate di funzioni standard SQL.

**Nota**  
Tutte le funzioni SQL non incluse in questo elenco non sono attualmente supportate in DynamoDB.

## Funzioni di aggregazione
<a name="ql-functions.aggregate"></a>
+ [Utilizzo della funzione SIZE con PartiQL per Amazon DynamoDB](ql-functions.size.md)

## Funzioni condizionali
<a name="ql-functions.conditional"></a>
+ [Utilizzo della funzione EXISTS con PartiQL per DynamoDB](ql-functions.exists.md)
+ [Utilizzo della funzione ATTRIBUTE\$1TYPE con PartiQL per DynamoDB](ql-functions.attribute_type.md)
+ [Utilizzo della funzione BEGINS\$1WITH con PartiQL per DynamoDB](ql-functions.beginswith.md)
+ [Utilizzo della funzione CONTAINS con PartiQL per DynamoDB](ql-functions.contains.md)
+ [Utilizzo della funzione MISSING con PartiQL per DynamoDB](ql-functions.missing.md)

# Utilizzo della funzione EXISTS con PartiQL per DynamoDB
<a name="ql-functions.exists"></a>

È possibile utilizzare EXISTS (ESISTE) per eseguire la stessa funzione che `ConditionCheck` esegue nell'API [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems). La funzione EXISTS (ESISTE) può essere utilizzata solo nelle transazioni.

Dato un valore, restituisce `TRUE` se il valore è una raccolta non vuota. In caso contrario, restituisce `FALSE`.

**Nota**  
Questa funzione può essere utilizzata solo nelle operazioni transazionali.

## Sintassi
<a name="ql-functions.exists.syntax"></a>

```
EXISTS ( statement )
```

## Argomenti
<a name="ql-functions.exists.arguments"></a>

*Istruzione*  
(Obbligatorio) L'istruzione SELECT (SELEZIONA) valutata dalla funzione.  
L'istruzione SELECT (SELEZIONA) deve specificare una chiave primaria completa e un'altra condizione.

## Tipo restituito
<a name="ql-functions.exists.return-type"></a>

`bool`

## Esempi
<a name="ql-functions.exists.examples"></a>

```
EXISTS(
    SELECT * FROM "Music" 
    WHERE "Artist" = 'Acme Band' AND "SongTitle" = 'PartiQL Rocks')
```

# Utilizzo della funzione BEGINS\$1WITH con PartiQL per DynamoDB
<a name="ql-functions.beginswith"></a>

Restituisce `TRUE` se l'attributo specificato inizia con una particolare sottostringa.

## Sintassi
<a name="ql-functions.beginswith.syntax"></a>

```
begins_with(path, value )
```

## Argomenti
<a name="ql-functions.beginswith.arguments"></a>

*path*  
(Obbligatorio) Il nome attributo o il percorso del documento da utilizzare.

*value*  
(Obbligatorio) La stringa da cercare.

## Tipo restituito
<a name="ql-functions.beginswith.return-type"></a>

`bool`

## Esempi
<a name="ql-functions.beginswith.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND begins_with("Address", '7834 24th')
```

# Utilizzo della funzione MISSING con PartiQL per DynamoDB
<a name="ql-functions.missing"></a>

Restituisce `TRUE` se l'elemento non contiene l'attributo specificato. Con questa funzione possono essere utilizzati solo gli operatori di uguaglianza e disuguaglianza.

## Sintassi
<a name="ql-functions.missing.syntax"></a>

```
 attributename IS | IS NOT  MISSING 
```

## Argomenti
<a name="ql-functions.missing.arguments"></a>

*attributename*  
(Obbligatorio) Il nome dell'attributo da utilizzare.

## Tipo restituito
<a name="ql-functions.missing.return-type"></a>

`bool`

## Esempi
<a name="ql-functions.missing.examples"></a>

```
SELECT * FROM Music WHERE "Awards" is MISSING
```

# Utilizzo della funzione ATTRIBUTE\$1TYPE con PartiQL per DynamoDB
<a name="ql-functions.attribute_type"></a>

Restituisce `TRUE` se l'attributo del percorso specificato è di un particolare tipo di dati.

## Sintassi
<a name="ql-functions.attribute_type.syntax"></a>

```
attribute_type( attributename, type )
```

## Argomenti
<a name="ql-functions.attribute_type.arguments"></a>

*attributename*  
(Obbligatorio) Il nome dell'attributo da utilizzare.

*tipo*  
(Obbligatorio) Il tipo di attributo da controllare. Per visualizzare un elenco di valori validi, consulta [attribute\$1type](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) di DynamoDB.

## Tipo restituito
<a name="ql-functions.attribute_type.return-type"></a>

`bool`

## Esempi
<a name="ql-functions.attribute_type.examples"></a>

```
SELECT * FROM "Music" WHERE attribute_type("Artist", 'S')
```

# Utilizzo della funzione CONTAINS con PartiQL per DynamoDB
<a name="ql-functions.contains"></a>

Restituisce `TRUE` se l'attributo specificato dal percorso è uno dei seguenti:
+ Una stringa che contiene una particolare sottostringa. 
+ Un set che contiene un particolare determinato elemento.

Per ulteriori informazioni, consulta la funzione [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) di DynamoDB. 

## Sintassi
<a name="ql-functions.contains.syntax"></a>

```
contains( path, substring )
```

## Argomenti
<a name="ql-functions.contains.arguments"></a>

*path*  
(Obbligatorio) Il nome attributo o il percorso del documento da utilizzare.

*sottostringa*  
(Obbligatorio) La sottostringa dell'attributo o il membro del set da controllare. Per ulteriori informazioni, consulta la funzione [contains](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) di DynamoDB.

## Tipo restituito
<a name="ql-functions.contains.return-type"></a>

`bool`

## Esempi
<a name="ql-functions.contains.examples"></a>

```
SELECT * FROM "Orders" WHERE "OrderID"=1 AND contains("Address", 'Kirkland')
```

# Utilizzo della funzione SIZE con PartiQL per Amazon DynamoDB
<a name="ql-functions.size"></a>

Restituisce un numero che rappresenta le dimensioni di un attributo (in byte). I seguenti sono tipi di dati validi per l'utilizzo con size. Per ulteriori informazioni, consulta la funzione [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) di DynamoDB.

## Sintassi
<a name="ql-functions.size.syntax"></a>

```
size( path)
```

## Argomenti
<a name="ql-functions.size.arguments"></a>

*path*  
(Obbligatorio) Il nome attributo o il percorso del documento.   
Per i tipi supportati, consulta la funzione [size](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions) di DynamoDB.

## Tipo restituito
<a name="ql-functions.size.return-type"></a>

`int`

## Esempi
<a name="ql-functions.size.examples"></a>

```
 SELECT * FROM "Orders" WHERE "OrderID"=1 AND size("Image") >300
```

# Operatori PartiQL aritmetici, di confronto e logici per DynamoDB
<a name="ql-operators"></a>

PartiQL in Amazon DynamoDB supporta i seguenti [operatori SQL standard](https://www.w3schools.com/sql/sql_operators.asp).

**Nota**  
Tutti gli operatori SQL che non sono inclusi in questo elenco non sono attualmente supportati in DynamoDB.

## Operatori aritmetici
<a name="ql-operators.arithmetic"></a>


****  

| Operatore | Description | 
| --- | --- | 
| \$1 | Add (Aggiungi) | 
| - | Subtract | 

## Operatori di confronto
<a name="ql-operators.comparison"></a>


****  

| Operatore | Description | 
| --- | --- | 
| = | Equal to | 
| <> | Not Equal to | 
| \$1= | Not Equal to | 
| > | Greater than | 
| < | Less than | 
| >= | Greater than or equal to | 
| <= | Less than or equal to | 

## Operatori logici
<a name="ql-operators.logical"></a>


****  

| Operatore | Description | 
| --- | --- | 
| AND | TRUE se tutte le condizioni separate da AND sono TRUE | 
| BETWEEN |  `TRUE` se l’operando è all’interno dell’intervallo di confronti. Questo operatore include il limite inferiore e superiore degli operandi su cui viene applicato.  | 
| IN | `TRUE`se l'operando è uguale a uno di un elenco di espressioni (con un massimo di 50 valori di attributi hash o un massimo di 100 valori di attributi non chiave). I risultati vengono restituiti in pagine contenenti un massimo di 10 elementi. Se l'`IN`elenco contiene più valori, è necessario utilizzare quello `NextToken` restituito nella risposta per recuperare le pagine successive. | 
| IS | TRUE se l'operando è un dato tipo di dati PartiQL, inclusoNULL o MISSING | 
| NOT | Inverte il valore di una determinata espressione booleana | 
| OR | TRUE se una delle condizioni separate da OR è TRUE | 

Per ulteriori informazioni sull’utilizzo degli operatori logici, consulta [Realizzazione di confronti](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Comparators) e [Valutazioni logiche](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.LogicalEvaluations).

# Esecuzione di transazioni con PartiQL per DynamoDB
<a name="ql-reference.multiplestatements.transactions"></a>

In questa sezione viene descritto come utilizzare le transazioni con PartiQL per DynamoDB. Le transazioni PartiQL sono limitate a 100 istruzioni totali (operazioni).

Per ulteriori informazioni sulle transazioni DynamoDB, consulta [Gestione di flussi di lavoro complessi con transazioni DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transactions.html).

**Nota**  
L'intera transazione deve essere costituita da istruzioni di lettura o di scrittura. Non puoi combinare entrambe in un'unica transazione. La funzione EXISTS è un'eccezione. È possibile utilizzarlo per verificare la condizione degli attributi specifici dell'elemento in modo simile al funzionamento `ConditionCheck` dell'[TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html#transaction-apis-txwriteitems)API.

**Topics**
+ [Sintassi](#ql-reference.multiplestatements.transactions.syntax)
+ [Parameters](#ql-reference.multiplestatements.transactions.parameters)
+ [Valori restituiti](#ql-reference.multiplestatements.transactions.return)
+ [Esempi](#ql-reference.multiplestatements.transactions.examples)

## Sintassi
<a name="ql-reference.multiplestatements.transactions.syntax"></a>

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## Parameters
<a name="ql-reference.multiplestatements.transactions.parameters"></a>

***statement***  
(Obbligatorio) Un'istruzione supportata PartiQL per DynamoDB.  
L'intera transazione deve essere costituita da istruzioni di lettura o di scrittura. Non puoi combinare entrambe in un'unica transazione.

***parametertype***  
(Facoltativo) Un tipo DynamoDB, se durante la specifica dell'istruzione PartiQL sono stati utilizzati dei parametri.

***parametervalue***  
(Facoltativo) Il valore di un parametro se durante la specifica dell'istruzione PartiQL sono stati utilizzati dei parametri.

## Valori restituiti
<a name="ql-reference.multiplestatements.transactions.return"></a>

Questa istruzione non restituisce alcun valore per le operazioni di scrittura (INSERT, UPDATE o DELETE). Tuttavia, restituisce valori diversi per le operazioni di lettura (SELECT) in base alle condizioni specificate nella clausola WHERE.

**Nota**  
Se una qualsiasi delle singole operazioni INSERT, UPDATE o DELETE restituisce un errore, le transazioni verranno annullate con l'eccezione `TransactionCanceledException` e il codice motivo dell'annullamento includerà gli errori delle singole operazioni.

## Esempi
<a name="ql-reference.multiplestatements.transactions.examples"></a>

L'esempio seguente esegue più istruzioni come transazione.

------
#### [ AWS CLI ]

1. Salva il codice JSON seguente in un file chiamato partiql.json. 

   ```
   [
       {
           "Statement": "EXISTS(SELECT * FROM \"Music\" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"
       },
       {
           "Statement": "INSERT INTO Music value {'Artist':?,'SongTitle':'?'}",
           "Parameters": [{\"S\": \"Acme Band\"}, {\"S\": \"Best Song\"}]
       },
       {
           "Statement": "UPDATE \"Music\" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. Esegui il comando seguente al prompt dei comandi.

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

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

```
public class DynamoDBPartiqlTransaction {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create ExecuteTransactionRequest
            ExecuteTransactionRequest executeTransactionRequest = createExecuteTransactionRequest();
            ExecuteTransactionResult executeTransactionResult = dynamoDB.executeTransaction(executeTransactionRequest);
            System.out.println("ExecuteTransaction successful.");
            // Handle executeTransactionResult

        } catch (Exception e) {
            handleExecuteTransactionErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static ExecuteTransactionRequest createExecuteTransactionRequest() {
        ExecuteTransactionRequest request = new ExecuteTransactionRequest();
        
        // Create statements
        List<ParameterizedStatement> statements = getPartiQLTransactionStatements();

        request.setTransactStatements(statements);
        return request;
    }

    private static List<ParameterizedStatement> getPartiQLTransactionStatements() {
        List<ParameterizedStatement> statements = new ArrayList<ParameterizedStatement>();

        statements.add(new ParameterizedStatement()
                               .withStatement("EXISTS(SELECT * FROM "Music" where Artist='No One You Know' and SongTitle='Call Me Today' and Awards is  MISSING)"));

        statements.add(new ParameterizedStatement()
                               .withStatement("INSERT INTO "Music" value {'Artist':'?','SongTitle':'?'}")
                               .withParameters(new AttributeValue("Acme Band"),new AttributeValue("Best Song")));

        statements.add(new ParameterizedStatement()
                               .withStatement("UPDATE "Music" SET AwardsWon=1 SET AwardDetail={'Grammys':[2020, 2018]}  where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during ExecuteTransaction execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleExecuteTransactionErrors(Exception exception) {
        try {
            throw exception;
        } catch (TransactionCanceledException tce) {
            System.out.println("Transaction Cancelled, implies a client issue, fix before retrying. Error: " + tce.getErrorMessage());
        } catch (TransactionInProgressException tipe) {
            System.out.println("The transaction with the given request token is already in progress, consider changing " +
                "retry strategy for this type of error. Error: " + tipe.getErrorMessage());
        } catch (IdempotentParameterMismatchException ipme) {
            System.out.println("Request rejected because it was retried with a different payload but with a request token that was already used, " +
                "change request token for this payload to be accepted. Error: " + ipme.getErrorMessage());
        } catch (Exception e) {
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

L'esempio seguente mostra i diversi valori restituiti quando DynamoDB legge elementi con condizioni diverse specificate nella clausola WHERE.

------
#### [ AWS CLI ]

1. Salva il codice JSON seguente in un file chiamato partiql.json.

   ```
   [
       // Item exists and projected attribute exists
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item exists but projected attributes do not exist
       {
           "Statement": "SELECT non_existent_projected_attribute FROM "Music" WHERE Artist='No One You Know' and SongTitle='Call Me Today'"
       },
       // Item does not exist
       {
           "Statement": "SELECT * FROM "Music" WHERE Artist='No One I Know' and SongTitle='Call You Today'"
       }
   ]
   ```

1.  Esegui il comando seguente in un prompt dei comandi.

   ```
   aws dynamodb execute-transaction --transact-statements  file://partiql.json
   ```

1. Viene restituita la risposta seguente:

   ```
   {
       "Responses": [
           // Item exists and projected attribute exists
           {
               "Item": {
                   "Artist":{
                       "S": "No One You Know"
                   },
                   "SongTitle":{
                       "S": "Call Me Today"
                   }    
               }
           },
           // Item exists but projected attributes do not exist
           {
               "Item": {}
           },
           // Item does not exist
           {}
       ]
   }
   ```

------

# Esecuzione di operazioni in batch con PartiQL per DynamoDB
<a name="ql-reference.multiplestatements.batching"></a>

In questa sezione viene descritto come utilizzare le istruzioni in batch con PartiQL per DynamoDB.

**Nota**  
L'intera transazione deve essere costituita da istruzioni di lettura o di scrittura; non è possibile combinare entrambe le istruzioni in un batch.
`BatchExecuteStatement` e `BatchWriteItem` possono eseguire al massimo 25 istruzioni per batch.
`BatchExecuteStatement` utilizza `BatchGetItem`, che richiede un elenco di chiavi primarie in istruzioni separate.

**Topics**
+ [Sintassi](#ql-reference.multiplestatements.batching.syntax)
+ [Parameters](#ql-reference.multiplestatements.batching.parameters)
+ [Esempi](#ql-reference.multiplestatements.batching.examples)

## Sintassi
<a name="ql-reference.multiplestatements.batching.syntax"></a>

```
[
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#9StkWHYTxm7x2AqSXcrfu7' AND sk = 'info'"
  },
  {
    "Statement": "SELECT pk FROM ProblemSet WHERE pk = 'p#isC2ChceGbxHgESc4szoTE' AND sk = 'info'"
  }
]
```

```
[
   {
      "Statement":" statement ",
      "Parameters":[
         {
            " parametertype " : " parametervalue "
         }, ...]
   } , ...
]
```

## Parameters
<a name="ql-reference.multiplestatements.batching.parameters"></a>

***statement***  
(Obbligatorio) Un'istruzione supportata PartiQL per DynamoDB.  
+ L'intera transazione deve essere costituita da istruzioni di lettura o di scrittura; non è possibile combinare entrambe le istruzioni in un batch.
+ `BatchExecuteStatement` e `BatchWriteItem` possono eseguire al massimo 25 istruzioni per batch.

***parametertype***  
(Facoltativo) Un tipo DynamoDB, se durante la specifica dell'istruzione PartiQL sono stati utilizzati dei parametri.

***parametervalue***  
(Facoltativo) Il valore di un parametro se durante la specifica dell'istruzione PartiQL sono stati utilizzati dei parametri.

## Esempi
<a name="ql-reference.multiplestatements.batching.examples"></a>

------
#### [ AWS CLI ]

1. Salvataggio del JSON seguente in un file chiamato partiql.json

   ```
   [
      {
   	 "Statement": "INSERT INTO Music VALUE {'Artist':?,'SongTitle':?}",
   	  "Parameters": [{"S": "Acme Band"}, {"S": "Best Song"}]
   	},
   	{
   	 "Statement": "UPDATE Music SET AwardsWon=1, AwardDetail={'Grammys':[2020, 2018]} WHERE Artist='Acme Band' AND SongTitle='PartiQL Rocks'"
       }
   ]
   ```

1. Esegui il comando seguente al prompt dei comandi.

   ```
   aws dynamodb batch-execute-statement  --statements  file://partiql.json
   ```

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

```
public class DynamoDBPartiqlBatch {

    public static void main(String[] args) {
        // Create the DynamoDB Client with the region you want
        AmazonDynamoDB dynamoDB = createDynamoDbClient("us-west-2");
        
        try {
            // Create BatchExecuteStatementRequest
            BatchExecuteStatementRequest batchExecuteStatementRequest = createBatchExecuteStatementRequest();
            BatchExecuteStatementResult batchExecuteStatementResult = dynamoDB.batchExecuteStatement(batchExecuteStatementRequest);
            System.out.println("BatchExecuteStatement successful.");
            // Handle batchExecuteStatementResult

        } catch (Exception e) {
            handleBatchExecuteStatementErrors(e);
        }
    }

    private static AmazonDynamoDB createDynamoDbClient(String region) {

        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }

    private static BatchExecuteStatementRequest createBatchExecuteStatementRequest() {
        BatchExecuteStatementRequest request = new BatchExecuteStatementRequest();

        // Create statements
        List<BatchStatementRequest> statements = getPartiQLBatchStatements();

        request.setStatements(statements);
        return request;
    }

    private static List<BatchStatementRequest> getPartiQLBatchStatements() {
        List<BatchStatementRequest> statements = new ArrayList<BatchStatementRequest>();

        statements.add(new BatchStatementRequest()
                               .withStatement("INSERT INTO Music value {'Artist':'Acme Band','SongTitle':'PartiQL Rocks'}"));

        statements.add(new BatchStatementRequest()
                               .withStatement("UPDATE Music set AwardDetail.BillBoard=[2020] where Artist='Acme Band' and SongTitle='PartiQL Rocks'"));

        return statements;
    }

    // Handles errors during BatchExecuteStatement execution. Use recommendations in error messages below to add error handling specific to 
    // your application use-case.
    private static void handleBatchExecuteStatementErrors(Exception exception) {
        try {
            throw exception;
        } catch (Exception e) {
            // There are no API specific errors to handle for BatchExecuteStatement, common DynamoDB API errors are handled below
            handleCommonErrors(e);
        }
    }

    private static void handleCommonErrors(Exception exception) {
        try {
            throw exception;
        } catch (InternalServerErrorException isee) {
            System.out.println("Internal Server Error, generally safe to retry with exponential back-off. Error: " + isee.getErrorMessage());
        } catch (RequestLimitExceededException rlee) {
            System.out.println("Throughput exceeds the current throughput limit for your account, increase account level throughput before " + 
                "retrying. Error: " + rlee.getErrorMessage());
        } catch (ProvisionedThroughputExceededException ptee) {
            System.out.println("Request rate is too high. If you're using a custom retry strategy make sure to retry with exponential back-off. " +
                "Otherwise consider reducing frequency of requests or increasing provisioned capacity for your table or secondary index. Error: " + 
                ptee.getErrorMessage());
        } catch (ResourceNotFoundException rnfe) {
            System.out.println("One of the tables was not found, verify table exists before retrying. Error: " + rnfe.getErrorMessage());
        } catch (AmazonServiceException ase) {
            System.out.println("An AmazonServiceException occurred, indicates that the request was correctly transmitted to the DynamoDB " + 
                "service, but for some reason, the service was not able to process it, and returned an error response instead. Investigate and " +
                "configure retry strategy. Error type: " + ase.getErrorType() + ". Error message: " + ase.getErrorMessage());
        } catch (AmazonClientException ace) {
            System.out.println("An AmazonClientException occurred, indicates that the client was unable to get a response from DynamoDB " +
                "service, or the client was unable to parse the response from the service. Investigate and configure retry strategy. "+
                "Error: " + ace.getMessage());
        } catch (Exception e) {
            System.out.println("An exception occurred, investigate and configure retry strategy. Error: " + e.getMessage());
        }
    }

}
```

------

# Policy di sicurezza IAM con PartiQL per DynamoDB
<a name="ql-iam"></a>

Sono richieste le seguenti autorizzazioni:
+ Per leggere gli elementi utilizzando PartiQL per DynamoDB, è necessario disporre dell'autorizzazione `dynamodb:PartiQLSelect` sulla tabella o sull'indice.
+ Per inserire gli elementi utilizzando PartiQL per DynamoDB, è necessario disporre dell'autorizzazione `dynamodb:PartiQLInsert` sulla tabella o sull'indice.
+ Per aggiornare gli elementi utilizzando PartiQL per DynamoDB, è necessario disporre dell'autorizzazione `dynamodb:PartiQLUpdate` sulla tabella o sull'indice.
+ Per inserire gli elementi utilizzando PartiQL per DynamoDB, è necessario disporre dell'autorizzazione `dynamodb:PartiQLDelete` sulla tabella o sull'indice.

## Esempio: consentire tutte le istruzioni PartiQL for DynamoDB () su una tabella Select/Insert/Update/Delete
<a name="access-policy-ql-iam-example1"></a>

La seguente policy IAM concede le autorizzazioni per eseguire tutte le istruzioni PartiQL per DynamoDB su una tabella specifica. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Esempio: Consentire le istruzioni SELECT (SELEZIONA) PartiQL per DynamoDB su una tabella
<a name="access-policy-ql-iam-example2"></a>

La seguente policy IAM concede le autorizzazioni per eseguire l'istruzione `select` su una tabella specifica.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Esempio: Consentire le istruzioni INSERT PartiQL per DynamoDB su un indice
<a name="access-policy-ql-iam-example3"></a>

La seguente policy IAM concede le autorizzazioni per eseguire l'istruzione `insert` su un indice specifico. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music/index/index1"
         ]
      }
   ]
}
```

------

## Esempio: Consentire le istruzioni transazionali PartiQL per DynamoDB solo su una tabella
<a name="access-policy-ql-iam-example4"></a>

La seguente policy IAM concede le autorizzazioni per eseguire le istruzioni transazionali su una tabella specifica. 

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      }
   ]
}
```

------

## Esempio: Consentire letture e scritture non transazionali di PartiQL per DynamoDB e bloccare le istruzioni transazionali di letture e scritture transazionali di PartiQL su una tabella.
<a name="access-policy-ql-iam-example5"></a>

 La seguente policy IAM concede le autorizzazioni per eseguire letture e le scritture non transazionali PartiQL per DynamoDB bloccando le letture e le scritture transazionali PartiQL per DynamoDB.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ],
         "Condition":{
            "StringEquals":{
               "dynamodb:EnclosingOperation":[
                  "ExecuteTransaction"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLInsert",
            "dynamodb:PartiQLUpdate",
            "dynamodb:PartiQLDelete",
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/Music"
         ]
      }
   ]
}
```

------

## Esempio: Consentire le istruzioni Select e rifiutare le istruzioni di scansione completa della tabella in PartiQL per DynamoDB
<a name="access-policy-ql-iam-example6"></a>

La seguente policy IAM concede le autorizzazioni per eseguire l'istruzione `select` su una tabella specifica durante il blocco delle istruzioni `select` che determinano una scansione completa della tabella.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement":[
      {
         "Effect":"Deny",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ],
         "Condition":{
            "Bool":{
               "dynamodb:FullTableScan":[
                  "true"
               ]
            }
         }
      },
      {
         "Effect":"Allow",
         "Action":[
            "dynamodb:PartiQLSelect"
         ],
         "Resource":[
            "arn:aws:dynamodb:us-west-2:123456789012:table/WatchList"
         ]
      }
   ]
}
```

------

# Utilizzo degli elementi: Java
<a name="JavaDocumentAPIItemCRUD"></a>

Puoi utilizzare l'API AWS SDK per Java Document per eseguire operazioni tipiche di creazione, lettura, aggiornamento ed eliminazione (CRUD) sugli elementi di Amazon DynamoDB in una tabella.

**Nota**  
L'SDK per Java offre inoltre un modello di persistenza degli oggetti che permette di mappare le classi lato client alle tabelle DynamoDB. Questo approccio può ridurre la quantità di codice da scrivere. Per ulteriori informazioni, consulta [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

Questa sezione contiene esempi Java per eseguire diverse operazioni operazioni sugli elementi dell'API documento Java e diversi esempi di lavoro completi.

**Topics**
+ [Collocazione di un elemento](#PutDocumentAPIJava)
+ [Ottenimento di un elemento](#JavaDocumentAPIGetItem)
+ [Scrittura in batch: collocazione ed eliminazione di più elementi](#BatchWriteDocumentAPIJava)
+ [Ricezione in batch: ricezione di più elementi](#JavaDocumentAPIBatchGetItem)
+ [Aggiornamento di un elemento](#JavaDocumentAPIItemUpdate)
+ [Eliminazione di un elemento](#DeleteMidLevelJava)
+ [Esempio: operazioni CRUD che utilizzano l'API del documento AWS SDK per Java](JavaDocumentAPICRUDExample.md)
+ [Esempio: operazioni Batch utilizzando l'API AWS SDK per Java dei documenti](batch-operation-document-api-java.md)
+ [Esempio: gestione degli attributi di tipo binario utilizzando l'API del AWS SDK per Java documento](JavaDocumentAPIBinaryTypeExample.md)

## Collocazione di un elemento
<a name="PutDocumentAPIJava"></a>

Il metodo `putItem` memorizza un item nella tabella. Se l'item esiste, lo sostituisce per intero. Se invece di sostituire l'intero item vuoi aggiornare solo attributi specifici, puoi utilizzare il metodo `updateItem`. Per ulteriori informazioni, consulta [Aggiornamento di un elemento](#JavaDocumentAPIItemUpdate). 

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

```
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.PutItemResponse;
import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import java.util.HashMap;

/**
 * Before running this Java V2 code example, set up your development
 * environment, including your credentials.
 *
 * For more information, see the following documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 *
 * To place items into an Amazon DynamoDB table using the AWS SDK for Java V2,
 * its better practice to use the
 * Enhanced Client. See the EnhancedPutItem example.
 */
public class PutItem {
    public static void main(String[] args) {
        final String usage = """

                Usage:
                    <tableName> <key> <keyVal> <albumtitle> <albumtitleval> <awards> <awardsval> <Songtitle> <songtitleval>

                Where:
                    tableName - The Amazon DynamoDB table in which an item is placed (for example, Music3).
                    key - The key used in the Amazon DynamoDB table (for example, Artist).
                    keyval - The key value that represents the item to get (for example, Famous Band).
                    albumTitle - The Album title (for example, AlbumTitle).
                    AlbumTitleValue - The name of the album (for example, Songs About Life ).
                    Awards - The awards column (for example, Awards).
                    AwardVal - The value of the awards (for example, 10).
                    SongTitle - The song title (for example, SongTitle).
                    SongTitleVal - The value of the song title (for example, Happy Day).
                **Warning** This program will  place an item that you specify into a table!
                """;

        if (args.length != 9) {
            System.out.println(usage);
            System.exit(1);
        }

        String tableName = args[0];
        String key = args[1];
        String keyVal = args[2];
        String albumTitle = args[3];
        String albumTitleValue = args[4];
        String awards = args[5];
        String awardVal = args[6];
        String songTitle = args[7];
        String songTitleVal = args[8];

        Region region = Region.US_EAST_1;
        DynamoDbClient ddb = DynamoDbClient.builder()
                .region(region)
                .build();

        putItemInTable(ddb, tableName, key, keyVal, albumTitle, albumTitleValue, awards, awardVal, songTitle,
                songTitleVal);
        System.out.println("Done!");
        ddb.close();
    }

    public static void putItemInTable(DynamoDbClient ddb,
            String tableName,
            String key,
            String keyVal,
            String albumTitle,
            String albumTitleValue,
            String awards,
            String awardVal,
            String songTitle,
            String songTitleVal) {

        HashMap<String, AttributeValue> itemValues = new HashMap<>();
        itemValues.put(key, AttributeValue.builder().s(keyVal).build());
        itemValues.put(songTitle, AttributeValue.builder().s(songTitleVal).build());
        itemValues.put(albumTitle, AttributeValue.builder().s(albumTitleValue).build());
        itemValues.put(awards, AttributeValue.builder().s(awardVal).build());

        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(itemValues)
                .build();

        try {
            PutItemResponse response = ddb.putItem(request);
            System.out.println(tableName + " was successfully updated. The request id is "
                    + response.responseMetadata().requestId());

        } catch (ResourceNotFoundException e) {
            System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
            System.err.println("Be sure that it exists and that you've typed its name correctly!");
            System.exit(1);
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
```

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

Completare la procedura riportata di seguito. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `Table` per rappresentare la tabella con cui vuoi lavorare.

1. Crea un'istanza della classe `Item` per rappresentare il nuovo item. Devi specificare la chiave primaria del nuovo item e gli attributi.

1. Chiama il metodo `putItem` dell'oggetto `Table` usando l'elemento `Item` creato nella fase precedente.

Il seguente esempio di codice Java mostra le attività precedenti. Il codice scrive un nuovo item nella tabella `ProductCatalog`.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

// Build a list of related items
List<Number> relatedItems = new ArrayList<Number>();
relatedItems.add(341);
relatedItems.add(472);
relatedItems.add(649);

//Build a map of product pictures
Map<String, String> pictures = new HashMap<String, String>();
pictures.put("FrontView", "http://example.com/products/123_front.jpg");
pictures.put("RearView", "http://example.com/products/123_rear.jpg");
pictures.put("SideView", "http://example.com/products/123_left_side.jpg");

//Build a map of product reviews
Map<String, List<String>> reviews = new HashMap<String, List<String>>();

List<String> fiveStarReviews = new ArrayList<String>();
fiveStarReviews.add("Excellent! Can't recommend it highly enough!  Buy it!");
fiveStarReviews.add("Do yourself a favor and buy this");
reviews.put("FiveStar", fiveStarReviews);

List<String> oneStarReviews = new ArrayList<String>();
oneStarReviews.add("Terrible product!  Do not buy this.");
reviews.put("OneStar", oneStarReviews);

// Build the item
Item item = new Item()
    .withPrimaryKey("Id", 123)
    .withString("Title", "Bicycle 123")
    .withString("Description", "123 description")
    .withString("BicycleType", "Hybrid")
    .withString("Brand", "Brand-Company C")
    .withNumber("Price", 500)
    .withStringSet("Color",  new HashSet<String>(Arrays.asList("Red", "Black")))
    .withString("ProductCategory", "Bicycle")
    .withBoolean("InStock", true)
    .withNull("QuantityOnHand")
    .withList("RelatedItems", relatedItems)
    .withMap("Pictures", pictures)
    .withMap("Reviews", reviews);

// Write the item to the table
PutItemOutcome outcome = table.putItem(item);
```

Nell'esempio precedente, l'item ha attributi scalari (`String`, `Number`, `Boolean`, `Null`), set (`String Set`) e tipi di documento (`List`, `Map`).

------

### Specifica dei parametri facoltativi
<a name="PutItemJavaDocumentAPIOptions"></a>

Insieme ai parametri richiesti, puoi anche specificare parametri opzionali per il metodo `putItem`. Ad esempio, il seguente esempio di codice Java utilizza un parametro facoltativo per specificare una condizione per il caricamento dell'item. Se la condizione specificata non è soddisfatta, genera un. AWS SDK per Java `ConditionalCheckFailedException` L'esempio di codice specifica i seguenti parametri facoltativi nel metodo `putItem`:
+ un item `ConditionExpression` che definisce le condizioni della richiesta. Il codice definisce la condizione in cui l'item esistente che ha la stessa chiave primaria viene sostituito solo se ha un attributo ISBN uguale a un valore specifico. 
+ Una mappa per `ExpressionAttributeValues` che viene usata nella condizione. In questo caso, è necessaria una sola sostituzione: il segnaposto `:val` nell'espressione della condizione viene sostituito al runtime con il valore ISBN effettivo da verificare.

Nell'esempio seguente viene aggiunto un nuovo item del libro utilizzando questi parametri facoltativi.

**Example**  

```
Item item = new Item()
    .withPrimaryKey("Id", 104)
    .withString("Title", "Book 104 Title")
    .withString("ISBN", "444-4444444444")
    .withNumber("Price", 20)
    .withStringSet("Authors",
        new HashSet<String>(Arrays.asList("Author1", "Author2")));

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val", "444-4444444444");

PutItemOutcome outcome = table.putItem(
    item,
    "ISBN = :val", // ConditionExpression parameter
    null,          // ExpressionAttributeNames parameter - we're not using it for this example
    expressionAttributeValues);
```

### PutItem e documenti JSON
<a name="PutItemJavaDocumentAPI.JSON"></a>

È possibile memorizzare un documento JSON come attributo in una tabella DynamoDB. Per eseguire questa operazione, usa il metodo `withJSON` di `Item`. Questo metodo analizza il documento JSON e mappa ciascun elemento a un tipo di dati DynamoDB nativo.

Supponiamo di voler memorizzare il seguente documento JSON, contenente i fornitori in grado di soddisfare gli ordini di un determinato prodotto.

**Example**  

```
{
    "V01": {
        "Name": "Acme Books",
        "Offices": [ "Seattle" ]
    },
    "V02": {
        "Name": "New Publishers, Inc.",
        "Offices": ["London", "New York"
        ]
    },
    "V03": {
        "Name": "Better Buy Books",
        "Offices": [ "Tokyo", "Los Angeles", "Sydney"
        ]
    }
}
```

Puoi utilizzare il metodo `withJSON` per memorizzarlo nella tabella `ProductCatalog`, in un attributo `Map` denominato `VendorInfo`. Il seguente codice di esempio Java dimostra come eseguire questa operazione.

```
// Convert the document into a String.  Must escape all double-quotes.
String vendorDocument = "{"
    + "    \"V01\": {"
    + "        \"Name\": \"Acme Books\","
    + "        \"Offices\": [ \"Seattle\" ]"
    + "    },"
    + "    \"V02\": {"
    + "        \"Name\": \"New Publishers, Inc.\","
    + "        \"Offices\": [ \"London\", \"New York\"" + "]" + "},"
    + "    \"V03\": {"
    + "        \"Name\": \"Better Buy Books\","
    +          "\"Offices\": [ \"Tokyo\", \"Los Angeles\", \"Sydney\""
    + "            ]"
    + "        }"
    + "    }";

Item item = new Item()
    .withPrimaryKey("Id", 210)
    .withString("Title", "Book 210 Title")
    .withString("ISBN", "210-2102102102")
    .withNumber("Price", 30)
    .withJSON("VendorInfo", vendorDocument);

PutItemOutcome outcome = table.putItem(item);
```

## Ottenimento di un elemento
<a name="JavaDocumentAPIGetItem"></a>

Per recuperare un singolo item usa il metodo `getItem` di un oggetto `Table`. Completare la procedura riportata di seguito. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `Table` per rappresentare la tabella con cui vuoi lavorare.

1. Chiama il metodo `getItem` dell'istanza di `Table`. Devi specificare la chiave primaria dell'item che intendi recuperare.

Il seguente esempio di codice Java mostra le fasi precedenti. Il codice ottiene l'item che ha la chiave di partizione specificata.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Item item = table.getItem("Id", 210);
```

### Specifica dei parametri facoltativi
<a name="GetItemJavaDocumentAPIOptions"></a>

Insieme ai parametri richiesti, puoi anche specificare parametri opzionali per il metodo `getItem`. Ad esempio, il seguente esempio di codice Java utilizza un metodo facoltativo per recuperare un solo elenco specifico di attributi e per specificare letture fortemente consistenti. Per ulteriori informazioni sulla lettura consistente, consulta [Coerenza di lettura di DynamoDB](HowItWorks.ReadConsistency.md).

Puoi usare un `ProjectionExpression` per recuperare solo attributi o elementi specifici, piuttosto che un intero item. Un `ProjectionExpression` può specificare attributi nidificati o di primo livello usando i percorsi dei documenti. Per ulteriori informazioni, consulta [Utilizzo di espressioni di proiezione in DynamoDB](Expressions.ProjectionExpressions.md).

I parametri del metodo `getItem` non consentono di specificare lettura coerente. Tuttavia, puoi creare un `GetItemSpec`, che fornisce l'accesso completo a tutti gli input all'operazione `GetItem` di basso livello. Il seguente esempio di codice consente di creare un `GetItemSpec` e utilizzare tale specifica come input per il metodo `getItem`.

**Example**  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 206)
    .withProjectionExpression("Id, Title, RelatedItems[0], Reviews.FiveStar")
    .withConsistentRead(true);

Item item = table.getItem(spec);

System.out.println(item.toJSONPretty());
```

 Per stampare un `Item` in un formato leggibile, utilizza il metodo `toJSONPretty`. L'aspetto dell'output dall'esempio precedente è simile al seguente.

```
{
  "RelatedItems" : [ 341 ],
  "Reviews" : {
    "FiveStar" : [ "Excellent! Can't recommend it highly enough! Buy it!", "Do yourself a favor and buy this" ]
  },
  "Id" : 123,
  "Title" : "20-Bicycle 123"
}
```

### GetItem e documenti JSON
<a name="GetItemJavaDocumentAPI.JSON"></a>

Nella sezione [PutItem e documenti JSON](#PutItemJavaDocumentAPI.JSON), viene archiviato un documento JSON in un attributo `Map` denominato `VendorInfo`. Puoi utilizzare il metodo `getItem` per recuperare l'intero documento nel formato JSON. Oppure puoi utilizzare la notazione del percorso del documento per recuperare solo gli stessi elementi nel documento. Il seguente esempio di codice Java mostra queste tecniche.

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210);

System.out.println("All vendor info:");
spec.withProjectionExpression("VendorInfo");
System.out.println(table.getItem(spec).toJSON());

System.out.println("A single vendor:");
spec.withProjectionExpression("VendorInfo.V03");
System.out.println(table.getItem(spec).toJSON());

System.out.println("First office location for this vendor:");
spec.withProjectionExpression("VendorInfo.V03.Offices[0]");
System.out.println(table.getItem(spec).toJSON());
```

L'aspetto dell'output dall'esempio precedente è simile al seguente.

```
All vendor info:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]},"V02":{"Name":"New Publishers, Inc.","Offices":["London","New York"]},"V01":{"Name":"Acme Books","Offices":["Seattle"]}}}
A single vendor:
{"VendorInfo":{"V03":{"Name":"Better Buy Books","Offices":["Tokyo","Los Angeles","Sydney"]}}}
First office location for a single vendor:
{"VendorInfo":{"V03":{"Offices":["Tokyo"]}}}
```

**Nota**  
Puoi usare il metodo `toJSON` per convertire qualsiasi item (o gli attributi) in una stringa in formato JSON. Il seguente codice recupera diversi attributi di primo livello e nidificati e stampa i risultati come JSON.  

```
GetItemSpec spec = new GetItemSpec()
    .withPrimaryKey("Id", 210)
    .withProjectionExpression("VendorInfo.V01, Title, Price");

Item item = table.getItem(spec);
System.out.println(item.toJSON());
```
L'output sarà simile al seguente.  

```
{"VendorInfo":{"V01":{"Name":"Acme Books","Offices":["Seattle"]}},"Price":30,"Title":"Book 210 Title"}
```

## Scrittura in batch: collocazione ed eliminazione di più elementi
<a name="BatchWriteDocumentAPIJava"></a>

La *scrittura in batch* fa riferimento alla collocazione e all'eliminazione di più item in un batch. Il metodo `batchWriteItem` ti consente di inserire ed eliminare più item da una o più tabelle con un'unica chiamata. Di seguito sono riportati i passaggi per inserire o eliminare più elementi utilizzando l'API AWS SDK per Java Document.

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `TableWriteItems` che descrive tutte le operazioni di inserimento ed eliminazione per una tabella. Se vuoi scrivere su più tabelle in una sola operazione di scrittura in batch, devi creare un'istanza di `TableWriteItems` per tabella.

1. Chiama il metodo `batchWriteItem` fornendo gli oggetti `TableWriteItems` creati nella fase precedente. 

1. Elabora la risposta. Dovresti controllare se erano presenti item di richiesta non elaborati restituiti nella risposta. Questo potrebbe accadere se raggiungi la quota di throughput assegnata o si verifica un altro errore transitorio. Inoltre, DynamoDB limita la dimensione della richiesta e il numero di operazioni che possono essere specificate in una richiesta. Se si superano questi limiti, DynamoDB rifiuta la richiesta. Per ulteriori informazioni, consulta [Quote in Amazon DynamoDB](ServiceQuotas.md). 

Il seguente esempio di codice Java mostra le fasi precedenti. L'esempio esegue un'operazione `batchWriteItem` su due tabelle: `Forum` e `Thread`. Gli oggetti `TableWriteItems` corrispondenti definiscono le operazioni seguenti:
+ inserimento di un item nella tabella `Forum`.
+ Inserimento ed eliminazione di un item nella tabella `Thread`.

Il codice quindi chiama `batchWriteItem` per eseguire l'operazione.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

TableWriteItems forumTableWriteItems = new TableWriteItems("Forum")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("Name", "Amazon RDS")
            .withNumber("Threads", 0));

TableWriteItems threadTableWriteItems = new TableWriteItems("Thread")
    .withItemsToPut(
        new Item()
            .withPrimaryKey("ForumName","Amazon RDS","Subject","Amazon RDS Thread 1")
    .withHashAndRangeKeysToDelete("ForumName","Some partition key value", "Amazon S3", "Some sort key value");

BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

// Code for checking unprocessed items is omitted in this example
```

Per un esempio di utilizzo, consulta [Esempio: operazione di scrittura in batch utilizzando l'API del AWS SDK per Java documento](batch-operation-document-api-java.md#JavaDocumentAPIBatchWrite). 

## Ricezione in batch: ricezione di più elementi
<a name="JavaDocumentAPIBatchGetItem"></a>

Il metodo `batchGetItem` ti consente di recuperare più item da una o più tabelle. Per recuperare un singolo item puoi usare il metodo `getItem`. 

Completare la procedura riportata di seguito. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `TableKeysAndAttributes` e descrivi un elenco di valori delle chiavi primarie da recuperare da una tabella. Se vuoi leggere da più tabelle in una sola operazione Get in batch, devi creare un'istanza di `TableKeysAndAttributes` per tabella.

1. Chiama il metodo `batchGetItem` fornendo gli oggetti `TableKeysAndAttributes` creati nella fase precedente.

Il seguente esempio di codice Java mostra le fasi precedenti. L'esempio consente di recuperare due item dalla tabella `Forum` e tre item dalla tabella `Thread`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

    TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
    forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject",
    "Amazon DynamoDB","DynamoDB Thread 1",
    "Amazon DynamoDB","DynamoDB Thread 2",
    "Amazon S3","S3 Thread 1");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(
    forumTableKeysAndAttributes, threadTableKeysAndAttributes);

for (String tableName : outcome.getTableItems().keySet()) {
    System.out.println("Items in table " + tableName);
    List<Item> items = outcome.getTableItems().get(tableName);
    for (Item item : items) {
        System.out.println(item);
    }
}
```

### Specifica dei parametri facoltativi
<a name="BatchGetItemJavaDocumentAPIOptions"></a>

Insieme ai parametri richiesti, puoi anche specificare parametri opzionali usando `batchGetItem`. Puoi ad esempio fornire un `ProjectionExpression` con ogni `TableKeysAndAttributes` che definisci. Ciò ti consente di specificare gli attributi che vuoi recuperare dalla tabella.

L'esempio di codice seguente recupera due item dalla tabella `Forum`. Il parametro `withProjectionExpression` specifica che deve essere recuperato solo l'attributo `Threads`.

**Example**  

```
TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes("Forum")
    .withProjectionExpression("Threads");

forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name",
    "Amazon S3",
    "Amazon DynamoDB");

BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes);
```

## Aggiornamento di un elemento
<a name="JavaDocumentAPIItemUpdate"></a>

Il metodo `updateItem` di un oggetto `Table` può aggiornare i valori degli attributi esistenti, aggiungere nuovi attributi o eliminare attributi da un item esistente. 

Il metodo `updateItem` si comporta nel modo seguente:
+ Se un item non esiste (nessun item nella tabella con la chiave primaria specificata), `updateItem` aggiunge un nuovo item alla tabella.
+ Se un item esiste, `updateItem` esegue l'aggiornamento come specificato dal parametro `UpdateExpression`.

**Nota**  
È anche possibile "aggiornare" un item usando `putItem`. Ad esempio, se chiami `putItem` per aggiungere un item alla tabella ma esiste già un item con la chiave primaria specificata, `putItem` sostituisce l'intero item. Se nell'item esistente sono presenti attributi che non sono specificati nell'input, `putItem` rimuove quegli attributi dall'item.  
Come regola generale, ti consigliamo di usare `updateItem` ogni volta che desideri modificare qualsiasi attributo dell'item. Il metodo `updateItem` modifica solo gli attributi specificati nell'input e gli altri attributi dell'item rimangono invariati.

Completare la procedura riportata di seguito. 

1. Crea un'istanza della classe `Table` per rappresentare la tabella da utilizzare.

1. Chiama il metodo `updateTable` dell'istanza di `Table`. Dovrai specificare la chiave primaria dell'item che vuoi recuperare, insieme a una `UpdateExpression` che descrive gli attributi da modificare e come modificarli.

Il seguente esempio di codice Java mostra le attività precedenti. Il codice aggiorna un item libro nella tabella `ProductCatalog`. Aggiunge un nuovo autore al set di `Authors` ed elimina l'attributo `ISBN` esistente. Inoltre, riduce il prezzo di una unità.

Una mappa `ExpressionAttributeValues` viene usata in `UpdateExpression`. I segnaposto `:val1` e `:val2` vengono sostituiti al runtime con i valori effettivi per `Authors` e `Price`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#A", "Authors");
expressionAttributeNames.put("#P", "Price");
expressionAttributeNames.put("#I", "ISBN");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1",
    new HashSet<String>(Arrays.asList("Author YY","Author ZZ")));
expressionAttributeValues.put(":val2", 1);   //Price

UpdateItemOutcome outcome =  table.updateItem(
    "Id",          // key attribute name
    101,           // key attribute value
    "add #A :val1 set #P = #P - :val2 remove #I", // UpdateExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### Specifica dei parametri facoltativi
<a name="UpdateItemJavaDocumentAPIOptions"></a>

Insieme ai parametri obbligatori puoi specificare anche dei parametri facoltativi per il metodo `updateItem`, inclusa una condizione che deve essere soddisfatta affinché l'aggiornamento possa avere luogo. Se la condizione specificata non è soddisfatta, AWS SDK per Java genera un`ConditionalCheckFailedException`. Ad esempio, il seguente esempio di codice Java aggiorna in base a condizioni il prezzo di un libro a 25. Specifica una `ConditionExpression` che afferma che il prezzo deve essere aggiornato solo se il prezzo esistente è 20.

**Example**  

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#P", "Price");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", 25);  // update Price to 25...
expressionAttributeValues.put(":val2", 20);  //...but only if existing Price is 20

UpdateItemOutcome outcome = table.updateItem(
    new PrimaryKey("Id",101),
    "set #P = :val1", // UpdateExpression
    "#P = :val2",     // ConditionExpression
    expressionAttributeNames,
    expressionAttributeValues);
```

### Contatore atomico
<a name="AtomicCounterJavaDocumentAPI"></a>

Puoi usare il metodo `updateItem` per implementare un contatore atomico e incrementare o decrementare il valore di un attributo esistente senza interferire con altre richieste di scrittura. Per incrementare un contatore atomico, usa un `UpdateExpression` con un'operazione `set` per aggiungere un valore numerico a un attributo esistente di tipo `Number`.

Il seguente esempio ne dimostra l'uso, incrementando l'attributo `Quantity` di uno. Dimostra anche l'uso del parametro `ExpressionAttributeNames` in una `UpdateExpression`.

```
Table table = dynamoDB.getTable("ProductCatalog");

Map<String,String> expressionAttributeNames = new HashMap<String,String>();
expressionAttributeNames.put("#p", "PageCount");

Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", 1);

UpdateItemOutcome outcome = table.updateItem(
    "Id", 121,
    "set #p = #p + :val",
    expressionAttributeNames,
    expressionAttributeValues);
```

## Eliminazione di un elemento
<a name="DeleteMidLevelJava"></a>

Il metodo `deleteItem` elimina un item da una tabella. È necessario fornire la chiave primaria dell'item che intendi eliminare.

Completare la procedura riportata di seguito. 

1. Crea un'istanza del client `DynamoDB`.

1. Chiama il metodo `deleteItem` fornendo la chiave dell'item che desideri eliminare. 

Il seguente esempio Java mostra queste attività.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("ProductCatalog");

DeleteItemOutcome outcome = table.deleteItem("Id", 101);
```

### Specifica dei parametri facoltativi
<a name="DeleteItemJavaDocumentAPIOptions"></a>

Puoi specificare i parametri facoltativi per `deleteItem`. Ad esempio, il seguente esempio di codice Java specifica una `ConditionExpression`, in cui si afferma che un item libro in `InPublication` può essere eliminato solo se il libro non è più in pubblicazione (l'attributo `ProductCatalog` è false).

**Example**  

```
Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
expressionAttributeValues.put(":val", false);

DeleteItemOutcome outcome = table.deleteItem("Id",103,
    "InPublication = :val",
    null, // ExpressionAttributeNames - not used in this example
    expressionAttributeValues);
```

# Esempio: operazioni CRUD che utilizzano l'API del documento AWS SDK per Java
<a name="JavaDocumentAPICRUDExample"></a>

Il seguente esempio di codice illustra le operazioni CRUD su un elemento di Amazon DynamoDB. L'esempio consente di creare un item, recuperarlo, eseguire vari aggiornamenti e infine eliminare l'item.

**Nota**  
L'SDK per Java offre inoltre un modello di persistenza degli oggetti che permette di mappare le classi lato client alle tabelle DynamoDB. Questo approccio può ridurre la quantità di codice da scrivere. Per ulteriori informazioni, consulta [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

**Nota**  
In questo esempio di codice si presuppone che i dati siano già stati caricati in DynamoDB per l'account seguendo le istruzioni riportate nella sezione [Creazione di tabelle e caricamento di dati per esempi di codice in DynamoDB](SampleData.md).  
Per step-by-step istruzioni su come eseguire l'esempio seguente, vedere[Esempi di codice Java](CodeSamples.Java.md).

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DocumentAPIItemCRUDExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "ProductCatalog";

    public static void main(String[] args) throws IOException {

        createItems();

        retrieveItem();

        // Perform various updates.
        updateMultipleAttributes();
        updateAddNewAttribute();
        updateExistingAttributeConditionally();

        // Delete the item.
        deleteItem();

    }

    private static void createItems() {

        Table table = dynamoDB.getTable(tableName);
        try {

            Item item = new Item().withPrimaryKey("Id", 120).withString("Title", "Book 120 Title")
                    .withString("ISBN", "120-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author12", "Author22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", false).withString("ProductCategory", "Book");
            table.putItem(item);

            item = new Item().withPrimaryKey("Id", 121).withString("Title", "Book 121 Title")
                    .withString("ISBN", "121-1111111111")
                    .withStringSet("Authors", new HashSet<String>(Arrays.asList("Author21", "Author 22")))
                    .withNumber("Price", 20).withString("Dimensions", "8.5x11.0x.75").withNumber("PageCount", 500)
                    .withBoolean("InPublication", true).withString("ProductCategory", "Book");
            table.putItem(item);

        } catch (Exception e) {
            System.err.println("Create items failed.");
            System.err.println(e.getMessage());

        }
    }

    private static void retrieveItem() {
        Table table = dynamoDB.getTable(tableName);

        try {

            Item item = table.getItem("Id", 120, "Id, ISBN, Title, Authors", null);

            System.out.println("Printing item after retrieving it....");
            System.out.println(item.toJSONPretty());

        } catch (Exception e) {
            System.err.println("GetItem failed.");
            System.err.println(e.getMessage());
        }

    }

    private static void updateAddNewAttribute() {
        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 121)
                    .withUpdateExpression("set #na = :val1").withNameMap(new NameMap().with("#na", "NewAttribute"))
                    .withValueMap(new ValueMap().withString(":val1", "Some value"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after adding new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to add new attribute in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void updateMultipleAttributes() {

        Table table = dynamoDB.getTable(tableName);

        try {

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withUpdateExpression("add #a :val1 set #na=:val2")
                    .withNameMap(new NameMap().with("#a", "Authors").with("#na", "NewAttribute"))
                    .withValueMap(
                            new ValueMap().withStringSet(":val1", "Author YY", "Author ZZ").withString(":val2",
                                    "someValue"))
                    .withReturnValues(ReturnValue.ALL_NEW);

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after multiple attribute update...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Failed to update multiple attributes in " + tableName);
            System.err.println(e.getMessage());

        }
    }

    private static void updateExistingAttributeConditionally() {

        Table table = dynamoDB.getTable(tableName);

        try {

            // Specify the desired price (25.00) and also the condition (price =
            // 20.00)

            UpdateItemSpec updateItemSpec = new UpdateItemSpec().withPrimaryKey("Id", 120)
                    .withReturnValues(ReturnValue.ALL_NEW).withUpdateExpression("set #p = :val1")
                    .withConditionExpression("#p = :val2").withNameMap(new NameMap().with("#p", "Price"))
                    .withValueMap(new ValueMap().withNumber(":val1", 25).withNumber(":val2", 20));

            UpdateItemOutcome outcome = table.updateItem(updateItemSpec);

            // Check the response.
            System.out.println("Printing item after conditional update to new attribute...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error updating item in " + tableName);
            System.err.println(e.getMessage());
        }
    }

    private static void deleteItem() {

        Table table = dynamoDB.getTable(tableName);

        try {

            DeleteItemSpec deleteItemSpec = new DeleteItemSpec().withPrimaryKey("Id", 120)
                    .withConditionExpression("#ip = :val").withNameMap(new NameMap().with("#ip", "InPublication"))
                    .withValueMap(new ValueMap().withBoolean(":val", false)).withReturnValues(ReturnValue.ALL_OLD);

            DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);

            // Check the response.
            System.out.println("Printing item that was deleted...");
            System.out.println(outcome.getItem().toJSONPretty());

        } catch (Exception e) {
            System.err.println("Error deleting item in " + tableName);
            System.err.println(e.getMessage());
        }
    }
}
```

# Esempio: operazioni Batch utilizzando l'API AWS SDK per Java dei documenti
<a name="batch-operation-document-api-java"></a>

Questa sezione fornisce esempi di operazioni di scrittura e acquisizione in batch in Amazon DynamoDB utilizzando AWS SDK per Java l'API Document.

**Nota**  
L'SDK per Java offre inoltre un modello di persistenza degli oggetti che permette di mappare le classi lato client alle tabelle DynamoDB. Questo approccio può ridurre la quantità di codice da scrivere. Per ulteriori informazioni, consulta [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

**Topics**
+ [Esempio: operazione di scrittura in batch utilizzando l'API del AWS SDK per Java documento](#JavaDocumentAPIBatchWrite)
+ [Esempio: operazione Batch get utilizzando l'API del AWS SDK per Java documento](#JavaDocumentAPIBatchGet)

## Esempio: operazione di scrittura in batch utilizzando l'API del AWS SDK per Java documento
<a name="JavaDocumentAPIBatchWrite"></a>

Nel seguente esempio di codice Java viene utilizzato il metodo `batchWriteItem` per eseguire le seguenti operazioni di eliminazione e inserimento:
+ inserimento di un item nella tabella `Forum`;
+ Inserimento di un item ed eliminazione di un item dalla tabella `Thread`. 

Quando crei la tua risposta di scrittura in batch, puoi specificare qualsiasi quantità di richieste di inserimento ed eliminazione in una o più tabelle. Tuttavia, `batchWriteItem` limita la dimensione di una richiesta di scrittura in batch e il numero di operazioni di inserimento ed eliminazione in una singola operazione di scrittura in batch. Se la tua richiesta eccede questi limiti, essa verrà rigettata. Se la tua tabella non dispone di sufficiente throughput assegnato per soddisfare questa richiesta, gli elementi di richiesta non eseguiti vengono restituiti nella risposta. 

Il seguente esempio controlla la risposta nel caso in cui vi siano degli elementi di richiesta non eseguiti. Se sono presenti, esegue il loopback e invia nuovamente la richiesta `batchWriteItem` con gli elementi non elaborati della richiesta. Seguendo gli esempi presenti in questa guida dovrebbe essere già avvenuta la creazione delle tabelle `Forum` e `Thread`. Puoi anche creare queste tabelle e caricare i dati di esempio a livello di programmazione. Per ulteriori informazioni, consulta [Creazione di tabelle di esempio e caricamento di dati utilizzando AWS SDK per Java](AppendixSampleDataCodeJava.md).

Per step-by-step istruzioni su come testare il seguente esempio, vedere[Esempi di codice Java](CodeSamples.Java.md). 

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchWriteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableWriteItems;
import com.amazonaws.services.dynamodbv2.model.WriteRequest;

public class DocumentAPIBatchWrite {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {

        writeMultipleItemsBatchWrite();

    }

    private static void writeMultipleItemsBatchWrite() {
        try {

            // Add a new item to Forum
            TableWriteItems forumTableWriteItems = new TableWriteItems(forumTableName) // Forum
                    .withItemsToPut(new Item().withPrimaryKey("Name", "Amazon RDS").withNumber("Threads", 0));

            // Add a new item, and delete an existing item, from Thread
            // This table has a partition key and range key, so need to specify
            // both of them
            TableWriteItems threadTableWriteItems = new TableWriteItems(threadTableName)
                    .withItemsToPut(
                            new Item().withPrimaryKey("ForumName", "Amazon RDS", "Subject", "Amazon RDS Thread 1")
                                    .withString("Message", "ElastiCache Thread 1 message")
                                    .withStringSet("Tags", new HashSet<String>(Arrays.asList("cache", "in-memory"))))
                    .withHashAndRangeKeysToDelete("ForumName", "Subject", "Amazon S3", "S3 Thread 100");

            System.out.println("Making the request.");
            BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem(forumTableWriteItems, threadTableWriteItems);

            do {

                // Check for unprocessed keys which could happen if you exceed
                // provisioned throughput

                Map<String, List<WriteRequest>> unprocessedItems = outcome.getUnprocessedItems();

                if (outcome.getUnprocessedItems().size() == 0) {
                    System.out.println("No unprocessed items found");
                } else {
                    System.out.println("Retrieving the unprocessed items");
                    outcome = dynamoDB.batchWriteItemUnprocessed(unprocessedItems);
                }

            } while (outcome.getUnprocessedItems().size() > 0);

        } catch (Exception e) {
            System.err.println("Failed to retrieve items: ");
            e.printStackTrace(System.err);
        }

    }

}
```

## Esempio: operazione Batch get utilizzando l'API del AWS SDK per Java documento
<a name="JavaDocumentAPIBatchGet"></a>

Nel seguente esempio di codice Java si utilizza il metodo `batchGetItem` per recuperare più item dalle tabelle `Forum` e `Thread`. L'item `BatchGetItemRequest` specifica i nomi delle tabelle e un elenco di chiavi per ogni item da ottenere. Nell'esempio si esegue la risposta stampando gli elementi recuperati.

**Nota**  
In questo esempio di codice si presuppone che i dati siano già stati caricati in DynamoDB per l'account seguendo le istruzioni riportate nella sezione [Creazione di tabelle e caricamento di dati per esempi di codice in DynamoDB](SampleData.md).  
Per step-by-step istruzioni su come eseguire l'esempio seguente, consulta[Esempi di codice Java](CodeSamples.Java.md).

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.BatchGetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableKeysAndAttributes;
import com.amazonaws.services.dynamodbv2.model.KeysAndAttributes;

public class DocumentAPIBatchGet {
    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String forumTableName = "Forum";
    static String threadTableName = "Thread";

    public static void main(String[] args) throws IOException {
        retrieveMultipleItemsBatchGet();
    }

    private static void retrieveMultipleItemsBatchGet() {

        try {

            TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes(forumTableName);
            // Add a partition key
            forumTableKeysAndAttributes.addHashOnlyPrimaryKeys("Name", "Amazon S3", "Amazon DynamoDB");

            TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes(threadTableName);
            // Add a partition key and a sort key
            threadTableKeysAndAttributes.addHashAndRangePrimaryKeys("ForumName", "Subject", "Amazon DynamoDB",
                    "DynamoDB Thread 1", "Amazon DynamoDB", "DynamoDB Thread 2", "Amazon S3", "S3 Thread 1");

            System.out.println("Making the request.");

            BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes,
                    threadTableKeysAndAttributes);

            Map<String, KeysAndAttributes> unprocessed = null;

            do {
                for (String tableName : outcome.getTableItems().keySet()) {
                    System.out.println("Items in table " + tableName);
                    List<Item> items = outcome.getTableItems().get(tableName);
                    for (Item item : items) {
                        System.out.println(item.toJSONPretty());
                    }
                }

                // Check for unprocessed keys which could happen if you exceed
                // provisioned
                // throughput or reach the limit on response size.
                unprocessed = outcome.getUnprocessedKeys();

                if (unprocessed.isEmpty()) {
                    System.out.println("No unprocessed keys found");
                } else {
                    System.out.println("Retrieving the unprocessed keys");
                    outcome = dynamoDB.batchGetItemUnprocessed(unprocessed);
                }

            } while (!unprocessed.isEmpty());

        } catch (Exception e) {
            System.err.println("Failed to retrieve items.");
            System.err.println(e.getMessage());
        }

    }

}
```

# Esempio: gestione degli attributi di tipo binario utilizzando l'API del AWS SDK per Java documento
<a name="JavaDocumentAPIBinaryTypeExample"></a>

Il seguente esempio di codice Java illustra come gestire gli attributi di tipo binario. L'esempio aggiunge un item alla tabella `Reply`. L'item include un attributo di tipo binario (`ExtendedMessage`) che memorizza i dati compressi. L'esempio recupera quindi l'item e stampa tutti valori degli attributi. Nell'esempio si utilizza la classe `GZIPOutputStream` per comprimere un flusso di esempio e assegnarlo all'attributo `ExtendedMessage`. Quando l'attributo binario viene recuperato, viene decompresso utilizzando la classe `GZIPInputStream`. 

**Nota**  
L'SDK per Java offre inoltre un modello di persistenza degli oggetti che permette di mappare le classi lato client alle tabelle DynamoDB. Questo approccio può ridurre la quantità di codice da scrivere. Per ulteriori informazioni, consulta [Java 1.x: Dinamo DBMapper](DynamoDBMapper.md).

Se hai seguito la sezione [Creazione di tabelle e caricamento di dati per esempi di codice in DynamoDB](SampleData.md) dovresti aver già creato la tabella `Reply`. Puoi anche creare questa tabella a livello di programmazione. Per ulteriori informazioni, consulta [Creazione di tabelle di esempio e caricamento di dati utilizzando AWS SDK per Java](AppendixSampleDataCodeJava.md).

Per step-by-step istruzioni su come testare il seguente esempio, vedere[Esempi di codice Java](CodeSamples.Java.md). 

**Example**  

```
package com.amazonaws.codesamples.document;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;

public class DocumentAPIItemBinaryExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    static String tableName = "Reply";
    static SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

    public static void main(String[] args) throws IOException {
        try {

            // Format the primary key values
            String threadId = "Amazon DynamoDB#DynamoDB Thread 2";

            dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            String replyDateTime = dateFormatter.format(new Date());

            // Add a new reply with a binary attribute type
            createItem(threadId, replyDateTime);

            // Retrieve the reply with a binary attribute type
            retrieveItem(threadId, replyDateTime);

            // clean up by deleting the item
            deleteItem(threadId, replyDateTime);
        } catch (Exception e) {
            System.err.println("Error running the binary attribute type example: " + e);
            e.printStackTrace(System.err);
        }
    }

    public static void createItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        // Craft a long message
        String messageInput = "Long message to be compressed in a lengthy forum reply";

        // Compress the long message
        ByteBuffer compressedMessage = compressString(messageInput.toString());

        table.putItem(new Item().withPrimaryKey("Id", threadId).withString("ReplyDateTime", replyDateTime)
                .withString("Message", "Long message follows").withBinary("ExtendedMessage", compressedMessage)
                .withString("PostedBy", "User A"));
    }

    public static void retrieveItem(String threadId, String replyDateTime) throws IOException {

        Table table = dynamoDB.getTable(tableName);

        GetItemSpec spec = new GetItemSpec().withPrimaryKey("Id", threadId, "ReplyDateTime", replyDateTime)
                .withConsistentRead(true);

        Item item = table.getItem(spec);

        // Uncompress the reply message and print
        String uncompressed = uncompressString(ByteBuffer.wrap(item.getBinary("ExtendedMessage")));

        System.out.println("Reply message:\n" + " Id: " + item.getString("Id") + "\n" + " ReplyDateTime: "
                + item.getString("ReplyDateTime") + "\n" + " PostedBy: " + item.getString("PostedBy") + "\n"
                + " Message: "
                + item.getString("Message") + "\n" + " ExtendedMessage (uncompressed): " + uncompressed + "\n");
    }

    public static void deleteItem(String threadId, String replyDateTime) {

        Table table = dynamoDB.getTable(tableName);
        table.deleteItem("Id", threadId, "ReplyDateTime", replyDateTime);
    }

    private static ByteBuffer compressString(String input) throws IOException {
        // Compress the UTF-8 encoded String into a byte[]
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream os = new GZIPOutputStream(baos);
        os.write(input.getBytes("UTF-8"));
        os.close();
        baos.close();
        byte[] compressedBytes = baos.toByteArray();

        // The following code writes the compressed bytes to a ByteBuffer.
        // A simpler way to do this is by simply calling
        // ByteBuffer.wrap(compressedBytes);
        // However, the longer form below shows the importance of resetting the
        // position of the buffer
        // back to the beginning of the buffer if you are writing bytes directly
        // to it, since the SDK
        // will consider only the bytes after the current position when sending
        // data to DynamoDB.
        // Using the "wrap" method automatically resets the position to zero.
        ByteBuffer buffer = ByteBuffer.allocate(compressedBytes.length);
        buffer.put(compressedBytes, 0, compressedBytes.length);
        buffer.position(0); // Important: reset the position of the ByteBuffer
                            // to the beginning
        return buffer;
    }

    private static String uncompressString(ByteBuffer input) throws IOException {
        byte[] bytes = input.array();
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPInputStream is = new GZIPInputStream(bais);

        int chunkSize = 1024;
        byte[] buffer = new byte[chunkSize];
        int length = 0;
        while ((length = is.read(buffer, 0, chunkSize)) != -1) {
            baos.write(buffer, 0, length);
        }

        String result = new String(baos.toByteArray(), "UTF-8");

        is.close();
        baos.close();
        bais.close();

        return result;
    }
}
```

# Uso di elementi: .NET
<a name="LowLevelDotNetItemCRUD"></a>

È possibile utilizzare l'API di AWS SDK per .NET basso livello per eseguire operazioni tipiche di creazione, lettura, aggiornamento ed eliminazione (CRUD) su un elemento di una tabella. Di seguito sono riportate le fasi comuni per eseguire le operazione CRUD sui dati, usando l'API di basso livello .NET:

1. Crea un'istanza della classe `AmazonDynamoDBClient` (client).

1. Fornisci i parametri obbligatori e specifici per l'operazione in un oggetto di richiesta corrispondente.

   Per esempio, usa l'oggetto di richiesta `PutItemRequest` durante il caricamento di un item e l'oggetto di richiesta `GetItemRequest` quando recuperi un item esistente. 

   Puoi usare l'oggetto di richiesta per fornire sia i parametri obbligatori sia quelli facoltativi; 

1. Eseguire il metodo appropriato fornito dal client inviando l'oggetto di richiesta creato nella fase precedente. 

   Il client `AmazonDynamoDBClient` fornisce i metodi `PutItem`, `GetItem`, `UpdateItem` e `DeleteItem` per le operazioni CRUD.

**Topics**
+ [Collocazione di un elemento](#PutItemLowLevelAPIDotNet)
+ [Ottenimento di un elemento](#GetItemLowLevelDotNET)
+ [Aggiornamento di un elemento](#UpdateItemLowLevelDotNet)
+ [Contatore atomico](#AtomicCounterLowLevelDotNet)
+ [Eliminazione di un elemento](#DeleteMidLevelDotNet)
+ [Scrittura in batch: collocazione ed eliminazione di più elementi](#BatchWriteLowLevelDotNet)
+ [Ricezione in batch: ricezione di più elementi](#BatchGetLowLevelDotNet)
+ [Esempio: operazioni CRUD che utilizzano l'API di AWS SDK per .NET basso livello](LowLevelDotNetItemsExample.md)
+ [Esempio: operazioni Batch utilizzando l'API AWS SDK per .NET di basso livello](batch-operation-lowlevel-dotnet.md)
+ [Esempio: gestione degli attributi di tipo binario utilizzando l'API di AWS SDK per .NET basso livello](LowLevelDotNetBinaryTypeExample.md)

## Collocazione di un elemento
<a name="PutItemLowLevelAPIDotNet"></a>

Il metodo `PutItem` carica un item nella tabella. Se l'item esiste, lo sostituisce per intero.

**Nota**  
Se invece di sostituire l'intero item vuoi aggiornare solo attributi specifici, puoi utilizzare il metodo `UpdateItem`. Per ulteriori informazioni, consulta [Aggiornamento di un elemento](#UpdateItemLowLevelDotNet).

Di seguito sono riportate le fasi per caricare un item usando l'API di basso livello dell'SDK per .NET:

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. fornisci i parametri obbligatori creando un istanza della classe `PutItemRequest`.

   Per inserire un item, è necessario fornire il nome della tabella e l'item; 

1. Eseguire il metodo `PutItem` fornendo l'oggetto `PutItemRequest` creato nella fase precedente.

Il seguente esempio C\$1 mostra le fasi precedenti. L'esempio carica un item nella tabella `ProductCatalog`.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new PutItemRequest
{
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
      {
          { "Id", new AttributeValue { N = "201" }},
          { "Title", new AttributeValue { S = "Book 201 Title" }},
          { "ISBN", new AttributeValue { S = "11-11-11-11" }},
          { "Price", new AttributeValue { S = "20.00" }},
          {
            "Authors",
            new AttributeValue
            { SS = new List<string>{"Author1", "Author2"}   }
          }
      }
};
client.PutItem(request);
```

Nell'esempio precedente, carica un item libro che abbia gli attributi `Id`, `Title`, `ISBN` e `Authors`. Nota che `Id` è un attributo di tipo numerico, mentre tutti gli altri sono tipo stringa. Authors è un set di `String`.

### Specifica dei parametri facoltativi
<a name="PutItemLowLevelAPIDotNetOptions"></a>

Puoi anche fornire parametri facoltativi usando l'oggetto `PutItemRequest`, come mostrato nel seguente esempio C\$1. L'esempio specifica i parametri facoltativi seguenti:
+ `ExpressionAttributeNames`, `ExpressionAttributeValues` e `ConditionExpression` specificano che l'item può essere sostituito solo se l'item esistente ha l'attributo ISBN con un valore specifico.
+ Il parametro `ReturnValues` per richiedere il vecchio item nella risposta.

**Example**  

```
var request = new PutItemRequest
 {
   TableName = tableName,
   Item = new Dictionary<string, AttributeValue>()
               {
                   { "Id", new AttributeValue { N = "104" }},
                   { "Title", new AttributeValue { S = "Book 104  Title" }},
                   { "ISBN", new AttributeValue { S = "444-4444444444" }},
                   { "Authors",
                     new AttributeValue { SS = new List<string>{"Author3"}}}
               },
    // Optional parameters.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":isbn",new AttributeValue {S = "444-4444444444"}}
    },
    ConditionExpression = "#I = :isbn"

};
var response = client.PutItem(request);
```

Per ulteriori informazioni, consulta [PutItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html).

## Ottenimento di un elemento
<a name="GetItemLowLevelDotNET"></a>

Il metodo `GetItem` recupera un item.

**Nota**  
Per recuperare più item puoi usare il metodo `BatchGetItem`. Per ulteriori informazioni, consulta [Ricezione in batch: ricezione di più elementi](#BatchGetLowLevelDotNet).

Di seguito sono riportate le fasi per recuperare un item esistente usando l'API di basso livello di AWS SDK per .NET .

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. fornisci i parametri obbligatori creando un istanza della classe `GetItemRequest`.

   Per ottenere un item, è necessario fornire il nome della tabella e la chiave primaria dell'item. 

1. Eseguire il metodo `GetItem` fornendo l'oggetto `GetItemRequest` creato nella fase precedente.

Il seguente esempio C\$1 mostra le fasi precedenti. L'esempio recupera un item dalla tabella `ProductCatalog`.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
 };
 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item; // Attribute list in the response.
```

### Specifica dei parametri facoltativi
<a name="GetItemLowLevelDotNETOptions"></a>

Puoi anche fornire parametri facoltativi usando l'oggetto `GetItemRequest`, come mostrato nel seguente esempio C\$1. L'esempio specifica i parametri facoltativi seguenti:
+ Il parametro `ProjectionExpression` per specificare gli attributi da recuperare.
+ Il parametro `ConsistentRead` per eseguire una lettura estremamente coerente. Per ulteriori informazioni sulla lettura coerente, consulta [Coerenza di lettura di DynamoDB](HowItWorks.ReadConsistency.md).

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new GetItemRequest
 {
   TableName = tableName,
   Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
   // Optional parameters.
   ProjectionExpression = "Id, ISBN, Title, Authors",
   ConsistentRead = true
 };

 var response = client.GetItem(request);

// Check the response.
var result = response.GetItemResult;
var attributeMap = result.Item;
```

Per ulteriori informazioni, consulta [GetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html).

## Aggiornamento di un elemento
<a name="UpdateItemLowLevelDotNet"></a>

Il metodo `UpdateItem` aggiorna un item esistente se presente. Puoi usare l'operazione `UpdateItem` per aggiornare i valori degli attributi esistenti, aggiungere nuovi attributi o eliminare attributi dalla raccolta esistente. Se non viene trovato l'item che dispone della chiave primaria specificata, viene aggiunto un nuovo item.

L'operazione `UpdateItem` usa le seguenti linee guida:
+ Se l'item non esiste, `UpdateItem` aggiunge un nuovo item usando la chiave primaria specificata nell'input.
+ Se l'item esiste, `UpdateItem` applica gli aggiornamenti come segue:
  + sostituisce il valore dell'attributo esistente attraverso i valori dell'aggiornamento;
  + se l'attributo che fornisci nell'input non esiste, viene aggiunto un nuovo attributo all'item;
  + se l'attributo di input è nullo, viene eliminato l'attributo qualora presente; 
  + se utilizzi `ADD` per `Action`, puoi aggiungere valori a un set esistente (di stringhe o numeri) o aggiungere (se usi un numero positivo) o sottrarre (se usi un numero negativo) matematicamente dal valore dell'attributo numerico esistente.

**Nota**  
L'operazione `PutItem` può anche eseguire un aggiornamento. Per ulteriori informazioni, consulta [Collocazione di un elemento](#PutItemLowLevelAPIDotNet). Ad esempio, se chiami `PutItem` per caricare un item e la chiave primaria esiste, l'operazione `PutItem` sostituisce l'intero item. Se vi sono attributi nell'item esistente e quegli attributi non sono specificati nell'input, l'operazione `PutItem` li elimina. Tuttavia, `UpdateItem` aggiorna solo gli attributi di input specificati. Qualsiasi altro attributo esistente di quell'item rimarrà invariato. 

Di seguito sono riportate le fasi per aggiornare un item esistente usando l'API di basso livello dell'SDK per .NET:

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. fornisci i parametri obbligatori creando un istanza della classe `UpdateItemRequest`.

   Questo è l'oggetto di richiesta in cui descrivi tutti gli aggiornamenti, come l'aggiunta di attributi, l'aggiornamento di quelli esistenti o l'eliminazione di attributi. Per rimuovere un attributo esistente, specifica il nome dell'attributo con valore nullo; 

1. Eseguire il metodo `UpdateItem` fornendo l'oggetto `UpdateItemRequest` creato nella fase precedente. 

Il seguente esempio di codice C\$1 mostra le fasi precedenti. L'esempio aggiorna un item libro nella tabella `ProductCatalog`. Aggiunge un nuovo autore alla raccolta `Authors` ed elimina l'attributo `ISBN` esistente. Inoltre, riduce il prezzo di una unità.



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#A", "Authors"},
        {"#P", "Price"},
        {"#NA", "NewAttribute"},
        {"#I", "ISBN"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":auth",new AttributeValue { SS = {"Author YY","Author ZZ"}}},
        {":p",new AttributeValue {N = "1"}},
        {":newattr",new AttributeValue {S = "someValue"}},
    },

    // This expression does the following:
    // 1) Adds two new authors to the list
    // 2) Reduces the price
    // 3) Adds a new attribute to the item
    // 4) Removes the ISBN attribute from the item
    UpdateExpression = "ADD #A :auth SET #P = #P - :p, #NA = :newattr REMOVE #I"
};
var response = client.UpdateItem(request);
```

### Specifica dei parametri facoltativi
<a name="UpdateItemLowLevelDotNETOptions"></a>

Puoi anche fornire parametri facoltativi usando l'oggetto `UpdateItemRequest`, come mostrato nel seguente esempio C\$1. Esso specifica i seguenti parametri opzionali:
+ `ExpressionAttributeValues` e `ConditionExpression` per specificare che il prezzo può essere aggiornato solo se il prezzo esistente è 20,00;
+ il parametro `ReturnValues` per richiedere l'item aggiornato nella risposta. 

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "202" } } },

    // Update price only if the current price is 20.00.
    ExpressionAttributeNames = new Dictionary<string,string>()
    {
        {"#P", "Price"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":newprice",new AttributeValue {N = "22"}},
        {":currprice",new AttributeValue {N = "20"}}
    },
    UpdateExpression = "SET #P = :newprice",
    ConditionExpression = "#P = :currprice",
    TableName = tableName,
    ReturnValues = "ALL_NEW" // Return all the attributes of the updated item.
};

var response = client.UpdateItem(request);
```

Per ulteriori informazioni, consulta [UpdateItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html). 

## Contatore atomico
<a name="AtomicCounterLowLevelDotNet"></a>

Puoi usare il metodo `updateItem` per implementare un contatore atomico e incrementare o decrementare il valore di un attributo esistente senza interferire con altre richieste di scrittura. Per aggiornare un contatore atomico, usa `updateItem` con un attributo di tipo `Number` nel parametro `UpdateExpression` e `ADD` come `Action`.

Il seguente esempio ne dimostra l'uso, incrementando l'attributo `Quantity` di uno.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new UpdateItemRequest
{
    Key = new Dictionary<string, AttributeValue>() { { "Id", new AttributeValue { N = "121" } } },
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#Q", "Quantity"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":incr",new AttributeValue {N = "1"}}
    },
    UpdateExpression = "SET #Q = #Q + :incr",
    TableName = tableName
};

var response = client.UpdateItem(request);
```

## Eliminazione di un elemento
<a name="DeleteMidLevelDotNet"></a>

Il metodo `DeleteItem` elimina un item da una tabella. 

Di seguito sono riportate le fasi per eliminare un item usando l'API dell'SDK per .NET di basso livello. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. fornisci i parametri obbligatori creando un istanza della classe `DeleteItemRequest`.

    Per eliminare un item, sono necessari il nome della tabella e la chiave primaria dell'item; 

1. Eseguire il metodo `DeleteItem` fornendo l'oggetto `DeleteItemRequest` creato nella fase precedente. 

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "ProductCatalog";

var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },
};

var response = client.DeleteItem(request);
```

### Specifica dei parametri facoltativi
<a name="DeleteItemLowLevelDotNETOptions"></a>

Puoi anche fornire parametri facoltativi usando l'oggetto `DeleteItemRequest`, come mostrato nel seguente esempio di codice C\$1. Esso specifica i seguenti parametri opzionali:
+ `ExpressionAttributeValues`e `ConditionExpression` per specificare che l'elemento del libro può essere eliminato solo se non è più in pubblicazione (il valore dell' InPublication attributo è false). 
+ il parametro `ReturnValues` per richiedere l'item eliminato nella risposta.

**Example**  

```
var request = new DeleteItemRequest
{
    TableName = tableName,
    Key = new Dictionary<string,AttributeValue>() { { "Id", new AttributeValue { N = "201" } } },

    // Optional parameters.
    ReturnValues = "ALL_OLD",
    ExpressionAttributeNames = new Dictionary<string, string>()
    {
        {"#IP", "InPublication"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":inpub",new AttributeValue {BOOL = false}}
    },
    ConditionExpression = "#IP = :inpub"
};

var response = client.DeleteItem(request);
```

Per ulteriori informazioni, consulta [DeleteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html).

## Scrittura in batch: collocazione ed eliminazione di più elementi
<a name="BatchWriteLowLevelDotNet"></a>

La *scrittura in batch* fa riferimento alla collocazione e all'eliminazione di più item in un batch. Il metodo `BatchWriteItem` ti consente di inserire ed eliminare più item da una o più tabelle con un'unica chiamata. Di seguito sono riportate le fasi per recuperare più item usando l'API di basso livello dell'SDK per .NET.

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. descrivi tutte le operazioni di inserimento ed eliminazione creando un istanza della classe `BatchWriteItemRequest`;

1. Eseguire il metodo `BatchWriteItem` fornendo l'oggetto `BatchWriteItemRequest` creato nella fase precedente.

1. Elabora la risposta. Dovresti controllare se erano presenti item di richiesta non elaborati restituiti nella risposta. Questo potrebbe accadere se raggiungi la quota di throughput assegnata o si verifica un altro errore transitorio. Inoltre, DynamoDB limita la dimensione della richiesta e il numero di operazioni che possono essere specificate in una richiesta. Se si superano questi limiti, DynamoDB rifiuta la richiesta. Per ulteriori informazioni, consulta [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). 

Il seguente esempio di codice C\$1 mostra le fasi precedenti. L'esempio crea un `BatchWriteItemRequest` per eseguire le seguenti operazioni di scrittura:
+ inserisci un item nella tabella `Forum`;
+ inserisce ed elimina un item dalla tabella `Thread`.

Il codice quindi esegue `BatchWriteItem` per l'operazione in batch.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchWriteItemRequest
 {
   RequestItems = new Dictionary<string, List<WriteRequest>>
    {
      {
        table1Name, new List<WriteRequest>
        {
          new WriteRequest
          {
             PutRequest = new PutRequest
             {
                Item = new Dictionary<string,AttributeValue>
                {
                  { "Name", new AttributeValue { S = "Amazon S3 forum" } },
                  { "Threads", new AttributeValue { N = "0" }}
                }
             }
          }
        }
      } ,
      {
        table2Name, new List<WriteRequest>
        {
          new WriteRequest
          {
            PutRequest = new PutRequest
            {
               Item = new Dictionary<string,AttributeValue>
               {
                 { "ForumName", new AttributeValue { S = "Amazon S3 forum" } },
                 { "Subject", new AttributeValue { S = "My sample question" } },
                 { "Message", new AttributeValue { S = "Message Text." } },
                 { "KeywordTags", new AttributeValue { SS = new List<string> { "Amazon S3", "Bucket" }  } }
               }
            }
          },
          new WriteRequest
          {
             DeleteRequest = new DeleteRequest
             {
                Key = new Dictionary<string,AttributeValue>()
                {
                   { "ForumName", new AttributeValue { S = "Some forum name" } },
                   { "Subject", new AttributeValue { S = "Some subject" } }
                }
             }
          }
        }
      }
    }
 };
response = client.BatchWriteItem(request);
```

Per un esempio di utilizzo, consulta [Esempio: operazioni Batch utilizzando l'API AWS SDK per .NET di basso livello](batch-operation-lowlevel-dotnet.md). 

## Ricezione in batch: ricezione di più elementi
<a name="BatchGetLowLevelDotNet"></a>

Il metodo `BatchGetItem` ti consente di recuperare più item da una o più tabelle. 

**Nota**  
Per recuperare un singolo item puoi usare il metodo `GetItem`. 

Di seguito sono riportate le fasi per recuperare più item usando l'API di basso livello di AWS SDK per .NET .

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. fornisci i parametri obbligatori creando un istanza della classe `BatchGetItemRequest`.

   Per recuperare più item, sono necessari il nome della tabella e un elenco dei valori della chiave primaria. 

1. Eseguire il metodo `BatchGetItem` fornendo l'oggetto `BatchGetItemRequest` creato nella fase precedente.

1. Elabora la risposta. Dovresti controllare se erano presenti chiavi non elaborate. Questo potrebbe accadere se hai raggiunto la quota di throughput assegnata o alcuni errori di transizione.

Il seguente esempio di codice C\$1 mostra le fasi precedenti. L'esempio recupera gli elementi da due tabelle, `Forum` e `Thread`. La richiesta specifica due item nella tabella `Forum` e tre nella tabella `Thread`. La risposta include item da entrambe le tabelle. Il codice mostra come puoi elaborare la risposta.



```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";
string table2Name = "Thread";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      }
    },
    {
      table2Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 1" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "DynamoDB" } },
            { "Subject", new AttributeValue { S = "DynamoDB Thread 2" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "ForumName", new AttributeValue { S = "Amazon S3" } },
            { "Subject", new AttributeValue { S = "Amazon S3 Thread 1" } }
          }
        }
      }
    }
  }
};

var response = client.BatchGetItem(request);

// Check the response.
var result = response.BatchGetItemResult;
var responses = result.Responses; // The attribute list in the response.

var table1Results = responses[table1Name];
Console.WriteLine("Items in table {0}" + table1Name);
foreach (var item1 in table1Results.Items)
{
  PrintItem(item1);
}

var table2Results = responses[table2Name];
Console.WriteLine("Items in table {1}" + table2Name);
foreach (var item2 in table2Results.Items)
{
  PrintItem(item2);
}
// Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
Dictionary<string, KeysAndAttributes> unprocessedKeys = result.UnprocessedKeys;
foreach (KeyValuePair<string, KeysAndAttributes> pair in unprocessedKeys)
{
    Console.WriteLine(pair.Key, pair.Value);
}
```



### Specifica dei parametri facoltativi
<a name="BatchGetItemLowLevelDotNETOptions"></a>

Puoi anche fornire parametri facoltativi usando l'oggetto `BatchGetItemRequest`, come mostrato nel seguente esempio di codice C\$1. L'esempio recupera un item dalla tabella `Forum`. Esso specifica il seguente parametro opzionale:
+  Il parametro `ProjectionExpression` per specificare gli attributi da recuperare.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();

string table1Name = "Forum";

var request = new BatchGetItemRequest
{
  RequestItems = new Dictionary<string, KeysAndAttributes>()
  {
    { table1Name,
      new KeysAndAttributes
      {
        Keys = new List<Dictionary<string, AttributeValue>>()
        {
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "DynamoDB" } }
          },
          new Dictionary<string, AttributeValue>()
          {
            { "Name", new AttributeValue { S = "Amazon S3" } }
          }
        }
      },
      // Optional - name of an attribute to retrieve.
      ProjectionExpression = "Title"
    }
  }
};

var response = client.BatchGetItem(request);
```

Per ulteriori informazioni, consulta [BatchGetItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html). 

# Esempio: operazioni CRUD che utilizzano l'API di AWS SDK per .NET basso livello
<a name="LowLevelDotNetItemsExample"></a>

Il seguente esempio di codice C\$1 illustra le operazioni CRUD su un elemento di Amazon DynamoDB. L'esempio consente di aggiungere un item alla tabella `ProductCatalog`, di recuperarlo, eseguire diversi aggiornamenti e, infine, eliminare l'item. Se questa tabella non è stata creata, è possibile crearla anche tramite programmazione. Per ulteriori informazioni, consulta [Creazione di tabelle di esempio e caricamento di dati utilizzando AWS SDK per .NET](AppendixSampleDataCodeDotNET.md).

Per step-by-step istruzioni su come testare il seguente esempio, vedere. [Esempi di codice .NET](CodeSamples.DotNet.md) 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelItemCRUDExample
    {
        private static string tableName = "ProductCatalog";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                CreateItem();
                RetrieveItem();

                // Perform various updates.
                UpdateMultipleAttributes();
                UpdateExistingAttributeConditionally();

                // Delete item.
                DeleteItem();
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
        }

        private static void CreateItem()
        {
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  }},
                { "Title", new AttributeValue {
                      S = "Book 201 Title"
                  }},
                { "ISBN", new AttributeValue {
                      S = "11-11-11-11"
                  }},
                { "Authors", new AttributeValue {
                      SS = new List<string>{"Author1", "Author2" }
                  }},
                { "Price", new AttributeValue {
                      N = "20.00"
                  }},
                { "Dimensions", new AttributeValue {
                      S = "8.5x11.0x.75"
                  }},
                { "InPublication", new AttributeValue {
                      BOOL = false
                  } }
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem()
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ProjectionExpression = "Id, ISBN, Title, Authors",
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");
            PrintItem(attributeList);
        }

        private static void UpdateMultipleAttributes()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                // Perform the following updates:
                // 1) Add two new authors to the list
                // 1) Set a new attribute
                // 2) Remove the ISBN attribute
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#A","Authors"},
                {"#NA","NewAttribute"},
                {"#I","ISBN"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":auth",new AttributeValue {
                     SS = {"Author YY", "Author ZZ"}
                 }},
                {":new",new AttributeValue {
                     S = "New Value"
                 }}
            },

                UpdateExpression = "ADD #A :auth SET #NA = :new REMOVE #I",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
                                                     // print attributeList.
            Console.WriteLine("\nPrinting item after multiple attribute update ............");
            PrintItem(attributeList);
        }

        private static void UpdateExistingAttributeConditionally()
        {
            var request = new UpdateItemRequest
            {
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#P", "Price"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":newprice",new AttributeValue {
                     N = "22.00"
                 }},
                {":currprice",new AttributeValue {
                     N = "20.00"
                 }}
            },
                // This updates price only if current price is 20.00.
                UpdateExpression = "SET #P = :newprice",
                ConditionExpression = "#P = :currprice",

                TableName = tableName,
                ReturnValues = "ALL_NEW" // Give me all attributes of the updated item.
            };
            var response = client.UpdateItem(request);

            // Check the response.
            var attributeList = response.Attributes; // attribute list in the response.
            Console.WriteLine("\nPrinting item after updating price value conditionally ............");
            PrintItem(attributeList);
        }

        private static void DeleteItem()
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      N = "1000"
                  } }
            },

                // Return the entire item as it appeared before the update.
                ReturnValues = "ALL_OLD",
                ExpressionAttributeNames = new Dictionary<string, string>()
            {
                {"#IP", "InPublication"}
            },
                ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
            {
                {":inpub",new AttributeValue {
                     BOOL = false
                 }}
            },
                ConditionExpression = "#IP = :inpub"
            };

            var response = client.DeleteItem(request);

            // Check the response.
            var attributeList = response.Attributes; // Attribute list in the response.
                                                     // Print item.
            Console.WriteLine("\nPrinting item that was just deleted ............");
            PrintItem(attributeList);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# Esempio: operazioni Batch utilizzando l'API AWS SDK per .NET di basso livello
<a name="batch-operation-lowlevel-dotnet"></a>

**Topics**
+ [Esempio: operazione di scrittura in batch utilizzando l'API AWS SDK per .NET di basso livello](#batch-write-low-level-dotnet)
+ [Esempio: operazione Batch get utilizzando l'API di AWS SDK per .NET basso livello](#LowLevelDotNetBatchGet)

In questa sezione vengono forniti esempi di operazioni in batch, *scrittura in batch* e *get in batch* supportate da Amazon DynamoDB.

## Esempio: operazione di scrittura in batch utilizzando l'API AWS SDK per .NET di basso livello
<a name="batch-write-low-level-dotnet"></a>

Nel seguente esempio di codice C\$1 viene utilizzato il metodo `BatchWriteItem` per eseguire le seguenti operazioni di eliminazione e inserimento:
+ inserimento di un item nella tabella `Forum`;
+ Inserimento di un item ed eliminazione di un item dalla tabella `Thread`. 

Quando crei la tua risposta di scrittura in batch, puoi specificare qualsiasi quantità di richieste di inserimento ed eliminazione in una o più tabelle. Tuttavia, `BatchWriteItem` limita la dimensione di una richiesta di scrittura in batch e il numero di operazioni put e delete in una singola operazione di scrittura in batch. Per ulteriori informazioni, consulta [BatchWriteItem](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html). Se la tua richiesta eccede questi limiti, essa verrà rigettata. Se la tua tabella non dispone di sufficiente throughput assegnato per soddisfare questa richiesta, gli elementi di richiesta non eseguiti vengono restituiti nella risposta. 

Il seguente esempio controlla la risposta nel caso in cui vi siano degli elementi di richiesta non eseguiti. Se sono presenti, esegue il loopback e invia nuovamente la richiesta `BatchWriteItem` con gli elementi non elaborati della richiesta. Puoi anche creare queste tabelle di esempio e caricare i dati di esempio in modo programmatico. Per ulteriori informazioni, consulta [Creazione di tabelle di esempio e caricamento di dati utilizzando AWS SDK per .NET](AppendixSampleDataCodeDotNET.md).

Per step-by-step istruzioni su come testare il seguente esempio, vedere[Esempi di codice .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchWrite
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                TestBatchWrite();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }

            Console.WriteLine("To continue, press Enter");
            Console.ReadLine();
        }

        private static void TestBatchWrite()
        {
            var request = new BatchWriteItemRequest
            {
                ReturnConsumedCapacity = "TOTAL",
                RequestItems = new Dictionary<string, List<WriteRequest>>
            {
                {
                    table1Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "Name", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Threads", new AttributeValue {
                                          N = "0"
                                      }}
                                }
                            }
                        }
                    }
                },
                {
                    table2Name, new List<WriteRequest>
                    {
                        new WriteRequest
                        {
                            PutRequest = new PutRequest
                            {
                                Item = new Dictionary<string, AttributeValue>
                                {
                                    { "ForumName", new AttributeValue {
                                          S = "S3 forum"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "My sample question"
                                      } },
                                    { "Message", new AttributeValue {
                                          S = "Message Text."
                                      } },
                                    { "KeywordTags", new AttributeValue {
                                          SS = new List<string> { "S3", "Bucket" }
                                      } }
                                }
                            }
                        },
                        new WriteRequest
                        {
                            // For the operation to delete an item, if you provide a primary key value
                            // that does not exist in the table, there is no error, it is just a no-op.
                            DeleteRequest = new DeleteRequest
                            {
                                Key = new Dictionary<string, AttributeValue>()
                                {
                                    { "ForumName",  new AttributeValue {
                                          S = "Some partition key value"
                                      } },
                                    { "Subject", new AttributeValue {
                                          S = "Some sort key value"
                                      } }
                                }
                            }
                        }
                    }
                }
            }
            };

            CallBatchWriteTillCompletion(request);
        }

        private static void CallBatchWriteTillCompletion(BatchWriteItemRequest request)
        {
            BatchWriteItemResponse response;

            int callCount = 0;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchWriteItem(request);
                callCount++;

                // Check the response.

                var tableConsumedCapacities = response.ConsumedCapacity;
                var unprocessed = response.UnprocessedItems;

                Console.WriteLine("Per-table consumed capacity");
                foreach (var tableConsumedCapacity in tableConsumedCapacities)
                {
                    Console.WriteLine("{0} - {1}", tableConsumedCapacity.TableName, tableConsumedCapacity.CapacityUnits);
                }

                Console.WriteLine("Unprocessed");
                foreach (var unp in unprocessed)
                {
                    Console.WriteLine("{0} - {1}", unp.Key, unp.Value.Count);
                }
                Console.WriteLine();

                // For the next iteration, the request will have unprocessed items.
                request.RequestItems = unprocessed;
            } while (response.UnprocessedItems.Count > 0);

            Console.WriteLine("Total # of batch write API calls made: {0}", callCount);
        }
    }
}
```

## Esempio: operazione Batch get utilizzando l'API di AWS SDK per .NET basso livello
<a name="LowLevelDotNetBatchGet"></a>

Il seguente esempio di codice C\$1 utilizza il metodo `BatchGetItem` per recuperare più elementi dalle tabelle `Forum` e `Thread` in Amazon DynamoDB. L'item `BatchGetItemRequest` specifica i nomi delle tabelle e un elenco di chiavi primarie per ogni tabella. Nell'esempio si esegue la risposta stampando gli elementi recuperati. 

Per step-by-step istruzioni su come testare il seguente esempio, vedere[Esempi di codice .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelBatchGet
    {
        private static string table1Name = "Forum";
        private static string table2Name = "Thread";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            try
            {
                RetrieveMultipleItemsBatchGet();

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void RetrieveMultipleItemsBatchGet()
        {
            var request = new BatchGetItemRequest
            {
                RequestItems = new Dictionary<string, KeysAndAttributes>()
            {
                { table1Name,
                  new KeysAndAttributes
                  {
                      Keys = new List<Dictionary<string, AttributeValue> >()
                      {
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon DynamoDB"
                        } }
                          },
                          new Dictionary<string, AttributeValue>()
                          {
                              { "Name", new AttributeValue {
                            S = "Amazon S3"
                        } }
                          }
                      }
                  }},
                {
                    table2Name,
                    new KeysAndAttributes
                    {
                        Keys = new List<Dictionary<string, AttributeValue> >()
                        {
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 1"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon DynamoDB"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "DynamoDB Thread 2"
                                  } }
                            },
                            new Dictionary<string, AttributeValue>()
                            {
                                { "ForumName", new AttributeValue {
                                      S = "Amazon S3"
                                  } },
                                { "Subject", new AttributeValue {
                                      S = "S3 Thread 1"
                                  } }
                            }
                        }
                    }
                }
            }
            };

            BatchGetItemResponse response;
            do
            {
                Console.WriteLine("Making request");
                response = client.BatchGetItem(request);

                // Check the response.
                var responses = response.Responses; // Attribute list in the response.

                foreach (var tableResponse in responses)
                {
                    var tableResults = tableResponse.Value;
                    Console.WriteLine("Items retrieved from table {0}", tableResponse.Key);
                    foreach (var item1 in tableResults)
                    {
                        PrintItem(item1);
                    }
                }

                // Any unprocessed keys? could happen if you exceed ProvisionedThroughput or some other error.
                Dictionary<string, KeysAndAttributes> unprocessedKeys = response.UnprocessedKeys;
                foreach (var unprocessedTableKeys in unprocessedKeys)
                {
                    // Print table name.
                    Console.WriteLine(unprocessedTableKeys.Key);
                    // Print unprocessed primary keys.
                    foreach (var key in unprocessedTableKeys.Value.Keys)
                    {
                        PrintItem(key);
                    }
                }

                request.RequestItems = unprocessedKeys;
            } while (response.UnprocessedKeys.Count > 0);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }
    }
}
```

# Esempio: gestione degli attributi di tipo binario utilizzando l'API di AWS SDK per .NET basso livello
<a name="LowLevelDotNetBinaryTypeExample"></a>

Il seguente esempio di codice C\$1 illustra come gestire gli attributi di tipo binario. L'esempio aggiunge un item alla tabella `Reply`. L'item include un attributo di tipo binario (`ExtendedMessage`) che memorizza i dati compressi. L'esempio recupera quindi l'item e stampa tutti valori degli attributi. A titolo illustrativo, l'esempio usa la classe `GZipStream` per comprimere un flusso di esempio, assegnarlo all'attributo `ExtendedMessage` e per poi decomprimerlo durante la stampa del valore dell'attributo. 

Per step-by-step istruzioni su come testare l'esempio seguente, consulta[Esempi di codice .NET](CodeSamples.DotNet.md). 

**Example**  

```
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;

namespace com.amazonaws.codesamples
{
    class LowLevelItemBinaryExample
    {
        private static string tableName = "Reply";
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();

        static void Main(string[] args)
        {
            // Reply table primary key.
            string replyIdPartitionKey = "Amazon DynamoDB#DynamoDB Thread 1";
            string replyDateTimeSortKey = Convert.ToString(DateTime.UtcNow);

            try
            {
                CreateItem(replyIdPartitionKey, replyDateTimeSortKey);
                RetrieveItem(replyIdPartitionKey, replyDateTimeSortKey);
                // Delete item.
                DeleteItem(replyIdPartitionKey, replyDateTimeSortKey);
                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateItem(string partitionKey, string sortKey)
        {
            MemoryStream compressedMessage = ToGzipMemoryStream("Some long extended message to compress.");
            var request = new PutItemRequest
            {
                TableName = tableName,
                Item = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  }},
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  }},
                { "Subject", new AttributeValue {
                      S = "Binary type "
                  }},
                { "Message", new AttributeValue {
                      S = "Some message about the binary type"
                  }},
                { "ExtendedMessage", new AttributeValue {
                      B = compressedMessage
                  }}
            }
            };
            client.PutItem(request);
        }

        private static void RetrieveItem(string partitionKey, string sortKey)
        {
            var request = new GetItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            },
                ConsistentRead = true
            };
            var response = client.GetItem(request);

            // Check the response.
            var attributeList = response.Item; // attribute list in the response.
            Console.WriteLine("\nPrinting item after retrieving it ............");

            PrintItem(attributeList);
        }

        private static void DeleteItem(string partitionKey, string sortKey)
        {
            var request = new DeleteItemRequest
            {
                TableName = tableName,
                Key = new Dictionary<string, AttributeValue>()
            {
                { "Id", new AttributeValue {
                      S = partitionKey
                  } },
                { "ReplyDateTime", new AttributeValue {
                      S = sortKey
                  } }
            }
            };
            var response = client.DeleteItem(request);
        }

        private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
        {
            foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
            {
                string attributeName = kvp.Key;
                AttributeValue value = kvp.Value;

                Console.WriteLine(
                    attributeName + " " +
                    (value.S == null ? "" : "S=[" + value.S + "]") +
                    (value.N == null ? "" : "N=[" + value.N + "]") +
                    (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
                    (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]") +
                    (value.B == null ? "" : "B=[" + FromGzipMemoryStream(value.B) + "]")
                    );
            }
            Console.WriteLine("************************************************");
        }

        private static MemoryStream ToGzipMemoryStream(string value)
        {
            MemoryStream output = new MemoryStream();
            using (GZipStream zipStream = new GZipStream(output, CompressionMode.Compress, true))
            using (StreamWriter writer = new StreamWriter(zipStream))
            {
                writer.Write(value);
            }
            return output;
        }

        private static string FromGzipMemoryStream(MemoryStream stream)
        {
            using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress))
            using (StreamReader reader = new StreamReader(zipStream))
            {
                return reader.ReadToEnd();
            }
        }
    }
}
```

# Miglioramento dell’accesso ai dati con gli indici secondari in DynamoDB
<a name="SecondaryIndexes"></a>

Amazon DynamoDB offre l'accesso rapido agli elementi in una tabella specificando i valori della chiave primaria. Tuttavia, molte applicazioni potrebbero trarre vantaggio dalla presenza di una o più chiavi secondarie (o alternative) disponibili, per permettere un accesso ai dati efficiente con altri attributi rispetto alla chiave primaria. A tale scopo, puoi creare uno o più indici secondari in una tabella ed emettere delle richieste `Query` o `Scan` rispetto a tali indici.

Un *indice secondario* è una struttura di dati contente un sottoinsieme di attributi di una tabella, oltre a una chiave alternativa per il supporto delle operazioni `Query`. Puoi recuperare dati dall'indice tramite una `Query`, nello stesso modo in cui utilizzi `Query` con una tabella. Una tabella può presentare più indici secondari, che consentono alle applicazioni di accedere a molti modelli di query diversi.

**Nota**  
Puoi inoltre eseguire un'operazione `Scan` su un indice nello stesso modo in cui esegui eseguiresti una `Scan` su una tabella.   
L’accesso multi-account per le operazioni di scansione degli indici secondari non è attualmente supportato dalle [policy basate su risorse](access-control-resource-based.md).

Ciascun indice secondario è associato esattamente a una tabella della quale ottiene i dati. Questa è denominata *tabella di base* dell'indice. Quando crei un indice, è necessario definire una chiave alternativa dell'indice (chiave di partizione e chiave di ordinamento). Vengono definiti anche gli attributi che si desidera siano *proiettati*, o copiati, dalla tabella di base nell'indice. DynamoDB copia questi attributi dell'indice insieme agli attributi della chiave primaria dalla tabella di base. Puoi scansionare o eseguire una query sull'indice nello stesso modo in cui lo faresti su una tabella. 

Ciascun indice secondario viene gestito automaticamente da DynamoDB. Quando aggiungi, modifichi o elimini item nella tabella di base, verranno aggiornati tutti gli indici della tabella sulla base di tali modifiche.

DynamoDB supporta due tipi di indici secondari:
+ **[Indice secondario globale](GSI.html)**: un indice con una chiave di partizione e una chiave di ordinamento che possono essere differenti da quelle presenti sulla tabella di base. Un indice secondario viene considerato globale perché le query possono riferirsi a tutti i dati di una tabella di base, in tutte le partizioni. Un indice secondario locale è memorizzato nel suo spazio di partizione lontano dalla tabella di base e viene dimensionato separatamente dalla tabella di base.
+ **[Indice secondario locale](LSI.html):** un indice con la stessa chiave di partizione della tabella di base ma con una chiave di ordinamento diversa. Un indice secondario è locale nel senso che l'ambito di ogni partizione di un indice secondario locale è rappresentato da una partizione di tabella di base con lo stesso valore di chiave di partizione.

Per un confronto tra gli indici secondari globali e gli indici secondari locali, guarda questo video.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/BkEu7zBWge8/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/BkEu7zBWge8)


**Topics**
+ [Utilizzo degli indici secondari globali in DynamoDB](GSI.md)
+ [Indici secondari locali](LSI.md)

Quando determini il tipo di indice da utilizzare, è consigliabile prendere in considerazione i requisiti della tua applicazione. Nella tabella riportata di seguito sono riportate le differenze principali tra un indice secondario globale e un indice secondario locale.


****  

| Caratteristica | Indice secondario globale | Indice secondario locale | 
| --- | --- | --- | 
| Schema della chiave | La chiave primaria di un indice secondario globale può essere sia semplice (chiave di partizione) che composita (chiave di partizione e chiave di ordinamento). | La chiave primaria di un indice secondario locale deve essere composita (chiave di partizione e chiave di ordinamento). | 
| Attributi della chiave | La chiave di partizione e la chiave di ordinamento (se presente) dell'indice possono essere costituite da qualsiasi attributo della tabella di base di tipo stringa, numero o binario. | La chiave di partizione dell'indice è lo stesso attributo della chiave di partizione della tabella di base. La chiave di partizione può essere qualsiasi attributo della tabella di base di tipo stringa, numero o binario. | 
| Limitazioni della dimensione per valore di chiave di partizione | Non sono previste limitazioni sulle dimensioni per gli indici secondari globali. | Per ciascun valore della chiave di partizione, la dimensione totale tutti gli elementi indicizzati deve essere minore o uguale a 10 GB. | 
| Operazioni di indici online | Gli indici secondari globali possono essere creati al momento della creazione di una tabella. È inoltre possibile aggiungere un nuovo indice secondario globale a una tabella esistente oppure eliminare un indice secondario globale esistente. Per ulteriori informazioni, consulta [Gestione degli indici secondari globali in DynamoDB](GSI.OnlineOps.md).  | È possibile creare indici secondari locali al momento della creazione di una tabella. Non è possibile aggiungere un indice secondario locale a una tabella esistente né eliminare gli indici secondari locali presenti correntemente. | 
| Query e partizioni | Un indice secondario globale consente di eseguire una query sull'intera tabella, su tutte le partizioni.  | Un indice secondario locale consente di eseguire una query su una singola partizione, come specificato dal valore della chiave di partizione nella query. | 
| Consistenza di lettura | Tuttavia, le query sugli indici secondari globali supportano solo la consistenza finale. | Quando si esegue una query su un indice secondario locale, è possibile scegliere tra consistenza finale o forte consistenza. | 
| Utilizzo del throughput assegnato | Ciascun indice secondario globale ha le proprie impostazioni di velocità effettiva assegnata per l'attività di lettura e scrittura. Le query o le scansioni su un indice secondario globale utilizzano unità di capacità dall'indice, non della tabella di base. Lo stesso vale per gli aggiornamenti dell'indice secondario globale a causa delle scritture nella tabella. Un indice secondario globale associato a tabelle globali consuma unità di capacità di scrittura.  | Le query o le scansioni su un indice secondario locale utilizzano unità di capacità di lettura della tabella di base. Quando si scrive su una tabella, vengono aggiornati anche i relativi indici secondari locali; tali aggiornamenti utilizzano unità di capacità di scrittura della tabella di base. Un indice secondario globale associato a tabelle globali consuma unità di capacità di scrittura replicate. | 
| Attributi proiettati | Con le query o le scansioni dell'indice secondario globale, è possibile richiedere solo gli attributi proiettati nell'indice. DynamoDB non recupera alcun attributo dalla tabella. | Se si esegue una query o una scansione sull'indice secondario globale, è possibile richiedere gli attributi che non sono proiettati sull'indice. DynamoDB recupera automaticamente tali attributi dalla tabella. | 

Se si intende creare una o più tabelle con gli indici secondari, è necessario farlo in sequenza. Ad esempio, sarebbe necessario creare la prima tabella e attendere che il relativo stato divenga `ACTIVE` per poter creare la tabella successiva, dunque attendere che il suo stato divenga `ACTIVE`e così via. Se si prova a creare più tabelle contemporaneamente con un indice secondario, DynamoDB restituisce una `LimitExceededException`.

Ogni indice secondario utilizza la stessa [classe di tabella](HowItWorks.TableClasses.html) e [modalità di capacità](capacity-mode.md) della tabella di base a cui è associato. Per ogni indice secondario, è necessario specificare quanto segue:
+ Tipo di indice da creare, ovvero un indice secondario globale o un indice secondario locale.
+ Un nome dell'indice. Le regole di denominazione per gli indici sono le stesse regole per le tabelle, come elencate in [Quote in Amazon DynamoDB](ServiceQuotas.md). Il nome deve essere univoco per la tabella di base a cui è associato, ma puoi utilizzare lo stesso nome per gli indici associati a tabelle di base diverse.
+ Lo schema delle chiavi dell'indice. Ciascun attributo dello schema della chiave di indicizzazione deve essere un attributo di tipo `String`, `Number` o `Binary`. Non sono consentiti altri tipi di dati, tra cui documenti e set. Altri requisiti della schema della chiave dipendono dal tipo di indice: 
  + Per un indice secondario globale, la chiave di partizione può essere qualsiasi attributo scalare della tabella di base. È facoltativa una chiave di ordinamento, che può essere anch'essa qualsiasi attributo scalare della tabella di base.
  + Per un indice secondario locale, la chiave di partizione deve essere uguale alla chiave di partizione della tabella di base; la chiave di ordinamento deve essere un attributo non chiave della tabella di base.
+ Gli attributi aggiuntivi, se presenti, da proiettare dalla tabella di base nell'indice. Questi attributi si aggiungono agli attributi di chiave della tabella, proiettati automaticamente in ciascun indice. Puoi proiettare attributi di qualsiasi tipo di dati, tra cui scalari, documenti e set.
+ Le impostazioni di throughput assegnato dell'indice, se necessario:
  + Per un indice secondario globale, è necessario specificare le impostazioni delle unità di capacità di lettura e scrittura. Queste impostazioni di throughput assegnato sono indipendenti dalle impostazioni della tabella di base.
  + Per un indice secondario locale, non è necessario specificare le impostazioni delle unità di capacità di lettura e scrittura. Tutte le operazioni di lettura e scrittura su un indice secondario locale utilizzano le impostazioni di velocità effettiva assegnata della relativa tabella di base.

Per la massima flessibilità delle query, è possibile creare fino a 20 indici secondari globali (quota predefinita) e fino a 5 indici secondari locali per tabella.

Per ottenere un elenco dettagliato di indici secondari su una tabella, utilizza l'operazione `DescribeTable`. `DescribeTable` restituisce il nome, la dimensione dell'archiviazione e il numero di elementi per ogni indice secondario nella tabella. Questi valori non vengono aggiornati in tempo reale, bensì ogni circa sei ore.

È possibile accedere ai dati in un indice secondario utilizzando l'operazione `Query` o `Scan`. È necessario specificare il nome della tabella di base e il nome dell'indice che si desidera utilizzare, gli attributi da restituire nei risultati e qualsiasi espressione di condizione o filtro da applicare. DynamoDB può restituire i risultati in ordine crescente o decrescente.

Quando elimini una tabella, verranno eliminati anche tutti gli indici associati alla tabella.

Per le best practice, consulta [Best practice per l'uso di indici secondari in DynamoDB.](bp-indexes.md).

# Utilizzo degli indici secondari globali in DynamoDB
<a name="GSI"></a>

Alcune applicazioni devono poter eseguire molti tipi di query, usando un'ampia gamma di attributi diversi come criteri di query. Per supportare questi requisiti, è possibile creare uno o più *indici secondari globali* ed emettere richieste `Query` rispetto a questi indici in Amazon DynamoDB.

**Topics**
+ [Scenario: Utilizzo di un indice secondario globale](#GSI.scenario)
+ [Proiezioni di attributi](#GSI.Projections)
+ [Schema chiave con più attributi](#GSI.MultiAttributeKeys)
+ [Lettura di dati da un indice secondario globale](#GSI.Reading)
+ [Sincronizzazione dei dati tra tabelle e indici secondari globali](#GSI.Writes)
+ [Classi di tabella con indici secondari globali](#GSI.tableclasses)
+ [Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari globali](#GSI.ThroughputConsiderations)
+ [Considerazioni sullo storage per indici secondari globali](#GSI.StorageConsiderations)
+ [Modelli di progettazione](GSI.DesignPatterns.md)
+ [Gestione degli indici secondari globali in DynamoDB](GSI.OnlineOps.md)
+ [Rilevamento e correzione delle violazioni delle chiavi in DynamoDB](GSI.OnlineOps.ViolationDetection.md)
+ [Utilizzo di indici secondari globali: Java](GSIJavaDocumentAPI.md)
+ [Utilizzo di indici secondari globali: .NET](GSILowLevelDotNet.md)
+ [Utilizzo di indici secondari in DynamoDB con la AWS CLI](GCICli.md)

## Scenario: Utilizzo di un indice secondario globale
<a name="GSI.scenario"></a>

A titolo illustrativo, considera una tabella denominata `GameScores` che tiene traccia di utenti e punteggi per un'applicazione di gioco per dispositivi mobili. Ogni item in `GameScores` è identificato da una chiave di partizione (`UserId`) e una chiave di ordinamento (`GameTitle`). Il seguente diagramma mostra in che modo verrebbero organizzarti gli elementi nella tabella. Non tutti gli attributi vengono visualizzati.

![\[GameScores tabella contenente un elenco di ID utente, titolo, punteggio, data e vittorie/sconfitte.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_01.png)


Supponi ora di voler scrivere un'applicazione di tipo classifica per visualizzare i punteggi più alti per ogni gioco. Una query che specifica gli attributi chiave (`UserId` e `GameTitle`) sarebbe molto efficiente. Tuttavia, se l'applicazione deve recuperare i dati da `GameScores` solo in base a `GameTitle`, occorre utilizzare un'operazione `Scan`. Con l'aggiunta di altri item alla tabella, le scansioni di tutti i dati rallenterebbero e diventerebbero meno pratiche, rendendo difficile rispondere a domande come le seguenti:
+ Qual è il punteggio più alto mai registrato per il gioco Meteor Blasters?
+ Quale utente ha il punteggio più alto per Galaxy Invaders?
+ Qual è il rapporto più elevato tra vittorie e sconfitte?

Per accelerare le query su attributi non chiave, è possibile creare un indice secondario globale. Un indice secondario globale contiene una selezione di attributi dalla tabella di base organizzati tramite una chiave primaria diversa da quella della tabella. La chiave dell'indice non deve avere alcuno degli attributi di chiave della tabella, né lo stesso schema della chiave di una tabella.

Ad esempio, è possibile creare un indice secondario globale denominato `GameTitleIndex` con una chiave di partizione `GameTitle` e una chiave di ordinamento `TopScore`. Gli attributi della chiave primaria della tabella di base vengono sempre proiettati in un indice, pertanto è presente anche l'attributo `UserId`. Il diagramma seguente mostra l'aspetto di un indice `GameTitleIndex`.

![\[GameTitleIndex tabella contenente un elenco di titoli, punteggi e ID utente.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_02.png)


A questo punto, puoi eseguire una query su `GameTitleIndex` e ottenere facilmente i punteggi per Meteor Blasters. I risultati sono ordinati in base ai valori della chiave di ordinamento, ovvero `TopScore`. Se imposti il parametro `ScanIndexForward` su false, i risultati vengono restituiti in ordine decrescente e di conseguenza il punteggio più alto viene restituito per primo.

Ogni indice secondario globale deve avere una chiave di partizione e può avere anche una chiave di ordinamento facoltativa. Lo schema della chiave di indicizzazione può essere diverso dallo schema della tabella di base. È possibile avere una tabella con una chiave primaria semplice (chiave di partizione) e creare un indice secondario globale con una chiave primaria composita (chiave di partizione e chiave di ordinamento) o viceversa. Gli attributi della chiave dell'indice possono essere costituiti da qualsiasi attributo `String`, `Number` o `Binary` di primo livello della tabella di base. Altri tipi scalari, documento e set non sono consentiti.

Se vuoi, puoi proiettare altri attributi della tabella di base nell'indice. Quando si esegue una query sull'indice, DynamoDB può recuperare questi attributi proiettati in modo efficiente. Tuttavia, le query su un indice secondario globale non possono recuperare gli attributi dalla tabella di base. Ad esempio, se esegui una query `GameTitleIndex` come mostrato nel diagramma precedente, la query non è in grado di accedere ad alcun attributo non di chiave diverso da `TopScore` (se vengono automaticamente proiettati gli attributi della chiave `GameTitle` e `UserId`).

In una tabella DynamoDB ogni valore di chiave deve essere univoco. Tuttavia, i valori delle chiavi in un indice secondario globale non devono essere univoci. A titolo illustrativo, supponi che un gioco denominato Comet Quest sia particolarmente difficile, con molti nuovi utenti che provano ma non riescono a ottenere un punteggio maggiore di zero. Di seguito sono illustrati alcuni dati che possono rappresentare questa situazione.


****  

| UserId | GameTitle | TopScore | 
| --- | --- | --- | 
| 123 | Comet Quest | 0 | 
| 201 | Comet Quest | 0 | 
| 301 | Comet Quest | 0 | 

Quando questi dati vengono aggiunti alla tabella `GameScores`, vengono propagati da DynamoDB a `GameTitleIndex`. Se quindi eseguiamo una query sull'indice utilizzando Comet Quest per `GameTitle` e 0 per `TopScore`, vengono restituiti i dati seguenti.

![\[Tabella contenente un elenco di titoli, punteggi più alti e ID utente.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_05.png)


Nella risposta vengono visualizzati solo gli elementi con i valori di chiave specificati. All'interno di questo set di dati, gli elementi non hanno un ordine specifico. 

Un indice secondario globale tiene traccia solo degli elementi di dati in cui esistono effettivamente i suoi attributi di chiave. Ad esempio, supponi di aver aggiunto un nuovo item alla tabella `GameScores`, ma di aver fornito solo gli attributi della chiave primaria obbligatori.


****  

| UserId | GameTitle | 
| --- | --- | 
| 400 | Comet Quest | 

Poiché non è stato specificato l'attributo `TopScore`, DynamoDB non propaga questo elemento a `GameTitleIndex`. Di conseguenza, se ha eseguito una query su `GameScores` per tutti gli elementi di Comet Quest, ottieni i quattro item seguenti:

![\[Tabella contenente un elenco di quattro titoli, punteggi più alti e ID utente.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_04.png)


Una query simile su `GameTitleIndex` continua a restituire tre item anziché quattro. Il motivo è che l'item con `TopScore` inesistente non viene propagato nell'indice.

![\[Tabella contenente un elenco di tre titoli, punteggi più alti e ID utente.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_05.png)


## Proiezioni di attributi
<a name="GSI.Projections"></a>

Una *proiezione* è l'insieme di attributi copiato da una tabella in un indice secondario. La chiave di partizione e la chiave di ordinamento della tabella vengono sempre proiettati nell'indice; è possibile proiettare altri attributi per supportare i requisiti di query dell'applicazione. Quando si esegue una query su un indice, Amazon DynamoDB può accedere a qualsiasi attributo nella proiezione come se tali attributi fossero in una propria tabella.

Quando si crea un indice secondario, è necessario specificare gli attributi che saranno proiettati nell'indice. DynamoDB fornisce tre diverse opzioni per questo:
+ *KEYS\$1ONLY*: ogni elemento dell'indice è costituito solo dalla chiave di partizione della tabella e dai valori della chiave di ordinamento, oltre ai valori della chiave di indice. L'opzione `KEYS_ONLY` si traduce nell'indice secondario più piccolo possibile.
+ *INCLUDE*: oltre agli attributi descritti in `KEYS_ONLY`, l'indice secondario includerà gli altri attributi non chiave che sono stati specificati.
+ *ALL*: l'indice secondario include tutti gli attributi della tabella di origine. Poiché tutti i dati della tabella sono duplicati nell'indice, una proiezione `ALL` restituisce il più grande indice secondario possibile.

Nel diagramma precedente, `GameTitleIndex` dispone di un solo attributo proiettato: `UserId`. Pertanto, sebbene un'applicazione possa determinare in maniera efficiente il valore `UserId` dei punteggi più alti per ogni partita utilizzando `GameTitle` e `TopScore` nelle query, non può determinare in maniera efficiente il rapporto più elevato tra vittorie e sconfitte per i punteggi più alti. A tale scopo, l'applicazione dovrebbe eseguire un'interrogazione aggiuntiva sulla tabella di base per recuperare le vittorie e le sconfitte di ciascuno dei migliori marcatori. Un modo più efficiente per supportare le query su questi dati consiste nel proiettare gli attributi dalla tabella di base nell'indice secondario globale, come mostrato in questo diagramma. 

![\[Rappresentazione della proiezione di attributi non chiave in un GSI per supportare l’esecuzione di query efficienti.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/GSI_06.png)


Poiché gli attributi non di chiave `Wins` e `Losses` vengono proiettati nell'indice, un'applicazione può determinare il rapporto tra vittorie e sconfitte per qualsiasi gioco o per qualsiasi combinazione di gioco e ID utente.

Quando si scelgono gli attributi da proiettare in un indice secondario globale, è necessario considerare il compromesso tra i costi correlati alla velocità effettiva assegnata e i costi di archiviazione:
+ Se è necessario accedere a pochi attributi con la latenza più bassa possibile, considerare la possibilità di proiettare solo quegli attributi in un indice secondario globale. Più piccolo è l'indice, minore è il costo per memorizzarlo e minori sono i costi di scrittura.
+ Se l'applicazione accede frequentemente ad alcuni attributi non chiave, è necessario considerare di proiettare quegli attributi in un indice secondario globale. I costi di archiviazione aggiuntivi per l'indice secondario globale compensano il costo di esecuzione di scansioni frequenti delle tabelle.
+ Se è necessario accedere alla maggior parte degli attributi non chiave su base frequente, è possibile proiettare questi attributi, o anche l'intera tabella di base, in un indice secondario globale. Questo offre massima flessibilità. Tuttavia, i costi di storage aumenteranno o addirittura raddoppieranno.
+ Se l'applicazione esegue di rado le query sulla tabella, ma esegue molte scritture o aggiornamenti dei dati nella tabella, considera di proiettare `KEYS_ONLY`. L'indice secondario globale avrebbe dimensioni minime e sarebbe comunque disponibile se necessario per l'attività di query. 

## Schema chiave con più attributi
<a name="GSI.MultiAttributeKeys"></a>

Gli indici secondari globali supportano chiavi con più attributi, che consentono di comporre chiavi di partizione e ordinare le chiavi a partire da più attributi. Con le chiavi multiattributo, è possibile creare una chiave di partizione da un massimo di quattro attributi e una chiave di ordinamento da un massimo di quattro attributi, per un totale di un massimo di otto attributi per schema di chiavi.

Le chiavi multiattributo semplificano il modello di dati eliminando la necessità di concatenare manualmente gli attributi in chiavi sintetiche. Invece di creare stringhe composite, ad esempio`TOURNAMENT#WINTER2024#REGION#NA-EAST`, puoi utilizzare direttamente gli attributi naturali del tuo modello di dominio. DynamoDB gestisce automaticamente la logica delle chiavi composite, eseguendo l'hashing di più attributi chiave di partizione per la distribuzione dei dati e mantenendo l'ordinamento gerarchico tra più attributi delle chiavi di ordinamento.

Ad esempio, prendi in considerazione un sistema di tornei di gioco in cui desideri organizzare le partite per torneo e regione. Con le chiavi multiattributo, è possibile definire la chiave di partizione come due attributi separati: `tournamentId` e. `region` Allo stesso modo, è possibile definire la chiave di ordinamento utilizzando più attributi come `round``bracket`, e `matchId` creare una gerarchia naturale. Questo approccio mantiene i dati digitati e il codice pulito, senza manipolazione o analisi delle stringhe.

Quando si esegue una query su un indice secondario globale con chiavi multiattributo, è necessario specificare tutti gli attributi delle chiavi di partizione utilizzando condizioni di uguaglianza. Per gli attributi chiave di ordinamento, è possibile interrogarli left-to-right nell'ordine in cui sono definiti nello schema chiave. Ciò significa che è possibile interrogare solo il primo attributo chiave di ordinamento, i primi due attributi insieme o tutti gli attributi insieme, ma non è possibile saltare gli attributi intermedi. Condizioni di disuguaglianza come`>`, `<``BETWEEN`, o `begins_with()` devono essere l'ultima condizione della query.

Le chiavi con più attributi funzionano particolarmente bene quando si creano indici secondari globali su tabelle esistenti. È possibile utilizzare gli attributi già presenti nella tabella senza inserire le chiavi sintetiche tra i dati. Ciò semplifica l'aggiunta di nuovi modelli di query all'applicazione creando indici che riorganizzano i dati utilizzando diverse combinazioni di attributi.

Ogni attributo in una chiave con più attributi può avere il proprio tipo di dati: `String` (S), (N) o `Number` (B). `Binary` Quando scegliete i tipi di dati, tenete presente che `Number` gli attributi vengono ordinati numericamente senza richiedere il riempimento zero, mentre gli attributi vengono ordinati lessicograficamente. `String` Ad esempio, se utilizzi un `Number` tipo per un attributo score, i valori 5, 50, 500 e 1000 vengono ordinati in ordine numerico naturale. Gli stessi valori `String` di type verrebbero ordinati come «1000", «5", «50", «500" a meno che non vengano riempiti con zeri iniziali.

Quando progettate chiavi con più attributi, ordinate gli attributi dal più generale al più specifico. Per le chiavi di partizione, combinate gli attributi che vengono sempre interrogati insieme e che garantiscono una buona distribuzione dei dati. Per le chiavi di ordinamento, posiziona gli attributi più richiesti al primo posto nella gerarchia per massimizzare la flessibilità delle query. Questo ordinamento consente di eseguire query a qualsiasi livello di granularità che corrisponda ai modelli di accesso.

Vedi gli esempi di [Chiavi con più attributi](GSI.DesignPattern.MultiAttributeKeys.md) implementazione.

## Lettura di dati da un indice secondario globale
<a name="GSI.Reading"></a>

È possibile recuperare gli elementi da un indice secondario globale utilizzando le operazioni `Query` e `Scan`. Le operazioni `GetItem` e `BatchGetItem` non possono essere utilizzate su un indice secondario globale.

### Esecuzione di query su un indice secondario globale
<a name="GSI.Querying"></a>

È possibile utilizzare l'operazione `Query` per accedere a uno o più elementi in un indice secondario globale. La query deve specificare il nome della tabella di base e il nome dell'indice che si desidera utilizzare, gli attributi da restituire nei risultati della query e qualsiasi condizione di query da applicare. DynamoDB può restituire i risultati in ordine crescente o decrescente.

Considera i dati seguenti restituiti da un'operazione `Query` che richiede dati di gioco per un'applicazione di tipo classifica.

```
{
    "TableName": "GameScores",
    "IndexName": "GameTitleIndex",
    "KeyConditionExpression": "GameTitle = :v_title",
    "ExpressionAttributeValues": {
        ":v_title": {"S": "Meteor Blasters"}
    },
    "ProjectionExpression": "UserId, TopScore",
    "ScanIndexForward": false
}
```

In questa query:
+ DynamoDB *GameTitleIndex*accede, utilizzando la chiave di partizione per individuare gli elementi *GameTitle*dell'indice per Meteor Blasters. Tutti gli elementi dell'indice con questa chiave sono memorizzati l'uno accanto all'altro per il recupero rapido.
+ All'interno di questo gioco, DynamoDB utilizza l'indice per accedere a tutti gli IDs utenti e ai punteggi più alti di questo gioco.
+ Vengono restituiti i risultati in base all'ordine decrescente, perché il parametro `ScanIndexForward` è impostato su false.

### Scansione di un indice secondario globale
<a name="GSI.Scanning"></a>

È possibile utilizzare l'operazione `Scan` per recuperare tutti i dati da un indice secondario globale. Devi fornire il nome della tabella di base e il nome dell'indice nella richiesta. Con un'operazione `Scan`, DynamoDB legge tutti i dati nell'indice e li restituisce all'applicazione. Inoltre puoi richiedere che vengano restituiti solo alcuni dati e che quelli rimanenti vengano eliminati. A questo scopo, usa il parametro `FilterExpression` dell'operazione `Scan`. Per ulteriori informazioni, consulta [Espressioni di filtro per la scansione](Scan.md#Scan.FilterExpression).

## Sincronizzazione dei dati tra tabelle e indici secondari globali
<a name="GSI.Writes"></a>

DynamoDB sincronizza automaticamente ogni indice secondario globale con la relativa tabella di base. Quando un'applicazione scrive o elimina elementi in una tabella, ogni indice secondario globale nella tabella viene aggiornato in modo asincrono, usando un modello a consistenza finale. Le applicazioni non scrivono mai direttamente in un indice. Tuttavia, è importante comprendere le implicazioni di come DynamoDB mantiene questi indici.

 Gli indici secondari globali ereditano la modalità di read/write capacità dalla tabella base. Per ulteriori informazioni, consulta [Considerazioni sul passaggio tra modalità di capacità in DynamoDB](bp-switching-capacity-modes.md). 

Quando si crea un indice secondario globale, viene specificato uno o più attributi della chiave di indice e i rispettivi tipi di dati. Questo significa che ogni volta che scrivi un item nella tabella di base, i tipi di dati per questi attributi devono corrispondere ai tipi di dati dello schema della chiave dell'indice. Nel caso di `GameTitleIndex`, la chiave di partizione `GameTitle` nell'indice è definita come un tipo di dati `String`. La chiave di ordinamento `TopScore` nell'indice è di tipo `Number`. Se si prova ad aggiungere un elemento alla tabella `GameScores` e si specifica un tipo di dati diverso per `GameTitle` o `TopScore`, DynamoDB restituisce un `ValidationException` perché il tipo di dati non corrisponde.

Quando inserisci o elimini item in una tabella, ogni indice secondario globale nella tabella viene aggiornato in base a un modello eventualmente consistente. Le modifiche apportate ai dati della tabella vengono propagate in ogni indice secondario globale entro una frazione di secondo in condizioni normali. Tuttavia, in alcuni improbabili scenari di errore, possono verificarsi ritardi di propagazione prolungati. Per questo motivo, le applicazioni devono poter prevedere e gestire le situazioni in cui una query su un indice secondario globale restituisce risultati non aggiornati.

Se si scrive un elemento in una tabella, non è necessario specificare gli attributi per la chiave di ordinamento di alcun indice secondario globale. Utilizzando `GameTitleIndex` come un esempio, non devi specificare un valore per l'attributo `TopScore` per scrivere un nuovo item nella tabella `GameScores`. In questo caso, DynamoDB non scrive alcun dato nell'indice per questo particolare elemento.

Una tabella con molti indici secondari globali comporta costi maggiori per l'attività di scrittura rispetto alle tabelle con meno indici. Per ulteriori informazioni, consulta [Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari globali](#GSI.ThroughputConsiderations).

## Classi di tabella con indici secondari globali
<a name="GSI.tableclasses"></a>

Un indice secondario globale utilizzerà sempre la stessa classe di tabella della tabella di base. Ogni volta che viene aggiunto un nuovo indice secondario globale per una tabella, il nuovo indice utilizzerà la stessa classe di tabella della tabella di base. Quando la classe di tabella di una tabella viene aggiornata, vengono aggiornati anche tutti gli indici secondari globali associati.

## Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari globali
<a name="GSI.ThroughputConsiderations"></a>

Quando si crea un indice secondario globale su una tabella con modalità assegnata, è necessario specificare le unità di capacità di lettura e scrittura per il carico di lavoro previsto sull'indice. Le impostazioni correlate alla velocità effettiva assegnata di un indice secondario globale sono separate da quelle della relativa tabella di base. Un'operazione `Query` su un indice secondario globale utilizza unità di capacità di lettura dell'indice e non della tabella di base. Quando inserisci, aggiorni o elimini item in una tabella, anche gli indici secondari globali nella tabella vengono aggiornati. Questi aggiornamenti dell'indice utilizzano unità di capacità in scrittura dell'indice, non della tabella.

Ad esempio, se si esegui un'operazione `Query` su un indice secondario globale e se ne supera la capacità di lettura assegnata, la richiesta sarà sottoposta a limitazione. Se si esegue un'attività di scrittura pesante sulla tabella, ma un indice secondario globale su quella tabella ha una capacità di scrittura insufficiente, l'attività di scrittura sulla tabella verrà limitata.

**Importante**  
 Per evitare il possibile throttling, la capacità in scrittura assegnata per un indice secondario globale deve essere maggiore o uguale alla capacità in scrittura della tabella di base poiché nuovi aggiornamenti scrivono nella tabella di base e nell'indice secondario globale. 

Per visualizzare le impostazioni di velocità effettiva assegnata per un indice secondario globale, utilizza l'operazione `DescribeTable`. Vengono restituite informazioni dettagliare relative a tutti gli indici secondari della tabella.

### Unità di capacità in lettura
<a name="GSI.ThroughputConsiderations.Reads"></a>

Gli indici secondari globali supportano letture consistenti finali, ognuna delle quali utilizza metà di un'unità di capacità in lettura. Questo significa che una singola query su un indice secondario globale può recuperare fino a 2 × 4 KB = 8 KB per ogni unità di capacità di lettura.

Per le query su un indice secondario globale, DynamoDB calcola l'attività di lettura assegnata come avviene per le query sulle tabelle. L'unica differenza è che il calcolo si basa sulle dimensioni delle voci dell'indice, piuttosto che sulla dimensione dell'item nella tabella di base. Il numero di unità di capacità in lettura è la somma di tutte le dimensioni degli attributi proiettati di tutti gli elementi restituiti. Il risultato viene arrotondato al limite di 4 KB successivo. Per ulteriori informazioni sul modo in cui DynamoDB calcola l'uso della velocità effettiva assegnata, consulta [Modalità con capacità allocata di DynamoDB](provisioned-capacity-mode.md).

La dimensione massima dei risultati restituiti da un'operazione `Query` è 1 MB. Sono incluse le dimensioni di tutti i nomi e i valori degli attributi in tutti gli elementi restituiti.

Ad esempio, si consideri un indice secondario globale in cui ogni elemento contiene 2.000 byte di dati. Si supponga ora di eseguire un'operazione `Query` su questo indice e che `KeyConditionExpression` della query restituisca otto elementi. La dimensione totale degli elementi corrispondenti è 2.000 byte 8 elementi = 16.000 byte. Questo risultato viene quindi arrotondato al limite da 4 KB più vicino. Poiché le query su un indice secondario globale sono a consistenza finale, il costo totale equivale a 0,5 × (16 KB / 4 KB) o 2 unità di capacità di lettura.

### Unità di capacità in scrittura
<a name="GSI.ThroughputConsiderations.Writes"></a>

Quando un elemento in una tabella viene aggiunto, aggiornato o eliminato e questa operazione interessa un indice secondario globale, l'indice utilizzerà le unità di capacità di scrittura assegnate per l'operazione. Il costo totale del throughput assegnato per una scrittura è la somma delle unità di capacità in scrittura utilizzate dalla scrittura nella tabella di base e quelle utilizzate dall'aggiornamento degli indici secondari globali. Se una scrittura in una tabella non richiede l'aggiornamento di un indice secondario globale, non viene utilizzata capacità di scrittura dell'indice.

Perché la scrittura in una tabella riesca, le impostazioni correlate al throughput assegnato per la tabella e tutti i suoi indici secondari globali devono avere capacità in scrittura sufficiente per la scrittura. In caso contrario, la scrittura nella tabella viene limitata. 

**Importante**  
Quando si crea un indice secondario globale (GSI), le operazioni di scrittura sulla tabella di base possono essere sottoposte a limitazione (della larghezza di banda della rete) se l’attività dei GSI risultante dalle scritture sulla tabella di base supera la capacità di scrittura allocata del GSI. Questa limitazione (della larghezza di banda della rete) influisce su tutte le operazioni di scrittura, dal processo di indicizzazione alla potenziale interruzione dei carichi di lavoro di produzione. Per ulteriori informazioni, consulta [Risoluzione dei problemi di limitazione (della larghezza di banda della rete) in Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TroubleshootingThrottling.html).

Il costo della scrittura di un elemento in un indice secondario globale dipende da diversi fattori:
+ Se scrivi un nuovo item nella tabella che definisce un attributo indicizzato o aggiorni un item esistente per definire un attributo indicizzato in precedenza non definito, è necessario eseguire un'operazione di scrittura per inserire l'item nell'indice.
+ Se un aggiornamento della tabella modifica il valore di un attributo chiave indicizzato (da A a B), sono necessarie due scritture, una per eliminare l'item precedente dall'indice e un'altra per inserire il nuovo item nell'indice.  
+ Se un item era presente nell'indice, ma una scrittura nella tabella ha causato la cancellazione dell'attributo indicizzato, è necessaria una scrittura per eliminare la proiezione dell'item precedente dall'indice.
+ Se un item non è presente nell'indice prima o dopo l'aggiornamento dell'item, non vi è alcun costo di scrittura aggiuntivo per l'indice.
+ Se un aggiornamento della tabella modifica solo il valore degli attributi proiettati nello schema della chiave dell'indice, ma non modifica il valore di alcun attributo di chiave indicizzato, è necessaria una scrittura per aggiornare i valori degli attributi proiettati nell'indice.

Tutti questi fattori presuppongono che la dimensione di ciascun elemento nell'indice sia minore o uguale alla dimensione dell'elemento di 1 KB per il calcolo delle unità di capacità di scrittura. Le voci di indice più grandi richiedono unità di capacità in scrittura aggiuntive. Puoi contenere al minimo i costi di scrittura considerando gli attributi che le query devono restituire e proiettando solo tali attributi nell'indice.

## Considerazioni sullo storage per indici secondari globali
<a name="GSI.StorageConsiderations"></a>

Quando un'applicazione scrive un elemento in una tabella, DynamoDB copia automaticamente il sottoinsieme di attributi corretto in qualsiasi indice secondario globale in cui devono essere presenti gli attributi. All' AWS account vengono addebitati i costi per la memorizzazione dell'articolo nella tabella di base e anche per la memorizzazione degli attributi in tutti gli indici secondari globali di tale tabella.

La quantità di spazio utilizzata da un item dell'indice è la somma di quanto segue:
+ La dimensione in byte della chiave primaria della tabella di base (chiave di partizione e chiave di ordinamento)
+ La dimensione in byte dell'attributo della chiave di indicizzazione
+ La dimensione in byte degli attributi proiettati (se presenti)
+ 100 byte di sovraccarico per elemento dell'indice

Per stimare i requisiti di archiviazione per un indice secondario globale, è possibile stimare la dimensione media di un elemento nell'indice e quindi moltiplicarla per il numero di elementi nella tabella di base che hanno attributi di chiave dell'indice secondario globale.

Se una tabella contiene un elemento in cui uno o più attributi particolari non sono definiti, ma tale attributo è definito come chiave di partizione dell'indice o chiave di ordinamento, DynamoDB non scrive alcun dato per quell'elemento nell'indice.

# Modelli di progettazione
<a name="GSI.DesignPatterns"></a>

I modelli di progettazione forniscono soluzioni comprovate alle sfide più comuni quando si lavora con indici secondari globali. Questi modelli consentono di creare applicazioni efficienti e scalabili mostrando come strutturare gli indici per casi d'uso specifici.

Ogni modello include una guida all'implementazione completa con esempi di codice, best practice e casi d'uso reali per aiutarvi ad applicare il pattern alle vostre applicazioni.

**Topics**
+ [Chiavi con più attributi](GSI.DesignPattern.MultiAttributeKeys.md)

# Schema di chiavi multiattributo
<a name="GSI.DesignPattern.MultiAttributeKeys"></a>

## Panoramica
<a name="GSI.DesignPattern.MultiAttributeKeys.Overview"></a>

Le chiavi multi-attributo consentono di creare chiavi di partizione e ordinamento del Global Secondary Index (GSI) composte da un massimo di quattro attributi ciascuna. Ciò riduce il codice lato client e semplifica la modellazione iniziale dei dati e l'aggiunta di nuovi modelli di accesso in un secondo momento.

Consideriamo uno scenario comune: per creare un GSI che interroghi gli elementi in base a più attributi gerarchici, tradizionalmente è necessario creare chiavi sintetiche concatenando i valori. Ad esempio, in un'app di gioco, per interrogare le partite dei tornei per torneo, regione e round, potresti creare una chiave di partizione GSI sintetica come TOURNAMENT\$1 WINTER2 024 \$1REGION \$1NA -EAST e una chiave di ordinamento sintetica come ROUND \$1SEMIFINALS \$1BRACKET \$1UPPER. Questo approccio funziona, ma richiede la concatenazione di stringhe durante la scrittura dei dati, l'analisi durante la lettura e il riempimento delle chiavi sintetiche su tutti gli elementi esistenti se si aggiunge il GSI a una tabella esistente. Ciò rende il codice più disordinato e difficile da mantenere la sicurezza dei tipi sui singoli componenti chiave.

Le chiavi multiattributo risolvono questo problema per. GSIs Definisci la tua chiave di partizione GSI utilizzando più attributi esistenti come TournamentID e region. DynamoDB gestisce automaticamente la logica delle chiavi composite, eseguendo l'hashing delle stesse per la distribuzione dei dati. Gli elementi vengono scritti utilizzando gli attributi naturali del modello di dominio e il GSI li indicizza automaticamente. Nessuna concatenazione, nessuna analisi, nessun riempimento. Il codice rimane pulito, i dati rimangono digitati e le query rimangono semplici. Questo approccio è particolarmente utile quando si hanno dati gerarchici con raggruppamenti di attributi naturali (come torneo → regione → round o organizzazione → dipartimento → squadra).

## Esempio di applicazione
<a name="GSI.DesignPattern.MultiAttributeKeys.ApplicationExample"></a>

Questa guida illustra la creazione di un sistema di tracciamento delle partite di torneo per una piattaforma di eSport. La piattaforma deve interrogare in modo efficiente le partite su più fronti: per torneo e regione per la gestione dei gironi, per giocatore per la cronologia delle partite e per data di programmazione.

## Modello di dati
<a name="GSI.DesignPattern.MultiAttributeKeys.DataModel"></a>

In questa procedura dettagliata, il sistema di tracciamento delle partite dei tornei supporta tre modelli di accesso principali, ognuno dei quali richiede una struttura chiave diversa:

**Schema di accesso 1:** cerca una partita specifica in base al relativo ID univoco
+ **Soluzione:** tabella di base con `matchId` chiave di partizione

**Schema di accesso 2:** interroga tutte le partite di un torneo e di una regione specifici, filtrandole facoltativamente per round, tabellone o partita
+ **Soluzione:** Indice secondario globale con chiave di partizione multiattributo (`tournamentId`\$1`region`) e chiave di ordinamento multiattributo (\$1) `round` `bracket` `matchId`
+ **Query di esempio:** «Tutte le partite WINTER2 024 nella regione NA-EST» o «Tutte le SEMIFINALI corrispondono nel girone SUPERIORE per 024/NA-EST» WINTER2

**Schema di accesso 3:** interroga la cronologia delle partite di un giocatore, filtrandola facoltativamente per intervallo di date o round del torneo
+ **Soluzione:** Indice secondario globale con chiave di partizione singola (`player1Id`) e chiave di ordinamento multiattributo (\$1) `matchDate` `round`
+ **Domande di esempio:** «Tutte le partite del giocatore 101" o «Le partite del giocatore 101 a gennaio 2024"

La differenza fondamentale tra gli approcci tradizionali e quelli con più attributi diventa evidente quando si esamina la struttura degli elementi:

**Approccio tradizionale all'indice secondario globale (chiavi concatenate):**

```
// Manual concatenation required for GSI keys
const item = {
    matchId: 'match-001',                                          // Base table PK
    tournamentId: 'WINTER2024',
    region: 'NA-EAST',
    round: 'SEMIFINALS',
    bracket: 'UPPER',
    player1Id: '101',
    // Synthetic keys needed for GSI
    GSI_PK: `TOURNAMENT#${tournamentId}#REGION#${region}`,       // Must concatenate
    GSI_SK: `${round}#${bracket}#${matchId}`,                    // Must concatenate
    // ... other attributes
};
```

**Approccio all'indice secondario globale multiattributo (chiavi native):**

```
// Use existing attributes directly - no concatenation needed
const item = {
    matchId: 'match-001',                                          // Base table PK
    tournamentId: 'WINTER2024',
    region: 'NA-EAST',
    round: 'SEMIFINALS',
    bracket: 'UPPER',
    player1Id: '101',
    matchDate: '2024-01-18',
    // No synthetic keys needed - GSI uses existing attributes directly
    // ... other attributes
};
```

Con le chiavi multiattributo, gli elementi vengono scritti una sola volta con attributi di dominio naturali. DynamoDB li indicizza automaticamente su GSIs più pagine senza richiedere chiavi sintetiche concatenate.

**Schema della tabella di base:**
+ Chiave di partizione: `matchId` (1 attributo)

**Schema dell'indice secondario globale (TournamentRegionIndex con chiavi multiattributo):**
+ Chiave di partizione:`tournamentId`, `region` (2 attributi)
+ Chiave di ordinamento: `round``bracket`,, `matchId` (3 attributi)

**Schema dell'indice secondario globale (PlayerMatchHistoryIndex con chiavi multiattributo):**
+ Chiave di partizione: `player1Id` (1 attributo)
+ Chiave di ordinamento:`matchDate`, `round` (2 attributi)

### Tabella base: TournamentMatches
<a name="GSI.DesignPattern.MultiAttributeKeys.BaseTable"></a>


| MatchID (PK) | ID del torneo | region | round | staffa | ID giocatore 1 | ID giocatore 2 | Data della partita | vincitore | punteggio | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| partita-001 | WINTER2024 | NA-EST | FINALE | CAMPIONATO | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| inquadrato-002 | WINTER2024 | NA-EST | SEMIFINALI | UPPER | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| inquadrato-003 | WINTER2024 | NA-EST | SEMIFINALI | UPPER | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| inquadrato-004 | WINTER2024 | NA-EST | QUARTI DI FINALE | UPPER | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| inquadrato-005 | WINTER2024 | NORD-OVEST | FINALE | CAMPIONATO | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| inquadrato-006 | WINTER2024 | NORD-OVEST | SEMIFINALI | UPPER | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| partita-007 | SPRING2024 | NA-EST | QUARTI DI FINALE | UPPER | 101 | 108 | 2024-03-15 | 101 | 3-0 | 
| inquadrato-008 | SPRING2024 | NA-EST | QUARTI DI FINALE | LOWER | 103 | 110 | 2024-03-15 | 103 | 3-2 | 

### GSI: TournamentRegionIndex (chiavi multiattributo)
<a name="GSI.DesignPattern.MultiAttributeKeys.TournamentRegionIndexTable"></a>


| ID torneo (PK) | regione (PK) | rotondo (SK) | staffa (SK) | MatchID (SK) | ID giocatore 1 | ID giocatore 2 | Data della partita | vincitore | punteggio | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| WINTER2024 | NA-EST | FINALE | CAMPIONATO | partita-001 | 101 | 103 | 2024-01-20 | 101 | 3-1 | 
| WINTER2024 | NA-EST | QUARTI DI FINALE | UPPER | match-004 | 101 | 109 | 2024-01-15 | 101 | 3-1 | 
| WINTER2024 | NA-EST | SEMIFINALI | UPPER | partita-002 | 101 | 105 | 2024-01-18 | 101 | 3-2 | 
| WINTER2024 | NA-EST | SEMIFINALI | UPPER | match-003 | 103 | 107 | 2024-01-18 | 103 | 3-0 | 
| WINTER2024 | NORD-OVEST | FINALE | CAMPIONATO | partita-005 | 102 | 104 | 2024-01-20 | 102 | 3-2 | 
| WINTER2024 | NORD-OVEST | SEMIFINALI | UPPER | partita-006 | 102 | 106 | 2024-01-18 | 102 | 3-1 | 
| SPRING2024 | NA-EST | QUARTI DI FINALE | LOWER | partita-008 | 103 | 110 | 2024-03-15 | 103 | 3-2 | 
| SPRING2024 | NA-EST | QUARTI DI FINALE | UPPER | match-007 | 101 | 108 | 2024-03-15 | 101 | 3-0 | 

### GSI: PlayerMatchHistoryIndex (chiavi multiattributo)
<a name="GSI.DesignPattern.MultiAttributeKeys.PlayerMatchHistoryIndexTable"></a>


| Player1ID (PK) | MatchDate (SK) | rotondo (SK) | ID del torneo | region | staffa | MatchID | ID giocatore 2 | vincitore | punteggio | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| 101 | 2024-01-15 | QUARTI DI FINALE | WINTER2024 | NA-EST | UPPER | partita-004 | 109 | 101 | 3-1 | 
| 101 | 2024-01-18 | SEMIFINALI | WINTER2024 | NA-EST | UPPER | partita-002 | 105 | 101 | 3-2 | 
| 101 | 2024-01-20 | FINALE | WINTER2024 | NA-EST | CAMPIONATO | partita-001 | 103 | 101 | 3-1 | 
| 101 | 2024-03-15 | QUARTI DI FINALE | SPRING2024 | NA-EST | UPPER | partita-007 | 108 | 101 | 3-0 | 
| 102 | 2024-01-18 | SEMIFINALI | WINTER2024 | NORD-OVEST | UPPER | incontro 006 | 106 | 102 | 3-1 | 
| 102 | 2024-01-20 | FINALE | WINTER2024 | NORD-OVEST | CAMPIONATO | partita-005 | 104 | 102 | 3-2 | 
| 103 | 2024-01-18 | SEMIFINALI | WINTER2024 | NA-EST | UPPER | partita-003 | 107 | 103 | 3-0 | 
| 103 | 2024-03-15 | QUARTI DI FINALE | SPRING2024 | NA-EST | LOWER | partita-008 | 110 | 103 | 3-2 | 

## Prerequisiti
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites"></a>

Prima di iniziare, assicurati di disporre dei seguenti elementi:

### Account e autorizzazioni
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.AWSAccount"></a>
+ Un AWS account attivo ([creane uno qui](https://aws.amazon.com/free/) se necessario)
+ Autorizzazioni IAM per le operazioni DynamoDB:
  + `dynamodb:CreateTable`
  + `dynamodb:DeleteTable`
  + `dynamodb:DescribeTable`
  + `dynamodb:PutItem`
  + `dynamodb:Query`
  + `dynamodb:BatchWriteItem`

**Nota**  
**Nota di sicurezza:** per l'uso in produzione, crea una policy IAM personalizzata con solo le autorizzazioni necessarie. Per questo tutorial, puoi utilizzare la policy AWS `AmazonDynamoDBFullAccessV2` gestita.

### Ambiente di sviluppo
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.DevEnvironment"></a>
+ Node.js installato sul tuo computer
+ AWS credenziali configurate utilizzando uno di questi metodi:

**Opzione 1: AWS CLI**

```
aws configure
```

**Opzione 2: variabili di ambiente**

```
export AWS_ACCESS_KEY_ID=your_access_key_here
export AWS_SECRET_ACCESS_KEY=your_secret_key_here
export AWS_DEFAULT_REGION=us-east-1
```

### Installazione dei pacchetti richiesti
<a name="GSI.DesignPattern.MultiAttributeKeys.Prerequisites.InstallPackages"></a>

```
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb
```

## Implementazione
<a name="GSI.DesignPattern.MultiAttributeKeys.Implementation"></a>

### Passaggio 1: creare una tabella GSIs utilizzando chiavi multiattributo
<a name="GSI.DesignPattern.MultiAttributeKeys.CreateTable"></a>

Crea una tabella con una struttura chiave di base semplice e GSIs che utilizzi chiavi multiattributo.

#### esempio di codice
<a name="w2aac19c13c45c23b9c11b3b5b1"></a>

```
import { DynamoDBClient, CreateTableCommand } from "@aws-sdk/client-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });

const response = await client.send(new CreateTableCommand({
    TableName: 'TournamentMatches',
    
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'matchId', KeyType: 'HASH' }              // Simple PK
    ],
    
    AttributeDefinitions: [
        { AttributeName: 'matchId', AttributeType: 'S' },
        { AttributeName: 'tournamentId', AttributeType: 'S' },
        { AttributeName: 'region', AttributeType: 'S' },
        { AttributeName: 'round', AttributeType: 'S' },
        { AttributeName: 'bracket', AttributeType: 'S' },
        { AttributeName: 'player1Id', AttributeType: 'S' },
        { AttributeName: 'matchDate', AttributeType: 'S' }
    ],
    
    // GSIs with multi-attribute keys
    GlobalSecondaryIndexes: [
        {
            IndexName: 'TournamentRegionIndex',
            KeySchema: [
                { AttributeName: 'tournamentId', KeyType: 'HASH' },    // GSI PK attribute 1
                { AttributeName: 'region', KeyType: 'HASH' },          // GSI PK attribute 2
                { AttributeName: 'round', KeyType: 'RANGE' },          // GSI SK attribute 1
                { AttributeName: 'bracket', KeyType: 'RANGE' },        // GSI SK attribute 2
                { AttributeName: 'matchId', KeyType: 'RANGE' }         // GSI SK attribute 3
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'PlayerMatchHistoryIndex',
            KeySchema: [
                { AttributeName: 'player1Id', KeyType: 'HASH' },       // GSI PK
                { AttributeName: 'matchDate', KeyType: 'RANGE' },      // GSI SK attribute 1
                { AttributeName: 'round', KeyType: 'RANGE' }           // GSI SK attribute 2
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    
    BillingMode: 'PAY_PER_REQUEST'
}));

console.log("Table with multi-attribute GSI keys created successfully");
```

**Principali decisioni di progettazione:**

**Tabella base:** la tabella base utilizza una semplice chiave di `matchId` partizione per le ricerche dirette, mantenendo la struttura della tabella di base semplice e GSIs fornendo al contempo modelli di interrogazione complessi.

**TournamentRegionIndex Indice secondario globale: l'indice** secondario `TournamentRegionIndex` globale utilizza `tournamentId` \$1 `region` come chiave di partizione multiattributo, creando un isolamento tra regione e torneo in cui i dati vengono distribuiti combinando l'hash di entrambi gli attributi, permettendo di eseguire query efficienti all'interno di un contesto specifico tra torneo e regione. La chiave di ordinamento multiattributo (`round`\$1 `bracket` \$1`matchId`) fornisce un ordinamento gerarchico che supporta le query a qualsiasi livello della gerarchia con un ordinamento naturale da generale (round) a specifico (match ID).

**PlayerMatchHistoryIndex Indice secondario globale:** il `PlayerMatchHistoryIndex` Global Secondary Index riorganizza i dati per giocatore utilizzandoli `player1Id` come chiave di partizione, abilitando le interrogazioni tra tornei per un giocatore specifico. La chiave di ordinamento multiattributo (`matchDate`\$1`round`) fornisce un ordine cronologico con la possibilità di filtrare per intervalli di date o turni di torneo specifici.

### Fase 2: Inserimento di dati con attributi nativi
<a name="GSI.DesignPattern.MultiAttributeKeys.InsertData"></a>

Aggiungi i dati delle partite del torneo utilizzando attributi naturali. Il GSI indicizzerà automaticamente questi attributi senza richiedere chiavi sintetiche.

#### esempio di codice
<a name="w2aac19c13c45c23b9c11b5b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Tournament match data - no synthetic keys needed for GSIs
const matches = [
    // Winter 2024 Tournament, NA-EAST region
    {
        matchId: 'match-001',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'FINALS',
        bracket: 'CHAMPIONSHIP',
        player1Id: '101',
        player2Id: '103',
        matchDate: '2024-01-20',
        winner: '101',
        score: '3-1'
    },
    {
        matchId: 'match-002',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '105',
        matchDate: '2024-01-18',
        winner: '101',
        score: '3-2'
    },
    {
        matchId: 'match-003',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '103',
        player2Id: '107',
        matchDate: '2024-01-18',
        winner: '103',
        score: '3-0'
    },
    {
        matchId: 'match-004',
        tournamentId: 'WINTER2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '109',
        matchDate: '2024-01-15',
        winner: '101',
        score: '3-1'
    },
    
    // Winter 2024 Tournament, NA-WEST region
    {
        matchId: 'match-005',
        tournamentId: 'WINTER2024',
        region: 'NA-WEST',
        round: 'FINALS',
        bracket: 'CHAMPIONSHIP',
        player1Id: '102',
        player2Id: '104',
        matchDate: '2024-01-20',
        winner: '102',
        score: '3-2'
    },
    {
        matchId: 'match-006',
        tournamentId: 'WINTER2024',
        region: 'NA-WEST',
        round: 'SEMIFINALS',
        bracket: 'UPPER',
        player1Id: '102',
        player2Id: '106',
        matchDate: '2024-01-18',
        winner: '102',
        score: '3-1'
    },
    
    // Spring 2024 Tournament, NA-EAST region
    {
        matchId: 'match-007',
        tournamentId: 'SPRING2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'UPPER',
        player1Id: '101',
        player2Id: '108',
        matchDate: '2024-03-15',
        winner: '101',
        score: '3-0'
    },
    {
        matchId: 'match-008',
        tournamentId: 'SPRING2024',
        region: 'NA-EAST',
        round: 'QUARTERFINALS',
        bracket: 'LOWER',
        player1Id: '103',
        player2Id: '110',
        matchDate: '2024-03-15',
        winner: '103',
        score: '3-2'
    }
];

// Insert all matches
for (const match of matches) {
    await docClient.send(new PutCommand({
        TableName: 'TournamentMatches',
        Item: match
    }));
    
    console.log(`Added: ${match.matchId} - ${match.tournamentId}/${match.region} - ${match.round} ${match.bracket}`);
}

console.log(`\nInserted ${matches.length} tournament matches`);
console.log("No synthetic keys created - GSIs use native attributes automatically");
```

**Struttura dei dati spiegata:**

**Utilizzo degli attributi naturali:** ogni attributo rappresenta un vero concetto di torneo senza necessità di concatenazione o analisi di stringhe, e fornisce una mappatura diretta al modello di dominio.

Indicizzazione **automatica dell'indice secondario globale: indicizza** GSIs automaticamente gli elementi utilizzando gli attributi esistenti (`tournamentId`,,,, `matchId` for TournamentRegionIndex e `region` `round` `bracket` `player1Id``matchDate`, `round` for PlayerMatchHistoryIndex) senza richiedere chiavi concatenate sintetiche.

**Non è necessario il backfill:** quando aggiungi un nuovo indice secondario globale con chiavi multiattributo a una tabella esistente, DynamoDB indicizza automaticamente tutti gli elementi esistenti utilizzando i loro attributi naturali, senza bisogno di aggiornare gli elementi con chiavi sintetiche.

### Fase 3: Interroga l'indice secondario globale con tutti gli attributi delle chiavi di partizione TournamentRegionIndex
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryAllPartitionKeys"></a>

Questo esempio interroga il TournamentRegionIndex Global Secondary Index che ha una chiave di partizione multiattributo (\$1). `tournamentId` `region` Tutti gli attributi delle chiavi di partizione devono essere specificati con condizioni di uguaglianza nelle query: non è possibile eseguire query `tournamentId` solo con o utilizzare operatori di disuguaglianza sugli attributi delle chiavi di partizione.

#### esempio di codice
<a name="w2aac19c13c45c23b9c11b7b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query GSI: All matches for WINTER2024 tournament in NA-EAST region
const response = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region',
    ExpressionAttributeNames: {
        '#region': 'region',  // 'region' is a reserved keyword
        '#tournament': 'tournament'
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST'
    }
}));

console.log(`Found ${response.Items.length} matches for WINTER2024/NA-EAST:\n`);
response.Items.forEach(match => {
    console.log(`  ${match.round} | ${match.bracket} | ${match.matchId}`);
    console.log(`    Players: ${match.player1Id} vs ${match.player2Id}`);
    console.log(`    Winner: ${match.winner}, Score: ${match.score}\n`);
});
```

**Output previsto:**

```
Found 4 matches for WINTER2024/NA-EAST:

  FINALS | CHAMPIONSHIP | match-001
    Players: 101 vs 103
    Winner: 101, Score: 3-1

  QUARTERFINALS | UPPER | match-004
    Players: 101 vs 109
    Winner: 101, Score: 3-1

  SEMIFINALS | UPPER | match-002
    Players: 101 vs 105
    Winner: 101, Score: 3-2

  SEMIFINALS | UPPER | match-003
    Players: 103 vs 107
    Winner: 103, Score: 3-0
```

**Interrogazioni non valide:**

```
// Missing region attribute
KeyConditionExpression: 'tournamentId = :tournament'

// Using inequality on partition key attribute
KeyConditionExpression: 'tournamentId = :tournament AND #region > :region'
```

**Prestazioni: le** chiavi di partizione con più attributi vengono codificate insieme, fornendo le stesse prestazioni di ricerca O (1) delle chiavi ad attributo singolo.

### Fase 4: Interroga le chiavi di ordinamento dell'indice secondario globale left-to-right
<a name="GSI.DesignPattern.MultiAttributeKeys.QuerySortKeysLeftToRight"></a>

Gli attributi delle chiavi di ordinamento devono essere interrogati left-to-right nell'ordine in cui sono definiti nell'indice secondario globale. Questo esempio dimostra l'esecuzione di interrogazioni TournamentRegionIndex a diversi livelli gerarchici: filtraggio per just`round`, per `round` \$1 `bracket` o per tutti e tre gli attributi chiave di ordinamento. Non è possibile saltare gli attributi al centro, ad esempio non è possibile eseguire una query per e mentre si salta. `round` `matchId` `bracket`

#### esempio di codice
<a name="w2aac19c13c45c23b9c11b9b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: Filter by first sort key attribute (round)
console.log("Query 1: All SEMIFINALS matches");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS'
    }
}));
console.log(`  Found ${query1.Items.length} matches\n`);

// Query 2: Filter by first two sort key attributes (round + bracket)
console.log("Query 2: SEMIFINALS UPPER bracket matches");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND bracket = :bracket',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':bracket': 'UPPER'
    }
}));
console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Filter by all three sort key attributes (round + bracket + matchId)
console.log("Query 3: Specific match in SEMIFINALS UPPER bracket");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND bracket = :bracket AND matchId = :matchId',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':bracket': 'UPPER',
        ':matchId': 'match-002'
    }
}));
console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: INVALID - skipping round
console.log("Query 4: Attempting to skip first sort key attribute (WILL FAIL)");
try {
    const query4 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND bracket = :bracket',
        ExpressionAttributeNames: {
            '#region': 'region'  // 'region' is a reserved keyword
        },
        ExpressionAttributeValues: {
            ':tournament': 'WINTER2024',
            ':region': 'NA-EAST',
            ':bracket': 'UPPER'
        }
    }));
} catch (error) {
    console.log(`  Error: ${error.message}`);
    console.log(`  Cannot skip sort key attributes - must query left-to-right\n`);
}
```

**Output previsto:**

```
Query 1: All SEMIFINALS matches
  Found 2 matches

Query 2: SEMIFINALS UPPER bracket matches
  Found 2 matches

Query 3: Specific match in SEMIFINALS UPPER bracket
  Found 1 matches

Query 4: Attempting to skip first sort key attribute (WILL FAIL)
  Error: Query key condition not supported
  Cannot skip sort key attributes - must query left-to-right
```

**Left-to-right regole di interrogazione:** è necessario interrogare gli attributi in ordine da sinistra a destra, senza saltarne nessuno.

**Modelli validi:**
+ Solo primo attributo: `round = 'SEMIFINALS'`
+ Primi due attributi: `round = 'SEMIFINALS' AND bracket = 'UPPER'`
+ Tutti e tre gli attributi: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId = 'match-002'`

**Schemi non validi:**
+ Il primo attributo viene ignorato: `bracket = 'UPPER'` (salta il giro)
+ Interrogazione non corretta: `matchId = 'match-002' AND round = 'SEMIFINALS'`
+ Lasciare spazi vuoti: `round = 'SEMIFINALS' AND matchId = 'match-002'` (salta la parentesi)

**Nota**  
**Suggerimento di progettazione:** ordina gli attributi chiave di ordinamento dal più generale al più specifico per massimizzare la flessibilità delle query.

### Fase 5: Utilizza le condizioni di disuguaglianza nelle chiavi di ordinamento dell'Indice secondario globale
<a name="GSI.DesignPattern.MultiAttributeKeys.InequalityConditions"></a>

Le condizioni di disuguaglianza devono essere l'ultima condizione della ricerca. Questo esempio dimostra l'utilizzo degli operatori di confronto (`>=`,`BETWEEN`) e del prefisso matching (`begins_with()`) sugli attributi delle chiavi di ordinamento. Una volta utilizzato un operatore di disuguaglianza, non è possibile aggiungere ulteriori condizioni di chiave di ordinamento dopo di esso: la disuguaglianza deve essere l'ultima condizione nell'espressione della condizione chiave.

#### esempio di codice
<a name="w2aac19c13c45c23b9c11c11b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: Round comparison (inequality on first sort key attribute)
console.log("Query 1: Matches from QUARTERFINALS onwards");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round >= :round',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'QUARTERFINALS'
    }
}));
console.log(`  Found ${query1.Items.length} matches\n`);

// Query 2: Round range with BETWEEN
console.log("Query 2: Matches between QUARTERFINALS and SEMIFINALS");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round BETWEEN :start AND :end',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':start': 'QUARTERFINALS',
        ':end': 'SEMIFINALS'
    }
}));
console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Prefix matching with begins_with (treated as inequality)
console.log("Query 3: Matches in brackets starting with 'U'");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'TournamentRegionIndex',
    KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round = :round AND begins_with(bracket, :prefix)',
    ExpressionAttributeNames: {
        '#region': 'region'  // 'region' is a reserved keyword
    },
    ExpressionAttributeValues: {
        ':tournament': 'WINTER2024',
        ':region': 'NA-EAST',
        ':round': 'SEMIFINALS',
        ':prefix': 'U'
    }
}));
console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: INVALID - condition after inequality
console.log("Query 4: Attempting condition after inequality (WILL FAIL)");
try {
    const query4 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region AND round > :round AND bracket = :bracket',
        ExpressionAttributeNames: {
            '#region': 'region'  // 'region' is a reserved keyword
        },
        ExpressionAttributeValues: {
            ':tournament': 'WINTER2024',
            ':region': 'NA-EAST',
            ':round': 'QUARTERFINALS',
            ':bracket': 'UPPER'
        }
    }));
} catch (error) {
    console.log(`  Error: ${error.message}`);
    console.log(`  Cannot add conditions after inequality - it must be last\n`);
}
```

**Regole degli operatori di disuguaglianza:** è possibile utilizzare gli operatori di confronto (`>`,,,`<=`) `>=``<`, `BETWEEN` per le interrogazioni sugli intervalli e per la corrispondenza dei prefissi. `begins_with()` La disuguaglianza deve essere l'ultima condizione della query.

**Schemi validi:**
+ Condizioni di uguaglianza seguite dalla disuguaglianza: `round = 'SEMIFINALS' AND bracket = 'UPPER' AND matchId > 'match-001'`
+ Disuguaglianza sul primo attributo: `round BETWEEN 'QUARTERFINALS' AND 'SEMIFINALS'`
+ Corrispondenza del prefisso come condizione finale: `round = 'SEMIFINALS' AND begins_with(bracket, 'U')`

**Schemi non validi:**
+ Aggiungere condizioni dopo una disuguaglianza: `round > 'QUARTERFINALS' AND bracket = 'UPPER'`
+ Utilizzo di più disuguaglianze: `round > 'QUARTERFINALS' AND bracket > 'L'`

**Importante**  
`begins_with()`viene considerata una condizione di disuguaglianza, quindi non può essere seguita da alcuna condizione di chiave di ordinamento aggiuntiva.

### Fase 6: Interrogazione dell'indice secondario PlayerMatchHistoryIndex globale con una chiave di ordinamento multiattributo
<a name="GSI.DesignPattern.MultiAttributeKeys.QueryPlayerHistory"></a>

Questo esempio interroga il PlayerMatchHistoryIndex che ha una chiave di partizione singola (`player1Id`) e una chiave di ordinamento con più attributi (\$1). `matchDate` `round` Ciò consente l'analisi tra tornei interrogando tutte le partite di un giocatore specifico senza conoscere il torneo, IDs mentre la tabella base richiederebbe interrogazioni separate per combinazione torneo-regione.

#### esempio di codice
<a name="w2aac19c13c45c23b9c11c13b5b1"></a>

```
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

// Query 1: All matches for Player 101 across all tournaments
console.log("Query 1: All matches for Player 101");
const query1 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player',
    ExpressionAttributeValues: {
        ':player': '101'
    }
}));

console.log(`  Found ${query1.Items.length} matches for Player 101:`);
query1.Items.forEach(match => {
    console.log(`    ${match.tournamentId}/${match.region} - ${match.matchDate} - ${match.round}`);
});
console.log();

// Query 2: Player 101 matches on specific date
console.log("Query 2: Player 101 matches on 2024-01-18");
const query2 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate = :date',
    ExpressionAttributeValues: {
        ':player': '101',
        ':date': '2024-01-18'
    }
}));

console.log(`  Found ${query2.Items.length} matches\n`);

// Query 3: Player 101 SEMIFINALS matches on specific date
console.log("Query 3: Player 101 SEMIFINALS matches on 2024-01-18");
const query3 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate = :date AND round = :round',
    ExpressionAttributeValues: {
        ':player': '101',
        ':date': '2024-01-18',
        ':round': 'SEMIFINALS'
    }
}));

console.log(`  Found ${query3.Items.length} matches\n`);

// Query 4: Player 101 matches in date range
console.log("Query 4: Player 101 matches in January 2024");
const query4 = await docClient.send(new QueryCommand({
    TableName: 'TournamentMatches',
    IndexName: 'PlayerMatchHistoryIndex',
    KeyConditionExpression: 'player1Id = :player AND matchDate BETWEEN :start AND :end',
    ExpressionAttributeValues: {
        ':player': '101',
        ':start': '2024-01-01',
        ':end': '2024-01-31'
    }
}));

console.log(`  Found ${query4.Items.length} matches\n`);
```

## Variazioni del modello
<a name="GSI.DesignPattern.MultiAttributeKeys.PatternVariations"></a>

### Dati di serie temporali con chiavi multiattributo
<a name="GSI.DesignPattern.MultiAttributeKeys.TimeSeries"></a>

Ottimizzazione per le query su serie temporali con attributi temporali gerarchici

#### esempio di codice
<a name="w2aac19c13c45c23b9c13b3b5b1"></a>

```
{
    TableName: 'IoTReadings',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'readingId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'readingId', AttributeType: 'S' },
        { AttributeName: 'deviceId', AttributeType: 'S' },
        { AttributeName: 'locationId', AttributeType: 'S' },
        { AttributeName: 'year', AttributeType: 'S' },
        { AttributeName: 'month', AttributeType: 'S' },
        { AttributeName: 'day', AttributeType: 'S' },
        { AttributeName: 'timestamp', AttributeType: 'S' }
    ],
    // GSI with multi-attribute keys for time-series queries
    GlobalSecondaryIndexes: [{
        IndexName: 'DeviceLocationTimeIndex',
        KeySchema: [
            { AttributeName: 'deviceId', KeyType: 'HASH' },
            { AttributeName: 'locationId', KeyType: 'HASH' },
            { AttributeName: 'year', KeyType: 'RANGE' },
            { AttributeName: 'month', KeyType: 'RANGE' },
            { AttributeName: 'day', KeyType: 'RANGE' },
            { AttributeName: 'timestamp', KeyType: 'RANGE' }
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query patterns enabled via GSI:
// - All readings for device in location
// - Readings for specific year
// - Readings for specific month in year
// - Readings for specific day
// - Readings in time range
```

**Vantaggi:** la gerarchia temporale naturale (anno → mese → giorno → timestamp) consente una granularità delle query efficienti in qualsiasi momento senza analisi o manipolazione della data. L'indice secondario globale indicizza automaticamente tutte le letture utilizzando i loro attributi temporali naturali.

### Ordini di e-commerce con chiavi multiattributo
<a name="GSI.DesignPattern.MultiAttributeKeys.ECommerce"></a>

Tieni traccia degli ordini con più dimensioni

#### esempio di codice
<a name="w2aac19c13c45c23b9c13b5b5b1"></a>

```
{
    TableName: 'Orders',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'orderId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'orderId', AttributeType: 'S' },
        { AttributeName: 'sellerId', AttributeType: 'S' },
        { AttributeName: 'region', AttributeType: 'S' },
        { AttributeName: 'orderDate', AttributeType: 'S' },
        { AttributeName: 'category', AttributeType: 'S' },
        { AttributeName: 'customerId', AttributeType: 'S' },
        { AttributeName: 'orderStatus', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'SellerRegionIndex',
            KeySchema: [
                { AttributeName: 'sellerId', KeyType: 'HASH' },
                { AttributeName: 'region', KeyType: 'HASH' },
                { AttributeName: 'orderDate', KeyType: 'RANGE' },
                { AttributeName: 'category', KeyType: 'RANGE' },
                { AttributeName: 'orderId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'CustomerOrdersIndex',
            KeySchema: [
                { AttributeName: 'customerId', KeyType: 'HASH' },
                { AttributeName: 'orderDate', KeyType: 'RANGE' },
                { AttributeName: 'orderStatus', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// SellerRegionIndex GSI queries:
// - Orders by seller and region
// - Orders by seller, region, and date
// - Orders by seller, region, date, and category

// CustomerOrdersIndex GSI queries:
// - Customer's orders
// - Customer's orders by date
// - Customer's orders by date and status
```

### Dati organizzativi gerarchici
<a name="GSI.DesignPattern.MultiAttributeKeys.Hierarchical"></a>

Gerarchie organizzative modello

#### esempio di codice
<a name="w2aac19c13c45c23b9c13b7b5b1"></a>

```
{
    TableName: 'Employees',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'employeeId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'employeeId', AttributeType: 'S' },
        { AttributeName: 'companyId', AttributeType: 'S' },
        { AttributeName: 'divisionId', AttributeType: 'S' },
        { AttributeName: 'departmentId', AttributeType: 'S' },
        { AttributeName: 'teamId', AttributeType: 'S' },
        { AttributeName: 'skillCategory', AttributeType: 'S' },
        { AttributeName: 'skillLevel', AttributeType: 'S' },
        { AttributeName: 'yearsExperience', AttributeType: 'N' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'OrganizationIndex',
            KeySchema: [
                { AttributeName: 'companyId', KeyType: 'HASH' },
                { AttributeName: 'divisionId', KeyType: 'HASH' },
                { AttributeName: 'departmentId', KeyType: 'RANGE' },
                { AttributeName: 'teamId', KeyType: 'RANGE' },
                { AttributeName: 'employeeId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'SkillsIndex',
            KeySchema: [
                { AttributeName: 'skillCategory', KeyType: 'HASH' },
                { AttributeName: 'skillLevel', KeyType: 'RANGE' },
                { AttributeName: 'yearsExperience', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'INCLUDE', NonKeyAttributes: ['employeeId', 'name'] }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// OrganizationIndex GSI query patterns:
// - All employees in company/division
// - Employees in specific department
// - Employees in specific team

// SkillsIndex GSI query patterns:
// - Employees by skill and experience level
```

### Chiavi sparse con più attributi
<a name="GSI.DesignPattern.MultiAttributeKeys.Sparse"></a>

Combina chiavi multiattributo per creare un GSI sparso

#### esempio di codice
<a name="w2aac19c13c45c23b9c13b9b5b1"></a>

```
{
    TableName: 'Products',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'productId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'productId', AttributeType: 'S' },
        { AttributeName: 'categoryId', AttributeType: 'S' },
        { AttributeName: 'subcategoryId', AttributeType: 'S' },
        { AttributeName: 'averageRating', AttributeType: 'N' },
        { AttributeName: 'reviewCount', AttributeType: 'N' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'CategoryIndex',
            KeySchema: [
                { AttributeName: 'categoryId', KeyType: 'HASH' },
                { AttributeName: 'subcategoryId', KeyType: 'HASH' },
                { AttributeName: 'productId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'ReviewedProductsIndex',
            KeySchema: [
                { AttributeName: 'categoryId', KeyType: 'HASH' },
                { AttributeName: 'averageRating', KeyType: 'RANGE' },  // Optional attribute
                { AttributeName: 'reviewCount', KeyType: 'RANGE' }     // Optional attribute
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// Only products with reviews appear in ReviewedProductsIndex GSI
// Automatic filtering without application logic
// Multi-attribute sort key enables rating and count queries
```

### Multi-tenancy SaaS
<a name="GSI.DesignPattern.MultiAttributeKeys.SaaS"></a>

Piattaforma SaaS multi-tenant con isolamento del cliente

#### esempio di codice
<a name="w2aac19c13c45c23b9c13c11b5b1"></a>

```
// Table design
{
    TableName: 'SaasData',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'resourceId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'resourceId', AttributeType: 'S' },
        { AttributeName: 'tenantId', AttributeType: 'S' },
        { AttributeName: 'customerId', AttributeType: 'S' },
        { AttributeName: 'resourceType', AttributeType: 'S' }
    ],
    // GSI with multi-attribute keys for tenant-customer isolation
    GlobalSecondaryIndexes: [{
        IndexName: 'TenantCustomerIndex',
        KeySchema: [
            { AttributeName: 'tenantId', KeyType: 'HASH' },
            { AttributeName: 'customerId', KeyType: 'HASH' },
            { AttributeName: 'resourceType', KeyType: 'RANGE' },
            { AttributeName: 'resourceId', KeyType: 'RANGE' }
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query GSI: All resources for tenant T001, customer C001
const resources = await docClient.send(new QueryCommand({
    TableName: 'SaasData',
    IndexName: 'TenantCustomerIndex',
    KeyConditionExpression: 'tenantId = :tenant AND customerId = :customer',
    ExpressionAttributeValues: {
        ':tenant': 'T001',
        ':customer': 'C001'
    }
}));

// Query GSI: Specific resource type for tenant/customer
const documents = await docClient.send(new QueryCommand({
    TableName: 'SaasData',
    IndexName: 'TenantCustomerIndex',
    KeyConditionExpression: 'tenantId = :tenant AND customerId = :customer AND resourceType = :type',
    ExpressionAttributeValues: {
        ':tenant': 'T001',
        ':customer': 'C001',
        ':type': 'document'
    }
}));
```

**Vantaggi:** interrogazioni efficienti nel contesto tra inquilino e cliente e organizzazione naturale dei dati.

### Transazioni finanziarie
<a name="GSI.DesignPattern.MultiAttributeKeys.Financial"></a>

Sistema bancario che monitora le transazioni del conto utilizzando GSIs

#### esempio di codice
<a name="w2aac19c13c45c23b9c13c13b5b1"></a>

```
// Table design
{
    TableName: 'BankTransactions',
    // Base table: Simple partition key
    KeySchema: [
        { AttributeName: 'transactionId', KeyType: 'HASH' }
    ],
    AttributeDefinitions: [
        { AttributeName: 'transactionId', AttributeType: 'S' },
        { AttributeName: 'accountId', AttributeType: 'S' },
        { AttributeName: 'year', AttributeType: 'S' },
        { AttributeName: 'month', AttributeType: 'S' },
        { AttributeName: 'day', AttributeType: 'S' },
        { AttributeName: 'transactionType', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [
        {
            IndexName: 'AccountTimeIndex',
            KeySchema: [
                { AttributeName: 'accountId', KeyType: 'HASH' },
                { AttributeName: 'year', KeyType: 'RANGE' },
                { AttributeName: 'month', KeyType: 'RANGE' },
                { AttributeName: 'day', KeyType: 'RANGE' },
                { AttributeName: 'transactionId', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        },
        {
            IndexName: 'TransactionTypeIndex',
            KeySchema: [
                { AttributeName: 'accountId', KeyType: 'HASH' },
                { AttributeName: 'transactionType', KeyType: 'RANGE' },
                { AttributeName: 'year', KeyType: 'RANGE' },
                { AttributeName: 'month', KeyType: 'RANGE' }
            ],
            Projection: { ProjectionType: 'ALL' }
        }
    ],
    BillingMode: 'PAY_PER_REQUEST'
}

// Query AccountTimeIndex GSI: All transactions for account in 2023
const yearTransactions = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'AccountTimeIndex',
    KeyConditionExpression: 'accountId = :account AND #year = :year',
    ExpressionAttributeNames: { '#year': 'year' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':year': '2023'
    }
}));

// Query AccountTimeIndex GSI: Transactions in specific month
const monthTransactions = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'AccountTimeIndex',
    KeyConditionExpression: 'accountId = :account AND #year = :year AND #month = :month',
    ExpressionAttributeNames: { '#year': 'year', '#month': 'month' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':year': '2023',
        ':month': '11'
    }
}));

// Query TransactionTypeIndex GSI: Deposits in 2023
const deposits = await docClient.send(new QueryCommand({
    TableName: 'BankTransactions',
    IndexName: 'TransactionTypeIndex',
    KeyConditionExpression: 'accountId = :account AND transactionType = :type AND #year = :year',
    ExpressionAttributeNames: { '#year': 'year' },
    ExpressionAttributeValues: {
        ':account': 'ACC-12345',
        ':type': 'deposit',
        ':year': '2023'
    }
}));
```

## Esempio completo
<a name="GSI.DesignPattern.MultiAttributeKeys.CompleteExample"></a>

L'esempio seguente illustra le chiavi con più attributi dalla configurazione alla pulizia:

### esempio di codice
<a name="w2aac19c13c45c23b9c15b5b1"></a>

```
import { 
    DynamoDBClient, 
    CreateTableCommand, 
    DeleteTableCommand, 
    waitUntilTableExists 
} from "@aws-sdk/client-dynamodb";
import { 
    DynamoDBDocumentClient, 
    PutCommand, 
    QueryCommand 
} from "@aws-sdk/lib-dynamodb";

const client = new DynamoDBClient({ region: 'us-west-2' });
const docClient = DynamoDBDocumentClient.from(client);

async function multiAttributeKeysDemo() {
    console.log("Starting Multi-Attribute GSI Keys Demo\n");
    
    // Step 1: Create table with GSIs using multi-attribute keys
    console.log("1. Creating table with multi-attribute GSI keys...");
    await client.send(new CreateTableCommand({
        TableName: 'TournamentMatches',
        KeySchema: [
            { AttributeName: 'matchId', KeyType: 'HASH' }
        ],
        AttributeDefinitions: [
            { AttributeName: 'matchId', AttributeType: 'S' },
            { AttributeName: 'tournamentId', AttributeType: 'S' },
            { AttributeName: 'region', AttributeType: 'S' },
            { AttributeName: 'round', AttributeType: 'S' },
            { AttributeName: 'bracket', AttributeType: 'S' },
            { AttributeName: 'player1Id', AttributeType: 'S' },
            { AttributeName: 'matchDate', AttributeType: 'S' }
        ],
        GlobalSecondaryIndexes: [
            {
                IndexName: 'TournamentRegionIndex',
                KeySchema: [
                    { AttributeName: 'tournamentId', KeyType: 'HASH' },
                    { AttributeName: 'region', KeyType: 'HASH' },
                    { AttributeName: 'round', KeyType: 'RANGE' },
                    { AttributeName: 'bracket', KeyType: 'RANGE' },
                    { AttributeName: 'matchId', KeyType: 'RANGE' }
                ],
                Projection: { ProjectionType: 'ALL' }
            },
            {
                IndexName: 'PlayerMatchHistoryIndex',
                KeySchema: [
                    { AttributeName: 'player1Id', KeyType: 'HASH' },
                    { AttributeName: 'matchDate', KeyType: 'RANGE' },
                    { AttributeName: 'round', KeyType: 'RANGE' }
                ],
                Projection: { ProjectionType: 'ALL' }
            }
        ],
        BillingMode: 'PAY_PER_REQUEST'
    }));
    
    await waitUntilTableExists({ client, maxWaitTime: 120 }, { TableName: 'TournamentMatches' });
    console.log("Table created\n");
    
    // Step 2: Insert tournament matches
    console.log("2. Inserting tournament matches...");
    const matches = [
        { matchId: 'match-001', tournamentId: 'WINTER2024', region: 'NA-EAST', round: 'FINALS', bracket: 'CHAMPIONSHIP', player1Id: '101', player2Id: '103', matchDate: '2024-01-20', winner: '101', score: '3-1' },
        { matchId: 'match-002', tournamentId: 'WINTER2024', region: 'NA-EAST', round: 'SEMIFINALS', bracket: 'UPPER', player1Id: '101', player2Id: '105', matchDate: '2024-01-18', winner: '101', score: '3-2' },
        { matchId: 'match-003', tournamentId: 'WINTER2024', region: 'NA-WEST', round: 'FINALS', bracket: 'CHAMPIONSHIP', player1Id: '102', player2Id: '104', matchDate: '2024-01-20', winner: '102', score: '3-2' },
        { matchId: 'match-004', tournamentId: 'SPRING2024', region: 'NA-EAST', round: 'QUARTERFINALS', bracket: 'UPPER', player1Id: '101', player2Id: '108', matchDate: '2024-03-15', winner: '101', score: '3-0' }
    ];
    
    for (const match of matches) {
        await docClient.send(new PutCommand({ TableName: 'TournamentMatches', Item: match }));
    }
    console.log(`Inserted ${matches.length} tournament matches\n`);
    
    // Step 3: Query GSI with multi-attribute partition key
    console.log("3. Query TournamentRegionIndex GSI: WINTER2024/NA-EAST matches");
    const gsiQuery1 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'TournamentRegionIndex',
        KeyConditionExpression: 'tournamentId = :tournament AND #region = :region',
        ExpressionAttributeNames: { '#region': 'region' },
        ExpressionAttributeValues: { ':tournament': 'WINTER2024', ':region': 'NA-EAST' }
    }));
    
    console.log(`  Found ${gsiQuery1.Items.length} matches:`);
    gsiQuery1.Items.forEach(match => {
        console.log(`    ${match.round} - ${match.bracket} - ${match.winner} won`);
    });
    
    // Step 4: Query GSI with multi-attribute sort key
    console.log("\n4. Query PlayerMatchHistoryIndex GSI: All matches for Player 101");
    const gsiQuery2 = await docClient.send(new QueryCommand({
        TableName: 'TournamentMatches',
        IndexName: 'PlayerMatchHistoryIndex',
        KeyConditionExpression: 'player1Id = :player',
        ExpressionAttributeValues: { ':player': '101' }
    }));
    
    console.log(`  Found ${gsiQuery2.Items.length} matches for Player 101:`);
    gsiQuery2.Items.forEach(match => {
        console.log(`    ${match.tournamentId}/${match.region} - ${match.matchDate} - ${match.round}`);
    });
    
    console.log("\nDemo complete");
    console.log("No synthetic keys needed - GSIs use native attributes automatically");
}

async function cleanup() {
    console.log("Deleting table...");
    await client.send(new DeleteTableCommand({ TableName: 'TournamentMatches' }));
    console.log("Table deleted");
}

// Run demo
multiAttributeKeysDemo().catch(console.error);

// Uncomment to cleanup:
// cleanup().catch(console.error);
```

**Scaffold di codice minimo**

### esempio di codice
<a name="w2aac19c13c45c23b9c15b9b1"></a>

```
// 1. Create table with GSI using multi-attribute keys
await client.send(new CreateTableCommand({
    TableName: 'MyTable',
    KeySchema: [
        { AttributeName: 'id', KeyType: 'HASH' }        // Simple base table PK
    ],
    AttributeDefinitions: [
        { AttributeName: 'id', AttributeType: 'S' },
        { AttributeName: 'attr1', AttributeType: 'S' },
        { AttributeName: 'attr2', AttributeType: 'S' },
        { AttributeName: 'attr3', AttributeType: 'S' },
        { AttributeName: 'attr4', AttributeType: 'S' }
    ],
    GlobalSecondaryIndexes: [{
        IndexName: 'MyGSI',
        KeySchema: [
            { AttributeName: 'attr1', KeyType: 'HASH' },    // GSI PK attribute 1
            { AttributeName: 'attr2', KeyType: 'HASH' },    // GSI PK attribute 2
            { AttributeName: 'attr3', KeyType: 'RANGE' },   // GSI SK attribute 1
            { AttributeName: 'attr4', KeyType: 'RANGE' }    // GSI SK attribute 2
        ],
        Projection: { ProjectionType: 'ALL' }
    }],
    BillingMode: 'PAY_PER_REQUEST'
}));

// 2. Insert items with native attributes (no concatenation needed for GSI)
await docClient.send(new PutCommand({
    TableName: 'MyTable',
    Item: {
        id: 'item-001',
        attr1: 'value1',
        attr2: 'value2',
        attr3: 'value3',
        attr4: 'value4',
        // ... other attributes
    }
}));

// 3. Query GSI with all partition key attributes
await docClient.send(new QueryCommand({
    TableName: 'MyTable',
    IndexName: 'MyGSI',
    KeyConditionExpression: 'attr1 = :v1 AND attr2 = :v2',
    ExpressionAttributeValues: {
        ':v1': 'value1',
        ':v2': 'value2'
    }
}));

// 4. Query GSI with sort key attributes (left-to-right)
await docClient.send(new QueryCommand({
    TableName: 'MyTable',
    IndexName: 'MyGSI',
    KeyConditionExpression: 'attr1 = :v1 AND attr2 = :v2 AND attr3 = :v3',
    ExpressionAttributeValues: {
        ':v1': 'value1',
        ':v2': 'value2',
        ':v3': 'value3'
    }
}));

// Note: If any attribute name is a DynamoDB reserved keyword, use ExpressionAttributeNames:
// KeyConditionExpression: 'attr1 = :v1 AND #attr2 = :v2'
// ExpressionAttributeNames: { '#attr2': 'attr2' }
```

## Risorse aggiuntive
<a name="GSI.DesignPattern.MultiAttributeKeys.AdditionalResources"></a>
+ [Best practice per DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html)
+ [Lavorare con tabelle e dati](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html)
+ [Indici secondari globali](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html)
+ [Operazioni di interrogazione e scansione](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html)

# Gestione degli indici secondari globali in DynamoDB
<a name="GSI.OnlineOps"></a>

In questa sezione viene descritto come creare, modificare ed eliminare indici secondari globali in Amazon DynamoDB.

**Topics**
+ [Creazione di una tabella con indici secondari globali](#GSI.Creating)
+ [Descrizione degli indici secondari globali su una tabella](#GSI.Describing)
+ [Aggiunta di un indice secondario globale a una tabella esistente](#GSI.OnlineOps.Creating)
+ [Eliminazione di un indice secondario globale](#GSI.OnlineOps.Deleting)
+ [Modifica di un indice secondario globale durante la creazione](#GSI.OnlineOps.Creating.Modify)

## Creazione di una tabella con indici secondari globali
<a name="GSI.Creating"></a>

Per creare una tabella con uno o più indici secondari globali, utilizza l'operazione `CreateTable` con il parametro `GlobalSecondaryIndexes`. Per una massima flessibilità delle query, è possibile creare fino a 20 indici secondari globali (quota predefinita) per tabella. 

Devi specificare un attributo che funga da chiave di partizione dell'indice. Facoltativamente, puoi specificare un altro attributo per la chiave di ordinamento dell'indice. Non è necessario che questi attributi di chiave coincidano con quelli della tabella. Ad esempio, nella *GameScores*tabella (vedi[Utilizzo degli indici secondari globali in DynamoDB](GSI.md)), `TopScore` né lo `TopScoreDateTime` sono gli attributi chiave. È possibile creare un indice secondario globale con una chiave di partizione `TopScore` e una chiave di ordinamento `TopScoreDateTime`. Puoi utilizzare questo indice per determinare se esiste una correlazione tra punteggi elevati e il periodo del giorno in cui si svolge un gioco.

Ogni attributo di chiave dell'indice deve essere uno scalare di tipo `String`, `Number` o `Binary` (non può essere un tipo documento o set). È possibile proiettare gli attributi di qualsiasi tipo di dati in un indice secondario globale. Questo include scalari, documenti e set. Per l'elenco completo dei tipi di dati, consulta [Tipi di dati](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

Se utilizzi la modalità assegnata, devi specificare le impostazioni `ProvisionedThroughput` per l'indice, consistenti di `ReadCapacityUnits` e `WriteCapacityUnits`. Queste impostazioni di throughput assegnato sono distinte da quelle della tabella, ma il funzionamento è analogo. Per ulteriori informazioni, consulta [Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari globali](GSI.md#GSI.ThroughputConsiderations).

 Gli indici secondari globali ereditano la modalità di read/write capacità dalla tabella di base. Per ulteriori informazioni, consulta [Considerazioni sul passaggio tra modalità di capacità in DynamoDB](bp-switching-capacity-modes.md). 

**Nota**  
 Quando si crea un nuovo GSI, può essere importante verificare se la chiave di partizione scelta sta producendo una distribuzione irregolare o ristretta di dati o traffico attraverso i valori chiave della partizione del nuovo indice. In questo caso, è possibile che si verifichino operazioni di backfill e scrittura contemporaneamente e limitando le scritture nella tabella di base. Il servizio adotta misure per ridurre al minimo il potenziale di questo scenario, ma non ha alcuna visione della forma dei dati dei clienti in relazione alla chiave di partizione dell'indice, alla proiezione scelta o alla scarsità della chiave primaria dell'indice.  
Se si sospetta che il nuovo indice secondario globale possa avere dati limitati o disallineati o distribuzione del traffico tra i valori chiave delle partizioni, considerare quanto segue prima di aggiungere nuovi indici alle tabelle di importanza operativa.  
Potrebbe essere più sicuro aggiungere l'indice in un momento in cui l’applicazione guida la quantità minima di traffico.
Valuta la possibilità di abilitare CloudWatch Contributor Insights sulla tabella e sugli indici di base. Questo ti darà informazioni preziose sulla distribuzione del traffico.
 Guarda `WriteThrottleEvents` e `OnlineIndexPercentageProgress` CloudWatch metriche `ThrottledRequests` durante tutto il processo. Adatta la capacità di scrittura assegnata in base alle esigenze per completare il backfill in un tempo ragionevole senza effetti di limitazione significativi sulle operazioni in corso. `OnlineIndexConsumedWriteCapacity`e `OnlineThrottleEvents` si prevede che mostrino 0 durante il riempimento dell'indice.
Preparatevi ad annullare la creazione dell'indice se doveste riscontrare un impatto operativo dovuto alla limitazione della scrittura.

## Descrizione degli indici secondari globali su una tabella
<a name="GSI.Describing"></a>

Per visualizzare lo stato di tutti gli indici secondari globali su una tabella, utilizza l'operazione `DescribeTable`. La parte `GlobalSecondaryIndexes` della risposta mostra tutti gli indici della tabella insieme allo stato corrente di ciascuno (`IndexStatus`).

`IndexStatus` per un indice secondario globale sarà uno dei seguenti:
+ `CREATING`: l'indice è in fase di creazione e non è ancora disponibile per l'uso.
+ `ACTIVE`: l'indice è pronto per l'uso e le applicazioni possono eseguire operazioni `Query` sull'indice.
+ `UPDATING`: vengono modificate le impostazioni di velocità effettiva assegnata dell'indice.
+ `DELETING`: l'indice è attualmente in fase di eliminazione e non può essere più utilizzato.

Quando DynamoDB ha terminato la creazione di un indice secondario globale, lo stato dell'indice cambia da `CREATING` a `ACTIVE`.

## Aggiunta di un indice secondario globale a una tabella esistente
<a name="GSI.OnlineOps.Creating"></a>

Per aggiungere un indice secondario globale a una tabella esistente, utilizza l'operazione `UpdateTable` con il parametro `GlobalSecondaryIndexUpdates`. Devi specificare quanto segue:
+ Un nome per l'indice. Il nome deve essere univoco tra tutti gli indici della tabella.
+ Lo schema delle chiavi dell'indice. Devi specificare un attributo per la chiave di partizione dell'indice; opzionalmente, puoi specificare un altro attributo per la chiave di ordinamento dell'indice. Non è necessario che questi attributi di chiave coincidano con quelli della tabella. I tipi di dati per ogni attributo dello schema devono essere scalari: `String`, `Number` o `Binary`.
+ Gli attributi da proiettare dalla tabella all'indice:
  + `KEYS_ONLY`: ogni elemento dell'indice è costituito solo dalla chiave di partizione della tabella e dai valori della chiave di ordinamento, oltre ai valori della chiave di indice. 
  + `INCLUDE`: oltre agli attributi descritti in `KEYS_ONLY`, l'indice secondario include gli altri attributi non chiave che sono stati specificati.
  + `ALL`: l'indice include tutti gli attributi della tabella di origine.
+ Le impostazioni di throughput assegnato dell'indice, consistenti di `ReadCapacityUnits` e `WriteCapacityUnits`. Queste impostazioni di throughput assegnato sono distinte da quelle della tabella.

È possibile creare un solo indice secondario globale per operazione `UpdateTable`.

### Fasi della creazione di un indice
<a name="GSI.OnlineOps.Creating.Phases"></a>

Quando si aggiunge un nuovo indice secondario locale a una tabella esistente, mentre l'indice viene creato la tabella continua a essere disponibile. Tuttavia, il nuovo indice non è disponibile per le operazioni Query finché il suo stato non cambia da `CREATING` ad `ACTIVE`.

**Nota**  
La creazione di un indice secondario globale non utilizza Application Auto Scaling. L’aumento della capacità di `MIN` Application Auto Scaling non diminuisce il tempo di creazione dell'indice secondario globale.

Dietro le quinte, DynamoDB crea l'indice in due fasi:

**Allocazione delle risorse**  
DynamoDB alloca le risorse di calcolo e archiviazione necessarie per la creazione dell'indice.  
Durante la fase di allocazione delle risorse, l'attributo `IndexStatus` è `CREATING` e l'attributo `Backfilling` è false. Utilizza l'operazione `DescribeTable` per recuperare lo stato di una tabella e di tutti i suoi indici secondari.  
Mentre l'indice si trova nella fase di allocazione delle risorse, non puoi eliminare l'indice o la sua tabella padre. Inoltre, non puoi modificare il throughput assegnato dell'indice o della tabella. Non puoi aggiungere o eliminare altri indici nella tabella. Tuttavia, puoi modificare il throughput assegnato di questi altri indici.

**Compilazione**  
Per ogni elemento nella tabella, DynamoDB determina quale set di attributi scrivere sull'indice in base alla relativa proiezione (`KEYS_ONLY`, `INCLUDE` o `ALL`). Procede quindi a scrivere questi attributi nell'indice. Durante la fase di backfill, DynamoDB tiene traccia degli elementi che vengono aggiunti, eliminati o aggiornati nella tabella. Anche gli attributi di questi item vengono aggiunti, eliminati o aggiornati nell'indice secondo il caso.  
Durante la fase di compilazione, l'attributo `IndexStatus` è impostato su `CREATING` e l'attributo `Backfilling` è true. Utilizza l'operazione `DescribeTable` per recuperare lo stato di una tabella e di tutti i suoi indici secondari.  
Mentre l'indice è in fase di compilazione, non puoi eliminare la tabella padre. Tuttavia, puoi comunque eliminare l'indice o modificare il throughput assegnato della tabella e di qualsiasi suoi indici secondari globali.  
Nella fase di compilazione, alcune scritture di item in violazione possono riuscire mentre altre vengono rifiutate. Dopo la compilazione, tutte le scritture negli elementi che violano lo schema delle chiavi del nuovo indice vengono rifiutate. È consigliabile eseguire lo strumento Rilevamento violazioni alla fine della fase di backfill per rilevare e risolvere le eventuali violazioni delle chiavi che possono essersi verificate. Per ulteriori informazioni, consulta [Rilevamento e correzione delle violazioni delle chiavi in DynamoDB](GSI.OnlineOps.ViolationDetection.md).

Mentre le fasi di allocazione delle risorse e compilazione sono in corso, l'indice si trova nello stato `CREATING`. Durante questo periodo, DynamoDB esegue operazioni di lettura sulla tabella. Le operazioni di lettura dalla tabella di base per popolare l'indice secondario globale non vengono addebitate.

Quando la creazione è terminata, lo stato dell'indice diventa `ACTIVE`. Non puoi eseguire operazioni di `Query` o `Scan` dell'indice finché è `ACTIVE`.

**Nota**  
In alcuni casi DynamoDB non è in grado di scrivere dati dalla tabella all'indice a causa di violazioni delle chiavi di indice. Ciò può verificarsi se:  
Il tipo di dati di un valore di attributo non corrisponde al tipo di dati di un tipo di dati dello schema della chiave dell'indice.
La dimensione di un attributo supera la lunghezza massima di un attributo della chiave dell'indice.
Un attributo della chiave dell'indice ha un valore di attributo String vuoto o Binary vuoto.
Le violazioni delle chiavi dell'indice non interferiscono con la creazione di un indice secondario. Tuttavia, quando l'indice diventa `ACTIVE`, le chiavi in violazione non sono presenti nell'indice.  
DynamoDB fornisce uno strumento autonomo per individuare e risolvere questi problemi. Per ulteriori informazioni, consulta [Rilevamento e correzione delle violazioni delle chiavi in DynamoDB](GSI.OnlineOps.ViolationDetection.md).

### Aggiunta di un indice secondario globale a una tabella di grandi dimensioni
<a name="GSI.OnlineOps.Creating.LargeTable"></a>

Il tempo necessario per creare un indice secondario globale dipende da diversi fattori, tra cui:
+ Le dimensioni della tabella
+ Il numero di item nella tabella idonei per essere inclusi nell'indice
+ Il numero di attributi proiettati nell'indice
+ L'attività di scrittura sulla tabella principale durante la creazione dell'indice

Se si aggiunge un indice secondario globale a una tabella molto grande, il processo di creazione potrebbe richiedere molto tempo. Per monitorare l'avanzamento e determinare se l'indice ha una capacità di scrittura sufficiente, consulta i seguenti CloudWatch parametri di Amazon:
+ `OnlineIndexPercentageProgress`

Per ulteriori informazioni sulle CloudWatch metriche relative a DynamoDB, vedere. [Parametri di DynamoDB](metrics-dimensions.md#dynamodb-metrics)

**Importante**  
Potrebbe essere necessario consentire l’inserimento di tabelle molto grandi prima di creare o aggiornare un indice secondario globale. Contatta l' AWS assistenza per inserire i tuoi tavoli nella lista dei preferiti.

Durante il backfill di un indice, DynamoDB utilizza la capacità interna del sistema per leggere dalla tabella. Ciò ha lo scopo di ridurre al minimo l'impatto della creazione dell'indice e di assicurare che la tabella non esaurisca la capacità di lettura.

## Eliminazione di un indice secondario globale
<a name="GSI.OnlineOps.Deleting"></a>

Se l'indice secondario globale non è più necessario, è possibile eliminarlo utilizzando l'operazione `UpdateTable`.

È possibile eliminare un solo indice secondario globale per operazione `UpdateTable`.

Mentre l'indice secondario globale viene eliminato, non vi sono effetti sull'attività di lettura o scrittura nella tabella padre. Durante l'eliminazione è comunque possibile modificare il throughput assegnato di altri indici.

**Nota**  
Quando elimini una tabella utilizzando l'operazione `DeleteTable`, vengono eliminati anche tutti gli indici secondari globali della tabella.
L'operazione di eliminazione dell'indice secondario globale non verrà addebitata sul tuo account.

## Modifica di un indice secondario globale durante la creazione
<a name="GSI.OnlineOps.Creating.Modify"></a>

Nel corso della creazione di un indice puoi utilizzare l'operazione `DescribeTable` per determinare in quale fase si trova. La descrizione dell'indice include un attributo booleano, `Backfilling`, che indica se DynamoDB sta attualmente caricando l'indice con elementi della tabella. Se `Backfilling` è true, la fase di allocazione delle risorse è terminata ed è in corso la compilazione dell'indice. 

Durante la fase di compilazione, puoi eliminare l'indice in corso di creazione. Durante questa fase, non puoi aggiungere o eliminare altri indici nella tabella.

**Nota**  
Per gli indici creati nell'ambito di un'operazione `CreateTable`, l'attributo `Backfilling` non compare nell'output di `DescribeTable`. Per ulteriori informazioni, consulta [Fasi della creazione di un indice](#GSI.OnlineOps.Creating.Phases).

# Rilevamento e correzione delle violazioni delle chiavi in DynamoDB
<a name="GSI.OnlineOps.ViolationDetection"></a>

Durante la fase di backfill della creazione dell'indice secondario globale, Amazon DynamoDB esamina ogni elemento nella tabella per determinare se è idoneo all'inclusione nell'indice. Alcuni elementi potrebbero non essere idonei perché causerebbero violazioni della chiave dell'indice. In questi casi, gli elementi rimangono nella tabella, ma l'indice non ha una voce corrispondente per tale elemento.

Una *violazione della chiave di indice* si verifica nelle seguenti situazioni:
+ È presente una mancata corrispondenza del tipo di dati tra un valore di attributo e il tipo di dati dello schema della chiave dell'indice. Si supponga, ad esempio, che uno degli elementi nella tabella `GameScores` aveva un valore `TopScore` di tipo `String`. Se è stato aggiunto un indice secondario globale con una chiave di partizione di `TopScore`, di tipo `Number`, l'elemento della tabella violerebbe la chiave di indice.
+ Il valore di un attributo supera la lunghezza massima di un attributo della chiave dell'indice. La lunghezza massima di una chiave di partizione è 2048 byte e la lunghezza massima di una chiave di ordinamento è 1024 byte. Se uno qualsiasi dei valori di attributo corrispondenti nella tabella supera questi limiti, l'elemento della tabella violerebbe la chiave di indice.

**Nota**  
Se un valore di attributo String o Binary è impostato per un attributo utilizzato come chiave di indice, il valore dell'attributo deve avere una lunghezza maggiore di zero; in caso contrario, l'elemento della tabella violerebbe la chiave di indice.  
Questo strumento non contrassegna questa violazione della chiave di indice, al momento.

Se si verifica una violazione della chiave di indice, la fase di backfill continua senza interruzioni. Tuttavia, gli elementi che violano non saranno inclusi nell'indice. Una volta completata la fase di backfill, tutte le scritture sugli elementi che violano lo schema delle chiavi del nuovo indice saranno rifiutate.

Per identificare e correggere i valori degli attributi in una tabella che violano una chiave di indice, utilizza lo strumento Rilevatore di violazioni. Per eseguire Rilevatore di violazioni, è necessario creare un file di configurazione che specifica il nome di una tabella da sottoporre a scansione, i nomi e i tipi di dati della chiave di partizione dell'indice secondario globale e della chiave di ordinamento e quali azioni intraprendere se vengono rilevate violazioni della chiave di indice. Rilevatore di violazioni può essere eseguito in una delle due diverse modalità:
+ **Modalità di rilevamento**: rileva le violazioni della chiave dell'indice. Utilizza la modalità di rilevamento per segnalare gli elementi della tabella che causerebbero violazioni chiave in un indice secondario globale. Facoltativamente, è possibile richiedere che questi elementi di tabella che violano vengano eliminati immediatamente quando vengono rilevati. L'output dalla modalità di rilevamento viene scritto in un file, che è possibile utilizzare per ulteriori analisi.
+ **Modalità di correzione**: correggere le violazioni della chiave di indice. In modalità di correzione, Rilevatore violazioni legge un file di input con lo stesso formato del file di output dalla modalità di rilevamento. La modalità di correzione legge i record dal file di input e, per ogni record, elimina o aggiorna gli elementi corrispondenti nella tabella. Se si sceglie di aggiornare gli elementi, è necessario modificare il file di input e impostare i valori appropriati per questi aggiornamenti.

## Download ed esecuzione di Rilevatore violazioni
<a name="GSI.OnlineOps.ViolationDetection.Running"></a>

Rilevatore violazioni è disponibile come file eseguibile Java Archive (`.jar`) e viene eseguito su computer Windows, macOS o Linux. Rilevatore violazioni richiede Java 1.7 (o versioni successive) e Apache Maven.
+ [Scarica il rilevatore di violazioni da GitHub](https://github.com/awslabs/dynamodb-online-index-violation-detector)

Seguire le istruzioni riportate nel file `README.md` per scaricare e installare Rilevatore violazioni tramite Maven.

Per avviare Rilevatore violazioni, passare alla directory dove è stato creato `ViolationDetector.java` ed immettere il comando seguente.

```
java -jar ViolationDetector.jar [options]
```

La riga di comando di Rilevatore violazioni accetta le seguenti opzioni:
+ `-h | --help`: stampa un riepilogo di utilizzo e le opzioni per Rilevatore violazioni.
+ `-p | --configFilePath` `value`: il nome completo di un file di configurazione di Rilevatore violazioni. Per ulteriori informazioni, consulta [File di configurazione di Rilevatore violazioni](#GSI.OnlineOps.ViolationDetection.ConfigFile).
+ `-t | --detect` `value`: rileva le violazioni della chiave di indice nella tabella e le scrive nel file di output di Rilevatore violazioni. Se il valore di questo parametro è impostato su `keep`, gli elementi con violazioni della chiave non vengono modificati. Se il valore è impostato su `delete`, gli elementi con violazioni della chiave vengono eliminati dalla tabella.
+ `-c | --correct` `value`: legge le violazioni della chiave di indice da un file di input ed esegue azioni correttive sugli elementi della tabella. Se il valore di questo parametro è impostato su `update`, gli elementi con violazioni della chiave vengono aggiornati con valori nuovi e che non violano. Se il valore è impostato su `delete`, gli elementi con violazioni della chiave vengono eliminati dalla tabella.

## File di configurazione di Rilevatore violazioni
<a name="GSI.OnlineOps.ViolationDetection.ConfigFile"></a>

Durante il runtime, lo strumento Rilevatore violazioni richiede un file di configurazione. I parametri di questo file determinano a quali risorse DynamoDB può accedere Rilevatore violazioni e la velocità effettiva assegnata che può utilizzare. Nella tabella seguente vengono descritti questi parametri.


****  

| Nome del parametro | Description | Obbligatorio? | 
| --- | --- | --- | 
|  `awsCredentialsFile`  |  Il nome completo di un file contenente le credenziali AWS . Il file delle credenziali deve avere il seguente formato: <pre>accessKey = access_key_id_goes_here<br />secretKey = secret_key_goes_here </pre>  |  Sì  | 
|  `dynamoDBRegion`  |  La AWS regione in cui risiede la tabella. Ad esempio: `us-west-2`.  |  Sì  | 
|  `tableName`  | Il nome della tabella DynamoDB da sottoporre a scansione. |  Sì  | 
|  `gsiHashKeyName`  |  Il nome della chiave della partizione dell'indice.  |  Sì  | 
|  `gsiHashKeyType`  |  Il tipo di dati della chiave di partizione dell'indice, `String`, `Number` o `Binary`: `S \| N \| B`  |  Sì  | 
|  `gsiRangeKeyName`  |  Il nome della chiave di ordinamento dell'indice. Non specificare questo parametro se l'indice dispone solo di una chiave primaria semplice (chiave di partizione).  |  No  | 
|  `gsiRangeKeyType`  |  Il tipo di dati della chiave di ordinamento dell'indice, `String`, `Number` o `Binary`: `S \| N \| B`  Non specificare questo parametro se l'indice dispone solo di una chiave primaria semplice (chiave di partizione).  |  No  | 
|  `recordDetails`  |  Indica se scrivere i dettagli completi delle violazioni della chiave di indice nel file di output. Se impostato su `true` (impostazione predefinita), vengono riportate tutte le informazioni sugli elementi che violano. Se impostato su `false`, viene riportato solo il numero di violazioni.  |  No  | 
|  `recordGsiValueInViolationRecord`  |  Indica se scrivere i valori delle chiavi di indice che violano nel file di output. Se impostato su `true` (impostazione predefinita), vengono riportati i valori chiave. Se impostato su `false` (impostazione predefinita), i valori chiave non vengono riportati.  |  No  | 
|  `detectionOutputPath`  |  Il percorso completo del file di output di Rilevatore violazioni. Questo parametro supporta la scrittura in una directory locale o in Amazon Simple Storage Service (Amazon S3). Di seguito vengono mostrati gli esempi: `detectionOutputPath = ``//local/path/filename.csv` `detectionOutputPath = ``s3://bucket/filename.csv` Le informazioni nel file di output vengono visualizzate in formato CSV (valori separati da virgola). Se non si imposta `detectionOutputPath`, il file di output è denominato `violation_detection.csv`e viene scritto nella directory di lavoro corrente.  |  No  | 
|  `numOfSegments`  | Il numero di segmenti di scansione parallela da utilizzare quando Rilevatore violazioni esegue la scansione della tabella. Il valore predefinito è 1, che indica che la tabella viene scansionata in modo sequenziale. Se il valore è 2 o superiore, Rilevatore violazioni divide la tabella in tanti segmenti logici e un numero uguale di thread di scansione. L'impostazione massima per `numOfSegments` è 4.096.Per le tabelle più grandi, una scansione parallela è generalmente più veloce di una scansione sequenziale. Inoltre, se la tabella è abbastanza grande da estendersi su più partizioni, una scansione parallela distribuisce l'attività di lettura in modo uniforme su più partizioni.Per ulteriori informazioni sulle scansioni parallele in DynamoDB, consulta [Scansione parallela](Scan.md#Scan.ParallelScan). |  No  | 
|  `numOfViolations`  |  Il limite superiore delle violazioni della chiave di indice da scrivere nel file di output. Se impostato su `-1` (impostazione predefinita), viene scansionata l'intera tabella. Se impostato su un numero intero positivo, Rilevatore violazioni si interrompe dopo il rilevamento di tale numero di violazioni.  |  No  | 
|  `numOfRecords`  |  Il numero di elementi nella tabella da sottoporre a scansione. Se impostato su -1 (impostazione predefinita), viene scansionata l'intera tabella. Se impostato su un numero intero positivo, Rilevatore violazioni si interrompe dopo la scansione di molti elementi nella tabella.  |  No  | 
|  `readWriteIOPSPercent`  |  Regola la percentuale di unità di capacità di lettura assegnata utilizzate durante la scansione della tabella. I valori validi sono compresi tra `1` e `100`. Il valore predefinito (`25`) significa che Rilevatore violazioni non consumerà più del 25% della velocità effettiva di lettura assegnata della tabella.  |  No  | 
|  `correctionInputPath`  |  Il percorso completo del file di output di correzione di Rilevatore violazioni. Se si esegue Rilevatore violazioni in modalità di correzione, il contenuto di questo file viene utilizzato per modificare o eliminare elementi di dati nella tabella che violano l'indice secondario globale. Il formato del file `correctionInputPath` è uguale a quello del file `detectionOutputPath`. Ciò consente di elaborare l'output dalla modalità di rilevamento come input in modalità di correzione.  |  No  | 
|  `correctionOutputPath`  |  Il percorso completo del file di output di correzione di Rilevatore violazioni. Questo file viene creato solo se ci sono errori di aggiornamento. Questo parametro supporta la scrittura in una directory locale o su Amazon S3. Di seguito vengono mostrati gli esempi: `correctionOutputPath = ``//local/path/filename.csv` `correctionOutputPath = ``s3://bucket/filename.csv` Le informazioni nel file di output vengono visualizzate in formato CSV. Se non si imposta `correctionOutputPath`, il file di output è denominato `violation_update_errors.csv`e viene scritto nella directory di lavoro corrente.  |  No  | 

## Rilevamento
<a name="GSI.OnlineOps.ViolationDetection.Detection"></a>

Per rilevare le violazioni della chiave di indice, utilizza Rilevatore violazioni con l'opzione `--detect` della riga di comando. Per mostrare come funziona questa opzione, si consideri la tabella `ProductCatalog`. Di seguito è riportato un elenco di elementi nella tabella. Sono visualizzati solo la chiave primaria (`Id`) e l'attributo `Price`.


****  

| ID (chiave primaria) | Prezzo | 
| --- | --- | 
| 101 |  5  | 
| 102 |  20  | 
| 103 | 200  | 
| 201 |  100  | 
| 202 |  200  | 
| 203 |  300  | 
| 204 |  400  | 
| 205 |  500  | 

Tutti i valori per `Price` sono di tipo `Number`. Tuttavia, poiché DynamoDB è senza schemi, è possibile aggiungere un elemento con un `Price` non numerico. Ad esempio, si supponga di aggiungere un altro elemento alla tabella `ProductCatalog`.


****  

| ID (chiave primaria) | Prezzo | 
| --- | --- | 
| 999 | "Hello" | 

La tabella ha ora un totale di nove elementi.

A questo punto aggiungere un nuovo indice secondario globale alla tabella: `PriceIndex`. La chiave primaria di questo indice è una chiave di partizione, `Price`, che è di tipo `Number`. Dopo che l'indice è stato creato, conterrà otto elementi, ma la tabella `ProductCatalog` ne ha nove. La ragione di questa discrepanza è che il valore `"Hello"` è di tipo `String`, ma `PriceIndex` ha una chiave primaria di tipo `Number`. Il valore `String` viola la chiave dell'indice secondario globale, quindi non è presente nell'indice.

Per utilizzare Rilevatore violazioni in questo scenario, è innanzitutto necessario creare un file di configurazione come il seguente.

```
# Properties file for violation detection tool configuration.
# Parameters that are not specified will use default values.

awsCredentialsFile = /home/alice/credentials.txt
dynamoDBRegion = us-west-2
tableName = ProductCatalog
gsiHashKeyName = Price
gsiHashKeyType = N
recordDetails = true
recordGsiValueInViolationRecord = true
detectionOutputPath = ./gsi_violation_check.csv
correctionInputPath = ./gsi_violation_check.csv
numOfSegments = 1
readWriteIOPSPercent = 40
```

Quindi, è possibile eseguire Rilevatore violazioni come nell'esempio seguente.

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --detect keep

Violation detection started: sequential scan, Table name: ProductCatalog, GSI name: PriceIndex
Progress: Items scanned in total: 9,    Items scanned by this thread: 9,    Violations found by this thread: 1, Violations deleted by this thread: 0
Violation detection finished: Records scanned: 9, Violations found: 1, Violations deleted: 0, see results at: ./gsi_violation_check.csv
```

Se il parametro di configurazione `recordDetails` è impostato su `true`, Rilevatore violazioni scrive i dettagli di ogni violazione nel file di output, come nell'esempio seguente.

```
Table Hash Key,GSI Hash Key Value,GSI Hash Key Violation Type,GSI Hash Key Violation Description,GSI Hash Key Update Value(FOR USER),Delete Blank Attributes When Updating?(Y/N) 

999,"{""S"":""Hello""}",Type Violation,Expected: N Found: S,,
```

Il file di output è in formato CSV. La prima riga del file è un'intestazione, seguita da un record per elemento che viola la chiave di indice. I campi di questi record di violazione sono i seguenti:
+ **Chiave hash tabella**: il valore della chiave di partizione dell'elemento nella tabella.
+ **Chiave di intervallo tabella**: il valore della chiave di ordinamento dell'elemento nella tabella.
+ **Valore chiave hash GSI**: il valore della chiave di partizione dell'indice secondario globale.
+ **Tipo di violazione della chiave hash GSI**: `Type Violation` o `Size Violation`.
+ **Descrizione della violazione della chiave hash GSI**: la causa della violazione.
+ **Valore di aggiornamento della chiave hash GSI (PER UTENTE)**: in modalità di correzione, un nuovo valore fornito dall'utente per l'attributo.
+ **Valore chiave hash GSI**: il valore della chiave di ordinamento dell'indice secondario globale.
+ **Tipo di violazione della chiave di intervallo GSI**: `Type Violation` o `Size Violation`.
+ **Descrizione della violazione della chiave di intervallo GSI**: la causa della violazione.
+ **Valore di aggiornamento della chiave di intervallo GSI (PER UTENTE)**: in modalità di correzione, un nuovo valore fornito dall'utente per l'attributo.
+ **Elimina attributo vuoto durante l'aggiornamento (S/N)**: in modalità di correzione, determina se eliminare (S) o mantenere (N) l'elemento di violazione nella tabella, ma solo se uno dei seguenti campi è vuoto:
  + `GSI Hash Key Update Value(FOR USER)`
  + `GSI Range Key Update Value(FOR USER)`

  Se uno di questi campi non è vuoto, allora `Delete Blank Attribute When Updating(Y/N)` non ha effetto.

**Nota**  
Il formato dell'output può variare a seconda del file di configurazione e delle opzioni della riga di comando. Ad esempio, se la tabella ha una chiave primaria semplice (senza una chiave di ordinamento), nell'output non saranno presenti campi della chiave di ordinamento.  
I record di violazione nel file potrebbero non essere ordinati.

## Correzione
<a name="GSI.OnlineOps.ViolationDetection.Correction"></a>

Per correggere le violazioni della chiave di indice, utilizza Rilevatore violazioni con l'opzione `--correct` della riga di comando. In modalità di correzione, Rilevatore violazioni legge il file di input specificato dal parametro `correctionInputPath`. Il file ha lo stesso formato del file `detectionOutputPath`, in modo da poter utilizzare l'output del rilevamento come input per la correzione.

Rilevatore violazioni fornisce due modi diversi per correggere le violazioni della chiave di indice:
+ **Elimina le violazioni**: eliminare gli elementi della tabella che hanno valori di attributi che violano.
+ **Aggiorna violazioni**: aggiornare gli elementi della tabella, sostituendo gli attributi che violano con valori che non violano.

In entrambi i casi, è possibile utilizzare il file di output dalla modalità di rilevamento come input per la modalità di correzione.

Continuando con l'esempio `ProductCatalog`, si supponga di voler eliminare l'elemento che viola dalla tabella. A tale scopo, utilizza la seguente riga di comando.

```
$  java -jar ViolationDetector.jar --configFilePath config.txt --correct delete
```

A questo punto, verrà richiesto di confermare se desideri eliminare gli elementi che violano.

```
Are you sure to delete all violations on the table?y/n
y
Confirmed, will delete violations on the table...
Violation correction from file started: Reading records from file: ./gsi_violation_check.csv, will delete these records from table.
Violation correction from file finished: Violations delete: 1, Violations Update: 0
```

Ora sia `ProductCatalog` che `PriceIndex` hanno lo stesso numero di elementi.

# Utilizzo di indici secondari globali: Java
<a name="GSIJavaDocumentAPI"></a>

Puoi utilizzare l'API AWS SDK per Java Document per creare una tabella Amazon DynamoDB con uno o più indici secondari globali, descrivere gli indici sulla tabella ed eseguire query utilizzando gli indici. 

Di seguito sono riportate le fasi comuni per le operazioni di tabella. 

1. Creare un'istanza della classe `DynamoDB`.

1. Fornisci i parametri obbligatori e facoltativi per l'operazione creando gli oggetti di richiesta corrispondenti. 

1. Chiama il metodo appropriato fornito dal client creato nella fase precedente. 

**Topics**
+ [Creazione di una tabella con un indice secondario globale](#GSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrizione di una tabella con un indice secondario globale](#GSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario globale](#GSIJavaDocumentAPI.QueryAnIndex)
+ [Esempio: indici secondari globali che utilizzano l'API del documento AWS SDK per Java](GSIJavaDocumentAPI.Example.md)

## Creazione di una tabella con un indice secondario globale
<a name="GSIJavaDocumentAPI.CreateTableWithIndex"></a>

Puoi creare indici secondari globali al momento della creazione di una tabella. A tale scopo, utilizza `CreateTable` e fornisci le specifiche per uno o più indici secondari globali. Il seguente esempio di codice Java crea una tabella per contenere le informazioni sui dati meteo. La chiave di partizione è `Location` e la chiave di ordinamento è `Date`. Un indice secondario globale denominato `PrecipIndex` consente di accedere rapidamente ai dati delle precipitazioni di vari luoghi.

Di seguito sono riportate le fasi per creare una tabella con un indice secondario globale, utilizzando l'API documento di DynamoDB. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `CreateTableRequest` per fornire le informazioni della richiesta.

   È necessario fornire il nome della tabella, la sua chiave primaria e i valori del throughput assegnato. Per l'indice secondario globale, è necessario fornire il nome dell'indice, le impostazioni di velocità effettiva assegnata, le definizioni degli attributi per la chiave di ordinamento dell'indice, lo schema della chiave per l'indice e la proiezione degli attributi.

1. Chiama il metodo `createTable` fornendo l'oggetto richiesta come parametro.

Il seguente esempio di codice Java mostra le fasi precedenti. Il codice crea una tabella (`WeatherData`) con un indice secondario globale (`PrecipIndex`). La chiave di partizione dell'indice è `Date` e la sua chiave di ordinamento è `Precipitation`. Tutti gli attributi della tabella vengono proiettati nell'indice. Gli utenti possono eseguire query su questo indice per ottenere dati sul meteo di una data specifica, ordinando facoltativamente i dati per quantità di precipitazioni. 

Poiché `Precipitation` non è un attributo chiave per la tabella, non è obbligatorio. Tuttavia, item `WeatherData` senza `Precipitation` non vengono visualizzati in `PrecipIndex`.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

// Attribute definitions
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();

attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Location")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Date")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Precipitation")
    .withAttributeType("N"));

// Table key schema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Location")
    .withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Date")
    .withKeyType(KeyType.RANGE));  //Sort key

// PrecipIndex
GlobalSecondaryIndex precipIndex = new GlobalSecondaryIndex()
    .withIndexName("PrecipIndex")
    .withProvisionedThroughput(new ProvisionedThroughput()
        .withReadCapacityUnits((long) 10)
        .withWriteCapacityUnits((long) 1))
        .withProjection(new Projection().withProjectionType(ProjectionType.ALL));

ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>();

indexKeySchema.add(new KeySchemaElement()
    .withAttributeName("Date")
    .withKeyType(KeyType.HASH));  //Partition key
indexKeySchema.add(new KeySchemaElement()
    .withAttributeName("Precipitation")
    .withKeyType(KeyType.RANGE));  //Sort key

precipIndex.setKeySchema(indexKeySchema);

CreateTableRequest createTableRequest = new CreateTableRequest()
    .withTableName("WeatherData")
    .withProvisionedThroughput(new ProvisionedThroughput()
        .withReadCapacityUnits((long) 5)
        .withWriteCapacityUnits((long) 1))
    .withAttributeDefinitions(attributeDefinitions)
    .withKeySchema(tableKeySchema)
    .withGlobalSecondaryIndexes(precipIndex);

Table table = dynamoDB.createTable(createTableRequest);
System.out.println(table.getDescription());
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella.

## Descrizione di una tabella con un indice secondario globale
<a name="GSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari globali in una tabella, utilizza `DescribeTable`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

Di seguito sono riportate le fasi per accedere alle informazioni dell'indice secondario globale su una tabella. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `Table` per rappresentare l'indice con cui intendi lavorare.

1. Chiama il metodo `describe` per l'oggetto `Table`.

Il seguente esempio di codice Java mostra le fasi precedenti.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
TableDescription tableDesc = table.describe();
    

Iterator<GlobalSecondaryIndexDescription> gsiIter = tableDesc.getGlobalSecondaryIndexes().iterator();
while (gsiIter.hasNext()) {
    GlobalSecondaryIndexDescription gsiDesc = gsiIter.next();
    System.out.println("Info for index "
         + gsiDesc.getIndexName() + ":");

    Iterator<KeySchemaElement> kseIter = gsiDesc.getKeySchema().iterator();
    while (kseIter.hasNext()) {
        KeySchemaElement kse = kseIter.next();
        System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType());
    }
    Projection projection = gsiDesc.getProjection();
    System.out.println("\tThe projection type is: "
        + projection.getProjectionType());
    if (projection.getProjectionType().toString().equals("INCLUDE")) {
        System.out.println("\t\tThe non-key projected attributes are: "
            + projection.getNonKeyAttributes());
    }
}
```

## Esecuzione di query su un indice secondario globale
<a name="GSIJavaDocumentAPI.QueryAnIndex"></a>

È possibile utilizzare l'operazione `Query` su un indice secondario globale quasi nello stesso modo in cui si esegue una `Query` su una tabella. È necessario specificare il nome dell'indice, i criteri di query per la chiave di partizione e di ordinamento dell'indice (se presente) e gli attributi da restituire. In questo esempio, l'indice è `PrecipIndex`, avente una chiave di partizione `Date` e una chiave di ordinamento `Precipitation`. La query di indice restituisce tutti i dati sul meteo di una data specifica in cui le precipitazioni sono maggiori di zero.

Di seguito sono riportati i passaggi per interrogare un indice secondario globale utilizzando l'API Document. AWS SDK per Java 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `Table` per rappresentare l'indice con cui intendi lavorare.

1. Crea un'istanza della classe `Index` per l'indice su cui intendi eseguire una query.

1. Chiama il metodo `query` per l'oggetto `Index`.

Il nome di attributo `Date` è una parola riservata in DynamoDB. Pertanto, devi utilizzare un nome di attributo di espressione come segnaposto in `KeyConditionExpression`.

Il seguente esempio di codice Java mostra le fasi precedenti.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
Index index = table.getIndex("PrecipIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("#d = :v_date and Precipitation = :v_precip")
    .withNameMap(new NameMap()
        .with("#d", "Date"))
    .withValueMap(new ValueMap()
        .withString(":v_date","2013-08-10")
        .withNumber(":v_precip",0));

ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator(); 
while (iter.hasNext()) {
    System.out.println(iter.next().toJSONPretty());
}
```

# Esempio: indici secondari globali che utilizzano l'API del documento AWS SDK per Java
<a name="GSIJavaDocumentAPI.Example"></a>

Il seguente esempio di codice Java mostra come utilizzare gli indici secondari globali. L'esempio crea una tabella denominata `Issues`, che può essere utilizzata in un semplice sistema di tracciamento di bug per lo sviluppo di software. La chiave di partizione è `IssueId` e la chiave di ordinamento è `Title`. In questa tabella esistono tre indici secondari globali:
+ `CreateDateIndex`: la chiave di partizione è `CreateDate` e la chiave di ordinamento è `IssueId`. Oltre alle chiavi di tabella, vengono proiettati nell'indice gli attributi `Description` e `Status`.
+ `TitleIndex`: la chiave di partizione è `Title` e la chiave di ordinamento è `IssueId`. Non vengono proiettati nell'indice attributi diversi dalle chiavi di tabella.
+ `DueDateIndex`: la chiave di partizione è `DueDate`; non è presente una chiave di ordinamento. Tutti gli attributi della tabella vengono proiettati nell'indice.

Una volta creata la tabella `Issues`, il programma carica la tabella con i dati che rappresentano i report sui bug del software. Quindi esegue una query sui dati utilizzando gli indici secondari globali. Infine, il programma elimina la tabella `Issues`.

Per step-by-step istruzioni su come testare l'esempio seguente, vedere. [Esempi di codice Java](CodeSamples.Java.md)

**Example**  

```
package com.amazonaws.codesamples.document;

import java.util.ArrayList;
import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Index;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;

public class DocumentAPIGlobalSecondaryIndexExample {

    static AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
    static DynamoDB dynamoDB = new DynamoDB(client);

    public static String tableName = "Issues";

    public static void main(String[] args) throws Exception {

        createTable();
        loadData();

        queryIndex("CreateDateIndex");
        queryIndex("TitleIndex");
        queryIndex("DueDateIndex");

        deleteTable(tableName);

    }

    public static void createTable() {

        // Attribute definitions
        ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();

        attributeDefinitions.add(new AttributeDefinition().withAttributeName("IssueId").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("Title").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("CreateDate").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("DueDate").withAttributeType("S"));

        // Key schema for table
        ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
        tableKeySchema.add(new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.HASH)); // Partition
                                                                                                           // key
        tableKeySchema.add(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.RANGE)); // Sort
                                                                                                          // key

        // Initial provisioned throughput settings for the indexes
        ProvisionedThroughput ptIndex = new ProvisionedThroughput().withReadCapacityUnits(1L)
                .withWriteCapacityUnits(1L);

        // CreateDateIndex
        GlobalSecondaryIndex createDateIndex = new GlobalSecondaryIndex().withIndexName("CreateDateIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("CreateDate").withKeyType(KeyType.HASH), // Partition
                                                                                                                 // key
                        new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.RANGE)) // Sort
                                                                                                        // key
                .withProjection(
                        new Projection().withProjectionType("INCLUDE").withNonKeyAttributes("Description", "Status"));

        // TitleIndex
        GlobalSecondaryIndex titleIndex = new GlobalSecondaryIndex().withIndexName("TitleIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.HASH), // Partition
                                                                                                            // key
                        new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.RANGE)) // Sort
                                                                                                        // key
                .withProjection(new Projection().withProjectionType("KEYS_ONLY"));

        // DueDateIndex
        GlobalSecondaryIndex dueDateIndex = new GlobalSecondaryIndex().withIndexName("DueDateIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("DueDate").withKeyType(KeyType.HASH)) // Partition
                                                                                                              // key
                .withProjection(new Projection().withProjectionType("ALL"));

        CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
                .withProvisionedThroughput(
                        new ProvisionedThroughput().withReadCapacityUnits((long) 1).withWriteCapacityUnits((long) 1))
                .withAttributeDefinitions(attributeDefinitions).withKeySchema(tableKeySchema)
                .withGlobalSecondaryIndexes(createDateIndex, titleIndex, dueDateIndex);

        System.out.println("Creating table " + tableName + "...");
        dynamoDB.createTable(createTableRequest);

        // Wait for table to become active
        System.out.println("Waiting for " + tableName + " to become ACTIVE...");
        try {
            Table table = dynamoDB.getTable(tableName);
            table.waitForActive();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void queryIndex(String indexName) {

        Table table = dynamoDB.getTable(tableName);

        System.out.println("\n***********************************************************\n");
        System.out.print("Querying index " + indexName + "...");

        Index index = table.getIndex(indexName);

        ItemCollection<QueryOutcome> items = null;

        QuerySpec querySpec = new QuerySpec();

        if (indexName == "CreateDateIndex") {
            System.out.println("Issues filed on 2013-11-01");
            querySpec.withKeyConditionExpression("CreateDate = :v_date and begins_with(IssueId, :v_issue)")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-01").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "TitleIndex") {
            System.out.println("Compilation errors");
            querySpec.withKeyConditionExpression("Title = :v_title and begins_with(IssueId, :v_issue)")
                    .withValueMap(
                            new ValueMap().withString(":v_title", "Compilation error").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "DueDateIndex") {
            System.out.println("Items that are due on 2013-11-30");
            querySpec.withKeyConditionExpression("DueDate = :v_date")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-30"));
            items = index.query(querySpec);
        } else {
            System.out.println("\nNo valid index name provided");
            return;
        }

        Iterator<Item> iterator = items.iterator();

        System.out.println("Query: printing results...");

        while (iterator.hasNext()) {
            System.out.println(iterator.next().toJSONPretty());
        }

    }

    public static void deleteTable(String tableName) {

        System.out.println("Deleting table " + tableName + "...");

        Table table = dynamoDB.getTable(tableName);
        table.delete();

        // Wait for table to be deleted
        System.out.println("Waiting for " + tableName + " to be deleted...");
        try {
            table.waitForDelete();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void loadData() {

        System.out.println("Loading data into table " + tableName + "...");

        // IssueId, Title,
        // Description,
        // CreateDate, LastUpdateDate, DueDate,
        // Priority, Status

        putItem("A-101", "Compilation error", "Can't compile Project X - bad version number. What does this mean?",
                "2013-11-01", "2013-11-02", "2013-11-10", 1, "Assigned");

        putItem("A-102", "Can't read data file", "The main data file is missing, or the permissions are incorrect",
                "2013-11-01", "2013-11-04", "2013-11-30", 2, "In progress");

        putItem("A-103", "Test failure", "Functional test of Project X produces errors", "2013-11-01", "2013-11-02",
                "2013-11-10", 1, "In progress");

        putItem("A-104", "Compilation error", "Variable 'messageCount' was not initialized.", "2013-11-15",
                "2013-11-16", "2013-11-30", 3, "Assigned");

        putItem("A-105", "Network issue", "Can't ping IP address 127.0.0.1. Please fix this.", "2013-11-15",
                "2013-11-16", "2013-11-19", 5, "Assigned");

    }

    public static void putItem(

            String issueId, String title, String description, String createDate, String lastUpdateDate, String dueDate,
            Integer priority, String status) {

        Table table = dynamoDB.getTable(tableName);

        Item item = new Item().withPrimaryKey("IssueId", issueId).withString("Title", title)
                .withString("Description", description).withString("CreateDate", createDate)
                .withString("LastUpdateDate", lastUpdateDate).withString("DueDate", dueDate)
                .withNumber("Priority", priority).withString("Status", status);

        table.putItem(item);
    }

}
```

# Utilizzo di indici secondari globali: .NET
<a name="GSILowLevelDotNet"></a>

Puoi utilizzare l'API di AWS SDK per .NET basso livello per creare una tabella Amazon DynamoDB con uno o più indici secondari globali, descrivere gli indici sulla tabella ed eseguire query utilizzando gli indici. Queste operazioni vengono mappate alle operazioni DynamoDB corrispondenti. Per ulteriori informazioni, consulta la [Documentazione di riferimento delle API di Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/). 

Di seguito sono riportate le operazioni comuni per le operazioni delle tabelle che utilizzano l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Fornisci i parametri obbligatori e facoltativi per l'operazione creando gli oggetti di richiesta corrispondenti.

   Ad esempio, creare un oggetto `CreateTableRequest` per creare una tabella e un oggetto `QueryRequest` per eseguire una query su una tabella o un indice. 

1. Eseguire il metodo appropriato fornito dal client creato nella fase precedente. 

**Topics**
+ [Creazione di una tabella con un indice secondario globale](#GSILowLevelDotNet.CreateTableWithIndex)
+ [Descrizione di una tabella con un indice secondario globale](#GSILowLevelDotNet.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario globale](#GSILowLevelDotNet.QueryAnIndex)
+ [Esempio AWS SDK per .NET : indici secondari globali che utilizzano l'API di basso livello](GSILowLevelDotNet.Example.md)

## Creazione di una tabella con un indice secondario globale
<a name="GSILowLevelDotNet.CreateTableWithIndex"></a>

Puoi creare indici secondari globali al momento della creazione di una tabella. A tale scopo, utilizza `CreateTable` e fornisci le specifiche per uno o più indici secondari globali. Il seguente esempio di codice C\$1 crea una tabella per contenere le informazioni sui dati meteo. La chiave di partizione è `Location` e la chiave di ordinamento è `Date`. Un indice secondario globale denominato `PrecipIndex` consente di accedere rapidamente ai dati delle precipitazioni di vari luoghi.

Di seguito sono riportate le fasi per creare una tabella con un indice secondario globale, utilizzando l'API di basso livello di DynamoDB. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Crea un'istanza della classe `CreateTableRequest` per fornire le informazioni della richiesta. 

   È necessario fornire il nome della tabella, la sua chiave primaria e i valori del throughput assegnato. Per l'indice secondario globale, è necessario fornire il nome dell'indice, le impostazioni di velocità effettiva assegnata, le definizioni degli attributi per la chiave di ordinamento dell'indice, lo schema della chiave per l'indice e la proiezione degli attributi.

1. Eseguire il metodo `CreateTable` fornendo l'oggetto della richiesta come parametro.

Il seguente esempio di codice C\$1 mostra le fasi precedenti. Il codice crea una tabella (`WeatherData`) con un indice secondario globale (`PrecipIndex`). La chiave di partizione dell'indice è `Date` e la sua chiave di ordinamento è `Precipitation`. Tutti gli attributi della tabella vengono proiettati nell'indice. Gli utenti possono eseguire query su questo indice per ottenere dati sul meteo di una data specifica, ordinando facoltativamente i dati per quantità di precipitazioni. 

Poiché `Precipitation` non è un attributo chiave per la tabella, non è obbligatorio. Tuttavia, item `WeatherData` senza `Precipitation` non vengono visualizzati in `PrecipIndex`.

```
client = new AmazonDynamoDBClient();
string tableName = "WeatherData";

// Attribute definitions
var attributeDefinitions = new List<AttributeDefinition>()
{
    {new AttributeDefinition{
        AttributeName = "Location",
        AttributeType = "S"}},
    {new AttributeDefinition{
        AttributeName = "Date",
        AttributeType = "S"}},
    {new AttributeDefinition(){
        AttributeName = "Precipitation",
        AttributeType = "N"}
    }
};

// Table key schema
var tableKeySchema = new List<KeySchemaElement>()
{
    {new KeySchemaElement {
        AttributeName = "Location",
        KeyType = "HASH"}},  //Partition key
    {new KeySchemaElement {
        AttributeName = "Date",
        KeyType = "RANGE"}  //Sort key
    }
};

// PrecipIndex
var precipIndex = new GlobalSecondaryIndex
{
    IndexName = "PrecipIndex",
    ProvisionedThroughput = new ProvisionedThroughput
    {
        ReadCapacityUnits = (long)10,
        WriteCapacityUnits = (long)1
    },
    Projection = new Projection { ProjectionType = "ALL" }
};

var indexKeySchema = new List<KeySchemaElement> {
    {new KeySchemaElement { AttributeName = "Date", KeyType = "HASH"}},  //Partition key
    {new KeySchemaElement{AttributeName = "Precipitation",KeyType = "RANGE"}}  //Sort key
};

precipIndex.KeySchema = indexKeySchema;

CreateTableRequest createTableRequest = new CreateTableRequest
{
    TableName = tableName,
    ProvisionedThroughput = new ProvisionedThroughput
    {
        ReadCapacityUnits = (long)5,
        WriteCapacityUnits = (long)1
    },
    AttributeDefinitions = attributeDefinitions,
    KeySchema = tableKeySchema,
    GlobalSecondaryIndexes = { precipIndex }
};

CreateTableResponse response = client.CreateTable(createTableRequest);
Console.WriteLine(response.CreateTableResult.TableDescription.TableName);
Console.WriteLine(response.CreateTableResult.TableDescription.TableStatus);
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella.

## Descrizione di una tabella con un indice secondario globale
<a name="GSILowLevelDotNet.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari globali in una tabella, utilizza `DescribeTable`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

Di seguito sono riportate le fasi per accedere alle informazioni dell'indice secondario globale per una tabella utilizzando l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Eseguire il metodo `describeTable` fornendo l'oggetto della richiesta come parametro.

   Crea un'istanza della classe `DescribeTableRequest` per fornire le informazioni della richiesta. Devi specificare il nome della tabella.

Il seguente esempio di codice C\$1 mostra le fasi precedenti.

**Example**  

```
client = new AmazonDynamoDBClient();
string tableName = "WeatherData";

DescribeTableResponse response = client.DescribeTable(new DescribeTableRequest { TableName = tableName});

List<GlobalSecondaryIndexDescription> globalSecondaryIndexes =
response.DescribeTableResult.Table.GlobalSecondaryIndexes;

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.

foreach (GlobalSecondaryIndexDescription gsiDescription in globalSecondaryIndexes) {
     Console.WriteLine("Info for index " + gsiDescription.IndexName + ":");

     foreach (KeySchemaElement kse in gsiDescription.KeySchema) {
          Console.WriteLine("\t" + kse.AttributeName + ": key type is " + kse.KeyType);
     }

      Projection projection = gsiDescription.Projection;
      Console.WriteLine("\tThe projection type is: " + projection.ProjectionType);

      if (projection.ProjectionType.ToString().Equals("INCLUDE")) {
           Console.WriteLine("\t\tThe non-key projected attributes are: "
                + projection.NonKeyAttributes);
      }
}
```

## Esecuzione di query su un indice secondario globale
<a name="GSILowLevelDotNet.QueryAnIndex"></a>

È possibile utilizzare l'operazione `Query` su un indice secondario globale quasi nello stesso modo in cui si esegue una `Query` su una tabella. È necessario specificare il nome dell'indice, i criteri di query per la chiave di partizione e di ordinamento dell'indice (se presente) e gli attributi da restituire. In questo esempio, l'indice è `PrecipIndex`, avente una chiave di partizione `Date` e una chiave di ordinamento `Precipitation`. La query di indice restituisce tutti i dati sul meteo di una data specifica in cui le precipitazioni sono maggiori di zero.

Di seguito sono riportate le fasi per eseguire una query su un indice secondario globale utilizzando l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Crea un'istanza della classe `QueryRequest` per fornire le informazioni della richiesta.

1. Eseguire il metodo `query` fornendo l'oggetto della richiesta come parametro.

Il nome di attributo `Date` è una parola riservata in DynamoDB. Pertanto, devi utilizzare un nome di attributo di espressione come segnaposto in `KeyConditionExpression`.

Il seguente esempio di codice C\$1 mostra le fasi precedenti.

**Example**  

```
client = new AmazonDynamoDBClient();

QueryRequest queryRequest = new QueryRequest
{
    TableName = "WeatherData",
    IndexName = "PrecipIndex",
    KeyConditionExpression = "#dt = :v_date and Precipitation > :v_precip",
    ExpressionAttributeNames = new Dictionary<String, String> {
        {"#dt", "Date"}
    },
    ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
        {":v_date", new AttributeValue { S =  "2013-08-01" }},
        {":v_precip", new AttributeValue { N =  "0" }}
    },
    ScanIndexForward = true
};

var result = client.Query(queryRequest);

var items = result.Items;
foreach (var currentItem in items)
{
    foreach (string attr in currentItem.Keys)
    {
        Console.Write(attr + "---> ");
        if (attr == "Precipitation")
        {
            Console.WriteLine(currentItem[attr].N);
    }
    else
    {
        Console.WriteLine(currentItem[attr].S);
    }

         }
     Console.WriteLine();
}
```

# Esempio AWS SDK per .NET : indici secondari globali che utilizzano l'API di basso livello
<a name="GSILowLevelDotNet.Example"></a>

Il seguente esempio di codice C\$1 mostra come utilizzare gli indici secondari globali. L'esempio crea una tabella denominata `Issues`, che può essere utilizzata in un semplice sistema di tracciamento di bug per lo sviluppo di software. La chiave di partizione è `IssueId` e la chiave di ordinamento è `Title`. In questa tabella esistono tre indici secondari globali:
+ `CreateDateIndex`: la chiave di partizione è `CreateDate` e la chiave di ordinamento è `IssueId`. Oltre alle chiavi di tabella, vengono proiettati nell'indice gli attributi `Description` e `Status`.
+ `TitleIndex`: la chiave di partizione è `Title` e la chiave di ordinamento è `IssueId`. Non vengono proiettati nell'indice attributi diversi dalle chiavi di tabella.
+ `DueDateIndex`: la chiave di partizione è `DueDate`; non è presente una chiave di ordinamento. Tutti gli attributi della tabella vengono proiettati nell'indice.

Una volta creata la tabella `Issues`, il programma carica la tabella con i dati che rappresentano i report sui bug del software. Quindi esegue una query sui dati utilizzando gli indici secondari globali. Infine, il programma elimina la tabella `Issues`.

Per step-by-step istruzioni su come testare il seguente esempio, vedere. [Esempi di codice .NET](CodeSamples.DotNet.md)

**Example**  

```
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelGlobalSecondaryIndexExample
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        public static String tableName = "Issues";

        public static void Main(string[] args)
        {
            CreateTable();
            LoadData();

            QueryIndex("CreateDateIndex");
            QueryIndex("TitleIndex");
            QueryIndex("DueDateIndex");

            DeleteTable(tableName);

            Console.WriteLine("To continue, press enter");
            Console.Read();
        }

        private static void CreateTable()
        {
            // Attribute definitions
            var attributeDefinitions = new List<AttributeDefinition>()
        {
            {new AttributeDefinition {
                 AttributeName = "IssueId", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "Title", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "CreateDate", AttributeType = "S"
             }},
            {new AttributeDefinition {
                 AttributeName = "DueDate", AttributeType = "S"
             }}
        };

            // Key schema for table
            var tableKeySchema = new List<KeySchemaElement>() {
            {
                new KeySchemaElement {
                    AttributeName= "IssueId",
                    KeyType = "HASH" //Partition key
                }
            },
            {
                new KeySchemaElement {
                    AttributeName = "Title",
                    KeyType = "RANGE" //Sort key
                }
            }
        };

            // Initial provisioned throughput settings for the indexes
            var ptIndex = new ProvisionedThroughput
            {
                ReadCapacityUnits = 1L,
                WriteCapacityUnits = 1L
            };

            // CreateDateIndex
            var createDateIndex = new GlobalSecondaryIndex()
            {
                IndexName = "CreateDateIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "CreateDate", KeyType = "HASH" //Partition key
                },
                new KeySchemaElement {
                    AttributeName = "IssueId", KeyType = "RANGE" //Sort key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "INCLUDE",
                    NonKeyAttributes = {
                    "Description", "Status"
                }
                }
            };

            // TitleIndex
            var titleIndex = new GlobalSecondaryIndex()
            {
                IndexName = "TitleIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "Title", KeyType = "HASH" //Partition key
                },
                new KeySchemaElement {
                    AttributeName = "IssueId", KeyType = "RANGE" //Sort key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "KEYS_ONLY"
                }
            };

            // DueDateIndex
            var dueDateIndex = new GlobalSecondaryIndex()
            {
                IndexName = "DueDateIndex",
                ProvisionedThroughput = ptIndex,
                KeySchema = {
                new KeySchemaElement {
                    AttributeName = "DueDate",
                    KeyType = "HASH" //Partition key
                }
            },
                Projection = new Projection
                {
                    ProjectionType = "ALL"
                }
            };



            var createTableRequest = new CreateTableRequest
            {
                TableName = tableName,
                ProvisionedThroughput = new ProvisionedThroughput
                {
                    ReadCapacityUnits = (long)1,
                    WriteCapacityUnits = (long)1
                },
                AttributeDefinitions = attributeDefinitions,
                KeySchema = tableKeySchema,
                GlobalSecondaryIndexes = {
                createDateIndex, titleIndex, dueDateIndex
            }
            };

            Console.WriteLine("Creating table " + tableName + "...");
            client.CreateTable(createTableRequest);

            WaitUntilTableReady(tableName);
        }

        private static void LoadData()
        {
            Console.WriteLine("Loading data into table " + tableName + "...");

            // IssueId, Title,
            // Description,
            // CreateDate, LastUpdateDate, DueDate,
            // Priority, Status

            putItem("A-101", "Compilation error",
                "Can't compile Project X - bad version number. What does this mean?",
                "2013-11-01", "2013-11-02", "2013-11-10",
                1, "Assigned");

            putItem("A-102", "Can't read data file",
                "The main data file is missing, or the permissions are incorrect",
                "2013-11-01", "2013-11-04", "2013-11-30",
                2, "In progress");

            putItem("A-103", "Test failure",
                "Functional test of Project X produces errors",
                "2013-11-01", "2013-11-02", "2013-11-10",
                1, "In progress");

            putItem("A-104", "Compilation error",
                "Variable 'messageCount' was not initialized.",
                "2013-11-15", "2013-11-16", "2013-11-30",
                3, "Assigned");

            putItem("A-105", "Network issue",
                "Can't ping IP address 127.0.0.1. Please fix this.",
                "2013-11-15", "2013-11-16", "2013-11-19",
                5, "Assigned");
        }

        private static void putItem(
            String issueId, String title,
            String description,
            String createDate, String lastUpdateDate, String dueDate,
            Int32 priority, String status)
        {
            Dictionary<String, AttributeValue> item = new Dictionary<string, AttributeValue>();

            item.Add("IssueId", new AttributeValue
            {
                S = issueId
            });
            item.Add("Title", new AttributeValue
            {
                S = title
            });
            item.Add("Description", new AttributeValue
            {
                S = description
            });
            item.Add("CreateDate", new AttributeValue
            {
                S = createDate
            });
            item.Add("LastUpdateDate", new AttributeValue
            {
                S = lastUpdateDate
            });
            item.Add("DueDate", new AttributeValue
            {
                S = dueDate
            });
            item.Add("Priority", new AttributeValue
            {
                N = priority.ToString()
            });
            item.Add("Status", new AttributeValue
            {
                S = status
            });

            try
            {
                client.PutItem(new PutItemRequest
                {
                    TableName = tableName,
                    Item = item
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        private static void QueryIndex(string indexName)
        {
            Console.WriteLine
                ("\n***********************************************************\n");
            Console.WriteLine("Querying index " + indexName + "...");

            QueryRequest queryRequest = new QueryRequest
            {
                TableName = tableName,
                IndexName = indexName,
                ScanIndexForward = true
            };


            String keyConditionExpression;
            Dictionary<string, AttributeValue> expressionAttributeValues = new Dictionary<string, AttributeValue>();

            if (indexName == "CreateDateIndex")
            {
                Console.WriteLine("Issues filed on 2013-11-01\n");

                keyConditionExpression = "CreateDate = :v_date and begins_with(IssueId, :v_issue)";
                expressionAttributeValues.Add(":v_date", new AttributeValue
                {
                    S = "2013-11-01"
                });
                expressionAttributeValues.Add(":v_issue", new AttributeValue
                {
                    S = "A-"
                });
            }
            else if (indexName == "TitleIndex")
            {
                Console.WriteLine("Compilation errors\n");

                keyConditionExpression = "Title = :v_title and begins_with(IssueId, :v_issue)";
                expressionAttributeValues.Add(":v_title", new AttributeValue
                {
                    S = "Compilation error"
                });
                expressionAttributeValues.Add(":v_issue", new AttributeValue
                {
                    S = "A-"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else if (indexName == "DueDateIndex")
            {
                Console.WriteLine("Items that are due on 2013-11-30\n");

                keyConditionExpression = "DueDate = :v_date";
                expressionAttributeValues.Add(":v_date", new AttributeValue
                {
                    S = "2013-11-30"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else
            {
                Console.WriteLine("\nNo valid index name provided");
                return;
            }

            queryRequest.KeyConditionExpression = keyConditionExpression;
            queryRequest.ExpressionAttributeValues = expressionAttributeValues;

            var result = client.Query(queryRequest);
            var items = result.Items;
            foreach (var currentItem in items)
            {
                foreach (string attr in currentItem.Keys)
                {
                    if (attr == "Priority")
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].N);
                    }
                    else
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].S);
                    }
                }
                Console.WriteLine();
            }
        }

        private static void DeleteTable(string tableName)
        {
            Console.WriteLine("Deleting table " + tableName + "...");
            client.DeleteTable(new DeleteTableRequest
            {
                TableName = tableName
            });
            WaitForTableToBeDeleted(tableName);
        }

        private static void WaitUntilTableReady(string tableName)
        {
            string status = null;
            // Let us wait until table is created. Call DescribeTable.
            do
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                    status = res.Table.TableStatus;
                }
                catch (ResourceNotFoundException)
                {
                    // DescribeTable is eventually consistent. So you might
                    // get resource not found. So we handle the potential exception.
                }
            } while (status != "ACTIVE");
        }

        private static void WaitForTableToBeDeleted(string tableName)
        {
            bool tablePresent = true;

            while (tablePresent)
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                }
                catch (ResourceNotFoundException)
                {
                    tablePresent = false;
                }
            }
        }
    }
}
```

# Utilizzo di indici secondari in DynamoDB con la AWS CLI
<a name="GCICli"></a>

È possibile utilizzare la AWS CLI per creare una tabella Amazon DynamoDB con uno o più indici secondari globali, descrivere gli indici sulla tabella ed eseguire query utilizzando gli indici.

**Topics**
+ [Creazione di una tabella con un indice secondario globale](#GCICli.CreateTableWithIndex)
+ [Aggiunta di un indice secondario globale a una tabella esistente](#GCICli.CreateIndexAfterTable)
+ [Descrizione di una tabella con un indice secondario globale](#GCICli.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario globale](#GCICli.QueryAnIndex)

## Creazione di una tabella con un indice secondario globale
<a name="GCICli.CreateTableWithIndex"></a>

Gli indici secondari globali possono essere creati al momento della creazione di una tabella. A tale scopo, utilizza il parametro `create-table` e fornire le specifiche per uno o più indici secondari globali. Nell'esempio seguente viene creata una tabella denominata `GameScores` con un indice secondario globale denominato `GameTitleIndex`. La tabella di base ha una chiave di partizione di `UserId` e una chiave di ordinamento di `GameTitle`, permettendo di trovare il miglior punteggio di un singolo utente per un gioco specifico in modo efficiente, mentre il GSI ha una chiave di partizione di `GameTitle` e una chiave di ordinamento di `TopScore`, permettendo di trovare rapidamente il punteggio più alto complessivo per un determinato gioco.

```
aws dynamodb create-table \
    --table-name GameScores \
    --attribute-definitions AttributeName=UserId,AttributeType=S \
                            AttributeName=GameTitle,AttributeType=S \
                            AttributeName=TopScore,AttributeType=N  \
    --key-schema AttributeName=UserId,KeyType=HASH \
                 AttributeName=GameTitle,KeyType=RANGE \
    --provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --global-secondary-indexes \
        "[
            {
                \"IndexName\": \"GameTitleIndex\",
                \"KeySchema\": [{\"AttributeName\":\"GameTitle\",\"KeyType\":\"HASH\"},
                                {\"AttributeName\":\"TopScore\",\"KeyType\":\"RANGE\"}],
                \"Projection\":{
                    \"ProjectionType\":\"INCLUDE\",
                    \"NonKeyAttributes\":[\"UserId\"]
                },
                \"ProvisionedThroughput\": {
                    \"ReadCapacityUnits\": 10,
                    \"WriteCapacityUnits\": 5
                }
            }
        ]"
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella. È possibile utilizzare [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) per determinare lo stato di avanzamento della creazione della tabella.

## Aggiunta di un indice secondario globale a una tabella esistente
<a name="GCICli.CreateIndexAfterTable"></a>

Gli indici secondari globali possono essere aggiunti o modificati anche dopo la creazione della tabella. A tale scopo, utilizza il parametro `update-table` e fornire le specifiche per uno o più indici secondari globali. Nell'esempio seguente viene utilizzato lo stesso schema dell'esempio precedente, ma si presuppone che la tabella sia già stata creata e che la GSI verrà aggiunta in seguito.

```
aws dynamodb update-table \
    --table-name GameScores \
    --attribute-definitions AttributeName=TopScore,AttributeType=N  \
    --global-secondary-index-updates \
        "[
            {
                \"Create\": {
                    \"IndexName\": \"GameTitleIndex\",
                    \"KeySchema\": [{\"AttributeName\":\"GameTitle\",\"KeyType\":\"HASH\"},
                                    {\"AttributeName\":\"TopScore\",\"KeyType\":\"RANGE\"}],
                    \"Projection\":{
                        \"ProjectionType\":\"INCLUDE\",
                        \"NonKeyAttributes\":[\"UserId\"]
                    }
                }
            }
        ]"
```

## Descrizione di una tabella con un indice secondario globale
<a name="GCICli.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari globali in una tabella, utilizza il parametro `describe-table`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

```
aws dynamodb describe-table --table-name GameScores
```

## Esecuzione di query su un indice secondario globale
<a name="GCICli.QueryAnIndex"></a>

È possibile utilizzare l'operazione `query` su un indice secondario globale nello stesso modo in cui si esegue una `query` su una tabella. È necessario specificare il nome dell'indice, i criteri della query per la chiave di ordinamento dell'indice e gli attributi da restituire. In questo esempio, l'indice è `GameTitleIndex` e la chiave di ordinamento dell'indice è `GameTitle`.

Gli unici attributi restituiti sono quelli proiettati nell'indice. È possibile modificare questa query per selezionare anche attributi non chiave, ma ciò richiederebbe un'attività di recupero della tabella relativamente costosa. Per ulteriori informazioni sul recupero delle tabelle, consulta [Proiezioni di attributi](GSI.md#GSI.Projections).

```
aws dynamodb query --table-name GameScores\
    --index-name GameTitleIndex \
    --key-condition-expression "GameTitle = :v_game" \
    --expression-attribute-values '{":v_game":{"S":"Alien Adventure"} }'
```

# Indici secondari locali
<a name="LSI"></a>

Alcune applicazioni devono eseguire query sui dati soltanto utilizzando la chiave primaria della tabella di base. Tuttavia, potrebbero esserci situazioni in cui una chiave di ordinamento alternativa sarebbe utile. Per dare all'applicazione una scelta di chiavi di ordinamento, è possibile creare uno o più indici secondari locali su una tabella Amazon DynamoDB ed emettere le richieste `Query` o `Scan` rispetto a questi indici.

**Topics**
+ [Scenario: Utilizzo di un indice secondario locale](#LSI.Scenario)
+ [Proiezioni di attributi](#LSI.Projections)
+ [Creazione di un indice secondario locale](#LSI.Creating)
+ [Lettura di dati da un indice secondario locale](#LSI.Reading)
+ [Scritture di elementi e indici secondari locali](#LSI.Writes)
+ [Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari locali](#LSI.ThroughputConsiderations)
+ [Considerazioni sull'archiviazione per indici secondari locali](#LSI.StorageConsiderations)
+ [Raccolte di elementi negli indici secondari locali](#LSI.ItemCollections)
+ [Utilizzo di indici secondari locali: Java](LSIJavaDocumentAPI.md)
+ [Utilizzo di indici secondari locali: .NET](LSILowLevelDotNet.md)
+ [Utilizzo di indici secondari locali nella AWS CLI di DynamoDB](LCICli.md)

## Scenario: Utilizzo di un indice secondario locale
<a name="LSI.Scenario"></a>

Ad esempio, si consideri la tabella `Thread`. Questa tabella è utile per un'applicazione come [Forum di discussione AWS](https://forums.aws.amazon.com/). Il seguente diagramma mostra in che modo verrebbero organizzarti gli elementi nella tabella. Non tutti gli attributi vengono visualizzati.

![\[Tabella dei thread contenente un elenco di nomi dei forum, argomenti, ora dell'ultimo post e numero di risposte.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/LSI_01.png)


DynamoDB archivia tutti gli elementi con lo stesso valore della chiave di partizione in modo continuo. In questo esempio, dato un particolare `ForumName`, un'operazione `Query` potrebbe individuare immediatamente tutti i thread per quel forum. All'interno di un gruppo di elementi con lo stesso valore della chiave di partizione, gli elementi vengono ordinati in base al valore della chiave di ordinamento. Se la chiave di ordinamento (`Subject`) viene fornita anche nella query, DynamoDB può restringere i risultati restituiti, ad esempio restituendo tutti i thread nel forum "S3" che hanno un `Subject` che inizia con la lettera "a".

Alcune richieste potrebbero richiedere modelli di accesso ai dati più complessi. Ad esempio:
+ Quali thread del forum ottengono il maggior numero di visualizzazioni e risposte?
+ Quale thread in un particolare forum ha il maggior numero di messaggi?
+ Quanti thread sono stati pubblicati in un particolare forum in un determinato periodo di tempo?

Per rispondere a queste domande, l'operazione `Query` non sarebbe sufficiente. Con questa procedura, sarà necessario eseguire una `Scan` di tutta la tabella. Per una tabella con milioni di elementi, questa operazione consumerebbe una grande quantità di velocità effettiva di lettura assegnata e richiederebbe molto tempo per il completamento.

Tuttavia, è possibile specificare uno o più indici secondari locali su attributi non chiave, ad esempio `Replies` o `LastPostDateTime`.

Un *indice secondario locale* gestisce una chiave di ordinamento alternativa per un determinato valore della chiave di partizione. Un indice secondario locale contiene anche una copia di alcuni o tutti gli attributi della relativa tabella di base. È possibile specificare gli attributi proiettati nell'indice secondario locale quando si crea la tabella. I dati in un indice secondario locale sono organizzati in base alla stessa chiave di partizione della tabella di base ma con una chiave di ordinamento diversa. Ciò consente di accedere in modo efficiente agli elementi di dati in questa diversa dimensione. Per una maggiore flessibilità di query o scansione, è possibile creare un massimo di cinque indici secondari locali per tabella. 

Supponiamo che un'applicazione debba trovare tutti i thread che sono stati pubblicati negli ultimi tre mesi in un particolare forum. Senza un indice secondario locale, l'applicazione dovrebbe eseguire la `Scan` dell'intera tabella `Thread` ed eliminare tutti i post che non erano nel periodo di tempo specificato. Con un indice secondario locale, un'operazione `Query`potrebbe usare `LastPostDateTime` come chiave di ordinamento e trovare rapidamente i dati.

Il seguente diagramma mostra un indice secondario locale denominato `LastPostIndex`. Si noti che la chiave di partizione è la stessa di quella della tabella `Thread`, ma la chiave di ordinamento è`LastPostDateTime`.

![\[LastPostIndex tabella contenente un elenco di nomi del forum, argomenti e ora dell'ultimo post.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/LSI_02.png)


Ciascun indice secondario locale deve soddisfare le seguenti condizioni:
+ La chiave di partizione deve essere la stessa della tabella di base.
+ La chiave di ordinamento deve essere costituita esattamente da un attributo scalare.
+ La chiave di ordinamento della tabella di base deve essere proiettata nell'indice, dove funzionerà da attributo non chiave.

In questo esempio, la chiave di partizione è `ForumName` e la chiave di ordinamento dell'indice secondario locale è `LastPostDateTime`. Inoltre, il valore della chiave di ordinamento dalla tabella di base (in questo esempio, `Subject`) viene proiettato nell'indice ma non fa parte della chiave di indice. Se un'applicazione ha bisogno di un elenco basato su `ForumName` e `LastPostDateTime`, può emettere una richiesta `Query` rispetto a `LastPostIndex`. I risultati della query sono ordinati per `LastPostDateTime` e possono essere restituiti in ordine crescente o decrescente. La query può applicare anche condizioni chiave, ad esempio restituendo solo gli elementi che dispongono di un `LastPostDateTime` entro un determinato lasso di tempo.

Ogni indice secondario locale contiene automaticamente le chiavi di partizione e ordinamento dalla relativa tabella di base; facoltativamente, è possibile proiettare gli attributi non chiave nell'indice. Quando si esegue una query sull'indice, DynamoDB può recuperare questi attributi proiettati in modo efficiente. Se si esegue una query sull'indice secondario locale, è possibile richiamare gli attributi che *non* sono proiettati sull'indice. DynamoDB recupera automaticamente questi attributi dalla tabella di base, ma a una latenza maggiore e con costi di velocità effettiva assegnata più elevati.

Per qualsiasi indice secondario locale, è possibile memorizzare fino a 10 GB di dati per ogni valore di chiave di partizione distinto. Questa figura include tutti gli elementi della tabella di base più tutti gli elementi degli indici, che hanno lo stesso valore della chiave di partizione. Per ulteriori informazioni, consulta [Raccolte di elementi negli indici secondari locali](#LSI.ItemCollections).

## Proiezioni di attributi
<a name="LSI.Projections"></a>

Con `LastPostIndex`, un'applicazione potrebbe usare `ForumName` e `LastPostDateTime` come criteri di query. Tuttavia, per richiamare eventuali altri attributi, DynamoDB deve eseguire ulteriori operazioni di lettura rispetto alla tabella `Thread`. Queste letture extra sono conosciute come *recuperi* e possono aumentare la quantità totale di velocità effettiva assegnata necessaria per una query.

Supponiamo di voler compilare una pagina web con un elenco di tutte le discussioni in «S3" e il numero di risposte per ogni thread, ordinate in base all'ultima risposta che inizia con la risposta più recente. date/time Per popolare questo elenco, sono necessari i seguenti attributi:
+ `Subject`
+ `Replies`
+ `LastPostDateTime`

Il modo più efficiente per interrogare questi dati e per evitare operazioni di recupero sarebbe quello di proiettare l'attributo `Replies` dalla tabella nell'indice secondario locale, come mostrato in questo diagramma.

![\[LastPostIndex tabella contenente un elenco di nomi del forum, orari degli ultimi post, argomenti e risposte.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/LSI_03.png)




Una *proiezione* è l'insieme di attributi copiato da una tabella in un indice secondario. La chiave di partizione e la chiave di ordinamento della tabella vengono sempre proiettati nell'indice; è possibile proiettare altri attributi per supportare i requisiti di query dell'applicazione. Quando si esegue una query su un indice, Amazon DynamoDB può accedere a qualsiasi attributo nella proiezione come se tali attributi fossero in una propria tabella.

Quando si crea un indice secondario, è necessario specificare gli attributi che saranno proiettati nell'indice. DynamoDB fornisce tre diverse opzioni per questo:
+ *KEYS\$1ONLY*: ogni elemento dell'indice è costituito solo dalla chiave di partizione della tabella e dai valori della chiave di ordinamento, oltre ai valori della chiave di indice. L'opzione `KEYS_ONLY` si traduce nell'indice secondario più piccolo possibile.
+ *INCLUDE*: oltre agli attributi descritti in `KEYS_ONLY`, l'indice secondario includerà gli altri attributi non chiave che sono stati specificati.
+ *ALL*: l'indice secondario include tutti gli attributi della tabella di origine. Poiché tutti i dati della tabella sono duplicati nell'indice, una proiezione `ALL` restituisce il più grande indice secondario possibile.

Nel diagramma precedente, l'attributo non chiave `Replies` è proiettato in `LastPostIndex`. Un'applicazione può interrogare `LastPostIndex` al posto della tabella `Thread` completa per popolare una pagina Web con`Subject`, `Replies` e `LastPostDateTime`. Se vengono richiesti altri attributi non chiave, DynamoDB dovrebbe recuperare tali attributi dalla tabella `Thread`. 

Dal punto di vista di un'applicazione, il recupero di attributi aggiuntivi dalla tabella di base è automatico e trasparente, quindi non è necessario riscrivere alcuna logica dell'applicazione. Tuttavia, tale recupero può ridurre notevolmente il vantaggio in termini di prestazioni dell'utilizzo di un indice secondario locale.

Quando si scelgono gli attributi da proiettare in un indice secondario locale, è necessario considerare il compromesso tra i costi correlati alla velocità effettiva assegnata e costi di archiviazione:
+ Se è necessario accedere a pochi attributi con la latenza più bassa possibile, considerare la possibilità di proiettare solo quegli attributi in un indice secondario locale. Più piccolo è l'indice, minore è il costo per memorizzarlo e minori sono i costi di scrittura. Se sono presenti attributi che occasionalmente è necessario recuperare, il costo per la velocità effettiva assegnata potrebbe superare il costo a lungo termine della memorizzazione di tali attributi.
+ Se l'applicazione accede frequentemente ad alcuni attributi non chiave, è necessario considerare di proiettare quegli attributi in un indice secondario locale. I costi di archiviazione aggiuntivi per l'indice secondario locale compensano il costo di esecuzione di scansioni frequenti delle tabelle.
+ Se è necessario accedere alla maggior parte degli attributi non chiave su base frequente, è possibile proiettare questi attributi, o anche l'intera tabella di base, in un indice secondario locale. Ciò offre la massima flessibilità e il minor consumo di velocità effettiva assegnata, in quanto non sarebbe necessario eseguire alcun recupero. Tuttavia, i costi di archiviazione aumenteranno o addirittura raddoppieranno se verranno proiettati tutti gli attributi.
+ Se l'applicazione esegue di rado le query sulla tabella ma esegue molte scritture o aggiornamenti dei dati, considerare la possibilità di proiettare *KEYS\$1ONLY*. L'indice secondario locale avrebbe dimensioni minime e sarebbe comunque disponibile, se necessario, per l'attività di query. 

## Creazione di un indice secondario locale
<a name="LSI.Creating"></a>

Per creare una tabella con uno o più indici secondari locali su una tabella, utilizza il parametro `LocalSecondaryIndexes` con l'operazione `CreateTable`. Gli indici secondari locali in una tabella vengono creati al momento della creazione della tabella. Quando si elimina una tabella, vengono eliminati anche tutti gli indici secondari locali della tabella.

È necessario specificare un attributo non chiave che funzioni da chiave di ordinamento dell'indice secondario locale. L'attributo scelto deve essere uno `String`, `Number` oppure `Binary` scalare. Altri tipi scalari, documento e set non sono consentiti. Per l'elenco completo dei tipi di dati, consulta [Tipi di dati](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

**Importante**  
Per le tabelle con gli indici secondari locali, esiste un limite di 10 GB per valore di chiave di partizione. Una tabella con indici secondari locali può memorizzare qualsiasi numero di elementi, a condizione che la dimensione totale per qualsiasi valore di una chiave di partizione non superi 10 GB. Per ulteriori informazioni, consulta [Limite delle dimensioni delle raccolte di elementi](#LSI.ItemCollections.SizeLimit).

È possibile proiettare gli attributi di qualsiasi tipo di dati in un indice secondario locale. Questo include scalari, documenti e set. Per l'elenco completo dei tipi di dati, consulta [Tipi di dati](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

## Lettura di dati da un indice secondario locale
<a name="LSI.Reading"></a>

È possibile richiamare gli elementi da un indice secondario locale utilizzando le operazioni `Query` e `Scan`. Le operazioni `GetItem` e `BatchGetItem` non possono essere utilizzate su un indice secondario locale.

### Esecuzione di una query su un indice secondario locale
<a name="LSI.Querying"></a>

In una tabella DynamoDB, il valore combinato della chiave di partizione e della chiave di ordinamento per ogni elemento deve essere univoco. Tuttavia, in un indice secondario locale, il valore della chiave di ordinamento non deve essere univoco per un determinato valore di chiave di partizione. Se nell'indice secondario locale sono presenti più elementi con lo stesso valore della chiave di ordinamento, un'operazione `Query` restituisce tutti gli elementi che hanno lo stesso valore della chiave di partizione. Nella risposta, gli articoli corrispondenti non vengono restituiti in un ordine particolare.

È possibile eseguire una query su un indice secondario locale utilizzando letture a consistenza finale o fortemente coerenti. Per specificare il tipo di coerenza desiderato, utilizza il parametro `ConsistentRead` dell'operazione `Query`. Una lettura fortemente consistente da un indice secondario locale restituisce sempre gli ultimi valori aggiornati. Se la query deve recuperare attributi aggiuntivi dalla tabella di base, tali attributi saranno coerenti rispetto all'indice.

**Example**  
Valuta i seguenti dati restituiti da una `Query` che richiede dati dai thread di discussione in un particolare forum.  

```
{
    "TableName": "Thread",
    "IndexName": "LastPostIndex",
    "ConsistentRead": false,
    "ProjectionExpression": "Subject, LastPostDateTime, Replies, Tags",
    "KeyConditionExpression": 
        "ForumName = :v_forum and LastPostDateTime between :v_start and :v_end",
    "ExpressionAttributeValues": {
        ":v_start": {"S": "2015-08-31T00:00:00.000Z"},
        ":v_end": {"S": "2015-11-31T00:00:00.000Z"},
        ":v_forum": {"S": "EC2"}
    }
}
```
In questa query:  
+ DynamoDB accede a `LastPostIndex` utilizzando la chiave di partizione `ForumName` per individuare gli elementi dell'indice per "EC2". Tutti gli elementi dell'indice con questa chiave sono memorizzati l'uno accanto all'altro per il recupero rapido.
+ All'interno di questo forum, DynamoDB utilizza l'indice per cercare le chiavi che corrispondono alla condizione `LastPostDateTime` specificata.
+ Poiché l'attributo `Replies` viene proiettato nell'indice, DynamoDB è in grado di recuperare questo attributo senza utilizzare alcuna velocità effettiva assegnata aggiuntiva.
+ L'attributo `Tags` non viene proiettato nell'indice, quindi DynamoDB deve accedere alla tabella `Thread` e recuperare questo attributo.
+ I risultati vengono restituiti, ordinati per `LastPostDateTime`. Le voci dell'indice vengono ordinate in base al valore della chiave di partizione e quindi in base al valore della chiave di ordinamento e `Query` li restituisce nell'ordine in cui sono memorizzati. È possibile utilizzare il parametro `ScanIndexForward` per restituire i risultati in ordine decrescente.
Poiché l'attributo `Tags` non viene proiettato nell'indice secondario locale, DynamoDB deve consumare unità di capacità di lettura aggiuntive per recuperare questo attributo dalla tabella di base. Se è necessario eseguire spesso questa query, è necessario proiettare `Tags` in `LastPostIndex` per evitare il recupero dalla tabella di base. Tuttavia, se è necessario accedere a `Tags` solo occasionalmente, il costo di archiviazione aggiuntivo per la proiezione `Tags` nell'indice potrebbe non valere la pena.

### Scansione di un indice secondario locale
<a name="LSI.Scanning"></a>

È possibile utilizzare l'operazione `Scan` per recuperare tutti i dati da un indice secondario globale. Devi fornire il nome della tabella di base e il nome dell'indice nella richiesta. Con un'operazione `Scan`, DynamoDB legge tutti i dati nell'indice e li restituisce all'applicazione. Inoltre puoi richiedere che vengano restituiti solo alcuni dati e che quelli rimanenti vengano eliminati. A questo scopo, utilizza il parametro `FilterExpression` dell'API `Scan`. Per ulteriori informazioni, consulta [Espressioni di filtro per la scansione](Scan.md#Scan.FilterExpression).

## Scritture di elementi e indici secondari locali
<a name="LSI.Writes"></a>

DynamoDB conserva automaticamente tutti gli indici secondari locali sincronizzati con le rispettive tabelle di base. Le applicazioni non scrivono mai direttamente in un indice. Tuttavia, è importante comprendere le implicazioni di come DynamoDB mantiene questi indici.

Quando si crea un indice secondario locale, viene specificato un attributo da utilizzare come chiave di ordinamento per l'indice. È inoltre possibile specificare un tipo di dati per tale attributo. Questo significa che ogni volta che si scrive un elemento nella tabella di base, se l'elemento definisce un attributo della chiave di indice, il relativo tipo deve corrispondere al tipo di dati dello schema della chiave di indice. Nel caso di `LastPostIndex`, la chiave di ordinamento `LastPostDateTime` nell'indice è definita come un tipo di dati `String`. Se si prova ad aggiungere un elemento alla tabella `Thread` e si specifica un tipo di dati diverso per `LastPostDateTime` (come `Number`), DynamoDB restituisce un `ValidationException` perché il tipo di dati non corrisponde.

Non è richiesta una one-to-one relazione tra gli elementi di una tabella di base e gli elementi di un indice secondario locale. In effetti, questo comportamento può essere vantaggioso per molte applicazioni. 

Una tabella con molti indici secondari globali comporta costi maggiori per l'attività di scrittura rispetto alle tabelle con meno indici. Per ulteriori informazioni, consulta [Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari locali](#LSI.ThroughputConsiderations).

**Importante**  
Per le tabelle con gli indici secondari locali, esiste un limite di 10 GB per valore di chiave di partizione. Una tabella con indici secondari locali può memorizzare qualsiasi numero di elementi, a condizione che la dimensione totale per qualsiasi valore di una chiave di partizione non superi 10 GB. Per ulteriori informazioni, consulta [Limite delle dimensioni delle raccolte di elementi](#LSI.ItemCollections.SizeLimit).

## Considerazioni sulla velocità di trasmissione effettiva assegnata per indici secondari locali
<a name="LSI.ThroughputConsiderations"></a>

Quando si crea una tabella in DynamoDB, vengono assegnate le unità di capacità di lettura e scrittura per il carico di lavoro previsto della tabella. Tale carico di lavoro include attività di lettura e scrittura sugli indici secondari locali della tabella.

Per visualizzare le tariffe correnti per la capacità di throughput assegnata, consulta [Prezzi di Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing).

### Unità di capacità in lettura
<a name="LSI.ThroughputConsiderations.Reads"></a>

Quando si esegue una query su un indice secondario locale, il numero di unità di capacità di lettura utilizzate dipende dal modo in cui si accede ai dati.

Come per le query su una tabella, una query su un indice può utilizzare letture a consistenza finale o fortemente consistenti a seconda del valore di `ConsistentRead`. Una lettura fortemente consistente utilizza una unità di capacità di lettura mentre una lettura a consistenza finale ne consuma solo la metà. Pertanto, scegliendo letture a consistenza finale, è possibile ridurre i costi delle unità di capacità di lettura.

Per le query su un indice che richiedono solo chiavi di indice e attributi proiettati, DynamoDB calcola l'attività di lettura assegnata come avviene per le query sulle tabelle. L'unica differenza è che il calcolo si basa sulle dimensioni delle voci dell'indice, piuttosto che sulla dimensione dell'item nella tabella di base. Il numero di unità di capacità in lettura è la somma di tutte le dimensioni degli attributi proiettati di tutti gli elementi restituiti; il risultato viene quindi arrotondato al successivo limite di 4 KB. Per ulteriori informazioni sul modo in cui DynamoDB calcola l'uso della velocità effettiva assegnata, consulta [Modalità con capacità allocata di DynamoDB](provisioned-capacity-mode.md).

Per le query sugli indici che leggono gli attributi non proiettati sull'indice secondario locale, oltre a leggere gli attributi proiettati dall'indice DynamoDB deve recuperare tali attributi dalla tabella di base. Questi recuperi si verificano quando si includono attributi non proiettati nei parametri `Select` o `ProjectionExpression` dell'operazione `Query`. Il recupero causa una latenza aggiuntiva nelle risposte alle query e comporta anche un costo della velocità effettiva assegnata più elevato: oltre alle letture dall'indice secondario locale descritto in precedenza, vengono addebitate le unità di capacità di lettura per ogni elemento della tabella di base recuperato. Questo addebito è per la lettura di ogni elemento intero dalla tabella, non solo degli attributi richiesti.

La dimensione massima dei risultati restituiti da un'operazione `Query` è 1 MB. Sono incluse le dimensioni di tutti i nomi e i valori degli attributi in tutti gli elementi restituiti. Tuttavia, se una query su un indice secondario locale fa sì che DynamoDB recuperi gli attributi dell'elemento dalla tabella di base, la dimensione massima dei dati nei risultati potrebbe essere inferiore. In questo caso, la dimensione del risultato è la somma di:
+ La dimensione degli elementi corrispondenti nell'indice, arrotondata per eccesso ai 4 KB successivi.
+ La dimensione di ogni elemento corrispondente nella tabella di base, con ogni elemento arrotondato singolarmente ai 4 KB successivi.

Utilizzando questa formula, la dimensione massima dei risultati restituiti da un'operazione Query è comunque 1 MB.

Ad esempio, si consideri una tabella in cui la dimensione di ogni elemento è 300 byte. Su quella tabella è presente un indice secondario locale, ma solo 200 byte di ogni elemento vengono proiettati sull'indice. Si supponga adesso che venga eseguita una `Query` su questo indice, che la query richieda recuperi di tabella per ogni elemento e che la query restituisca 4 elementi. DynamoDB riassume quanto segue:
+ Dimensione degli elementi corrispondenti nell'indice: 200 byte × 4 elementi = 800 byte; questo valore viene quindi arrotondato a 4 KB.
+ Dimensione di ogni elemento corrispondente nella tabella di base: (300 byte, arrotondato a 4 KB) × 4 elementi = 16 KB.

La dimensione totale dei dati nel risultato è pertanto 20 KB.

### Unità di capacità in scrittura
<a name="LSI.ThroughputConsiderations.Writes"></a>

Quando un elemento viene aggiunto, aggiornato o eliminato in una tabella, l'aggiornamento degli indici secondari locali utilizza le unità di capacità di scrittura assegnate per la tabella. Il costo totale della velocità effettiva assegnata per una scrittura è la somma delle unità di capacità di scrittura utilizzate scrivendo sulla tabella e di quelle utilizzate dall'aggiornamento degli indici secondari locali.

Il costo della scrittura di un elemento in un indice secondario locale dipende da diversi fattori:
+ Se scrivi un nuovo item nella tabella che definisce un attributo indicizzato o aggiorni un item esistente per definire un attributo indicizzato in precedenza non definito, è necessario eseguire un'operazione di scrittura per inserire l'item nell'indice.
+ Se un aggiornamento alla tabella modifica il valore di un attributo chiave indicizzato (da A a B), sono necessarie due scritture, una per eliminare l'elemento precedente dall'indice e un'altra per inserire il nuovo elemento nell'indice.  
+ Se un item era presente nell'indice, ma una scrittura nella tabella ha causato la cancellazione dell'attributo indicizzato, è necessaria una scrittura per eliminare la proiezione dell'item precedente dall'indice.
+ Se un item non è presente nell'indice prima o dopo l'aggiornamento dell'item, non vi è alcun costo di scrittura aggiuntivo per l'indice.

Tutti questi fattori presuppongono che la dimensione di ciascun elemento nell'indice sia minore o uguale alla dimensione dell'elemento di 1 KB per il calcolo delle unità di capacità di scrittura. Le voci di indice più grandi richiedono unità di capacità in scrittura aggiuntive. È possibile ridurre al minimo i costi di scrittura considerando gli attributi che le query devono restituire e proiettando solo tali attributi nell'indice.

## Considerazioni sull'archiviazione per indici secondari locali
<a name="LSI.StorageConsiderations"></a>

Quando un'applicazione scrive un elemento in una tabella, DynamoDB copia automaticamente il sottoinsieme di attributi corretto in qualsiasi indice secondario locale in cui devono essere presenti gli attributi. All' AWS account vengono addebitati i costi per la memorizzazione dell'elemento nella tabella di base e anche per l'archiviazione degli attributi in qualsiasi indice secondario locale di tale tabella.

La quantità di spazio utilizzata da un item dell'indice è la somma di quanto segue:
+ La dimensione in byte della chiave primaria della tabella di base (chiave di partizione e chiave di ordinamento)
+ La dimensione in byte dell'attributo della chiave di indicizzazione
+ La dimensione in byte degli attributi proiettati (se presenti)
+ 100 byte di sovraccarico per elemento dell'indice

Per stimare i requisiti di archiviazione per un indice secondario locale, è possibile stimare la dimensione media di un elemento nell'indice e quindi moltiplicarla per il numero di elementi nella tabella di base.

Se una tabella contiene un elemento in cui non è definito un attributo specifico, ma l'attributo è definito come una chiave di ordinamento dell'indice, DynamoDB non scrive alcun dato per tale elemento nell'indice. 

## Raccolte di elementi negli indici secondari locali
<a name="LSI.ItemCollections"></a>

**Nota**  
In questa sezione vengono trattate solo le tabelle con indici secondari locali.

In DynamoDB, una *raccolta di elementi* è un gruppo di elementi in che hanno lo stesso valore della chiave di partizione in una tabella e in tutti gli indici secondari locali. Negli esempi utilizzati in tutta questa sezione, la chiave di partizione per la tabella `Thread` è `ForumName` e la chiave di partizione per `LastPostIndex` è anch'essa `ForumName`. Tutti gli elementi della tabella e dell'indice con lo stesso `ForumName` fanno parte della stessa raccolta di elementi. Ad esempio, nella tabella `Thread` e nell'indice secondario locale `LastPostIndex` esiste una raccolta di elementi per il forum `EC2` e una raccolta di elementi diversa per il forum `RDS`.

Il seguente diagramma mostra la raccolta di elementi per il forum `S3`.

![\[Una raccolta di elementi DynamoDB ed elementi di indici secondari locali che hanno lo stesso valore di chiave di partizione di S3.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/LSI_04.png)


In questo diagramma, la raccolta di elementi è costituita da tutti gli elementi in `Thread` e `LastPostIndex` dove il valore della chiave di partizione `ForumName` è "S3". Se nella tabella sono presenti altri indici secondari locali, tutti gli elementi in tali indici con `ForumName` uguale a "S3" fanno parte della raccolta di elementi.

È possibile utilizzare una delle seguenti operazioni in DynamoDB per restituire informazioni sulle raccolte di elementi:
+ `BatchWriteItem`
+ `DeleteItem`
+ `PutItem`
+ `UpdateItem`
+ `TransactWriteItems`

Ognuna di queste operazioni supporta il parametro `ReturnItemCollectionMetrics`. Quando si .imposta questo parametro su `SIZE`, è possibile visualizzare informazioni sulle dimensioni di ogni raccolta di elementi nell'indice.

**Example**  
Di seguito è riportato un esempio dall'output di una operazione `UpdateItem` sulla tabella `Thread`, con `ReturnItemCollectionMetrics` impostato su `SIZE`. L'elemento che è stato aggiornato aveva un valore di `ForumName` pari a "EC2", quindi l'output include informazioni su tale raccolta di elementi.  

```
{
    ItemCollectionMetrics: {
        ItemCollectionKey: {
            ForumName: "EC2"
        },
        SizeEstimateRangeGB: [0.0, 1.0]
    }
}
```
L'oggetto `SizeEstimateRangeGB` indica che la dimensione di questa raccolta di elementi è compresa tra 0 e 1 GB. DynamoDB aggiorna periodicamente questa stima delle dimensioni, quindi i numeri potrebbero essere diversi la volta successiva che l'elemento viene modificato.

### Limite delle dimensioni delle raccolte di elementi
<a name="LSI.ItemCollections.SizeLimit"></a>

La dimensione massima di qualsiasi raccolta di elementi per una tabella con uno o più indici secondari locali è di 10 GB. Ciò non si applica alle raccolte di elementi nelle tabelle senza indici secondari locali e non si applica alle raccolte di elementi negli indici secondari globali. Sono interessate solo le tabelle con uno o più indici secondari locali.

Se una raccolta di elementi supera il limite di 10 GB, DynamoDB potrebbe restituire `ItemCollectionSizeLimitExceededException` un elemento e l'utente potrebbe non essere in grado di aggiungere altri elementi alla raccolta di elementi o aumentare le dimensioni degli elementi presenti nella raccolta di elementi. Le operazioni di lettura e scrittura che riducono le dimensioni della raccolta di elementi sono ancora consentite. Gli elementi possono comunque essere aggiunti ad altre raccolte di elementi.

Per ridurre le dimensioni di una raccolta di elementi, è possibile procedere in uno dei seguenti modi:
+ Eliminare eventuali elementi non necessari con il valore della chiave di partizione in questione. Quando si eliminano questi elementi dalla tabella di base, DynamoDB rimuove anche tutte le voci di indice che hanno lo stesso valore della chiave di partizione.
+ Aggiorna gli elementi rimuovendo gli attributi o riducendo le dimensioni degli attributi. Se questi attributi sono proiettati su qualsiasi indice secondario locale, DynamoDB riduce anche la dimensione delle voci di indice corrispondenti.
+ Crea una nuova tabella con la stessa chiave di partizione e la stessa chiave di ordinamento, quindi sposta gli elementi dalla tabella precedente alla nuova tabella. Questo potrebbe essere un buon approccio se una tabella dispone di dati cronologici a cui si accede raramente. È possibile anche considerare l'archiviazione di questi dati della cronologia in Amazon Simple Storage Service (Amazon S3).

Quando la dimensione totale della raccolta di elementi scende al di sotto di 10 GB, è possibile aggiungere nuovamente elementi con lo stesso valore della chiave di partizione.

Come best practice, consigliamo di strumentalizzare l'applicazione in modo da monitorare le dimensioni delle raccolte di elementi. Un modo per farlo è impostare il parametro `ReturnItemCollectionMetrics` su `SIZE`ogni volta che si utilizza `BatchWriteItem`, `DeleteItem`, `PutItem` o `UpdateItem`. L'applicazione dovrebbe esaminare l'oggetto `ReturnItemCollectionMetrics` nell'output e registrare un messaggio di errore ogni volta che una raccolta di elementi supera un limite definito dall'utente (ad esempio, 8 GB). L'impostazione di un limite inferiore a 10 GB fornirebbe un sistema di avviso anticipato in modo da sapere che una raccolta di elementi si sta avvicinando al limite in tempo per intervenire.

### Raccolte di elementi e partizioni
<a name="LSI.ItemCollections.OnePartition"></a>

In una tabella con uno o più indici secondari locali, ogni raccolta di elementi viene archiviata in una partizione. La dimensione totale di tale raccolta di elementi è limitata alla capacità di quella partizione: 10 GB. Per un'applicazione in cui il modello di dati include raccolte di elementi con dimensioni illimitate o in cui si potrebbe ragionevolmente aspettarsi che alcune raccolte di elementi crescano oltre i 10 GB in futuro, è consigliabile prendere in considerazione l'utilizzo di un indice secondario globale.

Progettare le applicazioni in modo che i dati della tabella siano distribuiti uniformemente tra valori distinti della chiave di partizione. Per le tabelle con indici secondari locali, le applicazioni non devono creare "hot spot" di attività di lettura e scrittura all'interno di una singola raccolta di elementi su una singola partizione. 

# Utilizzo di indici secondari locali: Java
<a name="LSIJavaDocumentAPI"></a>

Puoi utilizzare l'API AWS SDK per Java Document per creare una tabella Amazon DynamoDB con uno o più indici secondari locali, descrivere gli indici sulla tabella ed eseguire query utilizzando gli indici.

Di seguito sono riportati i passaggi più comuni per le operazioni sulle tabelle utilizzando l'API Document. AWS SDK per Java 

1. Creare un'istanza della classe `DynamoDB`.

1. Fornisci i parametri obbligatori e facoltativi per l'operazione creando gli oggetti di richiesta corrispondenti. 

1. Chiama il metodo appropriato fornito dal client creato nella fase precedente. 

**Topics**
+ [Creazione di una tabella con un indice secondario locale](#LSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrizione di una tabella con un indice secondario locale](#LSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario locale](#LSIJavaDocumentAPI.QueryAnIndex)
+ [Esempio: indici secondari locali che utilizzano l'API del documento Java](LSIJavaDocumentAPI.Example.md)

## Creazione di una tabella con un indice secondario locale
<a name="LSIJavaDocumentAPI.CreateTableWithIndex"></a>

Gli indici secondari locali devono essere creati al momento della creazione di una tabella. A tale scopo, utilizza il metodo `createTable` e fornire le specifiche per uno o più indici secondari locali. Il seguente esempio di codice Java crea una tabella per contenere le informazioni sui brani in una raccolta musicale. La chiave di partizione è `Artist` e la chiave di ordinamento è `SongTitle`. Un indice secondario, `AlbumTitleIndex`, facilita le query in base al titolo dell'album. 

Di seguito sono riportate le operazioni necessarie per creare una tabella con un indice secondario locale, utilizzando l'API documento di DynamoDB. 

1. Creare un'istanza della classe `DynamoDB`.

1. Crea un'istanza della classe `CreateTableRequest` per fornire le informazioni della richiesta. 

   È necessario fornire il nome della tabella, la sua chiave primaria e i valori del throughput assegnato. Per l'indice secondario locale, è necessario fornire il nome dell'indice, il nome e il tipo di dati della chiave di ordinamento dell'indice, lo schema della chiave per l'indice e la proiezione degli attributi.

1. Chiama il metodo `createTable` fornendo l'oggetto richiesta come parametro.

Il seguente esempio di codice Java mostra le fasi precedenti. Il codice crea una tabella (`Music`) con un indice secondario sull'attributo `AlbumTitle`. La chiave di partizione e la chiave di ordinamento della tabella, più la chiave di ordinamento dell'indice, sono gli unici attributi proiettati sull'indice.

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName);

//ProvisionedThroughput
createTableRequest.setProvisionedThroughput(new ProvisionedThroughput().withReadCapacityUnits((long)5).withWriteCapacityUnits((long)5));

//AttributeDefinitions
ArrayList<AttributeDefinition> attributeDefinitions= new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("Artist").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("SongTitle").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("AlbumTitle").withAttributeType("S"));

createTableRequest.setAttributeDefinitions(attributeDefinitions);

//KeySchema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement().withAttributeName("SongTitle").withKeyType(KeyType.RANGE));  //Sort key

createTableRequest.setKeySchema(tableKeySchema);

ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>();
indexKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
indexKeySchema.add(new KeySchemaElement().withAttributeName("AlbumTitle").withKeyType(KeyType.RANGE));  //Sort key

Projection projection = new Projection().withProjectionType(ProjectionType.INCLUDE);
ArrayList<String> nonKeyAttributes = new ArrayList<String>();
nonKeyAttributes.add("Genre");
nonKeyAttributes.add("Year");
projection.setNonKeyAttributes(nonKeyAttributes);

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
    .withIndexName("AlbumTitleIndex").withKeySchema(indexKeySchema).withProjection(projection);

ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new ArrayList<LocalSecondaryIndex>();
localSecondaryIndexes.add(localSecondaryIndex);
createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);

Table table = dynamoDB.createTable(createTableRequest);
System.out.println(table.getDescription());
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella.

## Descrizione di una tabella con un indice secondario locale
<a name="LSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari locali in una tabella, utilizza il metodo `describeTable`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

Di seguito sono riportate le fasi per accedere alle informazioni sull'indice secondario locale di una tabella utilizzando l'API documento AWS SDK per Java .

1. Creare un'istanza della classe `DynamoDB`.

1. Creare un'istanza della classe `Table`. Devi specificare il nome della tabella.

1. Chiama il metodo `describeTable` per l'oggetto `Table`.

Il seguente esempio di codice Java mostra le fasi precedenti.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);

TableDescription tableDescription = table.describe();

List<LocalSecondaryIndexDescription> localSecondaryIndexes 
    = tableDescription.getLocalSecondaryIndexes();

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.

Iterator<LocalSecondaryIndexDescription> lsiIter = localSecondaryIndexes.iterator();
while (lsiIter.hasNext()) {

    LocalSecondaryIndexDescription lsiDescription = lsiIter.next();
    System.out.println("Info for index " + lsiDescription.getIndexName() + ":");
    Iterator<KeySchemaElement> kseIter = lsiDescription.getKeySchema().iterator();
    while (kseIter.hasNext()) {
        KeySchemaElement kse = kseIter.next();
        System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType());
    }
    Projection projection = lsiDescription.getProjection();
    System.out.println("\tThe projection type is: " + projection.getProjectionType());
    if (projection.getProjectionType().toString().equals("INCLUDE")) {
        System.out.println("\t\tThe non-key projected attributes are: " + projection.getNonKeyAttributes());
    }
}
```

## Esecuzione di query su un indice secondario locale
<a name="LSIJavaDocumentAPI.QueryAnIndex"></a>

È possibile utilizzare l'operazione `Query` su un indice secondario locale nello stesso modo in cui si esegue una `Query` su una tabella. È necessario specificare il nome dell'indice, i criteri della query per la chiave di ordinamento dell'indice e gli attributi da restituire. In questo esempio, l'indice è `AlbumTitleIndex` e la chiave di ordinamento dell'indice è `AlbumTitle`. 

Gli unici attributi restituiti sono quelli proiettati nell'indice. È possibile modificare questa query per selezionare anche attributi non chiave, ma ciò richiederebbe un'attività di recupero della tabella relativamente costosa. Per ulteriori informazioni sul recupero delle tabelle, consulta [Proiezioni di attributi](LSI.md#LSI.Projections).

Di seguito sono riportati i passaggi per interrogare un indice secondario locale utilizzando l'API AWS SDK per Java Document. 

1. Creare un'istanza della classe `DynamoDB`.

1. Creare un'istanza della classe `Table`. Devi specificare il nome della tabella.

1. Creare un'istanza della classe `Index`. È necessario specificare il nome dell'indice.

1. Chiamare il metodo `query` della classe `Index`.

Il seguente esempio di codice Java mostra le fasi precedenti.

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);
Index index = table.getIndex("AlbumTitleIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"));

ItemCollection<QueryOutcome> items = index.query(spec);

Iterator<Item> itemsIter = items.iterator();

while (itemsIter.hasNext()) {
    Item item = itemsIter.next();
    System.out.println(item.toJSONPretty());
}
```

### Letture coerenti su un indice secondario locale
<a name="LSIJavaDocumentAPI.ConsistentReads"></a>

A differenza degli indici secondari globali, che supportano solo letture alla fine coerenti, un indice secondario locale supporta sia letture sostanzialmente coerenti che fortemente coerenti. Una lettura fortemente consistente da un indice secondario locale restituisce sempre gli ultimi valori aggiornati. Se la query deve recuperare attributi aggiuntivi dalla tabella di base, tali attributi recuperati sono coerenti anche rispetto all'indice.

Per impostazione predefinita, `Query` utilizza alla fine letture coerenti. Per richiedere una lettura fortemente coerente, imposta `ConsistentRead` su `true` in. `QuerySpec` Il seguente esempio esegue una query `AlbumTitleIndex` utilizzando una lettura fortemente coerente:

**Example**  

```
QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"))
    .withConsistentRead(true);
```

**Nota**  
Una lettura altamente coerente consuma un'unità di capacità di lettura per 4 KB di dati restituiti (arrotondati per eccesso), mentre una lettura sostanzialmente coerente ne consuma la metà. Ad esempio, una lettura altamente coerente che restituisce 9 KB di dati consuma 3 unità di capacità di lettura (9 KB/ 4 KB = 2,25, arrotondato a 3), mentre la stessa query che utilizza una lettura sostanzialmente coerente consuma 1,5 unità di capacità di lettura. Se l'applicazione è in grado di tollerare la lettura di dati che potrebbero essere leggermente obsoleti, utilizzate eventuali letture coerenti per ridurre l'utilizzo della capacità di lettura. Per ulteriori informazioni, consulta [Unità di capacità in lettura](LSI.md#LSI.ThroughputConsiderations.Reads).

# Esempio: indici secondari locali che utilizzano l'API del documento Java
<a name="LSIJavaDocumentAPI.Example"></a>

Il seguente esempio di codice Java mostra come utilizzare gli indici secondari globali in Amazon DynamoDB. Nell'esempio viene creata una tabella denominata `CustomerOrders` con una chiave di partizione `CustomerId` e una chiave di ordinamento `OrderId`. In questa tabella esistono due indici secondari locali:
+ `OrderCreationDateIndex`: la chiave di ordinamento è `OrderCreationDate` e i seguenti attributi sono proiettati sull'indice.
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: la chiave di ordinamento è `IsOpen` e tutti gli attributi della tabella vengono proiettati nell'indice.

Una volta creata la tabella `CustomerOrders`, il programma carica la tabella con i dati che rappresentano gli ordini dei clienti. Quindi esegue una query sui dati utilizzando gli indici secondari locali. Infine, il programma elimina la tabella `CustomerOrders`.

Per step-by-step istruzioni su come testare il seguente esempio, vedere. [Esempi di codice Java](CodeSamples.Java.md)

**Example**  

```
package com.example.dynamodb;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;

import java.util.HashMap;
import java.util.Map;

public class DocumentAPILocalSecondaryIndexExample {

    static DynamoDbClient client = DynamoDbClient.create();
    public static String tableName = "CustomerOrders";

    public static void main(String[] args) {
        createTable();
        loadData();
        query(null);
        query("IsOpenIndex");
        query("OrderCreationDateIndex");
        deleteTable(tableName);
    }

    public static void createTable() {
        CreateTableRequest request = CreateTableRequest.builder()
            .tableName(tableName)
            .provisionedThroughput(ProvisionedThroughput.builder()
                .readCapacityUnits(1L)
                .writeCapacityUnits(1L)
                .build())
            .attributeDefinitions(
                AttributeDefinition.builder().attributeName("CustomerId").attributeType(ScalarAttributeType.S).build(),
                AttributeDefinition.builder().attributeName("OrderId").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("OrderCreationDate").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("IsOpen").attributeType(ScalarAttributeType.N).build())
            .keySchema(
                KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                KeySchemaElement.builder().attributeName("OrderId").keyType(KeyType.RANGE).build())
            .localSecondaryIndexes(
                LocalSecondaryIndex.builder()
                    .indexName("OrderCreationDateIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("OrderCreationDate").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("ProductCategory", "ProductName")
                        .build())
                    .build(),
                LocalSecondaryIndex.builder()
                    .indexName("IsOpenIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("IsOpen").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.ALL)
                        .build())
                    .build())
            .build();

        System.out.println("Creating table " + tableName + "...");
        client.createTable(request);

        try (DynamoDbWaiter waiter = client.waiter()) {
            WaiterResponse<DescribeTableResponse> response = waiter.waitUntilTableExists(r -> r.tableName(tableName));
            response.matched().response().ifPresent(System.out::println);
        }
    }

    public static void query(String indexName) {
        System.out.println("\n***********************************************************\n");
        System.out.println("Querying table " + tableName + "...");

        if ("IsOpenIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that are open.");
            System.out.println("Only a user-specified list of attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_isopen", AttributeValue.builder().n("1").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and IsOpen = :v_isopen")
                .expressionAttributeValues(values)
                .projectionExpression("OrderCreationDate, ProductCategory, ProductName, OrderStatus")
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else if ("OrderCreationDateIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that were placed after 01/31/2015.");
            System.out.println("Only the projected attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_orddate", AttributeValue.builder().n("20150131").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and OrderCreationDate >= :v_orddate")
                .expressionAttributeValues(values)
                .select(Select.ALL_PROJECTED_ATTRIBUTES)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else {
            System.out.println("\nNo index: All of Bob's orders, by OrderId:\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .keyConditionExpression("CustomerId = :v_custid")
                .expressionAttributeValues(values)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);
        }
    }

    public static void deleteTable(String tableName) {
        System.out.println("Deleting table " + tableName + "...");
        client.deleteTable(DeleteTableRequest.builder().tableName(tableName).build());

        try (DynamoDbWaiter waiter = client.waiter()) {
            waiter.waitUntilTableNotExists(r -> r.tableName(tableName));
        }
    }

    public static void loadData() {
        System.out.println("Loading data into table " + tableName + "...");

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150101").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("The Great Outdoors").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Bike").build(),
            "ProductName", AttributeValue.builder().s("Super Mountain").build(),
            "OrderStatus", AttributeValue.builder().s("ORDER RECEIVED").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150304").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("A Quiet Interlude").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("176493").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150111").build(),
            "ProductCategory", AttributeValue.builder().s("Movie").build(),
            "ProductName", AttributeValue.builder().s("Calm Before The Storm").build(),
            "OrderStatus", AttributeValue.builder().s("SHIPPING DELAY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("859323").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150124").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("E-Z Listening").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("756943").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("Symphony 9").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("645193").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("4").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150222").build(),
            "ProductCategory", AttributeValue.builder().s("Hardware").build(),
            "ProductName", AttributeValue.builder().s("Extra Heavy Hammer").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("5").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150309").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("How To Cook").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("440185").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("6").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150318").build(),
            "ProductCategory", AttributeValue.builder().s("Luggage").build(),
            "ProductName", AttributeValue.builder().s("Really Big Suitcase").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("893927").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("7").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150324").build(),
            "ProductCategory", AttributeValue.builder().s("Golf").build(),
            "ProductName", AttributeValue.builder().s("PGA Pro II").build(),
            "OrderStatus", AttributeValue.builder().s("OUT FOR DELIVERY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("383283").build()));
    }

    private static void putItem(Map<String, AttributeValue> item) {
        client.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
    }
}
```

# Utilizzo di indici secondari locali: .NET
<a name="LSILowLevelDotNet"></a>

**Topics**
+ [Creazione di una tabella con un indice secondario locale](#LSILowLevelDotNet.CreateTableWithIndex)
+ [Descrizione di una tabella con un indice secondario locale](#LSILowLevelDotNet.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario locale](#LSILowLevelDotNet.QueryAnIndex)
+ [Esempio AWS SDK per .NET : indici secondari locali che utilizzano l'API di basso livello](LSILowLevelDotNet.Example.md)

Puoi utilizzare l'API di AWS SDK per .NET basso livello per creare una tabella Amazon DynamoDB con uno o più indici secondari locali, descrivere gli indici sulla tabella ed eseguire query utilizzando gli indici. Queste operazioni vengono mappate alle corrispondenti azioni dell'API DynamoDB di basso livello. Per ulteriori informazioni, consulta [Esempi di codice .NET](CodeSamples.DotNet.md). 

Di seguito sono riportate le operazioni comuni per le operazioni delle tabelle che utilizzano l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Fornisci i parametri obbligatori e facoltativi per l'operazione creando gli oggetti di richiesta corrispondenti.

   Ad esempio, creare un oggetto `CreateTableRequest` per creare una tabella e un oggetto `QueryRequest` per eseguire una query su una tabella o un indice. 

1. Eseguire il metodo appropriato fornito dal client creato nella fase precedente. 

## Creazione di una tabella con un indice secondario locale
<a name="LSILowLevelDotNet.CreateTableWithIndex"></a>

Gli indici secondari locali possono essere creati al momento della creazione di una tabella. A tale scopo, utilizza `CreateTable` e fornire le specifiche per uno o più indici secondari locali. Il seguente esempio di codice C\$1 crea una tabella per contenere le informazioni sui brani in una raccolta musicale. La chiave di partizione è `Artist` e la chiave di ordinamento è `SongTitle`. Un indice secondario, `AlbumTitleIndex`, facilita le query in base al titolo dell'album. 

Di seguito sono riportate le operazioni per creare una tabella con un indice secondario locale, utilizzando l'API di basso livello di DynamoDB. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Crea un'istanza della classe `CreateTableRequest` per fornire le informazioni della richiesta. 

   È necessario fornire il nome della tabella, la sua chiave primaria e i valori del throughput assegnato. Per l'indice secondario locale, è necessario fornire il nome dell'indice, il nome e il tipo di dati della chiave di ordinamento dell'indice, lo schema della chiave per l'indice e la proiezione degli attributi.

1. Eseguire il metodo `CreateTable` fornendo l'oggetto della richiesta come parametro.

Il seguente esempio di codice C\$1 mostra le fasi precedenti. Il codice crea una tabella (`Music`) con un indice secondario sull'attributo `AlbumTitle`. La chiave di partizione e la chiave di ordinamento della tabella, più la chiave di ordinamento dell'indice, sono gli unici attributi proiettati sull'indice.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest()
{
    TableName = tableName
};

//ProvisionedThroughput
createTableRequest.ProvisionedThroughput = new ProvisionedThroughput()
{
    ReadCapacityUnits = (long)5,
    WriteCapacityUnits = (long)5
};

//AttributeDefinitions
List<AttributeDefinition> attributeDefinitions = new List<AttributeDefinition>();

attributeDefinitions.Add(new AttributeDefinition()
{
    AttributeName = "Artist",
    AttributeType = "S"
});

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "SongTitle",
     AttributeType = "S"
 });

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "AlbumTitle",
     AttributeType = "S"
 });

createTableRequest.AttributeDefinitions = attributeDefinitions;

//KeySchema
List<KeySchemaElement> tableKeySchema = new List<KeySchemaElement>();

tableKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
tableKeySchema.Add(new KeySchemaElement() { AttributeName = "SongTitle", KeyType = "RANGE" });  //Sort key

createTableRequest.KeySchema = tableKeySchema;

List<KeySchemaElement> indexKeySchema = new List<KeySchemaElement>();
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "AlbumTitle", KeyType = "RANGE" });  //Sort key

Projection projection = new Projection() { ProjectionType = "INCLUDE" };

List<string> nonKeyAttributes = new List<string>();
nonKeyAttributes.Add("Genre");
nonKeyAttributes.Add("Year");
projection.NonKeyAttributes = nonKeyAttributes;

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
{
    IndexName = "AlbumTitleIndex",
    KeySchema = indexKeySchema,
    Projection = projection
};

List<LocalSecondaryIndex> localSecondaryIndexes = new List<LocalSecondaryIndex>();
localSecondaryIndexes.Add(localSecondaryIndex);
createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

CreateTableResponse result = client.CreateTable(createTableRequest);
Console.WriteLine(result.CreateTableResult.TableDescription.TableName);
Console.WriteLine(result.CreateTableResult.TableDescription.TableStatus);
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella.

## Descrizione di una tabella con un indice secondario locale
<a name="LSILowLevelDotNet.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari locali in una tabella, utilizza l'API `DescribeTable`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

Di seguito sono riportate le operazioni per accedere alle informazioni sull'indice secondario locale su una tabella utilizzando l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Crea un'istanza della classe `DescribeTableRequest` per fornire le informazioni della richiesta. Devi specificare il nome della tabella.

1. Eseguire il metodo `describeTable` fornendo l'oggetto della richiesta come parametro.

Il seguente esempio di codice C\$1 mostra le fasi precedenti.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

DescribeTableResponse response = client.DescribeTable(new DescribeTableRequest() { TableName = tableName });
List<LocalSecondaryIndexDescription> localSecondaryIndexes =
    response.DescribeTableResult.Table.LocalSecondaryIndexes;

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.
foreach (LocalSecondaryIndexDescription lsiDescription in localSecondaryIndexes)
{
    Console.WriteLine("Info for index " + lsiDescription.IndexName + ":");

    foreach (KeySchemaElement kse in lsiDescription.KeySchema)
    {
        Console.WriteLine("\t" + kse.AttributeName + ": key type is " + kse.KeyType);
    }

    Projection projection = lsiDescription.Projection;

    Console.WriteLine("\tThe projection type is: " + projection.ProjectionType);

    if (projection.ProjectionType.ToString().Equals("INCLUDE"))
    {
        Console.WriteLine("\t\tThe non-key projected attributes are:");

        foreach (String s in projection.NonKeyAttributes)
        {
            Console.WriteLine("\t\t" + s);
        }

    }
}
```

## Esecuzione di query su un indice secondario locale
<a name="LSILowLevelDotNet.QueryAnIndex"></a>

È possibile utilizzare l'operazione `Query` su un indice secondario locale nello stesso modo in cui si esegue una `Query` su una tabella. È necessario specificare il nome dell'indice, i criteri della query per la chiave di ordinamento dell'indice e gli attributi da restituire. In questo esempio, l'indice è `AlbumTitleIndex` e la chiave di ordinamento dell'indice è `AlbumTitle`. 

Gli unici attributi restituiti sono quelli proiettati nell'indice. È possibile modificare questa query per selezionare anche attributi non chiave, ma ciò richiederebbe un'attività di recupero della tabella relativamente costosa. Per ulteriori informazioni sul recupero delle tabelle, consulta [Proiezioni di attributi](LSI.md#LSI.Projections)

Di seguito sono riportate le operazioni per eseguire una query su un indice secondario locale utilizzando l'API di basso livello .NET. 

1. Creare un'istanza della classe `AmazonDynamoDBClient`.

1. Crea un'istanza della classe `QueryRequest` per fornire le informazioni della richiesta.

1. Eseguire il metodo `query` fornendo l'oggetto della richiesta come parametro.

Il seguente esempio di codice C\$1 mostra le fasi precedenti.

**Example**  

```
QueryRequest queryRequest = new QueryRequest
{
    TableName = "Music",
    IndexName = "AlbumTitleIndex",
    Select = "ALL_ATTRIBUTES",
    ScanIndexForward = true,
    KeyConditionExpression = "Artist = :v_artist and AlbumTitle = :v_title",
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":v_artist",new AttributeValue {S = "Acme Band"}},
        {":v_title",new AttributeValue {S = "Songs About Life"}}
    },
};

QueryResponse response = client.Query(queryRequest);

foreach (var attribs in response.Items)
{
    foreach (var attrib in attribs)
    {
        Console.WriteLine(attrib.Key + " ---> " + attrib.Value.S);
    }
    Console.WriteLine();
}
```

# Esempio AWS SDK per .NET : indici secondari locali che utilizzano l'API di basso livello
<a name="LSILowLevelDotNet.Example"></a>

Il seguente esempio di codice C\$1 mostra come utilizzare gli indici secondari locali in Amazon DynamoDB. Nell'esempio viene creata una tabella denominata `CustomerOrders` con una chiave di partizione `CustomerId` e una chiave di ordinamento `OrderId`. In questa tabella esistono due indici secondari locali:
+ `OrderCreationDateIndex`: la chiave di ordinamento è `OrderCreationDate` e i seguenti attributi sono proiettati sull'indice.
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: la chiave di ordinamento è `IsOpen` e tutti gli attributi della tabella vengono proiettati nell'indice.

Una volta creata la tabella `CustomerOrders`, il programma carica la tabella con i dati che rappresentano gli ordini dei clienti. Quindi esegue una query sui dati utilizzando gli indici secondari locali. Infine, il programma elimina la tabella `CustomerOrders`.

Per step-by-step istruzioni su come testare l'esempio seguente, consulta. [Esempi di codice .NET](CodeSamples.DotNet.md)

**Example**  

```
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelLocalSecondaryIndexExample
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        private static string tableName = "CustomerOrders";

        static void Main(string[] args)
        {
            try
            {
                CreateTable();
                LoadData();

                Query(null);
                Query("IsOpenIndex");
                Query("OrderCreationDateIndex");

                DeleteTable(tableName);

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateTable()
        {
            var createTableRequest =
                new CreateTableRequest()
                {
                    TableName = tableName,
                    ProvisionedThroughput =
                    new ProvisionedThroughput()
                    {
                        ReadCapacityUnits = (long)1,
                        WriteCapacityUnits = (long)1
                    }
                };

            var attributeDefinitions = new List<AttributeDefinition>()
        {
            // Attribute definitions for table primary key
            { new AttributeDefinition() {
                  AttributeName = "CustomerId", AttributeType = "S"
              } },
            { new AttributeDefinition() {
                  AttributeName = "OrderId", AttributeType = "N"
              } },
            // Attribute definitions for index primary key
            { new AttributeDefinition() {
                  AttributeName = "OrderCreationDate", AttributeType = "N"
              } },
            { new AttributeDefinition() {
                  AttributeName = "IsOpen", AttributeType = "N"
              }}
        };

            createTableRequest.AttributeDefinitions = attributeDefinitions;

            // Key schema for table
            var tableKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                  //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderId", KeyType = "RANGE"
              } }                                                //Sort key
        };

            createTableRequest.KeySchema = tableKeySchema;

            var localSecondaryIndexes = new List<LocalSecondaryIndex>();

            // OrderCreationDateIndex
            LocalSecondaryIndex orderCreationDateIndex = new LocalSecondaryIndex()
            {
                IndexName = "OrderCreationDateIndex"
            };

            // Key schema for OrderCreationDateIndex
            var indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                    //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderCreationDate", KeyType = "RANGE"
              } }                                                            //Sort key
        };

            orderCreationDateIndex.KeySchema = indexKeySchema;

            // Projection (with list of projected attributes) for
            // OrderCreationDateIndex
            var projection = new Projection()
            {
                ProjectionType = "INCLUDE"
            };

            var nonKeyAttributes = new List<string>()
        {
            "ProductCategory",
            "ProductName"
        };
            projection.NonKeyAttributes = nonKeyAttributes;

            orderCreationDateIndex.Projection = projection;

            localSecondaryIndexes.Add(orderCreationDateIndex);

            // IsOpenIndex
            LocalSecondaryIndex isOpenIndex
                = new LocalSecondaryIndex()
                {
                    IndexName = "IsOpenIndex"
                };

            // Key schema for IsOpenIndex
            indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              }},                                                     //Partition key
            { new KeySchemaElement() {
                  AttributeName = "IsOpen", KeyType = "RANGE"
              }}                                                  //Sort key
        };

            // Projection (all attributes) for IsOpenIndex
            projection = new Projection()
            {
                ProjectionType = "ALL"
            };

            isOpenIndex.KeySchema = indexKeySchema;
            isOpenIndex.Projection = projection;

            localSecondaryIndexes.Add(isOpenIndex);

            // Add index definitions to CreateTable request
            createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

            Console.WriteLine("Creating table " + tableName + "...");
            client.CreateTable(createTableRequest);
            WaitUntilTableReady(tableName);
        }

        public static void Query(string indexName)
        {
            Console.WriteLine("\n***********************************************************\n");
            Console.WriteLine("Querying table " + tableName + "...");

            QueryRequest queryRequest = new QueryRequest()
            {
                TableName = tableName,
                ConsistentRead = true,
                ScanIndexForward = true,
                ReturnConsumedCapacity = "TOTAL"
            };


            String keyConditionExpression = "CustomerId = :v_customerId";
            Dictionary<string, AttributeValue> expressionAttributeValues = new Dictionary<string, AttributeValue> {
            {":v_customerId", new AttributeValue {
                 S = "bob@example.com"
             }}
        };


            if (indexName == "IsOpenIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that are open.");
                Console.WriteLine("Only a user-specified list of attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and IsOpen = :v_isOpen";
                expressionAttributeValues.Add(":v_isOpen", new AttributeValue
                {
                    N = "1"
                });

                // ProjectionExpression
                queryRequest.ProjectionExpression = "OrderCreationDate, ProductCategory, ProductName, OrderStatus";
            }
            else if (indexName == "OrderCreationDateIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that were placed after 01/31/2013.");
                Console.WriteLine("Only the projected attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and OrderCreationDate > :v_Date";
                expressionAttributeValues.Add(":v_Date", new AttributeValue
                {
                    N = "20130131"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else
            {
                Console.WriteLine("\nNo index: All of Bob's orders, by OrderId:\n");
            }
            queryRequest.KeyConditionExpression = keyConditionExpression;
            queryRequest.ExpressionAttributeValues = expressionAttributeValues;

            var result = client.Query(queryRequest);
            var items = result.Items;
            foreach (var currentItem in items)
            {
                foreach (string attr in currentItem.Keys)
                {
                    if (attr == "OrderId" || attr == "IsOpen"
                        || attr == "OrderCreationDate")
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].N);
                    }
                    else
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].S);
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nConsumed capacity: " + result.ConsumedCapacity.CapacityUnits + "\n");
        }

        private static void DeleteTable(string tableName)
        {
            Console.WriteLine("Deleting table " + tableName + "...");
            client.DeleteTable(new DeleteTableRequest()
            {
                TableName = tableName
            });
            WaitForTableToBeDeleted(tableName);
        }

        public static void LoadData()
        {
            Console.WriteLine("Loading data into table " + tableName + "...");

            Dictionary<string, AttributeValue> item = new Dictionary<string, AttributeValue>();

            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130101"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "The Great Outdoors"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            PutItemRequest putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Bike"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Super Mountain"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "ORDER RECEIVED"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130304"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "A Quiet Interlude"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "176493"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130111"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Movie"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Calm Before The Storm"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "SHIPPING DELAY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "859323"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130124"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "E-Z Listening"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "756943"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Symphony 9"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "645193"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "4"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130222"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Hardware"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Extra Heavy Hammer"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "5"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130309"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "How To Cook"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "440185"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "6"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130318"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Luggage"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Really Big Suitcase"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "893927"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "7"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130324"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Golf"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "PGA Pro II"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "OUT FOR DELIVERY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "383283"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);
        }

        private static void WaitUntilTableReady(string tableName)
        {
            string status = null;
            // Let us wait until table is created. Call DescribeTable.
            do
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                    status = res.Table.TableStatus;
                }
                catch (ResourceNotFoundException)
                {
                    // DescribeTable is eventually consistent. So you might
                    // get resource not found. So we handle the potential exception.
                }
            } while (status != "ACTIVE");
        }

        private static void WaitForTableToBeDeleted(string tableName)
        {
            bool tablePresent = true;

            while (tablePresent)
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                }
                catch (ResourceNotFoundException)
                {
                    tablePresent = false;
                }
            }
        }
    }
}
```

# Utilizzo di indici secondari locali nella AWS CLI di DynamoDB
<a name="LCICli"></a>

Puoi utilizzare la AWS CLI per creare una tabella Amazon DynamoDB con uno o più indici secondari locali, descrivere gli indici nella tabella ed eseguire query utilizzando gli indici.

**Topics**
+ [Creazione di una tabella con un indice secondario locale](#LCICli.CreateTableWithIndex)
+ [Descrizione di una tabella con un indice secondario locale](#LCICli.DescribeTableWithIndex)
+ [Esecuzione di query su un indice secondario locale](#LCICli.QueryAnIndex)

## Creazione di una tabella con un indice secondario locale
<a name="LCICli.CreateTableWithIndex"></a>

Gli indici secondari locali devono essere creati al momento della creazione di una tabella. A tale scopo, utilizza il parametro `create-table` e fornisci le specifiche per uno o più indici secondari locali. Nel seguente esempio viene creata una tabella (`Music`) per contenere le informazioni sui brani in una raccolta musicale. La chiave di partizione è `Artist` e la chiave di ordinamento è `SongTitle`. Un indice secondario, `AlbumTitleIndex` sull'attributo `AlbumTitle`, facilita le query in base al titolo dell'album. 

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S \
        AttributeName=AlbumTitle,AttributeType=S  \
    --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --local-secondary-indexes \
        "[{\"IndexName\": \"AlbumTitleIndex\",
        \"KeySchema\":[{\"AttributeName\":\"Artist\",\"KeyType\":\"HASH\"},
                      {\"AttributeName\":\"AlbumTitle\",\"KeyType\":\"RANGE\"}],
        \"Projection\":{\"ProjectionType\":\"INCLUDE\",  \"NonKeyAttributes\":[\"Genre\", \"Year\"]}}]"
```

È necessario attendere fino a quando DynamoDB crea la tabella e imposta lo stato su `ACTIVE`. Dopodiché, puoi iniziare a inserire item di dati nella tabella. È possibile utilizzare [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) per determinare lo stato di avanzamento della creazione della tabella. 

## Descrizione di una tabella con un indice secondario locale
<a name="LCICli.DescribeTableWithIndex"></a>

Per ottenere informazioni sugli indici secondari locali in una tabella, utilizza il parametro `describe-table`. Puoi accedere al nome, allo schema della chiave e agli attributi proiettati di ciascun indice.

```
aws dynamodb describe-table --table-name Music
```

## Esecuzione di query su un indice secondario locale
<a name="LCICli.QueryAnIndex"></a>

Puoi utilizzare l'operazione `query` su un indice secondario locale nello stesso modo in cui esegui una `query` su una tabella. È necessario specificare il nome dell'indice, i criteri della query per la chiave di ordinamento dell'indice e gli attributi da restituire. In questo esempio, l'indice è `AlbumTitleIndex` e la chiave di ordinamento dell'indice è `AlbumTitle`. 

Gli unici attributi restituiti sono quelli proiettati nell'indice. È possibile modificare questa query per selezionare anche attributi non chiave, ma ciò richiederebbe un'attività di recupero della tabella relativamente costosa. Per ulteriori informazioni sul recupero delle tabelle, consulta [Proiezioni di attributi](LSI.md#LSI.Projections).

```
aws dynamodb query \
    --table-name Music \
    --index-name AlbumTitleIndex \
    --key-condition-expression "Artist = :v_artist and AlbumTitle = :v_title" \
    --expression-attribute-values  '{":v_artist":{"S":"Acme Band"},":v_title":{"S":"Songs About Life"} }'
```

# Gestione di flussi di lavoro complessi con transazioni DynamoDB
<a name="transactions"></a>

Le transazioni Amazon DynamoDB semplificano l'esperienza degli sviluppatori di apportare modifiche coordinate all-or-nothing a più elementi sia all'interno che tra tabelle. La transazioni forniscono atomicità, coerenza, isolamento e durabilità (ACID) in DynamoDB, consentendo di conservare più facilmente dati corretti nelle applicazioni.

Puoi utilizzare la lettura e la APIs scrittura transazionale di DynamoDB per gestire flussi di lavoro aziendali complessi che richiedono l'aggiunta, l'aggiornamento o l'eliminazione di più elementi in un'unica operazione. all-or-nothing Ad esempio, uno sviluppatore di videogiochi può garantire che i profili dei giocatori siano aggiornati correttamente quando si scambiano le voci in un videogioco o effettuano acquisti all'interno del gioco.

Con l'API di scrittura di transazione, è possibile raggruppare diverse operazioni `Put`, `Update`, `Delete` e `ConditionCheck`. Puoi quindi inviare le operazioni come un'operazione `TransactWriteItems` singola con esito positivo o negativo a livello di unità. Lo stesso vale per diverse azioni `Get`, che possono essere raggruppate e inviate come un'operazione `TransactGetItems` singola.

Non è previsto alcun costo aggiuntivo per abilitare le transazioni per le tabelle DynamoDB. Si paga solo per le letture o le scritture che fanno parte della transazione. DynamoDB esegue due letture o scritture sottostanti per ciascun elemento nella transazione: uno per preparare la transazione uno per eseguire il commit della transazione. Queste due read/write operazioni sottostanti sono visibili nelle CloudWatch metriche di Amazon.

Per iniziare a utilizzare le transazioni DynamoDB, scarica l'SDK AWS più recente o (). AWS Command Line Interface AWS CLI Quindi segui la procedura [Esempio di transazioni di DynamoDB](transaction-example.md).

Le seguenti sezioni forniscono una panoramica dettagliata della transazione APIs e di come utilizzarla in DynamoDB.

**Topics**
+ [Come funziona](transaction-apis.md)
+ [Utilizzo di IAM con le transazioni](transaction-apis-iam.md)
+ [Codice di esempio](transaction-example.md)

# Transazioni Amazon DynamoDB: come funzionano
<a name="transaction-apis"></a>

Con le transazioni Amazon DynamoDB, puoi raggruppare più azioni e inviarle come singola all-or-nothing `TransactWriteItems` operazione. `TransactGetItems` Le seguenti sezioni descrivono le operazioni delle API, la gestione della capacità, le best practice e altri dettagli sulle operazioni transazionali in DynamoDB.

**Topics**
+ [TransactWriteItems API](#transaction-apis-txwriteitems)
+ [TransactGetItems API](#transaction-apis-txgetitems)
+ [Livelli di isolamento per le transazioni DynamoDB](#transaction-isolation)
+ [Gestione dei conflitti nelle transazioni in DynamoDB](#transaction-conflict-handling)
+ [Utilizzo delle transazioni in APIs DynamoDB Accelerator (DAX)](#transaction-apis-dax)
+ [Gestione della capacità per le transazioni](#transaction-capacity-handling)
+ [Best practice per le transazioni](#transaction-best-practices)
+ [Utilizzo di tabelle transazionali con tabelle globali APIs](#transaction-integration)
+ [DynamoDB Transactions e la libreria client delle transazioni AWSLabs](#transaction-vs-library)

## TransactWriteItems API
<a name="transaction-apis-txwriteitems"></a>

`TransactWriteItems`è un'operazione di scrittura sincrona e idempotente che raggruppa fino a 100 azioni di scrittura in un'unica operazione. all-or-nothing Queste azioni possono indirizzare fino a 100 elementi distinti in una o più tabelle DynamoDB all'interno dello AWS stesso account e nella stessa regione. La dimensione aggregata degli elementi nella transazione non può superare i 4 MB. Le operazioni vengono completate in modo atomico, in maniera tale che abbiano tutte esito positivo oppure abbiano tutte esito negativo.

**Nota**  
 Un'operazione `TransactWriteItems` differisce da un'operazione `BatchWriteItem` nel fatto che tutte le operazioni che contiene devono essere completate con successo, altrimenti non viene apportata alcuna modifica. Con un'operazione `BatchWriteItem`, è possibile che solo alcune azioni nel batch abbiano esito positivo, contrariamente alle altre. 
 Le transazioni non possono essere eseguite utilizzando gli indici. 

Non è possibile fare riferimento allo stesso item con diverse operazioni all'interno della stessa transazione. Ad esempio, non è possibile eseguire un'operazione `ConditionCheck` e `Update` per lo stesso item nella stessa transazione.

È possibile aggiungere uno dei seguenti tipi di operazioni a una transazione:
+ `Put`: avvia un'operazione `PutItem` per creare un nuovo elemento o sostituire un vecchio elemento con uno nuovo, in base a condizioni o senza specificare alcuna condizione.
+ `Update`: avvia un'operazione `UpdateItem` per modificare gli attributi di un elemento esistente o aggiungere un nuovo elemento alla tabella se non è già presente. Utilizza questa operazione per aggiungere, eliminare o aggiornare attributi su un item esistente in base a condizioni o senza una condizione.
+ `Delete`: avvia un'operazione `DeleteItem` per eliminare un singolo elemento in una tabella identificata dalla chiave primaria.
+ `ConditionCheck`: verifica che un elemento esista o controlla la condizione di attributi specifici dell'elemento.

Quando una transazione viene completata in DynamoDB, le sue modifiche iniziano a propagarsi agli indici secondari globali (), ai flussi e ai backupGSIs. Questa propagazione avviene gradualmente: i record dei flussi della stessa transazione potrebbero apparire in momenti diversi e potrebbero risultare interleaved con i record di altre transazioni. I consumer dei flussi non dovrebbero presumere l’atomicità delle transazioni o garanzie d’ordine.

Per garantire un'istantanea atomica degli elementi modificati in una transazione, utilizza l'operazione per leggere tutti gli elementi pertinenti insieme. TransactGetItems Questa operazione fornisce una visione coerente dei dati, garantendo la visualizzazione di tutte le modifiche rispetto a una transazione completata o di nessuna.

Poiché la propagazione non è immediata, se una tabella viene ripristinata da backup ([RestoreTableFromBackup](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_RestoreTableFromBackup.html)) o esportata in un punto temporale ([ExportTableToPointInTime](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExportTableToPointInTime.html)) durante la propagazione, può contenere solo alcune delle modifiche apportate durante una transazione recente.

### Idempotenza
<a name="transaction-apis-txwriteitems-idempotency"></a>

È possibile includere un token client quando si effettua una chiamata `TransactWriteItems` per garantire che la richiesta sia *idempotente*. Rendere le transazioni idempotenti impedisce errori nelle applicazioni se la stessa operazione viene inviata più volte a causa di un timeout della connessione o altri problemi di connettività.

Se la chiamata `TransactWriteItems` originale è andata a buon fine, allora le successive chiamate `TransactWriteItems` con lo stesso token client hanno esito positivo senza apportare alcuna modifica. Se viene impostato il parametro `ReturnConsumedCapacity`, la chiamata `TransactWriteItems` iniziale restituisce il numero di unità di capacità in scrittura consumate mentre venivano apportate le modifiche. Le successive chiamate `TransactWriteItems` con lo stesso token client restituiscono il numero di unità di capacità in lettura consumate durante la lettura dell'item.

**Considerazioni importanti sull'idempotenza**
+ Un token client è valido per 10 minuti dopo il termine della richiesta che lo utilizza. Dopo 10 minuti, qualsiasi richiesta che utilizza lo stesso token client viene trattata come una nuova richiesta. Lo stesso token client non deve essere riutilizzato per la stessa richiesta dopo 10 minuti.
+ Se si ripete la richiesta con lo stesso token client all'interno della finestra di idempotenza di 10 minuti, ma vengono modificati altri parametri, DynamoDB restituisce un'eccezione `IdempotentParameterMismatch`.

### Gestione degli errori per scrittura
<a name="transaction-apis-txwriteitems-errors"></a>

Le transazioni di scrittura non hanno esito positivo nelle seguenti circostanze:
+ Quando una condizione in una delle espressioni di condizione non viene soddisfatta.
+ Quando un errore di convalida della transazione si verifica in quanto un'operazione all'interno della stessa operazione `TransactWriteItems` mira allo stesso item.
+ Quando una richiesta `TransactWriteItems` è in conflitto con un'operazione `TransactWriteItems` in corso su uno o più item nella richiesta `TransactWriteItems`. In questo caso, la richiesta ha esito negativo con una `TransactionCanceledException`.
+ Quando la capacità assegnata è insufficiente per il completamento della transazione.
+ Quando la dimensione di un item diventa eccessiva (superiore a 400 KB), un indice secondario locale (LSI) diventa eccessivo o si verifica un errore di convalida simile a causa delle modifiche apportate dalla transazione.
+ Quando è presente un errore utente, come un formato di dati invalido.

 Per ulteriori informazioni sulla gestione dei conflitti con le operazioni `TransactWriteItems`, consulta [Gestione dei conflitti nelle transazioni in DynamoDB](#transaction-conflict-handling).

## TransactGetItems API
<a name="transaction-apis-txgetitems"></a>

`TransactGetItems` è un'operazione di lettura sincrona che raggruppa fino a 100 operazioni `Get`. Queste azioni possono indirizzare fino a 100 elementi distinti in una o più tabelle DynamoDB all'interno dello stesso account e della AWS stessa regione. La dimensione aggregata degli elementi nella transazione non può superare i 4 MB. 

Le operazioni `Get` vengono eseguite in modo atomico, in maniera tale che abbiano tutte esito positivo oppure abbiano tutte esito negativo.
+ `Get`: avvia un'operazione `GetItem` per recuperare un set di attributi dell'elemento con la chiave primaria specificata. Se non viene trovato un item corrispondente, `Get` non restituisce dati.

### Gestione degli errori per lettura
<a name="transaction-apis-txgetitems-errors"></a>

Le transazioni di lettura non hanno esito positivo nelle seguenti circostanze:
+ Quando una richiesta `TransactGetItems` è in conflitto con un'operazione `TransactWriteItems` in corso su uno o più item nella richiesta `TransactGetItems`. In questo caso, la richiesta ha esito negativo con una `TransactionCanceledException`.
+ Quando la capacità assegnata è insufficiente per il completamento della transazione.
+ Quando è presente un errore utente, come un formato di dati invalido.

 Per ulteriori informazioni sulla gestione dei conflitti con le operazioni `TransactGetItems`, consulta [Gestione dei conflitti nelle transazioni in DynamoDB](#transaction-conflict-handling).

## Livelli di isolamento per le transazioni DynamoDB
<a name="transaction-isolation"></a>

I livelli di isolamento delle operazioni transazionali (`TransactWriteItems` o `TransactGetItems`) e di altre operazioni sono:

### SERIALIZZABILI
<a name="transaction-isolation-serializable"></a>

L'isolamento *serializzabile* garantisce che i risultati di diverse operazioni simultanee siano le stesse, come se nessuna operazione avesse inizio prima che l'ultima fosse finita.

L'isolamento serializzabile è presente tra i seguenti tipi di operazione:
+ Tra una qualsiasi operazione transazionale e una qualsiasi operazione di scrittura standard (`PutItem`, `UpdateItem` o `DeleteItem`).
+ Tra una qualsiasi operazione transazionale e una qualsiasi operazione di lettura standard (`GetItem`).
+ Tra un'operazione `TransactWriteItems` e un'operazione `TransactGetItems`.

Nonostante l’isolamento serializzabile sia presente tra le operazioni transazionali e ogni singola scrittura standard in un’operazione `BatchWriteItem`, l’isolamento serializzabile non è presente tra la transazione e l’operazione `BatchWriteItem` come un’unità.

Allo stesso modo, il livello di isolamento tra un'operazione transazionale e un `GetItems` individuale in un'operazione `BatchGetItem` è serializzabile. Tuttavia, il livello di isolamento tra la transazione e l'operazione `BatchGetItem`come unità è *read-committed*.

Una singola richiesta `GetItem` è serializzabile rispetto a una richiesta `TransactWriteItems` in uno dei due modi seguenti, prima o dopo la richiesta `TransactWriteItems`. Più richieste `GetItem`, rispetto alle chiavi in una richiesta `TransactWriteItems`simultanea, possono essere eseguite in qualsiasi ordine, e quindi i risultati sono *letti–commessi*.

Ad esempio, se le richieste `GetItem` per l'elemento A e l'elemento B vengono eseguite contemporaneamente a una richiesta `TransactWriteItems` che modifica sia l'elemento A che l'elemento B, esistono quattro possibilità:
+ Entrambe le richieste `GetItem` vengono eseguite prima della richiesta `TransactWriteItems`.
+ Entrambe le richieste `GetItem` vengono eseguite dopo la richiesta `TransactWriteItems`.
+ La richiesta `GetItem` per l'elemento A viene eseguita prima della richiesta `TransactWriteItems`. Per l'elemento B, `GetItem` viene eseguito dopo `TransactWriteItems`.
+ La richiesta `GetItem` per l'elemento B viene eseguita prima della richiesta `TransactWriteItems`. Per l'elemento A, `GetItem` viene eseguito dopo `TransactWriteItems`.

Sarebbe opportuno utilizzare `TransactGetItems` se si preferisce un livello di isolamento serializzabile per più richieste `GetItem`.

Se viene effettuata una lettura non transazionale su più elementi che facevano parte della stessa richiesta di scrittura della transazione in corso, è possibile che si sia in grado di leggere il nuovo stato di alcuni elementi e il vecchio stato degli altri elementi. Sarà possibile leggere il nuovo stato di tutti gli elementi che facevano parte della richiesta di scrittura della transazione solo quando si riceverà una risposta positiva per la scrittura transazionale, a indicare che la transazione è stata completata.

Una volta completata con successo la transazione e ricevuta una risposta, le successive operazioni di lettura *a coerenza finale* possono comunque restituire il vecchio stato per un breve periodo a causa di un modello di consistenza finale di DynamoDB. Per garantire la lettura della maggior parte up-to-date dei dati subito dopo una transazione, è necessario utilizzare letture [*fortemente coerenti*](HowItWorks.ReadConsistency.md#HowItWorks.ReadConsistency.Strongly) `ConsistentRead` impostando su true.

### READ-COMMITTED
<a name="transaction-isolation-read-committed"></a>

L'isolamento *Read-committed* garantisce che le operazioni di lettura restituiscano sempre valori sottoposti a commit per un elemento: la lettura non presenterà mai una vista dell'elemento che rappresenta uno stato di una scrittura transazionale terminata con un errore. L'isolamento read-committed non impedisce le modifiche dell'item immediatamente dopo l'operazione di lettura.

Il livello di isolamento è read-committed tra una qualsiasi operazione transazionale e una qualsiasi operazione di lettura che coinvolga diverse letture standard (`BatchGetItem`, `Query` o `Scan`). Se una scrittura transazionale aggiorna un elemento durante un'operazione `BatchGetItem`, `Query` o `Scan`, la fase successiva dell'operazione di lettura restituisce il nuovo valore sottoposto a commit, con `ConsistentRead)` o eventualmente un valore sottoposto a commit precedente (letture a consistenza finale).

### Riepilogo dell'operazione
<a name="transaction-isolation-table"></a>

Per riassumere, la seguente tabella mostra i livelli di isolamento tra un'operazione transazionale (`TransactWriteItems` o `TransactGetItems`) e altre operazioni.


| Operation | Livello di isolamento | 
| --- | --- | 
| `DeleteItem` | *Serializzabile* | 
| `PutItem` | *Serializzabile* | 
| `UpdateItem` | *Serializzabile* | 
| `GetItem` | *Serializzabile* | 
| `BatchGetItem` | *Read-committed*\$1 | 
| `BatchWriteItem` | *NON serializzabile*\$1 | 
| `Query` | *Read-committed* | 
| `Scan` | *Read-committed* | 
| Altra operazione transazionale | *Serializzabile* | 

I livelli contrassegnati da un asterisco (\$1) si applicano all'operazione come un'unità. Tuttavia, le singole operazioni all'interno di tali operazioni hanno un livello di isolamento *serializzabile*.

## Gestione dei conflitti nelle transazioni in DynamoDB
<a name="transaction-conflict-handling"></a>

Un conflitto transazionale si può verificare durante richieste simultanee a livello di voci su una singola voce all'interno di una transazione. I conflitti tra transazioni possono verificarsi nei seguenti scenari: 
+ Una richiesta `PutItem`,`UpdateItem` e `DeleteItem` per una voce è in conflitto con una richiesta `TransactWriteItems` continua che include la stessa voce.
+ Una voce all'interno di una richiesta `TransactWriteItems` è parte di un'altra richiesta `TransactWriteItems` continua.
+ Una voce all'interno di una richiesta `TransactGetItems` è parte di una richiesta continua `TransactWriteItems`, `BatchWriteItem`, `PutItem`, `UpdateItem` o `DeleteItem`.

**Nota**  
Quando una richiesta `PutItem`, `UpdateItem` o `DeleteItem` viene rifiutata, la richiesta dà esito negativo con un `TransactionConflictException`. 
Se una richiesta a livello di voce all'interno di `TransactWriteItems` o `TransactGetItems` viene rifiutata, la richiesta dà esito negativo con `TransactionCanceledException`. Se la richiesta fallisce, AWS SDKs non riprovarla.  
Se si utilizza il AWS SDK per Java, l'eccezione contiene l'elenco di [CancellationReasons](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CancellationReason.html), ordinato in base all'elenco di elementi nel parametro di `TransactItems` richiesta. Per altre lingue, una rappresentazione della stringa dell'elenco è inclusa nel messaggio di errore dell'eccezione. 
Quando un'operazione `TransactWriteItems` o `TransactGetItems` in corso è in conflitto con una richiesta `GetItem` simultanea, entrambe le operazione possono avere esito positivo.

La [TransactionConflict CloudWatch metrica](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/metrics-dimensions.html) viene incrementata per ogni richiesta a livello di elemento non riuscita.

## Utilizzo delle transazioni in APIs DynamoDB Accelerator (DAX)
<a name="transaction-apis-dax"></a>

`TransactWriteItems` e `TransactGetItems` sono entrambi supportati in DynamoDB Accelerator (DAX) con gli stessi livelli di isolamento di DynamoDB.

`TransactWriteItems` scrive tramite DAX. DAX passa una chiamata `TransactWriteItems` a DynamoDB e restituisce la risposta. Per popolare la cache dopo la scrittura, DAX chiama `TransactGetItems` in background per ogni elemento nell'operazione `TransactWriteItems`che consuma unità di capacità di lettura aggiuntive. Per ulteriori informazioni, consulta [Gestione della capacità per le transazioni](#transaction-capacity-handling). Questa funzionalità consente di mantenere la logica dell'applicazione semplice e di utilizzare DAX per operazioni sia transazionali che non transazionali.

Le chiamate `TransactGetItems` vengono passate tramite DAX senza che gli elementi vengano memorizzati nella cache in locale. Si tratta dello stesso comportamento utilizzato per una lettura fortemente coerente in DAX. APIs 

## Gestione della capacità per le transazioni
<a name="transaction-capacity-handling"></a>

Non è previsto alcun costo aggiuntivo per abilitare le transazioni per le tabelle DynamoDB. Si paga solo per le letture o le scritture che fanno parte della transazione. DynamoDB esegue due letture o scritture sottostanti per ciascun elemento nella transazione: uno per preparare la transazione uno per eseguire il commit della transazione. Le due read/write operazioni sottostanti sono visibili nelle CloudWatch metriche di Amazon.

Pianifica le letture e le scritture aggiuntive richieste da Transactional APIs per fornire capacità alle tabelle. Ad esempio, si supponga che l'applicazione esegua una transazione al secondo e che ciascuna transazione scriva nella tabella tre elementi da 500 byte. Ogni articolo richiede due unità di capacità di scrittura (WCUs): una per preparare la transazione e l'altra per confermare la transazione. Pertanto, è necessario assegnarne sei WCUs alla tabella. 

Se nell'esempio precedente si utilizzava DynamoDB Accelerator (DAX), si utilizzerebbero anche due unità di capacità di lettura RCUs () per ogni elemento della chiamata. `TransactWriteItems` Quindi è necessario aggiungere altre RCUs sei unità alla tabella.

Analogamente, se l'applicazione esegue una transazione di lettura al secondo e ogni transazione legge tre elementi da 500 byte della tabella, è necessario fornire sei unità di capacità di lettura (RCUs) alla tabella. La lettura di ogni elemento richiede due elementi RCUs: uno per preparare la transazione e uno per confermare la transazione.

Inoltre, il comportamento dell'SDK predefinito prevede di ritentare le transazioni in caso di un'eccezione `TransactionInProgressException`. Pianifica le unità di capacità di lettura aggiuntive (RCUs) utilizzate da questi nuovi tentativi. Lo stesso vale qualora si ritentino le transazioni nel proprio codice utilizzandone uno `ClientRequestToken`.

## Best practice per le transazioni
<a name="transaction-best-practices"></a>

Durante l'utilizzo delle transazioni DynamoDB, considerare le seguenti best practice suggerite.
+ Abilita il dimensionamento automatico o assicurati di aver effettuato il provisioning di una capacità di throughput sufficiente da eseguire le due operazioni di lettura o scrittura per ogni item della transazione.
+ Se non utilizzi un SDK AWS fornito, includi un `ClientRequestToken` attributo quando effettui una `TransactWriteItems` chiamata per assicurarti che la richiesta sia idempotente.
+ Non raggruppare le operazioni in una transazione qualora non sia necessario. Ad esempio, se una singola transazione con 10 operazioni può essere suddivisa in diverse transazioni senza compromettere la correttezza dell'applicazione, si raccomanda di frazionare la transazione. Le transazioni più semplici migliorano il throughput e hanno maggiori probabilità di successo. 
+ Diverse transazioni che aggiornano gli stessi item simultaneamente possono causare conflitti che annullano le transazioni. Per minimizzare tali conflitti, si consiglia di utilizzare le seguenti best practice DynamoDB per la modellazione dei dati.
+ Se un set di attributi viene spesso aggiornato tra più item come parte di una transazione singola, considera di raggruppare gli attributi in un singolo item per ridurre l'ambito della transazione.
+ Evita l'uso di transazioni per l'inserimento di dati in blocco. Per le scritture in blocco, è consigliabile utilizzare `BatchWriteItem`.

## Utilizzo di tabelle transazionali con tabelle globali APIs
<a name="transaction-integration"></a>

Le operazioni transazionali forniscono garanzie di atomicità, coerenza, isolamento e durabilità (ACID) solo all'interno della AWS regione in cui è stata richiamata l'API di scrittura. Le transazioni non sono supportate tra le Regioni nelle tabelle globali. Ad esempio, supponi di avere una tabella globale con repliche nelle Regioni Stati Uniti orientali (Ohio) e Stati Uniti occidentali (Oregon) e di eseguire un'operazione `TransactWriteItems` nella Regione Stati Uniti orientali (Virginia settentrionale). In questo caso, è possibile osservare transazioni parzialmente completate nella Regione degli Stati Uniti occidentali (Oregon) mentre le modifiche vengono replicate. Le modifiche vengono replicate in altre Regioni solo dopo essere state confermate nella Regione di origine.

## DynamoDB Transactions e la libreria client delle transazioni AWSLabs
<a name="transaction-vs-library"></a>

Le transazioni DynamoDB forniscono un sostituto più economico, robusto e performante della libreria client delle transazioni. [AWSLabs](https://github.com/awslabs) Ti suggeriamo di aggiornare le tue applicazioni per utilizzare la transazione nativa lato server. APIs

# Utilizzo di IAM con transazioni DynamoDB
<a name="transaction-apis-iam"></a>

Puoi usare AWS Identity and Access Management (IAM) per limitare le azioni che le operazioni transazionali possono eseguire in Amazon DynamoDB. Per ulteriori informazioni sull'uso di policy IAM in DynamoDB, consulta [Policy basate su identità per DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies).

Le autorizzazioni per le operazioni `Put`, `Update`, `Delete` e `Get` sono regolate dalle autorizzazioni utilizzate per le operazioni `PutItem`, `UpdateItem`, `DeleteItem` e `GetItem` sottostanti. Per l'operazione `ConditionCheck`, è possibile utilizzare l'autorizzazione `dynamodb:ConditionCheckItem` nelle policy IAM.

Di seguito sono riportati degli esempi di policy IAM che è possibile utilizzare per configurare le transazioni DynamoDB.

## Esempio 1: consentire le operazioni transazionali
<a name="tx-policy-example-1"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ]
        }
    ]
}
```

------

## Esempio 2: consentire solo le operazioni transazionali
<a name="tx-policy-example-2"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ],
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "dynamodb:EnclosingOperation": [
                        "TransactWriteItems",
                        "TransactGetItems"
                    ]
                }
            }
        }
    ]
}
```

------

## Esempio 3: consentire le letture e le scritture non transazionali e bloccare le letture e le scritture transazionali
<a name="tx-policy-example-3"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Deny",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:*:*:table/table04"
            ],
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "dynamodb:EnclosingOperation": [
                        "TransactWriteItems",
                        "TransactGetItems"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
             "Action": [
                 "dynamodb:PutItem",
                 "dynamodb:DeleteItem",
                 "dynamodb:GetItem",
                 "dynamodb:UpdateItem"
             ],
             "Resource": [
                 "arn:aws:dynamodb:*:*:table/table04"
             ]
         }
    ]
}
```

------

## Esempio 4: impedire che le informazioni vengano restituite in caso di errore ConditionCheck
<a name="tx-policy-example-4"></a>

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:ConditionCheckItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem",
                "dynamodb:DeleteItem",
                "dynamodb:GetItem"
            ],
            "Resource": "arn:aws:dynamodb:*:*:table/table01",
            "Condition": {
                "StringEqualsIfExists": {
                    "dynamodb:ReturnValues": "NONE"
                }
            }
        }
    ]
}
```

------

# Esempio di transazioni di DynamoDB
<a name="transaction-example"></a>

Come esempio di una situazione in cui le transazioni Amazon DynamoDB possono essere utili, si consideri questa applicazione Java di esempio per un marketplace online.

L'applicazione ha tre tabelle DynamoDB nel backend:
+ `Customers`: questa tabella archivia i dettagli sui clienti del marketplace. La sua chiave primaria è un identificatore univoco `CustomerId`.
+ `ProductCatalog`: questa tabella archivia dettagli quali prezzo e disponibilità dei prodotti in vendita nel marketplace. La sua chiave primaria è un identificatore univoco `ProductId`.
+ `Orders`: questa tabella archivia i dettagli sugli ordini del marketplace. La sua chiave primaria è un identificatore univoco `OrderId`.

## Come effettuare un ordine
<a name="transaction-example-write-order"></a>

I seguenti frammenti di codice illustrano come utilizzare le transazioni DynamoDB per coordinare i vari passaggi necessari per creare ed elaborare un ordine. L'utilizzo di una singola all-or-nothing operazione garantisce che, se una parte della transazione fallisce, non vengano eseguite azioni nella transazione e non vengano apportate modifiche.

In questo esempio, si configura un ordine da un cliente il cui `customerId` è `09e8e9c8-ec48`. Si esegue quindi come una singola transazione utilizzando il seguente flusso di lavoro semplice di elaborazione degli ordini:

1. Determinare che l'ID cliente sia valido.

1. Assicurati che il prodotto sia `IN_STOCK` e aggiornare lo stato del prodotto in `SOLD`.

1. Assicurati che l'ordine non esista già e creare l'ordine.

### Convalida del cliente
<a name="transaction-example-order-part-a"></a>

Per prima cosa, definire un'azione per verificare che un cliente con `customerId` uguale a `09e8e9c8-ec48` esista nella tabella dei clienti.

```
final String CUSTOMER_TABLE_NAME = "Customers";
final String CUSTOMER_PARTITION_KEY = "CustomerId";
final String customerId = "09e8e9c8-ec48";
final HashMap<String, AttributeValue> customerItemKey = new HashMap<>();
customerItemKey.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId));

ConditionCheck checkCustomerValid = new ConditionCheck()
    .withTableName(CUSTOMER_TABLE_NAME)
    .withKey(customerItemKey)
    .withConditionExpression("attribute_exists(" + CUSTOMER_PARTITION_KEY + ")");
```

### Aggiornamento dello stato dei prodotti
<a name="transaction-example-order-part-b"></a>

Quindi, definire un'operazione per aggiornare lo stato del prodotto in `SOLD` se la condizione in cui lo stato del prodotto è attualmente impostato su `IN_STOCK` è `true`. La configurazione del parametro `ReturnValuesOnConditionCheckFailure` restituisce l'elemento se l'attributo dello stato del prodotto dell'elemento non era uguale a `IN_STOCK`.

```
final String PRODUCT_TABLE_NAME = "ProductCatalog";
final String PRODUCT_PARTITION_KEY = "ProductId";
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
expressionAttributeValues.put(":new_status", new AttributeValue("SOLD"));
expressionAttributeValues.put(":expected_status", new AttributeValue("IN_STOCK"));

Update markItemSold = new Update()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey)
    .withUpdateExpression("SET ProductStatus = :new_status")
    .withExpressionAttributeValues(expressionAttributeValues)
    .withConditionExpression("ProductStatus = :expected_status")
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD);
```

### Creazione dell'ordine
<a name="transaction-example-order-part-c"></a>

Infine, creare l'ordine se un ordine con quell'`OrderId` non esiste già.

```
final String ORDER_PARTITION_KEY = "OrderId";
final String ORDER_TABLE_NAME = "Orders";

HashMap<String, AttributeValue> orderItem = new HashMap<>();
orderItem.put(ORDER_PARTITION_KEY, new AttributeValue(orderId));
orderItem.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));
orderItem.put(CUSTOMER_PARTITION_KEY, new AttributeValue(customerId));
orderItem.put("OrderStatus", new AttributeValue("CONFIRMED"));
orderItem.put("OrderTotal", new AttributeValue("100"));

Put createOrder = new Put()
    .withTableName(ORDER_TABLE_NAME)
    .withItem(orderItem)
    .withReturnValuesOnConditionCheckFailure(ReturnValuesOnConditionCheckFailure.ALL_OLD)
    .withConditionExpression("attribute_not_exists(" + ORDER_PARTITION_KEY + ")");
```

### Esecuzione della transazione
<a name="transaction-example-order-part-d"></a>

L'esempio seguente illustra come eseguire le azioni definite in precedenza come singola all-or-nothing operazione.

```
    Collection<TransactWriteItem> actions = Arrays.asList(
        new TransactWriteItem().withConditionCheck(checkCustomerValid),
        new TransactWriteItem().withUpdate(markItemSold),
        new TransactWriteItem().withPut(createOrder));

    TransactWriteItemsRequest placeOrderTransaction = new TransactWriteItemsRequest()
        .withTransactItems(actions)
        .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);

    // Run the transaction and process the result.
    try {
        client.transactWriteItems(placeOrderTransaction);
        System.out.println("Transaction Successful");

    } catch (ResourceNotFoundException rnf) {
        System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage());
    } catch (InternalServerErrorException ise) {
        System.err.println("Internal Server Error" + ise.getMessage());
    } catch (TransactionCanceledException tce) {
        System.out.println("Transaction Canceled " + tce.getMessage());
    }
```

## Lettura dei dettagli dell'ordine
<a name="transaction-example-read-order"></a>

L'esempio seguente mostra come leggere l'ordine completato in modo transazionale attraverso le tabelle `Orders` e `ProductCatalog`.

```
HashMap<String, AttributeValue> productItemKey = new HashMap<>();
productItemKey.put(PRODUCT_PARTITION_KEY, new AttributeValue(productKey));

HashMap<String, AttributeValue> orderKey = new HashMap<>();
orderKey.put(ORDER_PARTITION_KEY, new AttributeValue(orderId));

Get readProductSold = new Get()
    .withTableName(PRODUCT_TABLE_NAME)
    .withKey(productItemKey);
Get readCreatedOrder = new Get()
    .withTableName(ORDER_TABLE_NAME)
    .withKey(orderKey);

Collection<TransactGetItem> getActions = Arrays.asList(
    new TransactGetItem().withGet(readProductSold),
    new TransactGetItem().withGet(readCreatedOrder));

TransactGetItemsRequest readCompletedOrder = new TransactGetItemsRequest()
    .withTransactItems(getActions)
    .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);

// Run the transaction and process the result.
try {
    TransactGetItemsResult result = client.transactGetItems(readCompletedOrder);
    System.out.println(result.getResponses());
} catch (ResourceNotFoundException rnf) {
    System.err.println("One of the table involved in the transaction is not found" + rnf.getMessage());
} catch (InternalServerErrorException ise) {
    System.err.println("Internal Server Error" + ise.getMessage());
} catch (TransactionCanceledException tce) {
    System.err.println("Transaction Canceled" + tce.getMessage());
}
```

# Change Data Capture con Amazon DynamoDB
<a name="streamsmain"></a>

Molte applicazioni traggono vantaggio dalla possibilità di acquisire le modifiche apportate a elementi archiviati in una tabella DynamoDB, nel momento in cui si verificano tali modifiche. Di seguito sono riportati alcuni esempi di casi d'uso:
+ Un'applicazione per dispositivi mobili popolare modifica i dati in una tabella DynamoDB alla velocità di migliaia di aggiornamenti al secondo. Un'altra applicazione acquisisce e archivia i dati relativi a questi aggiornamenti, fornendo metriche di near-real-time utilizzo per l'app mobile.
+ Un'applicazione finanziaria modifica i dati del mercato azionario in una tabella DynamoDB. Diverse applicazioni eseguite in parallelo tracciano questi cambiamenti in tempo reale, calcolano e value-at-risk ribilanciano automaticamente i portafogli in base ai movimenti dei prezzi delle azioni.
+ I sensori nei veicoli di trasporto e nelle attrezzature industriali inviano dati a una tabella DynamoDB. Diverse applicazioni monitorano le prestazioni e inviano avvisi di messaggistica quando viene rilevato un problema, prevedono eventuali difetti applicando algoritmi di machine learning e comprimono e archiviano i dati in Amazon Simple Storage Service (Amazon S3).
+ Un'applicazione invia automaticamente notifiche ai dispositivi mobili di tutti gli amici inclusi in un gruppo non appena un amico carica una nuova immagine.
+ Un nuovo cliente aggiunge dati a una tabella DynamoDB. Questo evento richiama un'altra applicazione che invia un'e-mail di benvenuto al nuovo cliente.

DynamoDB supporta lo streaming dei record di acquisizione dei dati delle modifiche a livello di elemento in tempo quasi reale. È possibile creare applicazioni che utilizzano questi flussi e agiscono in base al contenuto.

**Nota**  
L’aggiunta di tag ai flussi DynamoDB e l’utilizzo del [controllo degli accessi basato su attributi (ABAC)](access-control-resource-based.md) con i flussi DynamoDB non sono supportati.

Il seguente video ti fornirà un'introduzione sul concetto di acquisizione dei dati di modifica.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/VVv_-mZ5Ge8/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/VVv_-mZ5Ge8)


**Topics**
+ [Opzioni di streaming per Change Data Capture](#streamsmain.choose)
+ [Utilizzo di Kinesis Data Streams per acquisire le modifiche apportate a Dynamo DB.](kds.md)
+ [Acquisizione dei dati di modifica per DynamoDB Streams](Streams.md)

## Opzioni di streaming per Change Data Capture
<a name="streamsmain.choose"></a>

DynamoDB offre due modelli di streaming per l'acquisizione dei dati delle modifiche: Kinesis Data Streams per DynamoDB e DynamoDB Streams.

Per scegliere la soluzione più adatta per l'applicazione, la tabella seguente riassume le caratteristiche di ciascun modello di streaming. 

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/streamsmain.html)

È possibile abilitare entrambi i modelli di streaming sulla stessa tabella DynamoDB.

Il video seguente analizza ulteriormente le differenze tra le due opzioni.

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/UgG17Wh2y0g/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/UgG17Wh2y0g)


# Utilizzo di Kinesis Data Streams per acquisire le modifiche apportate a Dynamo DB.
<a name="kds"></a>

Utilizzare Amazon Kinesis Data Streams per acquisire le modifiche apportate a Amazon DynamoDB.

Kinesis Data Streams acquisisce le modifiche a livello di elemento in qualsiasi tabella DynamoDB e le replica in un [flusso dei dati Kinesis](https://docs.aws.amazon.com/streams/latest/dev/introduction.html). Le applicazioni possono accedere a questo flusso e visualizzare le modifiche a livello di elemento quasi in tempo reale. Puoi acquisire e archiviare in modo continuo terabyte di dati ogni ora. Puoi sfruttare tempi di conservazione dei dati più lunghi e, grazie alla funzionalità di fan-out migliorata, puoi raggiungere contemporaneamente due o più applicazioni downstream. Altri vantaggi includono controlli aggiuntivi e trasparenza della sicurezza.

Il flusso di dati Kinesis consente inoltre di accedere ad [Amazon Data Firehose](https://docs.aws.amazon.com/firehose/latest/dev/what-is-this-service.html) e al [Servizio gestito da Amazon per Apache Flink](https://docs.aws.amazon.com/kinesisanalytics/latest/dev/what-is.html). Questi servizi consentono di creare applicazioni per utilizzare pannelli di controllo in tempo reale, generare avvisi, implementare prezzi e inserzioni dinamici ed eseguire analisi dei dati e algoritmi di machine learning sofisticati.

**Nota**  
[L'utilizzo di Kinesis Data Streams per DynamoDB è soggetto sia ai prezzi di Kinesis Data Streams per il flusso di dati che ai [prezzi di DynamoDB per](https://aws.amazon.com/kinesis/data-streams/pricing/) la tabella di origine.](https://aws.amazon.com/dynamodb/pricing/)

Per abilitare lo streaming Kinesis su una tabella DynamoDB utilizzando la console o Java SDK AWS CLI, consulta. [Nozioni di base su Kinesis Data Streams per Amazon DynamoDB](kds_gettingstarted.md)

**Topics**
+ [Funzionamento di Kinesis Data Streams con DynamoDB](#kds_howitworks)
+ [Nozioni di base su Kinesis Data Streams per Amazon DynamoDB](kds_gettingstarted.md)
+ [Utilizzo di shard e metriche con i flussi DynamoDB e il flusso di dati Kinesis](kds_using-shards-and-metrics.md)
+ [Utilizzo di policy IAM per il flusso di dati Amazon Kinesis e Amazon DynamoDB](kds_iam.md)

## Funzionamento di Kinesis Data Streams con DynamoDB
<a name="kds_howitworks"></a>

Quando un flusso dei dati Kinesis è abilitato per una tabella DynamoDB, quest'ultima invia un record di dati che acquisisce eventuali modifiche ai dati della tabella. Questo record di dati include:
+ L'ora specifica in cui qualsiasi elemento è stato creato, aggiornato o eliminato di recente
+ La chiave primaria di quell'elemento
+ Uno snapshot del record prima della modifica
+ Uno snapshot del record dopo la modifica 

Questi record di dati vengono acquisiti e pubblicati quasi in tempo reale. Dopo essere stati scritti sul flusso dei dati Kinesis, possono essere letti come qualsiasi altro record. È possibile utilizzare la Kinesis Client Library, utilizzare AWS Lambda, chiamare l'API Kinesis Data Streams e utilizzare altri servizi connessi. Per ulteriori informazioni, consulta [Lettura di dati da Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) nella Guida per gli sviluppatori di Amazon Kinesis Data Streams.

Queste modifiche dei dati vengono acquisite anche in modo asincrono. Kinesis non ha alcun impatto sulle prestazioni di una tabella da cui esegue lo streaming. I record del flusso archiviati nel flusso dei dati Kinesis sono crittografati anche a riposo. Per ulteriori informazioni, consulta [Protezione dei dati in Amazon Kinesis Data Streams](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html).

I record del flusso di dati Kinesis potrebbero essere visualizzati in un ordine diverso rispetto alle modifiche apportate all’elemento. Le notifiche dello stesso elemento potrebbero apparire anche più di una volta nel flusso. È possibile controllare l’attributo `ApproximateCreationDateTime` per identificare l’ordine in cui sono state apportate le modifiche all’elemento e i record duplicati. 

Abilitando un flusso di dati Kinesis come destinazione di streaming di una tabella DynamoDB, è possibile configurare la precisione dei valori `ApproximateCreationDateTime` in millisecondi o microsecondi. Per impostazione predefinita, `ApproximateCreationDateTime` indica l’ora della modifica in millisecondi. Inoltre, è possibile modificare questo valore su una destinazione di streaming attiva. Dopo tale aggiornamento, i record di flussi scritti su Kinesis avranno i valori `ApproximateCreationDateTime` della precisione desiderata. 

I valori binari scritti in DynamoDB devono essere codificati in [formato con codifica base64](HowItWorks.NamingRulesDataTypes.md). Tuttavia, quando i record di dati vengono scritti su un flusso di dati Kinesis, questi valori binari codificati vengono codificati una seconda volta con la codifica base64. Quando leggono questi record da un flusso di dati Kinesis, per recuperare i valori binari non elaborati, le applicazioni devono decodificare questi valori due volte.

DynamoDB addebita l’utilizzo di Kinesis Data Streams nelle unità di acquisizione dei dati di modifica. 1 KB di modifica per singolo elemento conta come un'unità di acquisizione dei dati di modifica. I KB di modifica in ogni elemento sono calcolati in base alla più grande delle immagini "prima" e "dopo" dell'elemento scritto nello stream, utilizzando la stessa logica di [consumo di unità di capacità per operazioni di scrittura](read-write-operations.md#write-operation-consumption). In modo analogo al funzionamento della modalità [on demand](capacity-mode.md#capacity-mode-on-demand) di DynamoDB, non è necessario effettuare il provisioning del throughput della capacità per le unità di acquisizione dei dati di modifica.

### Attivazione di un flusso di dati Kinesis per la tabella DynamoDB
<a name="kds_howitworks.enabling"></a>

Puoi abilitare o disabilitare lo streaming su Kinesis dalla tabella DynamoDB esistente utilizzando l' Console di gestione AWS, l' AWS SDK o il (). AWS Command Line Interface AWS CLI
+ Puoi trasmettere dati da DynamoDB a Kinesis Data Streams solo nello stesso account e nella stessa regione AWS della tabella. AWS 
+ Puoi eseguire lo streaming dei dati solo da una tabella DynamoDB a un flusso dei dati Kinesis.

  

### Applicazione di modifiche a una destinazione di un flusso di dati Kinesis su una tabella DynamoDB
<a name="kds_howitworks.makingchanges"></a>

Per impostazione predefinita, tutti i record del flusso di dati Kinesis includono un attributo `ApproximateCreationDateTime`. Questo attributo rappresenta un timestamp in millisecondi dell’ora approssimativa in cui ogni record è stato creato. È possibile modificare la precisione di questi valori utilizzando [https://console.aws.amazon.com/kinesis, l'SDK](https://console.aws.amazon.com/kinesis) o il AWS CLI 

# Nozioni di base su Kinesis Data Streams per Amazon DynamoDB
<a name="kds_gettingstarted"></a>

Questa sezione descrive come utilizzare Kinesis Data Streams per le tabelle Amazon DynamoDB con la console Amazon DynamoDB, il () e l'API AWS Command Line Interface .AWS CLI

## Creazione di un flusso di dati Amazon Kinesis attivo
<a name="kds_gettingstarted.making-changes"></a>

Tutti questi esempi utilizzano la tabella DynamoDB `Music` che è stata creata come parte del tutorial [Nozioni di base su DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html).

Per ulteriori informazioni su come creare consumatori e connettere il flusso di dati Kinesis ad altri servizi AWS , consulta [Leggere i dati dal flusso di dati Amazon Kinesis](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html), nella *Guida per gli sviluppatori del flusso di dati Amazon Kinesis*.

**Nota**  
 Quando utilizzi per la prima volta le partizioni KDS, consigliamo di impostarle in modo che aumentino o diminuiscano in base ai modelli di utilizzo. Dopo aver accumulato ulteriori dati sui modelli di utilizzo, è possibile adattare le partizioni nel flusso di conseguenza. 

------
#### [ Console ]

1. Accedi Console di gestione AWS e apri la console Kinesis all'indirizzo. [https://console.aws.amazon.com/kinesis/](https://console.aws.amazon.com/kinesis/)

1. Scegli **Crea flusso di dati** e segui le istruzioni per creare un flusso denominato `samplestream`. 

1. Apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Nel riquadro di navigazione sul lato sinistro della console scegli **Tables (Tabelle)**.

1. Seleziona la tabella **Music**.

1. Scegli la scheda **Exports and streams (Esportazioni e flussi)**.

1. (Facoltativo) Nella sezione **Dettagli del flusso di dati Amazon Kinesis**, è possibile modificare la precisione del timestamp del record da microsecondi (impostazione predefinita) a millisecondi. 

1. Scegli **samplestream** dall'elenco a discesa.

1. Seleziona il pulsante **Attiva**.

------
#### [ AWS CLI ]

1. Crea un flusso di dati Kinesis denominato `samplestream` utilizzando il comando [create-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/create-stream.html).

   ```
   aws kinesis create-stream --stream-name samplestream --shard-count 3 
   ```

   Prima di configurare il numero di partizioni per il flusso di dati Kinesis, consulta [Considerazioni sulla gestione delle partizioni per Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment).

1. Verificare che il flusso Kinesis sia attivo e pronto per l'uso utilizzando il comando [describe-stream](https://docs.aws.amazon.com/cli/latest/reference/kinesis/describe-stream.html).

   ```
   aws kinesis describe-stream --stream-name samplestream
   ```

1. Abilitare lo streaming di Kinesis sulla tabella DynamoDB utilizzando il comando DynamoDB `enable-kinesis-streaming-destination`. Sostituisci il valore `stream-arn` con quello restituito da `describe-stream` nella fase precedente. Facoltativamente, abilita lo streaming con una precisione più granulare (microsecondi) dei valori di timestamp restituiti su ogni record.

   Abilita lo streaming con la precisione del timestamp in microsecondi:

   ```
   aws dynamodb enable-kinesis-streaming-destination \
     --table-name Music \
     --stream-arn arn:aws:kinesis:us-west-2:12345678901:stream/samplestream
     --enable-kinesis-streaming-configuration ApproximateCreationDateTimePrecision=MICROSECOND
   ```

   Oppure abilita lo streaming con la precisione del timestamp predefinita (millisecondi):

   ```
   aws dynamodb enable-kinesis-streaming-destination \
     --table-name Music \
     --stream-arn arn:aws:kinesis:us-west-2:12345678901:stream/samplestream
   ```

1. Abilitare lo streaming di Kinesis sulla tabella DynamoDB utilizzando il comando `describe-kinesis-streaming-destination` DynamoDB.

   ```
   aws dynamodb describe-kinesis-streaming-destination --table-name Music
   ```

1. Scrivere i dati nella tabella DynamoDB utilizzando il comando `put-item`, come descritto nella [Guida per gli sviluppatori di DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html).

   ```
   aws dynamodb put-item \
       --table-name Music  \
       --item \
           '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}, "Awards": {"N": "1"}}'
   
   aws dynamodb put-item \
       --table-name Music \
       --item \
           '{"Artist": {"S": "Acme Band"}, "SongTitle": {"S": "Happy Day"}, "AlbumTitle": {"S": "Songs About Life"}, "Awards": {"N": "10"} }'
   ```

1. Utilizza il comando [get-record](https://docs.aws.amazon.com/cli/latest/reference/kinesis/get-records.html) della CLI di Kinesis per recuperare il contenuto del flusso Kinesis. Quindi utilizzare il seguente frammento di codice per deserializzare il contenuto del flusso.

   ```
   /**
    * Takes as input a Record fetched from Kinesis and does arbitrary processing as an example.
    */
   public void processRecord(Record kinesisRecord) throws IOException {
       ByteBuffer kdsRecordByteBuffer = kinesisRecord.getData();
       JsonNode rootNode = OBJECT_MAPPER.readTree(kdsRecordByteBuffer.array());
       JsonNode dynamoDBRecord = rootNode.get("dynamodb");
       JsonNode oldItemImage = dynamoDBRecord.get("OldImage");
       JsonNode newItemImage = dynamoDBRecord.get("NewImage");
       Instant recordTimestamp = fetchTimestamp(dynamoDBRecord);
   
       /**
        * Say for example our record contains a String attribute named "stringName" and we want to fetch the value
        * of this attribute from the new item image. The following code fetches this value.
        */
       JsonNode attributeNode = newItemImage.get("stringName");
       JsonNode attributeValueNode = attributeNode.get("S"); // Using DynamoDB "S" type attribute
       String attributeValue = attributeValueNode.textValue();
       System.out.println(attributeValue);
   }
   
   private Instant fetchTimestamp(JsonNode dynamoDBRecord) {
       JsonNode timestampJson = dynamoDBRecord.get("ApproximateCreationDateTime");
       JsonNode timestampPrecisionJson = dynamoDBRecord.get("ApproximateCreationDateTimePrecision");
       if (timestampPrecisionJson != null && timestampPrecisionJson.equals("MICROSECOND")) {
           return Instant.EPOCH.plus(timestampJson.longValue(), ChronoUnit.MICROS);
       }
       return Instant.ofEpochMilli(timestampJson.longValue());
   }
   ```

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

1. Seguire le istruzioni contenute nella guida per gli sviluppatori di Kinesis Data Streams per [creare](https://docs.aws.amazon.com/streams/latest/dev/kinesis-using-sdk-java-create-stream.html) un flusso di dati Kinesis denominato `samplestream` tramite Java.

   Prima di configurare il numero di partizioni per il flusso di dati Kinesis, consulta [Considerazioni sulla gestione delle partizioni per Kinesis Data Streams](kds_using-shards-and-metrics.md#kds_using-shards-and-metrics.shardmanagment). 

1. Utilizzo il seguente frammento di codice per abilitare lo streamingKinesis sulla tabella DynamoDB. Facoltativamente, abilita lo streaming con una precisione più granulare (microsecondi) dei valori di timestamp restituiti su ogni record. 

   Abilita lo streaming con la precisione del timestamp in microsecondi:

   ```
   EnableKinesisStreamingConfiguration enableKdsConfig = EnableKinesisStreamingConfiguration.builder()
     .approximateCreationDateTimePrecision(ApproximateCreationDateTimePrecision.MICROSECOND)
     .build();
   
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .enableKinesisStreamingConfiguration(enableKdsConfig)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

   Oppure abilita lo streaming con la precisione del timestamp predefinita (millisecondi):

   ```
   EnableKinesisStreamingDestinationRequest enableKdsRequest = EnableKinesisStreamingDestinationRequest.builder()
     .tableName(tableName)
     .streamArn(kdsArn)
     .build();
   
   EnableKinesisStreamingDestinationResponse enableKdsResponse = ddbClient.enableKinesisStreamingDestination(enableKdsRequest);
   ```

1. Segui le istruzioni contenute nella guida per gli sviluppatori di *Kinesis Data Streams* per [leggere](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html) dal flusso di dati creato.

1. Utilizza il seguente frammento di codice per deserializzare il contenuto del flusso.

   ```
   /**
    * Takes as input a Record fetched from Kinesis and does arbitrary processing as an example.
    */
   public void processRecord(Record kinesisRecord) throws IOException {
       ByteBuffer kdsRecordByteBuffer = kinesisRecord.getData();
       JsonNode rootNode = OBJECT_MAPPER.readTree(kdsRecordByteBuffer.array());
       JsonNode dynamoDBRecord = rootNode.get("dynamodb");
       JsonNode oldItemImage = dynamoDBRecord.get("OldImage");
       JsonNode newItemImage = dynamoDBRecord.get("NewImage");
       Instant recordTimestamp = fetchTimestamp(dynamoDBRecord);
   
       /**
        * Say for example our record contains a String attribute named "stringName" and we wanted to fetch the value
        * of this attribute from the new item image, the below code would fetch this.
        */
       JsonNode attributeNode = newItemImage.get("stringName");
       JsonNode attributeValueNode = attributeNode.get("S"); // Using DynamoDB "S" type attribute
       String attributeValue = attributeValueNode.textValue();
       System.out.println(attributeValue);
   }
   
   private Instant fetchTimestamp(JsonNode dynamoDBRecord) {
       JsonNode timestampJson = dynamoDBRecord.get("ApproximateCreationDateTime");
       JsonNode timestampPrecisionJson = dynamoDBRecord.get("ApproximateCreationDateTimePrecision");
       if (timestampPrecisionJson != null && timestampPrecisionJson.equals("MICROSECOND")) {
           return Instant.EPOCH.plus(timestampJson.longValue(), ChronoUnit.MICROS);
       }
       return Instant.ofEpochMilli(timestampJson.longValue());
   }
   ```

------

## Applicazione di modifiche a un flusso di dati Amazon Kinesis attivo
<a name="kds_gettingstarted.making-changes"></a>

Questa sezione descrive come apportare modifiche a una configurazione attiva di Kinesis Data Streams for DynamoDB utilizzando la console e l'API. AWS CLI 

**Console di gestione AWS**

1. Apri la console DynamoDB all'indirizzo [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Vai alla tabella.

1. Seleziona la scheda **Esportazioni e flussi**.

**AWS CLI**

1. Chiama `describe-kinesis-streaming-destination` per confermare che il flusso sia `ACTIVE`. 

1. Chiama `UpdateKinesisStreamingDestination`, come in questo esempio:

   ```
   aws dynamodb update-kinesis-streaming-destination --table-name enable_test_table --stream-arn arn:aws:kinesis:us-east-1:12345678901:stream/enable_test_stream --update-kinesis-streaming-configuration ApproximateCreationDateTimePrecision=MICROSECOND
   ```

1. Chiama `describe-kinesis-streaming-destination` per confermare che il flusso sia `UPDATING`.

1. Chiama `describe-kinesis-streaming-destination` periodicamente fino a quando lo stato dello streaming non è nuovamente `ACTIVE`. In genere sono necessari fino a 5 minuti perché gli aggiornamenti alla precisione del timestamp entrino in vigore. Una volta che lo stato è aggiornato, significa che l’aggiornamento è completo e il nuovo valore di precisione verrà applicato ai record futuri.

1. Scrivi nella tabella usando `putItem`.

1. Utilizza il comando `get-records` di Kinesis per recuperare il contenuto del flusso.

1. Verifica che `ApproximateCreationDateTime` delle scritture presenti la precisione desiderata.

**API Java**

1. Fornisci un frammento di codice che costruisce una richiesta `UpdateKinesisStreamingDestination` e una risposta `UpdateKinesisStreamingDestination`. 

1. Fornisci un frammento di codice che costruisce una richiesta `DescribeKinesisStreamingDestination` e una `DescribeKinesisStreamingDestination response`.

1. Chiama `describe-kinesis-streaming-destination` periodicamente fino a quando lo stato dello streaming non è nuovamente `ACTIVE`, a indicare che l’aggiornamento è completo e il nuovo valore di precisione verrà applicato ai record futuri.

1. Effettua le scritture sulla tabella.

1.  Effettua la lettura dal flusso e deserializza il contenuto del flusso.

1. Verifica che `ApproximateCreationDateTime` delle scritture presenti la precisione desiderata.

# Utilizzo di shard e metriche con i flussi DynamoDB e il flusso di dati Kinesis
<a name="kds_using-shards-and-metrics"></a>

## Considerazioni sulla gestione delle partizioni per Kinesis Data Streams
<a name="kds_using-shards-and-metrics.shardmanagment"></a>

Un flusso dei dati Kinesis calcola il proprio throughput in [partizioni](https://docs.aws.amazon.com/streams/latest/dev/key-concepts.html). Nel flusso di dati Amazon Kinesis è possibile scegliere tra la modalità con capacità on demand**** e la modalità **con provisioning** per i flussi di dati. 

Si consiglia di utilizzare la modalità on demand per il flusso di dati Kinesis se il carico di lavoro di scrittura di DynamoDB è altamente variabile e imprevedibile. Con la modalità on demand, non è richiesta pianificazione della capacità in quanto il flusso di dati Kinesis gestisce automaticamente gli shard per fornire il throughput necessario.

Per carichi di lavoro prevedibili è possibile utilizzare la modalità con provisioning per il flusso di dati Kinesis. Con la modalità con provisioning, è necessario specificare il numero di shard per il flusso di dati per ricevere i record di Change Data Capture da DynamoDB. Per determinare il numero di shard di cui il flusso di dati Kinesis avrà bisogno per supportare la tabella DynamoDB sono necessari i seguenti valori di input:
+ La dimensione media del record della tabella DynamoDB in byte (`average_record_size_in_bytes`).
+ Il numero massimo di operazioni di scrittura che la tabella DynamoDB eseguirà al secondo. Questo include le operazioni di creazione, eliminazione e aggiornamento eseguite dalle applicazioni, nonché le operazioni generate automaticamente come le eliminazioni generate dal Time to Live (TTL) (`write_throughput`).
+ La percentuale di operazioni di aggiornamento e sovrascrittura eseguite sulla tabella, rispetto alle operazioni di creazione o eliminazione (`percentage_of_updates`). Tieni a mente che le operazioni di aggiornamento e sovrascrittura replicano nel flusso sia le vecchie che le nuove immagini dell'elemento modificato al flusso. Questo genera il doppio della dimensione dell'elemento DynamoDB.

È possibile calcolare il numero di shard (`number_of_shards`) di cui il flusso di dati Kinesis ha bisogno utilizzando i valori di input nella formula seguente:

```
number_of_shards = ceiling( max( ((write_throughput * (4+percentage_of_updates) * average_record_size_in_bytes) / 1024 / 1024), (write_throughput/1000)), 1)
```

Ad esempio, si potrebbe avere un throughput massimo di 1040 operazioni di scrittura al secondo (`write_throughput`) con una dimensione media dei record di 800 byte (`average_record_size_in_bytes)`. Se il 25% di queste operazioni di scrittura sono operazioni di aggiornamento (`percentage_of_updates`) allora saranno necessari due shard (`number_of_shards`) per supportare il throughput di streaming DynamoDB:

```
ceiling( max( ((1040 * (4+25/100) * 800)/ 1024 / 1024), (1040/1000)), 1).
```

Considera quanto segue prima di utilizzare la formula per calcolare il numero di shard necessari con la modalità con provisioning per il flusso di dati Kinesis:
+ Questa formula aiuta a stimare il numero di shard necessari per ospitare i record di dati di modifica di DynamoDB. Non rappresenta il numero totale di shard necessari nel flusso di dati Kinesis, ad esempio gli shard necessari per supportare consumer del flusso di dati Kinesis aggiuntivi.
+ Nella modalità assegnata è possibile che si verifichino comunque eccezioni di velocità di trasmissione effettiva di lettura e scrittura se non si configura il flusso di dati per gestire i picchi di velocità di trasmissione effettiva. In questo caso, è necessario dimensionare manualmente il flusso di dati in modo da adattarlo al traffico di dati. 
+ Questa formula prende in considerazione il bloat aggiuntivo generato da DynamoDB prima di trasmettere i record di dati dei log delle modifiche ai flussi di dati Kinesis.

Per ulteriori informazioni sulle modalità di capacità sul flusso di dati Kinesis, consulta [Scelta della modalità di capacità del flusso di dati](https://docs.aws.amazon.com/streams/latest/dev/how-do-i-size-a-stream.html). Per ulteriori informazioni sulla differenza di prezzo tra le diverse modalità di capacità, consulta [Prezzi del flusso di dati Amazon Kinesis](https://aws.amazon.com/kinesis/data-streams/pricing/).

## Monitoraggio di Change Data Capture con Kinesis Data Streams
<a name="kds_using-shards-and-metrics.monitoring"></a>

DynamoDB fornisce diversi parametri CloudWatch Amazon per aiutarti a monitorare la replica dell'acquisizione dei dati di modifica su Kinesis. Per un elenco completo delle metriche, consulta. CloudWatch [Parametri e dimensioni di DynamoDB](metrics-dimensions.md)

Per determinare se il flusso dispone di capacità sufficiente, si consiglia di monitorare i seguenti elementi sia durante l'abilitazione del flusso che in produzione:
+ `ThrottledPutRecordCount`: il numero di record che sono stati limitati dal flusso dei dati Kinesis a causa della capacità insufficiente del flusso di dati Kinesis. Potrebbe verificarsi una limitazione della larghezza di banda della rete durante i picchi di utilizzo eccezionali, ma il `ThrottledPutRecordCount` dovrebbe rimanere il più basso possibile. DynamoDB prova a inviare i record con limitazione sul flusso di dati Kinesis, ma ciò potrebbe comportare una maggiore latenza di replica. 

  Se si verifica una limitazione eccessiva e regolare, potrebbe essere necessario aumentare il numero di partizioni del flusso Kinesis proporzionalmente alla velocità di scrittura osservata della tabella. Per ulteriori informazioni su come determinare le dimensioni di un flusso di dati Kinesis, consulta [Determinazione delle dimensioni iniziali di un flusso di dati Kinesis](https://docs.aws.amazon.com/streams/latest/dev/amazon-kinesis-streams.html#how-do-i-size-a-stream).
+ `AgeOfOldestUnreplicatedRecord`: il tempo trascorso dalla modifica a livello di elemento meno recente da replicare nel flusso di dati Kinesis è apparso nella tabella DynamoDB. In condizioni di funzionamento normale, `AgeOfOldestUnreplicatedRecord` dovrebbe essere nell'ordine dei millisecondi. Questo numero aumenta in base ai tentativi di replica non riusciti quando questi sono causati da scelte di configurazione controllate dal cliente.

   Se la metrica `AgeOfOldestUnreplicatedRecord` supera le 168 ore, la replica delle modifiche a livello di elemento dalla tabella DynamoDB al flusso di dati Kinesis verrà automaticamente disabilitata.

  Gli esempi di configurazioni controllate dal cliente che portano a tentativi di replica non riusciti sono una capacità del flusso dei dati Kinesis con provisioning insufficiente, che comporta una limitazione eccessiva o un aggiornamento manuale delle policy di accesso del flusso dei dati Kinesis, che impedisce a DynamoDB di aggiungere dati al flusso dei dati. Per mantenere questo parametro il più basso possibile, potrebbe essere necessario garantire il corretto provisioning della capacità del flusso di dati Kinesis e assicurarsi che le autorizzazioni di DynamoDB siano invariate. 
+ `FailedToReplicateRecordCount`: il numero di record che DynamoDB non è riuscito a replicare nel flusso dei dati Kinesis. Alcuni elementi di dimensioni superiori a 34 KB potrebbero espandersi per modificare i record di dati superiori al limite di dimensioni di 1 MB degli elementi di Kinesis Data Streams. Questo aumento delle dimensioni si verifica quando gli elementi più grandi di 34 KB includono un numero elevato di valori booleani o vuoti degli attributi. I valori booleani e vuoti degli attributi vengono archiviati come 1 byte in DynamoDB, ma si espandono fino a 5 byte quando vengono serializzati utilizzando JSON standard per la replica di Kinesis Data Streams. DynamoDB non può replicare tali record di modifica nel flusso dei dati Kinesis. DynamoDB ignora questi record di dati di modifica e continua automaticamente a replicare i record successivi. 

   

Puoi creare CloudWatch allarmi Amazon che inviano un messaggio Amazon Simple Notification Service (Amazon SNS) per la notifica quando una delle metriche precedenti supera una soglia specifica. 

# Utilizzo di policy IAM per il flusso di dati Amazon Kinesis e Amazon DynamoDB
<a name="kds_iam"></a>

La prima volta che abiliti Amazon Kinesis Data Streams per Amazon DynamoDB, DynamoDB crea automaticamente un ruolo collegato al servizio (IAM) per te. AWS Identity and Access Management Questo ruolo, `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`, consente a DynamoDB di gestire la replica delle modifiche a livello di elemento ai Kinesis Data Streams per conto dell'utente. Non eliminare questo ruolo collegato al servizio.

Per ulteriori informazioni sui ruoli collegati al servizio, consulta [Utilizzo dei ruoli collegati al servizio](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) nella *Guida per l'utente IAM*.

**Nota**  
DynamoDB non supporta le condizioni basate sui tag per le policy IAM.

Per abilitare il flusso di dati Amazon Kinesis per Amazon DynamoDB, è necessario disporre delle seguenti autorizzazioni sulla tabella:
+ `dynamodb:EnableKinesisStreamingDestination`
+ `kinesis:ListStreams`
+ `kinesis:PutRecords`
+ `kinesis:DescribeStream`

Per descrivere il flusso di dati Amazon Kinesis per Amazon DynamoDB per una determinata tabella DynamoDB, è necessario disporre delle seguenti autorizzazioni sulla tabella.
+ `dynamodb:DescribeKinesisStreamingDestination`
+ `kinesis:DescribeStreamSummary`
+ `kinesis:DescribeStream`

Per disabilitare il flusso di dati Amazon Kinesis per Amazon DynamoDB, è necessario disporre delle seguenti autorizzazioni sulla tabella.
+ `dynamodb:DisableKinesisStreamingDestination`

Per aggiornare un flusso di dati Amazon Kinesis per Amazon DynamoDB, è necessario disporre delle seguenti autorizzazioni sulla tabella.
+ `dynamodb:UpdateKinesisStreamingDestination`

Gli esempi seguenti mostrano come utilizzare le policy IAM per concedere autorizzazioni per Amazon Kinesis Data Streams per Amazon DynamoDB.

## Esempio: abilitazione di Amazon Kinesis Data Streams per Amazon DynamoDB
<a name="access-policy-kds-example1"></a>

La seguente policy IAM concede le autorizzazioni per abilitare un flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music`. Non concede le autorizzazioni per disabilitare, aggiornare o descrivere un flusso di dati Kinesis per DynamoDB per la tabella `Music`. 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "arn:aws:iam::*:role/aws-service-role/kinesisreplication.dynamodb.amazonaws.com/AWSServiceRoleForDynamoDBKinesisDataStreamsReplication",
            "Condition": {
                "StringLike": {
                    "iam:AWSServiceName": "kinesisreplication.dynamodb.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:EnableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Esempio: abilitazione di un flusso di dati Amazon Kinesis per Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

La seguente policy IAM concede le autorizzazioni per aggiornare un flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music`. Non concede le autorizzazioni per abilitare, disabilitare o descrivere un flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music`. 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:UpdateKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Esempio: disabilitazione di Amazon Kinesis Data Streams per Amazon DynamoDB
<a name="access-policy-kds-example2"></a>

La seguente policy IAM concede le autorizzazioni per aggiornare un flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music`. Non concede le autorizzazioni per abilitare, aggiornare o descrivere un flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music`. 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DisableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        }
    ]
}
```

------

## Esempio: applicazione selettiva delle autorizzazioni per il flusso di dati Amazon Kinesis per Amazon DynamoDB in base alla risorsa
<a name="access-policy-kds-example3"></a>

La seguente policy IAM concede le autorizzazioni per abilitare e descrivere il flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Music` e non concede le autorizzazioni per disabilitare il flusso di dati Amazon Kinesis per Amazon DynamoDB per la tabella `Orders`. 

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:EnableKinesisStreamingDestination",
                "dynamodb:DescribeKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Music"
        },
        {
            "Effect": "Deny",
            "Action": [
                "dynamodb:DisableKinesisStreamingDestination"
            ],
            "Resource": "arn:aws:dynamodb:us-west-2:111122223333:table/Orders"
        }
    ]
}
```

------

## Utilizzo di ruoli collegati ai servizi per Kinesis Data Streams per DynamoDB
<a name="kds-service-linked-roles"></a>

[Amazon Kinesis Data Streams per Amazon DynamoDB utilizza ruoli collegati ai servizi (IAM). AWS Identity and Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-service-linked-role) Un ruolo collegato al servizio è un tipo univoco di ruolo IAM collegato direttamente a Kinesis Data Streams per DynamoDB. I ruoli collegati ai servizi sono predefiniti da Kinesis Data Streams for DynamoDB e includono tutte le autorizzazioni richieste dal servizio per chiamare altri servizi per tuo conto. AWS 

Un ruolo collegato al servizio semplifica la configurazione di Kinesis Data Streams per DynamoDB perché non è necessario aggiungere manualmente le autorizzazioni necessarie. Kinesis Data Streams per DynamoDB definisce le autorizzazioni dei relativi ruoli associati ai servizi e, salvo diversamente definito, solo Kinesis Data Streams potrà assumere i propri ruoli. Le autorizzazioni definite includono la policy di attendibilità e la policy delle autorizzazioni che non può essere collegata a nessun'altra entità IAM.

Per informazioni sugli altri servizi che supportano i ruoli collegati ai servizi, consulta la sezione [Servizi AWS che funzionano con IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html) e cerca i servizi che riportano **Sì** nella colonna **Ruolo associato ai servizi**. Scegli **Sì** in corrispondenza di un link per visualizzare la documentazione relativa al ruolo collegato ai servizi per tale servizio.

### Autorizzazioni dei ruoli collegati ai servizi per Kinesis Data Streams per DynamoDB
<a name="slr-permissions"></a>

Kinesis Data Streams for DynamoDB utilizza il ruolo collegato al servizio denominato. **AWSServiceRoleForDynamoDBKinesisDataStreamsReplication** Lo scopo di questo ruolo collegato al servizio è di consentire ad Amazon DynamoDB di gestire la replica delle modifiche a livello di elemento al flusso di dati Kinesis per conto dell'utente.

Ai fini dell’assunzione del ruolo, il ruolo collegato al servizio `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` considera attendibili i seguenti servizi:
+ `kinesisreplication.dynamodb.amazonaws.com`

La policy delle autorizzazioni del ruolo consente a Kinesis Data Streams per DynamoDB per completare le seguenti operazioni sulle risorse specificate:
+ Operazione: `Put records and describe` su `Kinesis stream`
+ Azione: `Generate data keys` attiva per inserire dati `AWS KMS` negli stream Kinesis crittografati utilizzando chiavi generate dall'utente. AWS KMS 

[Per i contenuti esatti del documento informativo, consulta Dynamo. DBKinesis ReplicationServiceRolePolicy](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/aws-service-role/DynamoDBKinesisReplicationServiceRolePolicy)

Per consentire a un'entità IAM (come un utente, un gruppo o un ruolo) di creare, modificare o eliminare un ruolo collegato al servizio è necessario configurare le relative autorizzazioni. Per ulteriori informazioni, consulta [Autorizzazioni del ruolo collegato ai servizi](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#service-linked-role-permissions) nella *Guida per l'utente di IAM*.

### Creazione di un ruolo collegato ai servizi per Kinesis Data Streams per DynamoDB
<a name="create-slr"></a>

Non hai bisogno di creare manualmente un ruolo collegato ai servizi. Quando abiliti Kinesis Data Streams for DynamoDB nella, o nell' AWS CLI AWS API, Kinesis Data Streams for Console di gestione AWS DynamoDB crea automaticamente il ruolo collegato al servizio. 

Se elimini questo ruolo collegato al servizio, è possibile ricrearlo seguendo lo stesso processo utilizzato per ricreare il ruolo nell’account. Quando si abilita Kinesis Data Streams per DynamoDB, questo crea automaticamente il ruolo collegato ai servizi. 

### Modifica di un ruolo collegato ai servizi per Kinesis Data Streams per DynamoDB
<a name="edit-slr"></a>

Kinesis Data Streams per DynamoDB non consente di modificare il ruolo collegato ai servizi `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication`. Dopo avere creato un ruolo collegato al servizio, non sarà possibile modificarne il nome perché varie entità potrebbero farvi riferimento. È possibile tuttavia modificarne la descrizione utilizzando IAM. Per ulteriori informazioni, consulta la sezione [Modifica di un ruolo collegato ai servizi](https://docs.aws.amazon.com/IAM/latest/UserGuide/contributorinsights-service-linked-roles.html#edit-service-linked-role) nella *Guida per l'utente di IAM*.

### Eliminazione di un ruolo collegato ai servizi per Kinesis Data Streams per DynamoDB
<a name="delete-slr"></a>

Puoi anche utilizzare la console IAM, the o l'API per eliminare manualmente il ruolo collegato al servizio AWS CLI . AWS Per farlo, sarà necessario prima eseguire manualmente la pulizia delle risorse associate al ruolo collegato ai servizi e poi eliminarlo manualmente.

**Nota**  
Se il servizio Kinesis Data Streams per DynamoDB utilizza tale ruolo quando si prova a eliminare le risorse, è possibile che l'eliminazione non abbia esito positivo. In questo caso, attendi alcuni minuti e quindi ripeti l’operazione.

**Per eliminare manualmente il ruolo collegato ai servizi mediante IAM**

Utilizza la console IAM AWS CLI, o l' AWS API per eliminare il ruolo collegato al `AWSServiceRoleForDynamoDBKinesisDataStreamsReplication` servizio. Per ulteriori informazioni, consulta [Eliminazione del ruolo collegato al servizio](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html) nella *Guida per l’utente di IAM*.

# Acquisizione dei dati di modifica per DynamoDB Streams
<a name="Streams"></a>

 DynamoDB Streams acquisisce una sequenza cronologica di modifiche a livello di elemento in una tabella DynamoDB qualsiasi e le archivia in un log per un massimo di 24 ore. Le applicazioni possono accedere a questo log e visualizzare gli elementi di dati nel rispettivo stato prima e dopo la modifica, praticamente in tempo reale.

 La crittografia a riposo crittografa i dati in DynamoDB Streams. Per ulteriori informazioni, consulta [Crittografia a riposo per DynamoDB](EncryptionAtRest.md).

Un *flusso DynamoDB* è un flusso ordinato di informazioni sulle modifiche apportate agli elementi in una tabella DynamoDB. Quando si abilita un flusso in una tabella, DynamoDB acquisisce informazioni su ogni modifica apportata agli elementi di dati nella tabella.

Ogni volta che un'applicazione crea, aggiorna o elimina elementi nella tabella, DynamoDB Streams scrive un record di flusso con gli attributi della chiave primaria degli elementi che sono stati modificati. Un *record di flusso* contiene informazioni su una modifica di dati apportata a un singolo elemento in una tabella DynamoDB. Puoi configurare il flusso in modo che i record di flusso acquisiscano informazioni aggiuntive, come le immagini "prima" e "dopo" degli elementi modificati.

DynamoDB Streams garantisce quanto segue:
+ Ogni record di flusso viene visualizzato esattamente una volta nel flusso.
+ Per ogni elemento modificato in una tabella DynamoDB, i record di flusso vengono visualizzati nella stessa sequenza delle modifiche effettive apportate all'elemento.

DynamoDB Streams scrive i record di flusso praticamente in tempo reale per permettere di creare applicazioni che utilizzano questi flussi e agiscono in base al contenuto.

**Topics**
+ [Endpoint per DynamoDB Streams](#Streams.Endpoints)
+ [Abilitazione di un flusso](#Streams.Enabling)
+ [Lettura ed elaborazione di un flusso](#Streams.Processing)
+ [DynamoDB Streams e Time to Live](time-to-live-ttl-streams.md)
+ [Utilizzo dell'adattatore DynamoDB Streams Kinesis per elaborare i record di flusso](Streams.KCLAdapter.md)
+ [API di basso livello DynamoDB Streams: esempio Java](Streams.LowLevel.Walkthrough.md)
+ [Streams e trigger DynamoDB AWS Lambda](Streams.Lambda.md)
+ [Flussi DynamoDB e Apache Flink](StreamsApacheFlink.xml.md)

## Endpoint per DynamoDB Streams
<a name="Streams.Endpoints"></a>

AWS mantiene endpoint separati per DynamoDB e DynamoDB Streams. Per usare tabelle e indici di database, l'applicazione deve accedere a un endpoint DynamoDB. Per leggere ed elaborare i record di DynamoDB Streams, l'applicazione deve accedere a un endpoint DynamoDB Streams nella stessa regione.

DynamoDB Streams offre due set di endpoint. Questi sono:
+ **IPv4-only endpoint: endpoint** con la convenzione di denominazione. `streams.dynamodb.<region>.amazonaws.com`
+ Endpoint **dual-stack: nuovi endpoint** compatibili con entrambi e che seguono la convenzione di denominazione. IPv4 IPv6 `streams-dynamodb.<region>.api.aws`

**Nota**  
Per l'elenco completo delle regioni e degli endpoint di DynamoDB e DynamoDB Streams, consulta [Regioni ed endpoint](https://docs.aws.amazon.com/general/latest/gr/rande.html) in *Riferimenti generali di AWS*.

 AWS SDKs Forniscono client separati per DynamoDB e DynamoDB Streams. A seconda dei requisiti, l'applicazione può accedere a un endpoint DynamoDB, a un endpoint DynamoDB Streams o a entrambi contemporaneamente. Per connettersi a entrambi gli endpoint, l'applicazione deve creare un'istanza di due client, uno per DynamoDB e uno per DynamoDB Streams.

## Abilitazione di un flusso
<a name="Streams.Enabling"></a>

È possibile abilitare uno stream su una nuova tabella quando lo si crea utilizzando o uno dei AWS CLI . AWS SDKs È inoltre possibile abilitare o disabilitare un flusso in una tabella esistente oppure modificare le impostazioni di un flusso. DynamoDB Streams opera in modo asincrono, pertanto non vi è alcun impatto sulle prestazioni di una tabella se si abilita un flusso.

Il modo più semplice per gestire DynamoDB Streams consiste nell'usare la Console di gestione AWS.

1. Accedi Console di gestione AWS e apri la console DynamoDB all'indirizzo. [https://console.aws.amazon.com/dynamodb/](https://console.aws.amazon.com/dynamodb/)

1. Nel pannello di controllo della console DynamoDB, scegli **Tabelle** e seleziona una tabella esistente.

1. Scegli la scheda **Exports and streams (Esportazioni e flussi)**.

1. Nella sezione **Dettagli del flusso DynamoDB**, seleziona **Attiva.**

1. Nella pagina **Attiva il flusso DynamoDB**, seleziona le informazioni che verranno scritte nel flusso a ogni modifica dei dati nella tabella:
   + **Key attributes only (Solo attributi chiave)**: solo gli attributi chiave dell'elemento modificato.
   + **Nuova immagine**: l'intero elemento, così come visualizzato dopo che è stato modificato.
   + **Vecchia immagine**: l'intero elemento, così come visualizzato prima della modifica.
   + **Immagini nuove e vecchie**: le immagini dell'elemento nuove e vecchie.

   Dopo aver configurato le impostazioni, seleziona **Attiva il flusso**.

1. (Facoltativo) Per disabilitare un flusso esistente, seleziona **Disattiva**in **Dettagli del flusso DynamoDB**.

Per abilitare o modificare un flusso, puoi anche usare le operazioni API `CreateTable` o `UpdateTable`. Il parametro `StreamSpecification` determina la configurazione del flusso:
+ `StreamEnabled`: specifica se un flusso è abilitato (`true`) o disabilitato (`false`) per la tabella.
+ `StreamViewType`: specifica le informazioni che verranno scritte nel flusso a ogni modifica dei dati nella tabella:
  + `KEYS_ONLY`: solo gli attributi chiave dell'elemento modificato.
  + `NEW_IMAGE`: l'intero elemento, così come visualizzato dopo che è stato modificato.
  + `OLD_IMAGE`: l'intero elemento, così come visualizzato prima della modifica.
  + `NEW_AND_OLD_IMAGES`: le immagini dell'elemento nuove e vecchie.

Puoi abilitare o disabilitare un flusso in qualsiasi momento. Tuttavia, se provi ad abilitare un flusso in una tabella che include già un flusso riceverai un'eccezione `ValidationException`. Inoltre, se si tenta di disabilitare un flusso in una tabella che non include alcun flusso, verrà mostrata un’eccezione `ValidationException`.

Quando `StreamEnabled` viene impostato su `true`, DynamoDB crea un nuovo flusso con un descrittore di flusso univoco assegnato. Se disabiliti e quindi riabiliti un flusso nella tabella, viene creato un nuovo flusso con un descrittore di flusso diverso.

Ogni flusso è identificato in modo univoco da un Amazon Resource Name (ARN). Di seguito è riportato un ARN di esempio per un flusso in una tabella DynamoDB denominata `TestTable`.

```
arn:aws:dynamodb:us-west-2:111122223333:table/TestTable/stream/2015-05-11T21:21:33.291
```

Per determinare l'ultimo descrittore di flusso per una tabella, inviare una richiesta `DescribeTable` DynamoDB e cercare l'elemento `LatestStreamArn` nella risposta.

**Nota**  
Non è possibile modificare un `StreamViewType` una volta configurato un flusso. Se è necessario apportare modifiche a un flusso dopo che è stato configurato, è necessario disabilitare il flusso corrente e crearne uno nuovo.

## Lettura ed elaborazione di un flusso
<a name="Streams.Processing"></a>

Per leggere ed elaborare un flusso, l'applicazione deve connettersi a un endpoint DynamoDB Streams ed emettere le richieste API.

Un flusso è costituito da *record di flusso*. Ogni record di flusso rappresenta una singola modifica dei dati nella tabella DynamoDB cui appartiene il flusso. A ogni record di flusso è assegnato un numero in sequenza, corrispondente all'ordine in cui il record è stato pubblicato nel flusso.

I record di flusso sono organizzati in gruppi o *shard*. Ogni shard funge da container per più record di flusso e contiene le informazioni necessarie per l'accesso e l'iterazione attraverso i record. I record di flusso all'interno di uno shard vengono automaticamente rimossi dopo 24 ore.

Gli shard sono effimeri, ovvero vengono creati ed eliminati automaticamente in base alle necessità. Qualsiasi shard può anche essere suddiviso in più nuovi shard e anche questa operazione viene eseguita automaticamente. È anche possibile che per uno shard padre esista un solo shard figlio. Uno shard può essere suddiviso in risposta a livelli elevati di attività di scrittura nella tabella padre corrispondente, in modo che le applicazioni possano elaborare record da più shard in parallelo.

Se disabiliti un flusso, tutti gli shard aperti verranno chiusi. I dati nel flusso continueranno a essere leggibili per 24 ore.

Poiché gli shard hanno una derivazione (padre e figlio), un'applicazione deve sempre elaborare uno shard padre prima dello shard figlio. In questo modo, anche l'elaborazione dei record di flusso avviene sicuramente in base all'ordine corretto. Se si utilizza DynamoDB Streams Kinesis Adapter, questa operazione viene gestita automaticamente. L'applicazione elabora le partizioni e i record di flusso nell'ordine corretto e gestisce automaticamente partizioni nuove o scadute, nonché le partizioni che vengono suddivise durante l'esecuzione dell'applicazione. Per ulteriori informazioni, consultare[Utilizzo dell'adattatore DynamoDB Streams Kinesis per elaborare i record di flusso](Streams.KCLAdapter.md).

Il diagramma seguente mostra la relazione tra un flusso, gli shard nel flusso e i record di flusso negli shard.

![\[Struttura dei flussi DynamoDB. I record dei flussi che rappresentano le modifiche dei dati sono organizzati in shard.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/streams-terminology.png)


**Nota**  
Se si esegue un'operazione `PutItem` o `UpdateItem` che non modifica alcun dato in un elemento, DynamoDB Streams *non* scrive un record di flusso per tale operazione.

Per accedere a un flusso ed elaborare i record di flusso al suo interno, devi eseguire queste operazioni:
+ Determinare l'ARN univoco del flusso a cui vuoi accedere.
+ Determinare quali shard nel flusso contengono i record di flusso che ti interessano.
+ Accedi alle partizioni e recupera i record di flusso desiderati.

**Nota**  
Non più di due processi devono leggere dalla stessa partizione di flussi contemporaneamente. La presenza di più di due lettori per shard può causare il throttling.

L'API DynamoDB Streams fornisce le operazioni seguenti, che possono essere usate dai programmi applicativi:
+  `[ListStreams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_ListStreams.html)`: restituisce un elenco dei descrittori di flusso per il conto corrente e l'endpoint. Puoi facoltativamente richiedere solo i descrittori di flusso per un nome di tabella specifico.
+ `[DescribeStream](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_DescribeStream.html)`: restituisce informazioni su un flusso, inclusi lo stato attuale del flusso, il suo nome della risorsa Amazon (ARN), la composizione dei suoi shard e la corrispondente tabella su DynamoDB. Facoltativamente, è possibile utilizzare il campo `ShardFilter` per recuperare lo shard secondario esistente associato allo shard principale.
+ `[GetShardIterator](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetShardIterator.html)`: restituisce un *iteratore di partizioni*, che descrive una posizione all'interno di una partizione. Puoi richiedere che l'iterazione fornisca accesso al punto meno recente, al punto più recente o a un punto particolare nel flusso.
+ `[GetRecords](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_GetRecords.html)`: restituisce i record di flusso in una determinata partizione. Devi specificare l'iterazione shard restituita da una richiesta `GetShardIterator`.

Per la descrizione completa di queste operazioni API, incluse le richieste e le risposte di esempio, consulta la [Documentazione di riferimento delle API di Amazon DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Operations_Amazon_DynamoDB_Streams.html).

### Individuazione di shard
<a name="Streams.ShardDiscovery"></a>



Come individuare nuovi shard in un flusso DynamoDB con due potenti metodi. Gli utenti dei flussi Amazon DynamoDB hanno a disposizione due modi efficaci per tracciare e identificare nuovi shard:

**Polling della topologia dell’intero flusso**  
Utilizzo dell’API `DescribeStream` per eseguire regolarmente il polling del flusso. Questa operazione restituisce tutti gli shard del flusso, inclusi tutti i nuovi shard creati. Confrontando i risultati nel tempo è possibile rilevare i nuovi shard aggiunti.

**Individuazione di shard secondari**  
Usa l’API `DescribeStream`con il parametro `ShardFilter` per trovare un sottoinsieme di shard. Specificando uno shard principale nella richiesta, i flussi DynamoDB restituiranno i relativi shard secondari immediati. Questo approccio è utile quando è necessario solo tracciare la derivazione degli shard senza scansionare l’intero flusso.   
Le applicazioni che utilizzano dati dai flussi DynamoDB possono passare in modo efficiente dalla lettura di uno shard chiuso al relativo shard secondario utilizzando questo parametro `ShardFilter`, evitando chiamate ripetute all’API `DescribeStream` per recuperare e attraversare la mappa degli shard per tutti gli shard chiusi e aperti. Questo aiuta a individuare rapidamente gli shard secondari dopo la chiusura di uno shard principale, rendendo le applicazioni di elaborazione dei flussi più reattive e convenienti.

Entrambi i metodi consentono di rimanere aggiornati sulla struttura in evoluzione dei propri flussi DynamoDB, assicurandosi di non perdere mai aggiornamenti cruciali dei dati o modifiche agli shard.

### Limite di conservazione dei dati per DynamoDB Streams
<a name="Streams.DataRetention"></a>

Tutti i dati in DynamoDB Streams hanno una durata di 24 ore. Puoi recuperare e analizzare le ultime 24 ore di attività per qualsiasi tabella specifica. Tuttavia, i dati più vecchi di 24 ore sono soggetti a taglio (rimozione) in qualsiasi momento.

Se disabiliti un flusso in una tabella, i dati nel flusso restano leggibili per 24 ore. Dopo questo intervallo di tempo, i dati scadono e i record di flusso vengono automaticamente eliminati. Non esiste un meccanismo per eliminare manualmente un flusso esistente. Devi attendere fino allo scadere del limite di conservazione (24 ore) perché tutti i record di flusso vengano eliminati.

# DynamoDB Streams e Time to Live
<a name="time-to-live-ttl-streams"></a>

È possibile eseguire il backup o elaborare gli elementi che sono stati eliminati da [Time to Live](TTL.md) (TTL, Time to Live) abilitando Amazon DynamoDB Streams sulla tabella ed elaborando i record di flusso degli elementi scaduti. Per ulteriori informazioni, consulta [Lettura ed elaborazione di un flusso](Streams.md#Streams.Processing).

Il record Streams contiene un campo di identità utente `Records[<index>].userIdentity`.

Gli elementi eliminati dal processo Time to Live (TTL, Time to Live) dopo la scadenza hanno i seguenti campi:
+ `Records[<index>].userIdentity.type`

  `"Service"`
+ `Records[<index>].userIdentity.principalId`

  `"dynamodb.amazonaws.com"`

**Nota**  
Quando si utilizza il TTL in una tabella globale, il campo `userIdentity` verrà impostato nella Regione in cui è stato eseguito il TTL. Questo campo non verrà impostato in altre Regioni quando l’eliminazione viene replicata.

Il JSON seguente mostra la porzione rilevante di un singolo record Streams.

```
"Records": [
    {
        ...

        "userIdentity": {
            "type": "Service",
            "principalId": "dynamodb.amazonaws.com"
        }

        ...

    }
]
```

## Utilizzo di DynamoDB Streams e Lambda per archiviare gli elementi eliminati TTL
<a name="streams-archive-ttl-deleted-items"></a>

La combinazione di [DynamoDB Time to Live (TTL)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html), [DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html) e [AWS Lambda](https://aws.amazon.com/lambda/) può contribuire a semplificare l'archiviazione dei dati, ridurre i costi di storage DynamoDB e ridurre la complessità del codice. L'utilizzo di Lambda come consumatore di flussi offre molti vantaggi, in particolare la riduzione dei costi rispetto ad altri consumatori come Kinesis Client Library (KCL). Non ti viene addebitato alcun costo per le chiamate API `GetRecords` sul flusso DynamoDB quando si utilizza Lambda per consumare eventi e Lambda può fornire il filtraggio degli eventi identificando i modelli JSON in un evento stream. Attraverso il filtraggio dei contenuti del modello di eventi, è possibile definire fino a cinque filtri diversi per controllare quali eventi vengono inviati a Lambda per l'elaborazione. Ciò aiuta a ridurre le invocazioni delle funzioni Lambda, semplifica il codice e riduce i costi complessivi.

Sebbene DynamoDB Streams contenga tutte le modifiche ai dati, ad esempio `Create`, `Modify` e le azioni `Remove`, questo può causare invocazioni indesiderate della funzione Lambda di archivio. Ad esempio, supponiamo di avere una tabella con 2 milioni di modifiche ai dati all'ora che fluiscono nello stream, ma meno del 5% di queste sono eliminazioni di elementi che scadranno durante il processo TTL e devono essere archiviate. Con [Filtri di origine evento Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html), la funzione Lambda richiamerà solo 100.000 volte all'ora. Il risultato con il filtraggio degli eventi è che ti vengono addebitati solo le invocazioni necessarie anziché i 2 milioni di invocazioni che avresti avuto senza filtraggio degli eventi.

Il filtraggio degli eventi viene applicato alla [mappatura di origine evento Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventsourcemapping.html), una risorsa che legge da un evento scelto, ovvero il flusso DynamoDB, e invoca una funzione Lambda. Nel diagramma seguente, puoi vedere come un elemento eliminato Time to Live viene consumato da una funzione Lambda utilizzando flussi e filtri eventi.

![\[Un elemento eliminato tramite il processo TTL avvia una funzione Lambda che utilizza flussi e filtri di eventi.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/streams-lambda-ttl.png)


### Modello di filtro evento DynamoDB Time to Live
<a name="ttl-event-filter-pattern"></a>

L'aggiunta del seguente JSON ai [criteri di filtro](https://docs.aws.amazon.com/lambda/latest/dg/API_FilterCriteria.html) della mappatura dell'origine eventi consente l'invocazione della funzione Lambda solo per gli elementi eliminati dal TTL:

```
{
    "Filters": [
        {
            "Pattern": { "userIdentity": { "type": ["Service"], "principalId": ["dynamodb.amazonaws.com"] } }
        }
    ]
}
```

### AWS Lambda Crea una mappatura delle sorgenti degli eventi
<a name="create-event-source-mapping"></a>

Utilizza i seguenti frammenti di codice per creare una mappatura dell'origine eventi filtrata che è possibile connettere al flusso DynamoDB di una tabella. Ciascun blocco di codice include il modello di filtro eventi.

------
#### [ AWS CLI ]

```
aws lambda create-event-source-mapping \
--event-source-arn 'arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000' \
--batch-size 10 \
--enabled \
--function-name test_func \
--starting-position LATEST \
--filter-criteria '{"Filters": [{"Pattern": "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}"}]}'
```

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

```
LambdaClient client = LambdaClient.builder()
        .region(Region.EU_WEST_1)
        .build();

Filter userIdentity = Filter.builder()
        .pattern("{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}")
        .build();

FilterCriteria filterCriteria = FilterCriteria.builder()
        .filters(userIdentity)
        .build();

CreateEventSourceMappingRequest mappingRequest = CreateEventSourceMappingRequest.builder()
        .eventSourceArn("arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000")
        .batchSize(10)
        .enabled(Boolean.TRUE)
        .functionName("test_func")
        .startingPosition("LATEST")
        .filterCriteria(filterCriteria)
        .build();

try{
    CreateEventSourceMappingResponse eventSourceMappingResponse = client.createEventSourceMapping(mappingRequest);
    System.out.println("The mapping ARN is "+eventSourceMappingResponse.eventSourceArn());

}catch (ServiceException e){
    System.out.println(e.getMessage());
}
```

------
#### [ Node ]

```
const client = new LambdaClient({ region: "eu-west-1" });

const input = {
    EventSourceArn: "arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000",
    BatchSize: 10,
    Enabled: true,
    FunctionName: "test_func",
    StartingPosition: "LATEST",
    FilterCriteria: { "Filters": [{ "Pattern": "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}" }] }
}

const command = new CreateEventSourceMappingCommand(input);

try {
    const results = await client.send(command);
    console.log(results);
} catch (err) {
    console.error(err);
}
```

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

```
session = boto3.session.Session(region_name = 'eu-west-1')
client = session.client('lambda')

try:
    response = client.create_event_source_mapping(
        EventSourceArn='arn:aws:dynamodb:eu-west-1:012345678910:table/test/stream/2021-12-10T00:00:00.000',
        BatchSize=10,
        Enabled=True,
        FunctionName='test_func',
        StartingPosition='LATEST',
        FilterCriteria={
            'Filters': [
                {
                    'Pattern': "{\"userIdentity\":{\"type\":[\"Service\"],\"principalId\":[\"dynamodb.amazonaws.com\"]}}"
                },
            ]
        }
    )
    print(response)
except Exception as e:
    print(e)
```

------
#### [ JSON ]

```
{
  "userIdentity": {
     "type": ["Service"],
     "principalId": ["dynamodb.amazonaws.com"]
   }
}
```

------

# Utilizzo dell'adattatore DynamoDB Streams Kinesis per elaborare i record di flusso
<a name="Streams.KCLAdapter"></a>

L'utilizzo di Amazon Kinesis Adapter è il modo consigliato per utilizzare flussi da Amazon DynamoDB. L’API dei flussi DynamoDB è progettata in maniera simile a quella del flusso di dati Kinesis. In entrambi i servizi, i flussi di dati sono composti da partizioni, che sono container per i record di flusso. Entrambi i servizi APIs contengono`ListStreams`, `DescribeStream``GetShards`, e `GetShardIterator` operazioni. Sebbene queste operazioni DynamoDB Streams siano simili alle loro controparti in Kinesis Data Streams, non sono identiche al 100%.

Come utente di DynamoDB Streams, è possibile utilizzare i modelli di progettazione presenti all'interno di KCL per elaborare partizioni e record di flusso DynamoDB Streams. Per fare ciò, si utilizza l'adattatore Kinesis DynamoDB Streams. L'adattatore Kinesis implementa l'interfaccia Kinesis Data Streams in modo che si possa utilizzare KCL per l'uso e l'elaborazione di record da DynamoDB Streams. [Per istruzioni su come configurare e installare il DynamoDB Streams Kinesis Adapter, consulta il repository. GitHub](https://github.com/awslabs/dynamodb-streams-kinesis-adapter)

È possibile scrivere applicazioni per Kinesis Data Streams utilizzando la libreria client Kinesis (Kinesis Client Library, KCL). KCL semplifica la codifica fornendo astrazioni utili sull'API Kinesis Data Streams di basso livello. Per ulteriori informazioni su KCL, consulta [Sviluppo di consumatori utilizzando la libreria client Kinesis](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) nella *Guida per gli sviluppatori di Amazon Kinesis Data Streams*.

DynamoDB consiglia di utilizzare la versione 3.x di KCL con SDK AWS for Java v2.x. [L'attuale versione 1.x di DynamoDB Streams Kinesis Adapter con AWS SDK per Java SDK per la versione AWS 1.x continuerà a essere pienamente supportata per tutto il suo ciclo di vita, come previsto durante il periodo di transizione in linea con la politica di manutenzione degli strumenti.AWS SDKs ](https://docs.aws.amazon.com/sdkref/latest/guide/maint-policy.html)

**Nota**  
Le versioni 1.x e 2.x di Amazon KCL sono obsolete. end-of-supportKCL 1.x sarà disponibile il 30 gennaio 2026. Si consiglia vivamente di migrare le applicazioni KCL che utilizzano la versione 1.x all’ultima versione KCL prima del 30 gennaio 2026. Per trovare la versione più recente di KCL, consulta la pagina [Amazon Kinesis Client](https://github.com/awslabs/amazon-kinesis-client) Library su. GitHub Per informazioni sulle versioni più recenti di Kinesis Client Library, consulta [Use Kinesis Client Library](https://docs.aws.amazon.com/streams/latest/dev/kcl.html). Per ulteriori informazioni sulla migrazione da KCL 1.x a 3.x, consulta Migrating from KCL 1.x to KCL 3.x.

Nel seguente diagramma viene illustrato come queste librerie interagiscono tra loro.

![\[Interazione tra flussi DynamoDB, flusso di dati Kinesis e KCL per l’elaborazione dei record dei flussi DynamoDB.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/streams-kinesis-adapter.png)


Con l'adattatore Kinesis DynamoDB Streams abilitato, è possibile iniziare a sviluppare rispetto a KCL, con le chiamate API dirette senza soluzione di continuità all'endpoint DynamoDB Streams.

Quando si avvia l'applicazione , quest'ultima richiama la libreria KCL per creare un'istanza di un worker. È necessario fornire al lavoratore le informazioni di configurazione per l'applicazione, come il descrittore di flusso e AWS le credenziali, e il nome di una classe di processore di record fornita. Durante l'esecuzione del codice nel processore di record, il worker completa le seguenti attività:
+ Si collega al flusso
+ Enumera le partizioni all'interno del flusso
+ Controlla ed enumera gli shard secondari di uno shard principale chiuso all’interno del flusso
+ Coordina le associazioni di shard con altri processi di lavoro (se presenti)
+ Crea istanze di un elaboratore di record per ogni shard che gestisce
+ Estrae i record di dati dal flusso
+ Scala la velocità di chiamata delle GetRecords API durante un throughput elevato (se è configurata la modalità catch-up)
+ Inserisce i record nell'elaboratore di record corrispondente
+ Controlla i record elaborati
+ Bilancia le associazioni tra shard e processi di lavoro quando il conteggio delle istanze del lavoro cambia
+ Bilancia le associazioni tra partizioni e worker quando le partizioni sono suddivise

L'adattatore KCL supporta la modalità catch-up, una funzione di regolazione automatica della frequenza di chiamata per gestire aumenti temporanei della velocità di trasmissione. Quando il ritardo di elaborazione del flusso supera una soglia configurabile (impostazione predefinita: un minuto), la modalità catch-up ridimensiona la frequenza di chiamata dell' GetRecords API in base a un valore configurabile (impostazione predefinita 3x) per recuperare i record più velocemente, quindi torna alla normalità una volta che il ritardo diminuisce. Ciò è utile durante i periodi ad alto throughput in cui l'attività di scrittura di DynamoDB può sopraffare i consumatori utilizzando i tassi di polling predefiniti. La modalità Catch-up può essere abilitata tramite il parametro di configurazione (default false). `catchupEnabled`

**Nota**  
Per una descrizione dei concetti su KCL elencati qui, consulta [Sviluppo di consumatori utilizzando la libreria client Kinesis](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) nella *Guida per gli sviluppatori di Amazon Kinesis Data Streams*.  
Per ulteriori informazioni sull'utilizzo degli stream, vedere AWS Lambda [Streams e trigger DynamoDB AWS Lambda](Streams.Lambda.md)

# Migrazione di KLC da 1.x a 3.x
<a name="streams-migrating-kcl"></a>

## Panoramica di
<a name="migrating-kcl-overview"></a>

Questa guida fornisce istruzioni per la migrazione dell’applicazione consumer da KCL 1.x a KCL 3.x. A causa delle differenze di architettura tra KCL 1.x e KCL 3.x, la migrazione richiede l’aggiornamento di diversi componenti per garantire la compatibilità.

KCL 1.x utilizza classi e interfacce diverse rispetto a KCL 3.x. È necessario prima migrare l’elaboratore di record, il generatore dell’elaboratore di record e le classi di lavoratori al formato compatibile con KCL 3.x e seguire la procedura di migrazione per la migrazione da KCL 1.x a KCL 3.x.

## Fasi della migrazione
<a name="migration-steps"></a>

**Topics**
+ [Fase 1: migrare l’elaboratore di record](#step1-record-processor)
+ [Fase 2: migrare il generatore dell’elaboratore di record](#step2-record-processor-factory)
+ [Fase 3: eseguire la migrazione del lavoratore](#step3-worker-migration)
+ [Fase 4: panoramica e consigli sulla configurazione di KCL 3.x](#step4-configuration-migration)
+ [Fase 5: migrare da KCL 2.x a KCL 3.x](#step5-kcl2-to-kcl3)

### Fase 1: migrare l’elaboratore di record
<a name="step1-record-processor"></a>

L’esempio seguente mostra un elaboratore di record implementato per l’Adattatore Kinesis per i flussi DynamoDB con KCL 1.x:

```
package com.amazonaws.kcl;

import com.amazonaws.services.kinesis.clientlibrary.exceptions.InvalidStateException;
import com.amazonaws.services.kinesis.clientlibrary.exceptions.ShutdownException;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.IRecordProcessorCheckpointer;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware;
import com.amazonaws.services.kinesis.clientlibrary.lib.worker.ShutdownReason;
import com.amazonaws.services.kinesis.clientlibrary.types.InitializationInput;
import com.amazonaws.services.kinesis.clientlibrary.types.ProcessRecordsInput;
import com.amazonaws.services.kinesis.clientlibrary.types.ShutdownInput;

public class StreamsRecordProcessor implements IRecordProcessor, IShutdownNotificationAware {
    @Override
    public void initialize(InitializationInput initializationInput) {
        //
        // Setup record processor
        //
    }

    @Override
    public void processRecords(ProcessRecordsInput processRecordsInput) {
        for (Record record : processRecordsInput.getRecords()) {
            String data = new String(record.getData().array(), Charset.forName("UTF-8"));
            System.out.println(data);
            if (record instanceof RecordAdapter) {
                // record processing and checkpointing logic
            }
        }
    }

    @Override
    public void shutdown(ShutdownInput shutdownInput) {
        if (shutdownInput.getShutdownReason() == ShutdownReason.TERMINATE) {
            try {
                shutdownInput.getCheckpointer().checkpoint();
            } catch (ShutdownException | InvalidStateException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void shutdownRequested(IRecordProcessorCheckpointer checkpointer) {
        try {
            checkpointer.checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow exception
            //
            e.printStackTrace();
        }
    }
}
```

**Per migrare la classe RecordProcessor**

1. Modifica le interfacce da `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor` e `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware` verso `com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor` come segue:

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
   // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IShutdownNotificationAware;
   
   import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
   ```

1. Aggiorna le istruzioni di importazione per i metodi `initialize` e `processRecords`:

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.types.InitializationInput;
   import software.amazon.kinesis.lifecycle.events.InitializationInput;
   
   // import com.amazonaws.services.kinesis.clientlibrary.types.ProcessRecordsInput;
   import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
   ```

1. Sostituisci il metodo `shutdownRequested` con i seguenti nuovi metodi: `leaseLost`, `shardEnded` e `shutdownRequested`.

   ```
   //    @Override
   //    public void shutdownRequested(IRecordProcessorCheckpointer checkpointer) {
   //        //
   //        // This is moved to shardEnded(...) and shutdownRequested(ShutdownReauestedInput)
   //        //
   //        try {
   //            checkpointer.checkpoint();
   //        } catch (ShutdownException | InvalidStateException e) {
   //            //
   //            // Swallow exception
   //            //
   //            e.printStackTrace();
   //        }
   //    }
   
       @Override
       public void leaseLost(LeaseLostInput leaseLostInput) {
   
       }
   
       @Override
       public void shardEnded(ShardEndedInput shardEndedInput) {
           try {
               shardEndedInput.checkpointer().checkpoint();
           } catch (ShutdownException | InvalidStateException e) {
               //
               // Swallow the exception
               //
               e.printStackTrace();
           }
       }
   
       @Override
       public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
           try {
               shutdownRequestedInput.checkpointer().checkpoint();
           } catch (ShutdownException | InvalidStateException e) {
               //
               // Swallow the exception
               //
               e.printStackTrace();
           }
       }
   ```

Segue la versione aggiornata della classe dell’elaboratore di record:

```
package com.amazonaws.codesamples;

import software.amazon.kinesis.exceptions.InvalidStateException;
import software.amazon.kinesis.exceptions.ShutdownException;
import software.amazon.kinesis.lifecycle.events.InitializationInput;
import software.amazon.kinesis.lifecycle.events.LeaseLostInput;
import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
import software.amazon.kinesis.lifecycle.events.ShardEndedInput;
import software.amazon.kinesis.lifecycle.events.ShutdownRequestedInput;
import software.amazon.dynamodb.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import software.amazon.dynamodb.streamsadapter.adapter.DynamoDBStreamsKinesisClientRecord;
import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import com.amazonaws.services.dynamodbv2.streamsadapter.adapter.DynamoDBStreamsClientRecord;
import software.amazon.awssdk.services.dynamodb.model.Record;

public class StreamsRecordProcessor implements DynamoDBStreamsShardRecordProcessor {

    @Override
    public void initialize(InitializationInput initializationInput) {
        
    }

    @Override
    public void processRecords(DynamoDBStreamsProcessRecordsInput processRecordsInput) {
        for (DynamoDBStreamsKinesisClientRecord record: processRecordsInput.records())
            Record ddbRecord = record.getRecord();
            // processing and checkpointing logic for the ddbRecord
        }
    }

    @Override
    public void leaseLost(LeaseLostInput leaseLostInput) {
        
    }

    @Override
    public void shardEnded(ShardEndedInput shardEndedInput) {
        try {
            shardEndedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow the exception
            //
            e.printStackTrace();
        }
    }

    @Override
    public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
        try {
            shutdownRequestedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            //
            // Swallow the exception
            //
            e.printStackTrace();
        }
    }
}
```

**Nota**  
L'adattatore Kinesis di DynamoDB Streams ora utilizza il modello Record. SDKv2 In SDKv2, `AttributeValue` gli oggetti complessi (,`BS`,, `NS` `M``L`,`SS`) non restituiscono mai null. Utilizza i metodi `hasBs()`, `hasNs()`, `hasM()`, `hasL()`, `hasSs()` per verificare se questi valori esistono.

### Fase 2: migrare il generatore dell’elaboratore di record
<a name="step2-record-processor-factory"></a>

La fabbrica dell'elaboratore di record è responsabile per la creazione di elaboratori di record quando un lease è acquisito. Di seguito è illustrato un esempio di un generatore di KCL 1.x:

```
package com.amazonaws.codesamples;

import software.amazon.dynamodb.AmazonDynamoDB;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory;

public class StreamsRecordProcessorFactory implements IRecordProcessorFactory {
    
    @Override
    public IRecordProcessor createProcessor() {
        return new StreamsRecordProcessor(dynamoDBClient, tableName);
    }
}
```

**Per migrare `RecordProcessorFactory`**
+ Modifica l’interfaccia implementata da `com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory` a `software.amazon.kinesis.processor.ShardRecordProcessorFactory`, come segue:

  ```
  // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessor;
  import software.amazon.kinesis.processor.ShardRecordProcessor;
  
  // import com.amazonaws.services.kinesis.clientlibrary.interfaces.v2.IRecordProcessorFactory;
  import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
  
  // public class TestRecordProcessorFactory implements IRecordProcessorFactory {
  public class StreamsRecordProcessorFactory implements ShardRecordProcessorFactory {
  
  Change the return signature for createProcessor.
  
  // public IRecordProcessor createProcessor() {
  public ShardRecordProcessor shardRecordProcessor() {
  ```

Di seguito è riportato un esempio di generatore di elaboratore di record in 3.0:

```
package com.amazonaws.codesamples;

import software.amazon.kinesis.processor.ShardRecordProcessor;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;

public class StreamsRecordProcessorFactory implements ShardRecordProcessorFactory {

    @Override
    public ShardRecordProcessor shardRecordProcessor() {
        return new StreamsRecordProcessor();
    }
}
```

### Fase 3: eseguire la migrazione del lavoratore
<a name="step3-worker-migration"></a>

Nella versione 3.0 della KCL, una nuova classe, denominata **Pianificatore**, sostituisce la classe **Lavoratore**. Di seguito è illustrato un esempio di un lavoratore di KCL 1.x:

```
final KinesisClientLibConfiguration config = new KinesisClientLibConfiguration(...)
final IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
final Worker worker = StreamsWorkerFactory.createDynamoDbStreamsWorker(
        recordProcessorFactory,
        workerConfig,
        adapterClient,
        amazonDynamoDB,
        amazonCloudWatchClient);
```

**Per migrare il lavoratore**

1. Modifica la dichiarazione `import` per la classe `Worker` nelle dichiarazioni di importazione delle classi `Scheduler` e `ConfigsBuilder`.

   ```
   // import com.amazonaws.services.kinesis.clientlibrary.lib.worker.Worker;
   import software.amazon.kinesis.coordinator.Scheduler;
   import software.amazon.kinesis.common.ConfigsBuilder;
   ```

1. Importa `StreamTracker` e modifica l’importazione di `StreamsWorkerFactory` in `StreamsSchedulerFactory`.

   ```
   import software.amazon.kinesis.processor.StreamTracker;
   // import software.amazon.dynamodb.streamsadapter.StreamsWorkerFactory;
   import software.amazon.dynamodb.streamsadapter.StreamsSchedulerFactory;
   ```

1. Seleziona la posizione da cui avviare l’applicazione. Può essere `TRIM_HORIZON` o `LATEST`.

   ```
   import software.amazon.kinesis.common.InitialPositionInStream;
   import software.amazon.kinesis.common.InitialPositionInStreamExtended;
   ```

1. Creazione di un’istanza `StreamTracker`.

   ```
   StreamTracker streamTracker = StreamsSchedulerFactory.createSingleStreamTracker(
           streamArn,
           InitialPositionInStreamExtended.newInitialPosition(InitialPositionInStream.TRIM_HORIZON)
   );
   ```

1. Crea l’oggetto `AmazonDynamoDBStreamsAdapterClient`.

   ```
   import software.amazon.dynamodb.streamsadapter.AmazonDynamoDBStreamsAdapterClient; 
   import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
   import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
   
   ...
   
   AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.create();
   
   AmazonDynamoDBStreamsAdapterClient adapterClient = new AmazonDynamoDBStreamsAdapterClient(
           credentialsProvider, awsRegion);
   ```

1. Crea l’oggetto `ConfigsBuilder`.

   ```
   import software.amazon.kinesis.common.ConfigsBuilder;
   
   ...
   ConfigsBuilder configsBuilder = new ConfigsBuilder(
                   streamTracker,
                   applicationName,
                   adapterClient,
                   dynamoDbAsyncClient,
                   cloudWatchAsyncClient,
                   UUID.randomUUID().toString(),
                   new StreamsRecordProcessorFactory());
   ```

1. Crea `Scheduler` con `ConfigsBuilder` come mostrato nell’esempio seguente:

   ```
   import java.util.UUID;
   
   import software.amazon.awssdk.regions.Region;
   import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
   import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
   import software.amazon.awssdk.services.kinesis.KinesisAsyncClient;
   
   import software.amazon.kinesis.common.KinesisClientUtil;
   import software.amazon.kinesis.coordinator.Scheduler;
   
   ...
   
                   
   DynamoDbAsyncClient dynamoClient = DynamoDbAsyncClient.builder().region(region).build();
   CloudWatchAsyncClient cloudWatchClient = CloudWatchAsyncClient.builder().region(region).build();
   
                   
   DynamoDBStreamsPollingConfig pollingConfig = new DynamoDBStreamsPollingConfig(adapterClient);
   pollingConfig.idleTimeBetweenReadsInMillis(idleTimeBetweenReadsInMillis);
   
   // Use ConfigsBuilder to configure settings
   RetrievalConfig retrievalConfig = configsBuilder.retrievalConfig();
   retrievalConfig.retrievalSpecificConfig(pollingConfig);
   
   CoordinatorConfig coordinatorConfig = configsBuilder.coordinatorConfig();
   coordinatorConfig.clientVersionConfig(CoordinatorConfig.ClientVersionConfig.CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X);
                   
   Scheduler scheduler = StreamsSchedulerFactory.createScheduler(
                   configsBuilder.checkpointConfig(),
                   coordinatorConfig,
                   configsBuilder.leaseManagementConfig(),
                   configsBuilder.lifecycleConfig(),
                   configsBuilder.metricsConfig(),
                   configsBuilder.processorConfig(),
                   retrievalConfig,
                   adapterClient
           );
   ```

**Importante**  
L’impostazione `CLIENT_VERSION_CONFIG_COMPATIBLE_WITH_2X` mantiene la compatibilità tra l’Adattatore Kinesis per i flussi DynamoDB per KCL v3 e KCL v1, non tra KCL v2 e v3.

### Fase 4: panoramica e consigli sulla configurazione di KCL 3.x
<a name="step4-configuration-migration"></a>

Per una descrizione dettagliata delle configurazioni introdotte dopo KCL 1.x e rilevanti in KCL 3.x, consulta [KCL configurations](https://docs.aws.amazon.com//streams/latest/dev/kcl-configuration.html) and [KCL migration client configuration](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration.html#client-configuration).

**Importante**  
Invece di creare direttamente oggetti di `checkpointConfig`, `coordinatorConfig`, `leaseManagementConfig`, `metricsConfig`, `processorConfig` e `retrievalConfig`, si consiglia di utilizzare `ConfigsBuilder` per impostare le configurazioni in KCL 3.x e versioni successive per evitare problemi di inizializzazione del Pianificatore. `ConfigsBuilder` offre un modo più flessibile e gestibile per configurare l’applicazione KCL.

#### Configurazioni con aggiornamento del valore predefinito in KCL 3.x
<a name="kcl3-configuration-overview"></a>

`billingMode`  
Nella versione 1.x di KCL, il valore predefinito per `billingMode` è impostato su `PROVISIONED`. Tuttavia, con la versione 3.x di KCL, l’impostazione predefinita `billingMode` è `PAY_PER_REQUEST` (modalità on demand). Si consiglia di utilizzare la modalità con capacità on demand per la tabella di lease per regolare automaticamente la capacità in base all’utilizzo. Per indicazioni sull’utilizzo della capacità allocata per le tabelle di lease, consulta [Best practices for the lease table with provisioned capacity mode](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-lease-table.html).

`idleTimeBetweenReadsInMillis`  
Nella versione 1.x di KCL, il valore predefinito per `idleTimeBetweenReadsInMillis` è impostato su 1.000 (o 1 secondo). La versione 3.x di KCL imposta il valore predefinito per i`dleTimeBetweenReadsInMillis` su 1.500 (o 1,5 secondi), ma l’Adattatore Kinesis per i flussi Amazon DynamoDB sostituisce il valore predefinito su 1.000 (o 1 secondo).

#### Nuove configurazioni in KCL 3.x
<a name="kcl3-new-configs"></a>

`leaseAssignmentIntervalMillis`  
Questa configurazione definisce l’intervallo di tempo prima che gli shard di nuovo riscontro inizino l’elaborazione e viene calcolata come 1,5 × `leaseAssignmentIntervalMillis`. Se questa impostazione non è configurata in modo esplicito, l’intervallo di tempo predefinito è 1,5 × `failoverTimeMillis`. L’elaborazione di nuovi shard prevede la scansione della tabella di lease e l’interrogazione di un indice secondario globale (GSI) sulla tabella di lease. La riduzione di `leaseAssignmentIntervalMillis` aumenta la frequenza delle operazioni Scan e Query, con conseguente aumento dei costi di DynamoDB. Si consiglia di impostare questo valore su 2000 (o 2 secondi) per ridurre al minimo il ritardo nell’elaborazione di nuovi shard.

`shardConsumerDispatchPollIntervalMillis`  
Questa configurazione definisce l’intervallo tra polling successivi da parte del consumer dello shard per attivare le transizioni di stato. Nella versione 1.x di KCL, questo comportamento era controllato dal parametro `idleTimeInMillis`, che non era esposto come impostazione configurabile. Con la versione 3.x di KCL, si consiglia di impostare questa configurazione in modo che corrisponda al valore utilizzato per ` idleTimeInMillis` nella configurazione della versione 1.x di KCL.

### Fase 5: migrare da KCL 2.x a KCL 3.x
<a name="step5-kcl2-to-kcl3"></a>

Per garantire una transizione e una compatibilità fluide con l’ultima versione di Kinesis Client Library (KCL), segui le fasi 5 – 8 nelle istruzioni della guida alla migrazione per l’[aggiornamento da KCL 2.x a KCL 3.x](https://docs.aws.amazon.com//streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-worker-metrics).

Per la risoluzione dei problemi più comuni di KCL 3.x, consulta [Troubleshooting KCL consumer applications](https://docs.aws.amazon.com//streams/latest/dev/troubleshooting-consumers.html).

# Rollback a una versione di KCL precedente
<a name="kcl-migration-rollback"></a>

Questo argomento illustra come eseguire il rollback di un’applicazione consumer alla versione di KCL precedente. Il processo di rollback consiste in due fasi:

1. Esegui lo [Strumento di migrazione di KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Reimplementa il codice della versione precedente di KCL.

## Fase 1: eseguire lo Strumento di migrazione di KCL
<a name="kcl-migration-rollback-step1"></a>

Quando è necessario tornare alla versione precedente di KCL, occorre eseguire lo Strumento di migrazione KCL. Lo strumento svolge due attività importanti:
+ Rimuove una tabella di metadati denominata tabella delle metriche dei lavoratori e l’indice secondario globale nella tabella di lease in DynamoDB. Questi artefatti sono creati da KCL 3.x ma non sono necessari al ritorno alla versione precedente.
+ Consente a tutti i lavoratori di funzionare in una modalità compatibile con KCL 1.x e di iniziare a utilizzare l’algoritmo di bilanciamento del carico utilizzato nelle versioni precedenti di KCL. In caso di problemi con il nuovo algoritmo di bilanciamento del carico in KCL 3.x, questo ridurrà immediatamente il problema.

**Importante**  
La tabella dello stato del coordinatore in DynamoDB deve esistere e non deve essere eliminata durante il processo di migrazione, rollback e rollforward.

**Nota**  
È importante che tutti i lavoratori dell’applicazione consumer utilizzino lo stesso algoritmo di bilanciamento del carico in un determinato momento. Lo Strumento di migrazione di KCL assicura che tutti i lavoratori dell’applicazione consumer KCL 3.x passino alla modalità compatibile con KCL 1.x in modo che tutti i lavoratori eseguano lo stesso algoritmo di bilanciamento del carico durante il rollback dell’applicazione alla versione precedente di KCL.

[Puoi scaricare lo [strumento di migrazione KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py) nella directory degli script del repository KCL. GitHub](https://github.com/awslabs/amazon-kinesis-client/tree/master) Esegui lo script da un lavoratore o da un host con le autorizzazioni appropriate per scrivere nella tabella dello stato del coordinatore, nella tabella delle metriche dei lavoratori e nella tabella di lease. Assicurati che per le applicazioni consumer KCL siano configurate le [autorizzazioni IAM](https://docs.aws.amazon.com/streams/latest/dev/kcl-iam-permissions.html) appropriate. Esegui lo script solo una volta per applicazione KCL utilizzando il comando specificato:

```
python3 ./KclMigrationTool.py --region region --mode rollback [--application_name applicationName] [--lease_table_name leaseTableName] [--coordinator_state_table_name coordinatorStateTableName] [--worker_metrics_table_name workerMetricsTableName]
```

### Parameters
<a name="kcl-migration-rollback-parameters"></a>

`--region`  
Sostituisci con il tuo. *region* Regione AWS

`--application_name`  
Questo parametro è obbligatorio in caso di utilizzo di nomi predefiniti per le tabelle dei metadati di DynamoDB (tabella di lease, tabella dello stato del coordinatore e tabella delle metriche dei lavoratori). Se sono stati specificati nomi personalizzati per queste tabelle, è possibile omettere questo parametro. Sostituisci *applicationName* con il nome effettivo dell'applicazione KCL. Lo strumento utilizza questo nome per ricavare i nomi delle tabelle predefiniti se non vengono forniti nomi personalizzati.

`--lease_table_name`  
Questo parametro è necessario se si imposta un nome personalizzato per la tabella di lease nella configurazione KCL. Se si utilizza il nome della tabella predefinito, è possibile omettere questo parametro. Sostituisci *leaseTableName* con il nome della tabella personalizzata che hai specificato per la tabella di leasing.

`--coordinator_state_table_name`  
Questo parametro è necessario se si imposta un nome personalizzato per la tabella dello stato del coordinatore nella configurazione KCL. Se si utilizza il nome della tabella predefinito, è possibile omettere questo parametro. *coordinatorStateTableName*Sostituiscilo con il nome della tabella personalizzata che hai specificato per la tabella degli stati del coordinatore.

`--worker_metrics_table_name`  
Questo parametro è necessario se si imposta un nome personalizzato per la tabella delle metriche dei lavoratori nella configurazione KCL. Se si utilizza il nome della tabella predefinito, è possibile omettere questo parametro. *workerMetricsTableName*Sostituiscilo con il nome della tabella personalizzata che hai specificato per la tabella delle metriche dei lavoratori.

## Fase 2: reimplementare il codice con la versione precedente di KCL
<a name="kcl-migration-rollback-step2"></a>

**Importante**  
Qualsiasi menzione della versione 2.x nell’output generato dallo Strumento di migrazione di KCL deve essere interpretata come riferita alla versione 1.x di KCL. L’esecuzione dello script non esegue un rollback completo, ma passa solo l’algoritmo di bilanciamento del carico a quello utilizzato nella versione 1.x di KCL.

Dopo aver eseguito lo strumento di migrazione di KCL per un rollback, verrà mostrato uno di questi messaggi:

Messaggio 1  
“Rollback completato. L’applicazione eseguiva funzionalità della versione 2x compatibili. Torna ai file binari dell’applicazione precedente implementando il codice con la versione precedente di KCL.”  
**Azione richiesta:** significa che i lavoratori erano in esecuzione nella modalità compatibile con KCL 1.x. Reimplementa il codice con la versione precedente di KCL sui lavoratori.

Messaggio 2  
“Rollback completato. L’applicazione KCL eseguiva funzionalità della versione 3 e verrà ripristinata a funzionalità compatibili con la versione 2x. Se non è possibile visualizzare alcuna mitigazione dopo un breve periodo di tempo, esegui il rollback ai file binari dell’applicazione precedente implementando il codice con la versione KCL precedente.”  
**Azione richiesta:** significa che i lavoratori erano in esecuzione in modalità KCL 3.x e lo Strumento di migrazione di KCL ha portato tutti i lavoratori alla modalità compatibile con KCL 1.x. Reimplementa il codice con la versione precedente di KCL sui lavoratori.

Messaggio 3  
“Il rollback dell’applicazione è già stato effettuato. Tutte KCLv3 le risorse che potevano essere eliminate sono state ripulite per evitare addebiti fino a quando non è stato possibile avviare l'applicazione con la migrazione».  
**Azione richiesta:** significa che i lavoratori erano già stati sottoposti a rollback per essere eseguiti nella modalità compatibile con KCL 1.x. Reimplementa il codice con la versione precedente di KCL sui lavoratori.

# Rollforward a KCL 3.x dopo un rollback
<a name="kcl-migration-rollforward"></a>

Questo argomento illustra come eseguire il rollforward di un’applicazione consumer a KCL 3.x dopo un rollback. Quando è necessario eseguire il rollforward, occorre completare una procedura in due fasi:

1. Esegui lo [Strumento di migrazione di KCL](https://github.com/awslabs/amazon-kinesis-client/blob/master/amazon-kinesis-client/scripts/KclMigrationTool.py).

1. Implementa il codice con KCL 3.x.

## Fase 1: eseguire lo Strumento di migrazione di KCL
<a name="kcl-migration-rollforward-step1"></a>

Esegui lo Strumento di migrazione di KCL con il seguente comando per eseguire il rollforward a KCL 3.x:

```
python3 ./KclMigrationTool.py --region region --mode rollforward [--application_name applicationName] [--coordinator_state_table_name coordinatorStateTableName]
```

### Parameters
<a name="kcl-migration-rollforward-parameters"></a>

`--region`  
Sostituisci *region* con il tuo Regione AWS.

`--application_name`  
Questo parametro è obbligatorio se utilizzi i nomi predefiniti per la tabella dello stato del coordinatore. Se sono stati specificati nomi personalizzati per la tabella dello stato del coordinatore, è possibile omettere questo parametro. Sostituisci *applicationName* con il nome effettivo dell'applicazione KCL. Lo strumento utilizza questo nome per ricavare i nomi delle tabelle predefiniti se non vengono forniti nomi personalizzati.

`--coordinator_state_table_name`  
Questo parametro è necessario se si imposta un nome personalizzato per la tabella dello stato del coordinatore nella configurazione KCL. Se si utilizza il nome della tabella predefinito, è possibile omettere questo parametro. Sostituisci *coordinatorStateTableName* con il nome della tabella personalizzata che hai specificato per la tabella degli stati del coordinatore.

Dopo aver eseguito lo strumento di migrazione in modalità rollforward, KCL crea le seguenti risorse DynamoDB necessarie per KCL 3.x:
+ Un indice secondario globale nella tabella di lease
+ Una tabella delle metriche dei lavoratori

## Fase 2: implementare il codice con KCL 3.x
<a name="kcl-migration-rollforward-step2"></a>

Dopo aver eseguito lo Strumento di migrazione di KCL per un rollforward, implementa il codice con KCL 3.x sui lavoratori. Per completare la migrazione, consulta [Fase 8: completare la migrazione](https://docs.aws.amazon.com/streams/latest/dev/kcl-migration-from-2-3.html#kcl-migration-from-2-3-finish).

# Spiegazione passo per passo: Adattatore Kinesis DynamoDB Streams
<a name="Streams.KCLAdapter.Walkthrough"></a>

In questa sezione viene riportata una spiegazione passo per passo di un'applicazione Java che utilizza Amazon Kinesis Client Library e l'adattatore Amazon DynamoDB Streams Kinesis. L'applicazione mostra un esempio di replica dei dati, in cui l'attività di scrittura da una tabella viene applicata a una seconda tabella e i contenuti di entrambe le tabelle rimangono sincronizzati. Per il codice sorgente, consulta [Programma completo: Adattatore Kinesis di DynamoDB Streams](Streams.KCLAdapter.Walkthrough.CompleteProgram.md).

Il programma effettua le seguenti operazioni:

1. Crea due tabelle DynamoDB denominate `KCL-Demo-src` e `KCL-Demo-dst`. Su ognuna di queste tabelle è abilitato un flusso.

1. Genera l'attività di aggiornamento nella tabella di origine aggiungendo, aggiornando ed eliminando gli elementi. Questo fa sì che i dati vengano scritti nel flusso della tabella.

1. Legge i record dal flusso, li ricostruisce come richieste DynamoDB e applica le richieste alla tabella di destinazione.

1. Esegue la scansione delle tabelle di origine e di destinazione per garantire che i contenuti siano identici.

1. Esegue la pulizia eliminando le tabelle.

Queste fasi sono descritte nelle sezioni seguenti e l'applicazione completa viene mostrata alla fine della procedura guidata.

**Topics**
+ [Fase 1: creazione di tabelle DynamoDB](#Streams.KCLAdapter.Walkthrough.Step1)
+ [Fase 2: generazione dell'attività di aggiornamento nella tabella di origine](#Streams.KCLAdapter.Walkthrough.Step2)
+ [Fase 3: elaborazione del flusso](#Streams.KCLAdapter.Walkthrough.Step3)
+ [Fase 4: verifica che entrambe le tabelle abbiano contenuti identici](#Streams.KCLAdapter.Walkthrough.Step4)
+ [Fase 5: rimozione](#Streams.KCLAdapter.Walkthrough.Step5)
+ [Programma completo: Adattatore Kinesis di DynamoDB Streams](Streams.KCLAdapter.Walkthrough.CompleteProgram.md)

## Fase 1: creazione di tabelle DynamoDB
<a name="Streams.KCLAdapter.Walkthrough.Step1"></a>

Il primo passo consiste nel creare due tabelle DynamoDB, una di origine e una di destinazione. `StreamViewType` sul flusso della tabella di origine è `NEW_IMAGE`. Questo significa che ogni volta che un item viene modificato in questa tabella, l'immagine "successiva" dell'item viene scritta nel flusso. In questo modo, il flusso tiene traccia di tutte le attività di scrittura della tabella.

Il seguente esempio mostra il codice utilizzato per creare entrambe le tabelle.

```
java.util.List<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("Id").withAttributeType("N"));

java.util.List<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
keySchema.add(new KeySchemaElement().withAttributeName("Id").withKeyType(KeyType.HASH)); // Partition
                                                                                         // key

ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput().withReadCapacityUnits(2L)
    .withWriteCapacityUnits(2L);

StreamSpecification streamSpecification = new StreamSpecification();
streamSpecification.setStreamEnabled(true);
streamSpecification.setStreamViewType(StreamViewType.NEW_IMAGE);
CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
    .withAttributeDefinitions(attributeDefinitions).withKeySchema(keySchema)
    .withProvisionedThroughput(provisionedThroughput).withStreamSpecification(streamSpecification);
```

## Fase 2: generazione dell'attività di aggiornamento nella tabella di origine
<a name="Streams.KCLAdapter.Walkthrough.Step2"></a>

La fase successiva consiste nel generare le attività di scrittura sulla tabella di origine. Mentre questa attività è in corso, il flusso della tabella di origine viene aggiornato pressoché in tempo reale.

L'applicazione definisce una classe helper con metodi che chiamano le operazioni API `PutItem`, `UpdateItem` e `DeleteItem` per scrivere i dati. Il seguente esempio di codice mostra come vengono utilizzati questi metodi.

```
StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName, "101", "test1");
StreamsAdapterDemoHelper.updateItem(dynamoDBClient, tableName, "101", "test2");
StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName, "101");
StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName, "102", "demo3");
StreamsAdapterDemoHelper.updateItem(dynamoDBClient, tableName, "102", "demo4");
StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName, "102");
```

## Fase 3: elaborazione del flusso
<a name="Streams.KCLAdapter.Walkthrough.Step3"></a>

Ora il programma inizia l'elaborazione del flusso. L'adattatore Kinesis di DynamoDB Streams agisce come un livello trasparente tra KCL e l'endpoint DynamoDB Streams in modo che il codice possa utilizzare appieno KCL piuttosto che effettuare chiamate a DynamoDB Streams di basso livello. Il programma esegue le attività di seguito elencate:
+ Definisce una classe di elaboratore di record, `StreamsRecordProcessor`, con metodi conformi alla definizione dell'interfaccia KCL: `initialize`, `processRecords` e `shutdown`. Il metodo `processRecords` contiene la logica necessaria per la lettura dal flusso della tabella di origine e la scrittura nella tabella di destinazione.
+ Definisce una factory di classe per la classe di elaboratore di record (`StreamsRecordProcessorFactory`). Ciò è richiesto per i programmi Java che utilizzano KCL.
+ Crea un'istanza di un nuovo `Worker` KCL che è associato alla factory di classe.
+ Arresta il `Worker` quando l'elaborazione del record è completata.

Facoltativamente, abilita la modalità catch-up nella configurazione dell'adattatore Streams KCL per scalare automaticamente la velocità di chiamata GetRecords API di 3 volte (impostazione predefinita) quando il ritardo di elaborazione del flusso supera un minuto (impostazione predefinita), aiutando l'utente di streaming a gestire picchi di throughput elevati nella tabella.

Per ulteriori informazioni sulla definizione dell'interfaccia KCL, consulta [Sviluppo di consumatori utilizzando la Kinesis Client Library](https://docs.aws.amazon.com/kinesis/latest/dev/developing-consumers-with-kcl.html) nella *Guida per gli sviluppatori di Amazon Kinesis Data Streams*. 

Il seguente esempio di codice mostra il loop principale in `StreamsRecordProcessor`. L'istruzione `case` determina quale operazione eseguire, sulla base dell'item `OperationType` presente nel record del flusso.

```
for (Record record : records) {
    String data = new String(record.getData().array(), Charset.forName("UTF-8"));
    System.out.println(data);
    if (record instanceof RecordAdapter) {
                software.amazon.dynamodb.model.Record streamRecord = ((RecordAdapter) record)
                    .getInternalObject();

                switch (streamRecord.getEventName()) {
                    case "INSERT":
                    case "MODIFY":
                        StreamsAdapterDemoHelper.putItem(dynamoDBClient, tableName,
                            streamRecord.getDynamodb().getNewImage());
                        break;
                    case "REMOVE":
                        StreamsAdapterDemoHelper.deleteItem(dynamoDBClient, tableName,
                            streamRecord.getDynamodb().getKeys().get("Id").getN());
                }
    }
    checkpointCounter += 1;
    if (checkpointCounter % 10 == 0) {
        try {
            checkpointer.checkpoint();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

## Fase 4: verifica che entrambe le tabelle abbiano contenuti identici
<a name="Streams.KCLAdapter.Walkthrough.Step4"></a>

A questo punto, i contenuti delle tabelle di origine e destinazione sono sincronizzati. L'applicazione emette le richieste `Scan` su entrambe le tabelle per verificare che i loro contenuti siano effettivamente identici.

La classe `DemoHelper` contiene un metodo `ScanTable` che chiama l'API `Scan` di basso livello. L'esempio seguente mostra come viene utilizzato.

```
if (StreamsAdapterDemoHelper.scanTable(dynamoDBClient, srcTable).getItems()
    .equals(StreamsAdapterDemoHelper.scanTable(dynamoDBClient, destTable).getItems())) {
    System.out.println("Scan result is equal.");
}
else {
    System.out.println("Tables are different!");
}
```

## Fase 5: rimozione
<a name="Streams.KCLAdapter.Walkthrough.Step5"></a>

La demo è completata, quindi l'applicazione elimina le tabelle di origine e di destinazione. Vedere l'esempio di codice seguente. Anche dopo l'eliminazione delle tabelle, i flussi rimangono disponibili per altre 24 ore, dopo di che vengono automaticamente eliminati.

```
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(srcTable));
dynamoDBClient.deleteTable(new DeleteTableRequest().withTableName(destTable));
```

# Programma completo: Adattatore Kinesis di DynamoDB Streams
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram"></a>

Di seguito è riportato il programma Java completo che esegue le attività descritte in [Spiegazione passo per passo: Adattatore Kinesis DynamoDB Streams](Streams.KCLAdapter.Walkthrough.md). Quando lo esegui, dovresti vedere un output simile al seguente.

```
Creating table KCL-Demo-src
Creating table KCL-Demo-dest
Table is active.
Creating worker for stream: arn:aws:dynamodb:us-west-2:111122223333:table/KCL-Demo-src/stream/2015-05-19T22:48:56.601
Starting worker...
Scan result is equal.
Done.
```

**Importante**  
 Per eseguire questo programma, assicurati che l'applicazione client abbia accesso a DynamoDB e CloudWatch Amazon utilizzando le policy. Per ulteriori informazioni, consulta [Policy basate su identità per DynamoDB](security_iam_service-with-iam.md#security_iam_service-with-iam-id-based-policies). 

Il codice sorgente è composto da quattro `.java` file. Per creare questo programma, aggiungi la seguente dipendenza, che include Amazon Kinesis Client Library (KCL) 3.x e SDK AWS for Java v2 come dipendenze transitive:

------
#### [ Maven ]

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>dynamodb-streams-kinesis-adapter</artifactId>
    <version>2.1.0</version>
</dependency>
```

------
#### [ Gradle ]

```
implementation 'com.amazonaws:dynamodb-streams-kinesis-adapter:2.1.0'
```

------

I file sorgente sono:
+ `StreamsAdapterDemo.java`
+ `StreamsRecordProcessor.java`
+ `StreamsRecordProcessorFactory.java`
+ `StreamsAdapterDemoHelper.java`

## StreamsAdapterDemo.java
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsAdapterDemo"></a>

```
package com.amazonaws.codesamples;

import com.amazonaws.services.dynamodbv2.streamsadapter.AmazonDynamoDBStreamsAdapterClient;
import com.amazonaws.services.dynamodbv2.streamsadapter.StreamsSchedulerFactory;
import com.amazonaws.services.dynamodbv2.streamsadapter.polling.DynamoDBStreamsPollingConfig;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.kinesis.common.ConfigsBuilder;
import software.amazon.kinesis.common.InitialPositionInStream;
import software.amazon.kinesis.common.InitialPositionInStreamExtended;
import software.amazon.kinesis.coordinator.Scheduler;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
import software.amazon.kinesis.processor.StreamTracker;
import software.amazon.kinesis.retrieval.RetrievalConfig;

public class StreamsAdapterDemo {

    private static DynamoDbAsyncClient dynamoDbAsyncClient;
    private static CloudWatchAsyncClient cloudWatchAsyncClient;
    private static AmazonDynamoDBStreamsAdapterClient amazonDynamoDbStreamsAdapterClient;

    private static String tablePrefix = "KCL-Demo";
    private static String streamArn;

    private static Region region = Region.US_EAST_1;
    private static AwsCredentialsProvider credentialsProvider = DefaultCredentialsProvider.create();

    public static void main( String[] args ) throws Exception {
        System.out.println("Starting demo...");
        dynamoDbAsyncClient = DynamoDbAsyncClient.builder()
                .credentialsProvider(credentialsProvider)
                .region(region)
                .build();
        cloudWatchAsyncClient = CloudWatchAsyncClient.builder()
                .credentialsProvider(credentialsProvider)
                .region(region)
                .build();
        amazonDynamoDbStreamsAdapterClient = new AmazonDynamoDBStreamsAdapterClient(credentialsProvider, region);

        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";

        setUpTables();

        StreamTracker streamTracker = StreamsSchedulerFactory.createSingleStreamTracker(streamArn,
                InitialPositionInStreamExtended.newInitialPosition(InitialPositionInStream.TRIM_HORIZON));

        ShardRecordProcessorFactory shardRecordProcessorFactory =
                new StreamsAdapterDemoProcessorFactory(dynamoDbAsyncClient, destTable);

        ConfigsBuilder configsBuilder = new ConfigsBuilder(
                streamTracker,
                "streams-adapter-demo",
                amazonDynamoDbStreamsAdapterClient,
                dynamoDbAsyncClient,
                cloudWatchAsyncClient,
                "streams-demo-worker",
                shardRecordProcessorFactory
        );

        DynamoDBStreamsPollingConfig pollingConfig = new DynamoDBStreamsPollingConfig(amazonDynamoDbStreamsAdapterClient);
        RetrievalConfig retrievalConfig = configsBuilder.retrievalConfig();
        retrievalConfig.retrievalSpecificConfig(pollingConfig);

        System.out.println("Creating scheduler for stream " + streamArn);
        Scheduler scheduler = StreamsSchedulerFactory.createScheduler(
                configsBuilder.checkpointConfig(),
                configsBuilder.coordinatorConfig(),
                configsBuilder.leaseManagementConfig(),
                configsBuilder.lifecycleConfig(),
                configsBuilder.metricsConfig(),
                configsBuilder.processorConfig(),
                retrievalConfig,
                amazonDynamoDbStreamsAdapterClient
        );

        System.out.println("Starting scheduler...");
        Thread t = new Thread(scheduler);
        t.start();

        Thread.sleep(250000);

        System.out.println("Stopping scheduler...");
        scheduler.shutdown();
        t.join();

        if (StreamsAdapterDemoHelper.scanTable(dynamoDbAsyncClient, srcTable).items()
                .equals(StreamsAdapterDemoHelper.scanTable(dynamoDbAsyncClient, destTable).items())) {
            System.out.println("Scan result is equal.");
        } else {
            System.out.println("Tables are different!");
        }

        System.out.println("Done.");
        cleanupAndExit(0);
    }

    private static void setUpTables() {
        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";
        streamArn = StreamsAdapterDemoHelper.createTable(dynamoDbAsyncClient, srcTable);
        StreamsAdapterDemoHelper.createTable(dynamoDbAsyncClient, destTable);

        awaitTableCreation(srcTable);

        performOps(srcTable);
    }

    private static void awaitTableCreation(String tableName) {
        Integer retries = 0;
        Boolean created = false;
        while (!created && retries < 100) {
            DescribeTableResponse result = StreamsAdapterDemoHelper.describeTable(dynamoDbAsyncClient, tableName);
            created = result.table().tableStatusAsString().equals("ACTIVE");
            if (created) {
                System.out.println("Table is active.");
                return;
            } else {
                retries++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // do nothing
                }
            }
        }
        System.out.println("Timeout after table creation. Exiting...");
        cleanupAndExit(1);
    }

    private static void performOps(String tableName) {
        StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName, "101", "test1");
        StreamsAdapterDemoHelper.updateItem(dynamoDbAsyncClient, tableName, "101", "test2");
        StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName, "101");
        StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName, "102", "demo3");
        StreamsAdapterDemoHelper.updateItem(dynamoDbAsyncClient, tableName, "102", "demo4");
        StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName, "102");
    }

    private static void cleanupAndExit(Integer returnValue) {
        String srcTable = tablePrefix + "-src";
        String destTable = tablePrefix + "-dest";
        dynamoDbAsyncClient.deleteTable(DeleteTableRequest.builder().tableName(srcTable).build());
        dynamoDbAsyncClient.deleteTable(DeleteTableRequest.builder().tableName(destTable).build());
        System.exit(returnValue);
    }
}
```

## StreamsRecordProcessor.java
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsRecordProcessor"></a>

```
package com.amazonaws.codesamples;

import com.amazonaws.services.dynamodbv2.streamsadapter.adapter.DynamoDBStreamsClientRecord;
import com.amazonaws.services.dynamodbv2.streamsadapter.model.DynamoDBStreamsProcessRecordsInput;
import com.amazonaws.services.dynamodbv2.streamsadapter.processor.DynamoDBStreamsShardRecordProcessor;
import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.Record;
import software.amazon.kinesis.exceptions.InvalidStateException;
import software.amazon.kinesis.exceptions.ShutdownException;
import software.amazon.kinesis.lifecycle.events.InitializationInput;
import software.amazon.kinesis.lifecycle.events.LeaseLostInput;
import software.amazon.kinesis.lifecycle.events.ShardEndedInput;
import software.amazon.kinesis.lifecycle.events.ShutdownRequestedInput;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class StreamsRecordProcessor implements DynamoDBStreamsShardRecordProcessor {

    private Integer checkpointCounter;

    private final DynamoDbAsyncClient dynamoDbAsyncClient;
    private final String tableName;

    public StreamsRecordProcessor(DynamoDbAsyncClient dynamoDbAsyncClient, String tableName) {
        this.dynamoDbAsyncClient = dynamoDbAsyncClient;
        this.tableName = tableName;
    }

    @Override
    public void initialize(InitializationInput initializationInput) {
        this.checkpointCounter = 0;
    }

    @Override
    public void processRecords(DynamoDBStreamsProcessRecordsInput dynamoDBStreamsProcessRecordsInput) {
        for (DynamoDBStreamsClientRecord record: dynamoDBStreamsProcessRecordsInput.records()) {
            String data = new String(record.data().array(), StandardCharsets.UTF_8);
            System.out.println(data);
            Record streamRecord = record.getRecord();

            switch (streamRecord.eventName()) {
                case INSERT:
                case MODIFY:
                    StreamsAdapterDemoHelper.putItem(dynamoDbAsyncClient, tableName,
                            streamRecord.dynamodb().newImage());
                case REMOVE:
                    StreamsAdapterDemoHelper.deleteItem(dynamoDbAsyncClient, tableName,
                            streamRecord.dynamodb().keys().get("Id").n());
            }
            checkpointCounter += 1;
            if (checkpointCounter % 10 == 0) {
                try {
                    dynamoDBStreamsProcessRecordsInput.checkpointer().checkpoint();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void leaseLost(LeaseLostInput leaseLostInput) {
        System.out.println("Lease Lost");
    }

    @Override
    public void shardEnded(ShardEndedInput shardEndedInput) {
        try {
            shardEndedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void shutdownRequested(ShutdownRequestedInput shutdownRequestedInput) {
        try {
            shutdownRequestedInput.checkpointer().checkpoint();
        } catch (ShutdownException | InvalidStateException e) {
            e.printStackTrace();
        }
    }
}
```

## StreamsRecordProcessorFactory.java
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsRecordProcessorFactory"></a>

```
package com.amazonaws.codesamples;

import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.kinesis.processor.ShardRecordProcessor;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory;

public class StreamsAdapterDemoProcessorFactory implements ShardRecordProcessorFactory {
    private final String tableName;
    private final DynamoDbAsyncClient dynamoDbAsyncClient;

    public StreamsAdapterDemoProcessorFactory(DynamoDbAsyncClient asyncClient, String tableName) {
        this.tableName = tableName;
        this.dynamoDbAsyncClient = asyncClient;
    }

    @Override
    public ShardRecordProcessor shardRecordProcessor() {
        return new StreamsRecordProcessor(dynamoDbAsyncClient, tableName);
    }
}
```

## StreamsAdapterDemoHelper.java
<a name="Streams.KCLAdapter.Walkthrough.CompleteProgram.StreamsAdapterDemoHelper"></a>

```
package com.amazonaws.codesamples;

import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.OnDemandThroughput;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.ResourceInUseException;
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;
import software.amazon.awssdk.services.dynamodb.model.StreamSpecification;
import software.amazon.awssdk.services.dynamodb.model.StreamViewType;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StreamsAdapterDemoHelper {

    /**
     * @return StreamArn
     */
    public static String createTable(DynamoDbAsyncClient client, String tableName) {
        List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
        attributeDefinitions.add(AttributeDefinition.builder()
                .attributeName("Id")
                .attributeType("N")
                .build());

        List<KeySchemaElement> keySchema = new ArrayList<>();
        keySchema.add(KeySchemaElement.builder()
                .attributeName("Id")
                .keyType(KeyType.HASH) // Partition key
                .build());

        StreamSpecification streamSpecification = StreamSpecification.builder()
                .streamEnabled(true)
                .streamViewType(StreamViewType.NEW_IMAGE)
                .build();

        CreateTableRequest createTableRequest = CreateTableRequest.builder()
                .tableName(tableName)
                .attributeDefinitions(attributeDefinitions)
                .keySchema(keySchema)
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .streamSpecification(streamSpecification)
                .build();

        try {
            System.out.println("Creating table " + tableName);
            CreateTableResponse result = client.createTable(createTableRequest).join();
            return result.tableDescription().latestStreamArn();
        } catch (Exception e) {
            if (e.getCause() instanceof ResourceInUseException) {
                System.out.println("Table already exists.");
                return describeTable(client, tableName).table().latestStreamArn();
            }
            throw e;
        }
    }

    public static DescribeTableResponse describeTable(DynamoDbAsyncClient client, String tableName) {
        return client.describeTable(DescribeTableRequest.builder()
                        .tableName(tableName)
                        .build())
                .join();
    }

    public static ScanResponse scanTable(DynamoDbAsyncClient dynamoDbClient, String tableName) {
        return dynamoDbClient.scan(ScanRequest.builder()
                        .tableName(tableName)
                        .build())
                .join();
    }

    public static void putItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id, String val) {
        Map<String, AttributeValue> item = new HashMap<>();
        item.put("Id", AttributeValue.builder().n(id).build());
        item.put("attribute-1", AttributeValue.builder().s(val).build());

        putItem(dynamoDbClient, tableName, item);
    }

    public static void putItem(DynamoDbAsyncClient dynamoDbClient, String tableName,
                               Map<String, AttributeValue> items) {
        PutItemRequest putItemRequest = PutItemRequest.builder()
                .tableName(tableName)
                .item(items)
                .build();
        dynamoDbClient.putItem(putItemRequest).join();
    }

    public static void updateItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id, String val) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("Id", AttributeValue.builder().n(id).build());

        Map<String, String> expressionAttributeNames = new HashMap<>();
        expressionAttributeNames.put("#attr2", "attribute-2");

        Map<String, AttributeValue> expressionAttributeValues = new HashMap<>();
        expressionAttributeValues.put(":val", AttributeValue.builder().s(val).build());

        UpdateItemRequest updateItemRequest = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .updateExpression("SET #attr2 = :val")
                .expressionAttributeNames(expressionAttributeNames)
                .expressionAttributeValues(expressionAttributeValues)
                .build();

        dynamoDbClient.updateItem(updateItemRequest).join();
    }

    public static void deleteItem(DynamoDbAsyncClient dynamoDbClient, String tableName, String id) {
        Map<String, AttributeValue> key = new HashMap<>();
        key.put("Id", AttributeValue.builder().n(id).build());

        DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(key)
                .build();
        dynamoDbClient.deleteItem(deleteItemRequest).join();
    }
}
```

# API di basso livello DynamoDB Streams: esempio Java
<a name="Streams.LowLevel.Walkthrough"></a>

**Nota**  
Il codice in questa pagina non è completo e non prevede la gestione di tutti gli scenari di utilizzo di Amazon DynamoDB Streams. Il modo consigliato di utilizzare record di flusso da DynamoDB è tramite l'adattatore Amazon Kinesis utilizzando la Kinesis Client Library (KCL), come descritto in [Utilizzo dell'adattatore DynamoDB Streams Kinesis per elaborare i record di flusso](Streams.KCLAdapter.md).

Questa sezione contiene un programma Java che mostra il funzionamento di DynamoDB Streams. Il programma effettua le seguenti operazioni:

1. Crea una tabella DynamoDB con un flusso abilitato.

1. Descrive le impostazioni del flusso per questa tabella.

1. Modifica i dati nella tabella.

1. Descrive gli shard nel flusso.

1. Legge i record del flusso dagli shard.

1. Recupera gli shard secondari e continua a leggere i record.

1. Elimina.

Quando esegui il programma, vedrai un output simile al seguente:

```
Testing Streams Demo
Creating an Amazon DynamoDB table TestTableForStreams with a simple primary key: Id
Waiting for TestTableForStreams to be created...
Current stream ARN for TestTableForStreams: arn:aws:dynamodb:us-east-2:123456789012:table/TestTableForStreams/stream/2018-03-20T16:49:55.208
Stream enabled: true
Update view type: NEW_AND_OLD_IMAGES

Performing write activities on TestTableForStreams
Processing item 1 of 100
Processing item 2 of 100
Processing item 3 of 100
...
Processing item 100 of 100
Shard: {ShardId: shardId-1234567890-...,SequenceNumberRange: {StartingSequenceNumber: 100002572486797508907,},}
    Shard iterator: EjYFEkX2a26eVTWe...
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, NewImage={Message=AttributeValue(S=New Item!), Id=AttributeValue(S=4)}, SequenceNumber=2000001584047545833909, SizeBytes=22, StreamViewType=NEW_AND_OLD_IMAGES)
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, NewImage={Message=AttributeValue(S=This is an updated item), Id=AttributeValue(S=4)}, OldImage={Message=AttributeValue(S=New Item!), Id=AttributeValue(S=4)}, SequenceNumber=2100003604869767892701, SizeBytes=55, StreamViewType=NEW_AND_OLD_IMAGES)
        StreamRecord(ApproximateCreationDateTime=2025-04-09T13:11:58Z, Keys={Id=AttributeValue(S=4)}, OldImage={Message=AttributeValue(S=This is an updated item), Id=AttributeValue(S=4)}, SequenceNumber=2200001099771112898434, SizeBytes=36, StreamViewType=NEW_AND_OLD_IMAGES)
...
Deleting the table...
Table StreamsDemoTable deleted.
Demo complete
```

**Example Esempio**  

```
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeAction;
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.AttributeValueUpdate;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest;
import software.amazon.awssdk.services.dynamodb.model.CreateTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeStreamResponse;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsRequest;
import software.amazon.awssdk.services.dynamodb.model.GetRecordsResponse;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorRequest;
import software.amazon.awssdk.services.dynamodb.model.GetShardIteratorResponse;
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.Record;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;
import software.amazon.awssdk.services.dynamodb.model.Shard;
import software.amazon.awssdk.services.dynamodb.model.ShardFilter;
import software.amazon.awssdk.services.dynamodb.model.ShardFilterType;
import software.amazon.awssdk.services.dynamodb.model.ShardIteratorType;
import software.amazon.awssdk.services.dynamodb.model.StreamSpecification;
import software.amazon.awssdk.services.dynamodb.model.TableDescription;
import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;

public class StreamsLowLevelDemo {


    public static void main(String[] args) {
        final String usage = "Testing Streams Demo";
        try {
            System.out.println(usage);

            String tableName = "StreamsDemoTable";
            String key = "Id";
            System.out.println("Creating an Amazon DynamoDB table " + tableName + " with a simple primary key: " + key);
            Region region = Region.US_WEST_2;
            DynamoDbClient ddb = DynamoDbClient.builder()
                    .region(region)
                    .build();

            DynamoDbStreamsClient ddbStreams = DynamoDbStreamsClient.builder()
                    .region(region)
                    .build();
            DescribeTableRequest describeTableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();
            TableDescription tableDescription = null;
            try{
                tableDescription = ddb.describeTable(describeTableRequest).table();
            }catch (Exception e){
                System.out.println("Table " + tableName + " does not exist.");
                tableDescription = createTable(ddb, tableName, key);
            }

            // Print the stream settings for the table
            String streamArn = tableDescription.latestStreamArn();
           
            StreamSpecification streamSpec = tableDescription.streamSpecification();
            System.out.println("Current stream ARN for " + tableDescription.tableName() + ": " +
                   streamArn);
            System.out.println("Stream enabled: " + streamSpec.streamEnabled());
            System.out.println("Update view type: " + streamSpec.streamViewType());
            System.out.println();
            // Generate write activity in the table
            System.out.println("Performing write activities on " + tableName);
            int maxItemCount = 100;
            for (Integer i = 1; i <= maxItemCount; i++) {
                System.out.println("Processing item " + i + " of " + maxItemCount);
                // Write a new item
                putItemInTable(key, i, tableName, ddb);
                // Update the item
                updateItemInTable(key, i, tableName, ddb);
                // Delete the item
                deleteDynamoDBItem(key, i, tableName, ddb);
            }

            // Process Stream
            processStream(streamArn, maxItemCount, ddb, ddbStreams, tableName);

            // Delete the table
            System.out.println("Deleting the table...");
            DeleteTableRequest deleteTableRequest = DeleteTableRequest.builder()
                    .tableName(tableName)
                    .build();
            ddb.deleteTable(deleteTableRequest);
            System.out.println("Table " + tableName + " deleted.");
            System.out.println("Demo complete");
            ddb.close();
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }

    private static void processStream(String streamArn, int maxItemCount, DynamoDbClient ddb, DynamoDbStreamsClient ddbStreams, String tableName) {
        // Get all the shard IDs from the stream. Note that DescribeStream returns
        // the shard IDs one page at a time.
        String lastEvaluatedShardId = null;
        do {
            DescribeStreamRequest describeStreamRequest = DescribeStreamRequest.builder()
                    .streamArn(streamArn)
                    .exclusiveStartShardId(lastEvaluatedShardId).build();
            DescribeStreamResponse describeStreamResponse = ddbStreams.describeStream(describeStreamRequest);

            List<Shard> shards = describeStreamResponse.streamDescription().shards();

            // Process each shard on this page

            fetchShardsAndReadRecords(streamArn, maxItemCount, ddbStreams, shards);

            // If LastEvaluatedShardId is set, then there is
            // at least one more page of shard IDs to retrieve
            lastEvaluatedShardId = describeStreamResponse.streamDescription().lastEvaluatedShardId();

        } while (lastEvaluatedShardId != null);

    }

    private static void fetchShardsAndReadRecords(String streamArn, int maxItemCount, DynamoDbStreamsClient ddbStreams, List<Shard> shards) {
        for (Shard shard : shards) {
            String shardId = shard.shardId();
            System.out.println("Shard: " + shard);

            // Get an iterator for the current shard
            GetShardIteratorRequest shardIteratorRequest = GetShardIteratorRequest.builder()
                    .streamArn(streamArn).shardId(shardId)
                    .shardIteratorType(ShardIteratorType.TRIM_HORIZON).build();

            GetShardIteratorResponse getShardIteratorResult = ddbStreams.getShardIterator(shardIteratorRequest);

            String currentShardIter = getShardIteratorResult.shardIterator();

            // Shard iterator is not null until the Shard is sealed (marked as READ_ONLY).
            // To prevent running the loop until the Shard is sealed, we process only the
            // items that were written into DynamoDB and then exit.
            int processedRecordCount = 0;
            while (currentShardIter != null && processedRecordCount < maxItemCount) {
                // Use the shard iterator to read the stream records
                GetRecordsRequest getRecordsRequest = GetRecordsRequest.builder()
                        .shardIterator(currentShardIter).build();
                GetRecordsResponse getRecordsResult = ddbStreams.getRecords(getRecordsRequest);
                List<Record> records = getRecordsResult.records();
                for (Record record : records) {
                    System.out.println("        " + record.dynamodb());
                }
                processedRecordCount += records.size();
                currentShardIter = getRecordsResult.nextShardIterator();
            }
            if (currentShardIter == null){
                System.out.println("Shard has been fully processed. Shard iterator is null.");
                System.out.println("Fetch the child shard to continue processing instead of bulk fetching all shards");
                DescribeStreamRequest describeStreamRequestForChildShards = DescribeStreamRequest.builder()
                        .streamArn(streamArn)
                        .shardFilter(ShardFilter.builder()
                                .type(ShardFilterType.CHILD_SHARDS)
                                .shardId(shardId).build())
                        .build();
                DescribeStreamResponse describeStreamResponseChildShards = ddbStreams.describeStream(describeStreamRequestForChildShards);
                fetchShardsAndReadRecords(streamArn, maxItemCount, ddbStreams, describeStreamResponseChildShards.streamDescription().shards());
            }
        }
    }

    private static void putItemInTable(String key, Integer i, String tableName, DynamoDbClient ddb) {
        Map<String, AttributeValue> item = new HashMap<>();
        item.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());
        item.put("Message", AttributeValue.builder()
                .s("New Item!")
                .build());
        PutItemRequest request = PutItemRequest.builder()
                .tableName(tableName)
                .item(item)
                .build();
        ddb.putItem(request);
    }

    private static void updateItemInTable(String key, Integer i, String tableName, DynamoDbClient ddb) {

        HashMap<String, AttributeValue> itemKey = new HashMap<>();
        itemKey.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());


        HashMap<String, AttributeValueUpdate> updatedValues = new HashMap<>();
        updatedValues.put("Message", AttributeValueUpdate.builder()
                .value(AttributeValue.builder().s("This is an updated item").build())
                .action(AttributeAction.PUT)
                .build());

        UpdateItemRequest request = UpdateItemRequest.builder()
                .tableName(tableName)
                .key(itemKey)
                .attributeUpdates(updatedValues)
                .build();
        ddb.updateItem(request);
    }

    public static void deleteDynamoDBItem(String key, Integer i, String tableName, DynamoDbClient ddb) {
        HashMap<String, AttributeValue> keyToGet = new HashMap<>();
        keyToGet.put(key, AttributeValue.builder()
                .s(i.toString())
                .build());

        DeleteItemRequest deleteReq = DeleteItemRequest.builder()
                .tableName(tableName)
                .key(keyToGet)
                .build();
        ddb.deleteItem(deleteReq);
    }

    public static TableDescription createTable(DynamoDbClient ddb, String tableName, String key) {
        DynamoDbWaiter dbWaiter = ddb.waiter();
        StreamSpecification streamSpecification = StreamSpecification.builder()
                .streamEnabled(true)
                .streamViewType("NEW_AND_OLD_IMAGES")
                .build();
        CreateTableRequest request = CreateTableRequest.builder()
                .attributeDefinitions(AttributeDefinition.builder()
                        .attributeName(key)
                        .attributeType(ScalarAttributeType.S)
                        .build())
                .keySchema(KeySchemaElement.builder()
                        .attributeName(key)
                        .keyType(KeyType.HASH)
                        .build())
                .billingMode(BillingMode.PAY_PER_REQUEST) //  DynamoDB automatically scales based on traffic.
                .tableName(tableName)
                .streamSpecification(streamSpecification)
                .build();

        TableDescription newTable;
        try {
            CreateTableResponse response = ddb.createTable(request);
            DescribeTableRequest tableRequest = DescribeTableRequest.builder()
                    .tableName(tableName)
                    .build();
                    
            System.out.println("Waiting for " + tableName + " to be created...");

            // Wait until the Amazon DynamoDB table is created.
            WaiterResponse<DescribeTableResponse> waiterResponse = dbWaiter.waitUntilTableExists(tableRequest);
            waiterResponse.matched().response().ifPresent(System.out::println);
            newTable = response.tableDescription();
            return newTable;

        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
        return null;
    }



}
```

# Streams e trigger DynamoDB AWS Lambda
<a name="Streams.Lambda"></a>

Amazon DynamoDB è integrato AWS Lambda in modo da poter *creare* trigger, parti di codice che rispondono automaticamente agli eventi in DynamoDB Streams. Con i trigger è possibile creare applicazioni che rispondono alle modifiche di dati nelle tabelle DynamoDB.

**Topics**
+ [Tutorial \$11: Utilizzo dei filtri per elaborare tutti gli eventi con Amazon DynamoDB e utilizzo di AWS Lambda AWS CLI](Streams.Lambda.Tutorial.md)
+ [Tutorial n. 2: utilizzo di filtri per elaborare alcuni eventi con DynamoDB e Lambda](Streams.Lambda.Tutorial2.md)
+ [Best practice per l’utilizzo dei flussi DynamoDB con Lambda](Streams.Lambda.BestPracticesWithDynamoDB.md)

Se abiliti DynamoDB Streams su una tabella, puoi associare lo stream Amazon Resource Name (ARN) a una funzione che scrivi. AWS Lambda Tutte le operazioni di mutazione su quella tabella DynamoDB possono quindi essere acquisite come elemento nel flusso. Ad esempio, è possibile impostare un trigger in modo che quando un elemento in una tabella viene modificato, nel flusso della tabella venga immediatamente visualizzato un nuovo record. 

**Nota**  
In caso di sottoscrizione di più di due funzioni Lambda in un flusso DynamoDB, potrebbe verificarsi una limitazione (della larghezza di banda della rete) della lettura.

Il servizio [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html) esegue il polling del flusso alla ricerca di nuovi record quattro volte al secondo. Quando sono disponibili nuovi record di flusso, la funzione Lambda viene richiamata in modo sincrono. Puoi sottoscrivere fino a due funzioni Lambda allo stesso flusso DynamoDB. In caso di sottoscrizione di più di due funzioni Lambda nello stesso flusso DynamoDB, potrebbe verificarsi una limitazione (della larghezza di banda della rete) della lettura.

La funzione Lambda può inviare una notifica, avviare un flusso di lavoro o eseguire numerose altre operazioni specificate. Ad esempio, è possibile scrivere una funzione Lambda semplicemente per copiare ogni record di flusso in un'archiviazione persistente, come il Gateway di file di Amazon S3 (Amazon S3), per creare un percorso di verifica permanente dell'attività di scrittura della tabella. Oppure, supponi di avere un'applicazione di gioco per dispositivi mobili che scrive in una tabella `GameScores`. Quando l'attributo `TopScore` della tabella `GameScores` viene aggiornato, viene scritto un record di flusso corrispondente nel flusso della tabella. Questo evento potrebbe quindi attivare una funzione Lambda che pubblica un messaggio di congratulazioni su un social network. È anche possibile scrivere questa funzione per ignorare tutti i record di flusso che non sono aggiornamenti di `GameScores` o che non modificano l'attributo `TopScore`.

Se la funzione restituisce un errore, Lambda ritenta il batch fino a quando l'elaborazione non riesce o i dati scadono. È inoltre possibile configurare Lambda in modo da riprovare con un batch di dimensioni inferiori, limitare il numero di tentativi, eliminare i record una volta che diventano troppo vecchi e altre opzioni.

Come best practice in materia di prestazioni, la funzione Lambda deve essere di breve durata. Per evitare di introdurre ritardi di elaborazione non necessari, inoltre, non dovrebbe eseguire una logica complessa. In particolare, per un flusso a velocità elevata, è meglio attivare flussi di lavoro Step Function di post-elaborazione asincrona rispetto a funzioni Lambda sincrone a lunga durata.

 Puoi utilizzare i trigger Lambda su diversi AWS account configurando una policy basata sulle risorse sul flusso DynamoDB per concedere l'accesso in lettura tra account diversi alla funzione Lambda. Per ulteriori informazioni su come configurare lo stream per consentire l'accesso tra account diversi, consulta [Condividi l'accesso con le funzioni AWS Lambda tra account nella](rbac-cross-account-access.md#shared-access-cross-acount-lambda) DynamoDB Developer Guide.

[Per ulteriori informazioni, consulta la Guida per gli AWS Lambda sviluppatori.AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/)

# Tutorial \$11: Utilizzo dei filtri per elaborare tutti gli eventi con Amazon DynamoDB e utilizzo di AWS Lambda AWS CLI
<a name="Streams.Lambda.Tutorial"></a>

 

In questo tutorial, creerai un AWS Lambda trigger per elaborare un flusso da una tabella DynamoDB.

**Topics**
+ [Fase 1: creazione di una tabella DynamoDB con un flusso abilitato](#Streams.Lambda.Tutorial.CreateTable)
+ [Fase 2: creazione di un ruolo di esecuzione Lambda](#Streams.Lambda.Tutorial.CreateRole)
+ [Fase 3: creazione di un argomento Amazon SNS](#Streams.Lambda.Tutorial.SNSTopic)
+ [Fase 4: creazione e test di una funzione Lambda](#Streams.Lambda.Tutorial.LambdaFunction)
+ [Fase 5: creazione e test di un trigger](#Streams.Lambda.Tutorial.CreateTrigger)

Lo scenario di questo tutorial è Woofer, un semplice social network. Gli utenti di Woofer comunicano tramite i *bark*, brevi messaggi di testo che vengono inviati ad altri utenti di Woofer. Il seguente diagramma illustra i componenti e il flusso di lavoro di questa applicazione.

![\[Flusso di lavoro dell’applicazione Woofer di una tabella DynamoDB, record dei flussi, funzione Lambda e argomento Amazon SNS.\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/StreamsAndTriggers.png)


1. Un utente scrive un elemento in una tabella DynamoDB (`BarkTable`). Ogni item della tabella rappresenta un bark.

1. Viene scritto un nuovo record di flusso per riflettere l'aggiunta di un nuovo item a `BarkTable`.

1. Il nuovo record di flusso attiva una AWS Lambda funzione (). `publishNewBark`

1. Se il record di flusso indica che è stato aggiunto un nuovo elemento a `BarkTable`, la funzione Lambda legge i dati dal record di flusso e pubblica un messaggio in un argomento di Amazon Simple Notification Service (Amazon SNS).

1. Questo messaggio è ricevuto dai sottoscrittori dell'argomento Amazon SNS. (In questo tutorial, l'unico sottoscrittore è un indirizzo e-mail).

**Prima di iniziare**  
Questo tutorial utilizza il. AWS Command Line Interface AWS CLI Se non è stato ancora fatto, seguire le istruzioni contenute nella [Guida per l'utente di AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/) per installare e configurare la AWS CLI.

## Fase 1: creazione di una tabella DynamoDB con un flusso abilitato
<a name="Streams.Lambda.Tutorial.CreateTable"></a>

In questa fase, viene creata crea una tabella DynamoDB (`BarkTable`) per memorizzare tutti i bark degli utenti di Woofer. La chiave primaria è costituita da `Username` (chiave di partizione) e `Timestamp` (chiave di ordinamento). Entrambi questi attributi sono di tipo stringa.

In `BarkTable` è abilitato un flusso. Più avanti in questo tutorial, crei un trigger associando una AWS Lambda funzione allo stream.

1. Immetti il seguente comando per creare la tabella.

   ```
   aws dynamodb create-table \
       --table-name BarkTable \
       --attribute-definitions AttributeName=Username,AttributeType=S AttributeName=Timestamp,AttributeType=S \
       --key-schema AttributeName=Username,KeyType=HASH  AttributeName=Timestamp,KeyType=RANGE \
       --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
       --stream-specification StreamEnabled=true,StreamViewType=NEW_AND_OLD_IMAGES
   ```

1. Nell'output, cerca `LatestStreamArn`.

   ```
   ...
   "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

   Prendi nota dei valori `region` e `accountID`, in quanto sono necessari nelle altre fasi di questo tutorial.

## Fase 2: creazione di un ruolo di esecuzione Lambda
<a name="Streams.Lambda.Tutorial.CreateRole"></a>

In questo passaggio, crei un ruolo AWS Identity and Access Management (IAM) (`WooferLambdaRole`) e gli assegni le autorizzazioni. Questo ruolo viene utilizzato dalla funzione Lambda creata in [Fase 4: creazione e test di una funzione Lambda](#Streams.Lambda.Tutorial.LambdaFunction). 

Puoi creare anche una policy per il ruolo. La policy conterrà tutte le autorizzazioni necessarie alla funzione Lambda nella fase di runtime.

1. Crea un file denominato `trust-relationship.json` con i seguenti contenuti.

------
#### [ JSON ]

****  

   ```
   {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }
   ```

------

1. Immetti il seguente comando per creare `WooferLambdaRole`.

   ```
   aws iam create-role --role-name WooferLambdaRole \
       --path "/service-role/" \
       --assume-role-policy-document file://trust-relationship.json
   ```

1. Crea un file denominato `role-policy.json` con i seguenti contenuti. (Sostituisci `region` e inserisci `accountID` la tua AWS regione e l'ID dell'account.)

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "logs:CreateLogGroup",
                   "logs:CreateLogStream",
                   "logs:PutLogEvents"
               ],
               "Resource": "arn:aws:logs:us-east-1:111122223333:*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "dynamodb:DescribeStream",
                   "dynamodb:GetRecords",
                   "dynamodb:GetShardIterator",
                   "dynamodb:ListStreams"
               ],
               "Resource": "arn:aws:dynamodb:us-east-1:111122223333:table/BarkTable/stream/*"
           },
           {
               "Effect": "Allow",
               "Action": [
                   "sns:Publish"
               ],
               "Resource": [
                   "*"
               ]
           }
       ]
   }
   ```

------

   La policy include quattro dichiarazioni che consentono a `WooferLambdaRole` di eseguire le seguenti operazioni:
   + Eseguire una funzione Lambda (`publishNewBark`). Questa funzione viene creata in una fase successiva di questo tutorial.
   + Accedi ad Amazon CloudWatch Logs. La funzione Lambda scrive la diagnostica nei CloudWatch registri in fase di esecuzione.
   + Leggere i dati dal flusso di DynamoDB per `BarkTable`.
   + Pubblicare i messaggi su Amazon SNS.

1. Immetti il seguente comando per collegare la policy a `WooferLambdaRole`.

   ```
   aws iam put-role-policy --role-name WooferLambdaRole \
       --policy-name WooferLambdaRolePolicy \
       --policy-document file://role-policy.json
   ```

## Fase 3: creazione di un argomento Amazon SNS
<a name="Streams.Lambda.Tutorial.SNSTopic"></a>

In questa fase, viene creato un argomento Amazon SNS (`wooferTopic`) e viene registrato un indirizzo e-mail su di esso. La funzione Lambda utilizza questo argomento per pubblicare nuovi bark degli utenti di Woofer.

1. Immettere il seguente comando per creare un nuovo argomento Amazon SNS.

   ```
   aws sns create-topic --name wooferTopic
   ```

1. Immetti il comando seguente per sottoscrivere un indirizzo e-mail a `wooferTopic`. Sostituisci `region` e `accountID` con la regione e l'ID account AWS e sostituisci `example@example.com` con un indirizzo e-mail valido.

   ```
   aws sns subscribe \
       --topic-arn arn:aws:sns:region:accountID:wooferTopic \
       --protocol email \
       --notification-endpoint example@example.com
   ```

1. Amazon SNS invia un messaggio di conferma al tuo indirizzo e-mail. Scegli il link **Confirm subscription (Conferma sottoscrizione)** per completare la procedura di sottoscrizione.

## Fase 4: creazione e test di una funzione Lambda
<a name="Streams.Lambda.Tutorial.LambdaFunction"></a>

In questo passaggio, crei una AWS Lambda funzione (`publishNewBark`) da cui elaborare i record di flusso. `BarkTable`

La funzione `publishNewBark` elabora solo gli eventi di flusso che corrispondono a nuovi item in `BarkTable`. La funzione legge i dati di questo evento, quindi richiama Amazon SNS perché li pubblichi.

1. Crea un file denominato `publishNewBark.js` con i seguenti contenuti. Sostituisci `region` e `accountID` con la tua AWS regione e l'ID dell'account.

   ```
   'use strict';
   var AWS = require("aws-sdk");
   var sns = new AWS.SNS();
   
   exports.handler = (event, context, callback) => {
   
       event.Records.forEach((record) => {
           console.log('Stream record: ', JSON.stringify(record, null, 2));
   
           if (record.eventName == 'INSERT') {
               var who = JSON.stringify(record.dynamodb.NewImage.Username.S);
               var when = JSON.stringify(record.dynamodb.NewImage.Timestamp.S);
               var what = JSON.stringify(record.dynamodb.NewImage.Message.S);
               var params = {
                   Subject: 'A new bark from ' + who,
                   Message: 'Woofer user ' + who + ' barked the following at ' + when + ':\n\n ' + what,
                   TopicArn: 'arn:aws:sns:region:accountID:wooferTopic'
               };
               sns.publish(params, function(err, data) {
                   if (err) {
                       console.error("Unable to send message. Error JSON:", JSON.stringify(err, null, 2));
                   } else {
                       console.log("Results from sending message: ", JSON.stringify(data, null, 2));
                   }
               });
           }
       });
       callback(null, `Successfully processed ${event.Records.length} records.`);
   };
   ```

1. Crea un file zip che contenga `publishNewBark.js`. Per fare ciò, se disponi di una utility a riga di comando zip, puoi immettere il comando seguente.

   ```
   zip publishNewBark.zip publishNewBark.js
   ```

1. Quando si crea la funzione Lambda, si specifica l'Amazon Resource Name (ARN) per `WooferLambdaRole` che hai creato in [Fase 2: creazione di un ruolo di esecuzione Lambda](#Streams.Lambda.Tutorial.CreateRole). Immetti il comando seguente per recuperare questo ARN.

   ```
   aws iam get-role --role-name WooferLambdaRole
   ```

   Nell'output, cerca l'ARN di `WooferLambdaRole`.

   ```
   ...
   "Arn": "arn:aws:iam::region:role/service-role/WooferLambdaRole"
   ...
   ```

   Immetti il seguente comando per creare la funzione Lambda. Sostituire *roleARN* con l'ARN per. `WooferLambdaRole`

   ```
   aws lambda create-function \
       --region region \
       --function-name publishNewBark \
       --zip-file fileb://publishNewBark.zip \
       --role roleARN \
       --handler publishNewBark.handler \
       --timeout 5 \
       --runtime nodejs16.x
   ```

1. Ora esegui il test di `publishNewBark` per verificare che funziona. Per fare ciò, fornire un input simile a un record reale da DynamoDB Streams.

   Crea un file denominato `payload.json` con i seguenti contenuti. Sostituisci `region` e `accountID` con la Regione AWS e l’ID account.

   ```
   {
       "Records": [
           {
               "eventID": "7de3041dd709b024af6f29e4fa13d34c",
               "eventName": "INSERT",
               "eventVersion": "1.1",
               "eventSource": "aws:dynamodb",
               "awsRegion": "region",
               "dynamodb": {
                   "ApproximateCreationDateTime": 1479499740,
                   "Keys": {
                       "Timestamp": {
                           "S": "2016-11-18:12:09:36"
                       },
                       "Username": {
                           "S": "John Doe"
                       }
                   },
                   "NewImage": {
                       "Timestamp": {
                           "S": "2016-11-18:12:09:36"
                       },
                       "Message": {
                           "S": "This is a bark from the Woofer social network"
                       },
                       "Username": {
                           "S": "John Doe"
                       }
                   },
                   "SequenceNumber": "13021600000000001596893679",
                   "SizeBytes": 112,
                   "StreamViewType": "NEW_IMAGE"
               },
               "eventSourceARN": "arn:aws:dynamodb:region:account ID:table/BarkTable/stream/2016-11-16T20:42:48.104"
           }
       ]
   }
   ```

   Immetti il comando seguente per eseguire il test della funzione `publishNewBark`.

   ```
   aws lambda invoke --function-name publishNewBark --payload file://payload.json --cli-binary-format raw-in-base64-out output.txt
   ```

   Se il test viene superato, viene visualizzato il seguente output.

   ```
   {
       "StatusCode": 200,
       "ExecutedVersion": "$LATEST"
   }
   ```

   Inoltre, il file `output.txt` conterrà il testo seguente.

   ```
   "Successfully processed 1 records."
   ```

   Entro pochi minuti riceverai anche un nuovo messaggio e-mail.
**Nota**  
AWS Lambda scrive informazioni diagnostiche su Amazon CloudWatch Logs. Se si verificano errori nella funzione Lambda, è possibile utilizzare queste informazioni diagnostiche per la risoluzione dei problemi:  
Apri la CloudWatch console all'indirizzo [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
Nel riquadro di navigazione scegli **Logs (Log)**.
Scegli il seguente gruppo di log: `/aws/lambda/publishNewBark`
Scegli il flusso di log più recente per visualizzare l'output e gli errori della funzione.

## Fase 5: creazione e test di un trigger
<a name="Streams.Lambda.Tutorial.CreateTrigger"></a>

In [Fase 4: creazione e test di una funzione Lambda](#Streams.Lambda.Tutorial.LambdaFunction), è stato eseguito il test della funzione Lambda per verificarne la corretta esecuzione. In questa fase, è possibile creare un *trigger* associando la funzione Lambda (`publishNewBark`) a un'origine eventi (il flusso `BarkTable`).

1. Quando crei il trigger, è necessario specificare l'ARN del flusso `BarkTable`. Immetti il comando seguente per recuperare questo ARN.

   ```
   aws dynamodb describe-table --table-name BarkTable
   ```

   Nell'output, cerca `LatestStreamArn`.

   ```
   ...
    "LatestStreamArn": "arn:aws:dynamodb:region:accountID:table/BarkTable/stream/timestamp
   ...
   ```

1. Immetti il comando seguente per creare il trigger. Sostituisci `streamARN` con l'ARN del flusso effettivo.

   ```
   aws lambda create-event-source-mapping \
       --region region \
       --function-name publishNewBark \
       --event-source streamARN  \
       --batch-size 1 \
       --starting-position TRIM_HORIZON
   ```

1. Esegui il test del trigger. Immetti il comando seguente per aggiungere un elemento a `BarkTable`.

   ```
   aws dynamodb put-item \
       --table-name BarkTable \
       --item Username={S="Jane Doe"},Timestamp={S="2016-11-18:14:32:17"},Message={S="Testing...1...2...3"}
   ```

   Dovresti ricevere un nuovo messaggio e-mail entro pochi minuti.

1. Aprire la console DynamoDB e aggiungere altri elementi a `BarkTable`. È necessario specificare i valori degli attributi `Username` e `Timestamp`. (Sebbene non sia obbligatorio, si dovrebbe inoltre specificare un valore per `Message`) Dovresti ricevere un nuovo messaggio e-mail per ogni item aggiunto a `BarkTable`.

   La funzione Lambda elabora solo i nuovi elementi aggiunti a `BarkTable`. Se aggiorni o elimini un item della tabella, la funzione non esegue alcuna azione.

**Nota**  
AWS Lambda scrive informazioni diagnostiche su Amazon CloudWatch Logs. Se si verificano errori nella funzione Lambda, è possibile utilizzare queste informazioni diagnostiche per la risoluzione dei problemi:  
Apri la CloudWatch console all'indirizzo [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/).
Nel riquadro di navigazione scegli **Logs (Log)**.
Scegli il seguente gruppo di log: `/aws/lambda/publishNewBark`
Scegli il flusso di log più recente per visualizzare l'output e gli errori della funzione.

# Tutorial n. 2: utilizzo di filtri per elaborare alcuni eventi con DynamoDB e Lambda
<a name="Streams.Lambda.Tutorial2"></a>

In questo tutorial, creerai un AWS Lambda trigger per elaborare solo alcuni eventi in un flusso da una tabella DynamoDB.

**Topics**
+ [Mettere tutto insieme - CloudFormation](#Streams.Lambda.Tutorial2.Cloudformation)
+ [Mettere tutto insieme - CDK](#Streams.Lambda.Tutorial2.CDK)

Con il [filtro eventi Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) è possibile utilizzare espressioni di filtro per controllare quali eventi Lambda invia alla funzione per l'elaborazione. Puoi configurare fino a 5 diversi filtri per i flussi DynamoDB. Se si utilizzano finestre di batch, Lambda applica i criteri di filtro a ogni nuovo evento per stabilire se aggiungerlo al batch corrente.

I filtri vengono applicati tramite strutture chiamate `FilterCriteria`. I 3 attributi principali di `FilterCriteria` sono `metadata properties`, `data properties` e `filter patterns`. 

Ecco una struttura di esempio di un evento di flussi DynamoDB:

```
{
  "eventID": "c9fbe7d0261a5163fcb6940593e41797",
  "eventName": "INSERT",
  "eventVersion": "1.1",
  "eventSource": "aws:dynamodb",
  "awsRegion": "us-east-2",
  "dynamodb": {
    "ApproximateCreationDateTime": 1664559083.0,
    "Keys": {
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" }
    },
    "NewImage": {
      "quantity": { "N": "50" },
      "company_id": { "S": "1000" },
      "fabric": { "S": "Florida Chocolates" },
      "price": { "N": "15" },
      "stores": { "N": "5" },
      "product_id": { "S": "1000" },
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" },
      "state": { "S": "FL" },
      "type": { "S": "" }
    },
    "SequenceNumber": "700000000000888747038",
    "SizeBytes": 174,
    "StreamViewType": "NEW_AND_OLD_IMAGES"
  },
  "eventSourceARN": "arn:aws:dynamodb:us-east-2:111122223333:table/chocolate-table-StreamsSampleDDBTable-LUOI6UXQY7J1/stream/2022-09-30T17:05:53.209"
}
```

`metadata properties` sono i campi dell'oggetto evento. Nel caso di flussi DynamoDB, `metadata properties` sono campi come `dynamodb` o `eventName`. 

`data properties` sono i campi del corpo dell'evento. Per filtrare su `data properties`, bisogna assicurarsi di contenerli in `FilterCriteria` all'interno della chiave appropriata. Per le origini eventi Dynamo DB, la chiave dati è `NewImage` o `OldImage`.

Infine, le regole di filtro definiranno l'espressione del filtro che si desidera applicare a una proprietà specifica. Ecco alcuni esempi:


| Operatore di confronto | Esempio | Sintassi delle regole (parziale) | 
| --- | --- | --- | 
|  Null  |  Il tipo di prodotto è null  |  `{ "product_type": { "S": null } } `  | 
|  Empty  |  Il nome del prodotto è vuoto  |  `{ "product_name": { "S": [ ""] } } `  | 
|  Equals  |  Lo stato equivale a Florida  |  `{ "state": { "S": ["FL"] } } `  | 
|  And  |  Lo stato del prodotto equivale a Florida e la categoria di prodotto è Chocolate  |  `{ "state": { "S": ["FL"] } , "category": { "S": [ "CHOCOLATE"] } } `  | 
|  Or  |  Lo stato del prodotto è Florida o California  |  `{ "state": { "S": ["FL","CA"] } } `  | 
|  Not  |  Lo stato del prodotto non è Florida  |  `{"state": {"S": [{"anything-but": ["FL"]}]}}`  | 
|  Exists  |  Esiste il prodotto artigianale  |  `{"homemade": {"S": [{"exists": true}]}}`  | 
|  Does not exist  |  Il prodotto "homemade" non esiste  |  `{"homemade": {"S": [{"exists": false}]}}`  | 
|  Begins with  |  PK inizia con COMPANY  |  `{"PK": {"S": [{"prefix": "COMPANY"}]}}`  | 

Per una funzione Lambda è possibile specificare fino a 5 modelli di filtro eventi. Si noti che ognuno di questi 5 eventi verrà valutato come un OR logico. Quindi, se configuri due filtri denominati `Filter_One` e `Filter_Two`, la funzione Lambda eseguirà `Filter_One` OR `Filter_Two`.

**Nota**  
Nella pagina di [filtraggio degli eventi Lambda](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) ci sono alcune opzioni per filtrare e confrontare valori numerici, tuttavia nel caso degli eventi di filtro DynamoDB ciò non si applica perché i numeri in DynamoDB vengono memorizzati come stringhe. Ad esempio ` "quantity": { "N": "50" }`, sappiamo che è un numero a causa della proprietà `"N"`.

## Mettere tutto insieme - CloudFormation
<a name="Streams.Lambda.Tutorial2.Cloudformation"></a>

Per mostrare in pratica la funzionalità di filtraggio degli eventi, ecco un CloudFormation modello di esempio. Questo modello genererà una tabella DynamoDB semplice con una chiave di partizione PK e una chiave di ordinamento SK con flussi Amazon DynamoDB abilitati. Creerà una funzione Lambda e un semplice ruolo di esecuzione Lambda che consentirà di scrivere registri su Amazon Cloudwatch e leggere gli eventi dai flussi Amazon DynamoDB. Aggiungerà anche la mappatura dell'origine eventi tra flussi DynamoDB e la funzione Lambda, in modo che la funzione possa essere eseguita ogni volta che c'è un evento nei flussi Amazon DynamoDB.

```
AWSTemplateFormatVersion: "2010-09-09"

Description: Sample application that presents AWS Lambda event source filtering 
with Amazon DynamoDB Streams.

Resources:
  StreamsSampleDDBTable:
    Type: AWS::DynamoDB::Table
    Properties:
      AttributeDefinitions:
        - AttributeName: "PK"
          AttributeType: "S"
        - AttributeName: "SK"
          AttributeType: "S"
      KeySchema:
        - AttributeName: "PK"
          KeyType: "HASH"
        - AttributeName: "SK"
          KeyType: "RANGE"
      StreamSpecification:
        StreamViewType: "NEW_AND_OLD_IMAGES"
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17",		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: "/"
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: "2012-10-17",		 	 	 
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
              - Effect: Allow
                Action:
                  - dynamodb:DescribeStream
                  - dynamodb:GetRecords
                  - dynamodb:GetShardIterator
                  - dynamodb:ListStreams
                Resource: !GetAtt StreamsSampleDDBTable.StreamArn

  EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST

  ProcessEventLambda:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      Timeout: 300
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import logging

          LOGGER = logging.getLogger()
          LOGGER.setLevel(logging.INFO)

          def handler(event, context):
            LOGGER.info('Received Event: %s', event)
            for rec in event['Records']:
              LOGGER.info('Record: %s', rec)

Outputs:
  StreamsSampleDDBTable:
    Description: DynamoDB Table ARN created for this example
    Value: !GetAtt StreamsSampleDDBTable.Arn
  StreamARN:
    Description: DynamoDB Table ARN created for this example
    Value: !GetAtt StreamsSampleDDBTable.StreamArn
```

Dopo aver distribuito questo modello di CloudFormation, puoi inserire il seguente elemento Amazon DynamoDB:

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

Grazie alla semplice funzione lambda inclusa in linea in questo modello di formazione cloud, vedrai gli eventi nei gruppi di CloudWatch log di Amazon per la funzione lambda come segue:

```
{
  "eventID": "c9fbe7d0261a5163fcb6940593e41797",
  "eventName": "INSERT",
  "eventVersion": "1.1",
  "eventSource": "aws:dynamodb",
  "awsRegion": "us-east-2",
  "dynamodb": {
    "ApproximateCreationDateTime": 1664559083.0,
    "Keys": {
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" }
    },
    "NewImage": {
      "quantity": { "N": "50" },
      "company_id": { "S": "1000" },
      "fabric": { "S": "Florida Chocolates" },
      "price": { "N": "15" },
      "stores": { "N": "5" },
      "product_id": { "S": "1000" },
      "SK": { "S": "PRODUCT#CHOCOLATE#DARK#1000" },
      "PK": { "S": "COMPANY#1000" },
      "state": { "S": "FL" },
      "type": { "S": "" }
    },
    "SequenceNumber": "700000000000888747038",
    "SizeBytes": 174,
    "StreamViewType": "NEW_AND_OLD_IMAGES"
  },
  "eventSourceARN": "arn:aws:dynamodb:us-east-2:111122223333:table/chocolate-table-StreamsSampleDDBTable-LUOI6UXQY7J1/stream/2022-09-30T17:05:53.209"
}
```

**Esempi di filtri**
+ **Solo prodotti che corrispondono a un determinato stato**

Questo esempio modifica il CloudFormation modello per includere un filtro per abbinare tutti i prodotti provenienti dalla Florida, con l'abbreviazione «FL».

```
EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{ "dynamodb": { "NewImage": { "state": { "S": ["FL"] } } } }'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Dopo aver ridistribuito lo stack, puoi aggiungere il seguente elemento DynamoDB alla tabella. Si noti che non verrà visualizzato nei registri delle funzioni Lambda, poiché il prodotto in questo esempio proviene dalla California.

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK#1000",
 "company_id": "1000",
 "fabric": "Florida Chocolates",
 "price": 15,
 "product_id": "1000",
 "quantity": 50,
 "state": "CA",
 "stores": 5,
 "type": ""
}
```
+ **Solo gli elementi che iniziano con alcuni valori in PK e SK**

Questo esempio modifica il CloudFormation modello per includere la seguente condizione:

```
EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{"dynamodb": {"Keys": {"PK": { "S": [{ "prefix": "COMPANY" }] },"SK": { "S": [{ "prefix": "PRODUCT" }] }}}}'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Si noti che la condizione AND richiede che la condizione sia all'interno del modello, dove le chiavi PK e SK sono nella stessa espressione separate da una virgola.

O inizia con alcuni valori su PK e SK o proviene da un determinato stato.

Questo esempio modifica il CloudFormation modello per includere le seguenti condizioni:

```
  EventSourceDDBTableStream:
    Type: AWS::Lambda::EventSourceMapping
    Properties:
      BatchSize: 1
      Enabled: True
      FilterCriteria:
        Filters:
          - Pattern: '{"dynamodb": {"Keys": {"PK": { "S": [{ "prefix": "COMPANY" }] },"SK": { "S": [{ "prefix": "PRODUCT" }] }}}}'
          - Pattern: '{ "dynamodb": { "NewImage": { "state": { "S": ["FL"] } } } }'
      EventSourceArn: !GetAtt StreamsSampleDDBTable.StreamArn
      FunctionName: !GetAtt ProcessEventLambda.Arn
      StartingPosition: LATEST
```

Si noti che la condizione OR viene aggiunta introducendo nuovi modelli nella sezione del filtro.

## Mettere tutto insieme - CDK
<a name="Streams.Lambda.Tutorial2.CDK"></a>

Il seguente modello di formazione del progetto CDK di esempio illustra la funzionalità di filtro degli eventi. Prima di lavorare con questo progetto CDK è necessario [installare i prerequisiti](https://docs.aws.amazon.com/cdk/v2/guide/work-with.html), inclusa l'[esecuzione degli script di preparazione](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html).

**Creazione di un progetto CDK**

Per prima cosa crea un nuovo AWS CDK progetto, invocandolo `cdk init` in una directory vuota.

```
mkdir ddb_filters
cd ddb_filters
cdk init app --language python
```

Il comando `cdk init` utilizza il nome della cartella del progetto per denominare vari elementi del progetto, tra cui classi, sottocartelle e file. Tutti i trattini nel nome della cartella vengono convertiti in caratteri di sottolineatura. Altrimenti il nome dovrebbe seguire il formato di un identificatore Python. Ad esempio, non dovrebbe iniziare con un numero o contenere spazi.

Per lavorare con il nuovo progetto, attivare il suo ambiente virtuale. Ciò consente di installare le dipendenze del progetto localmente nella cartella del progetto, anziché globalmente.

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

**Nota**  
Potresti riconoscerlo come il Mac/Linux comando per attivare un ambiente virtuale. I modelli Python includono un file batch, `source.bat`, che consente di utilizzare lo stesso comando su Windows. Funziona anche il comando Windows tradizionale `.venv\Scripts\activate.bat`. Se hai inizializzato il tuo AWS CDK progetto utilizzando AWS CDK Toolkit v1.70.0 o precedente, il tuo ambiente virtuale si trova invece nella directory. `.env` `.venv` 

**Infrastruttura di base**

Apri il file `./ddb_filters/ddb_filters_stack.py` con l'editor di testo preferito. Questo file è stato generato automaticamente al momento della creazione del AWS CDK progetto. 

Quindi, aggiungi le funzioni `_create_ddb_table` e `_set_ddb_trigger_function`. Queste funzioni creeranno una tabella DynamoDB con chiave di partizione PK e una chiave di ordinamento SK in modalità di assegnazione in modalità on-demand, con flussi Amazon DynamoDB abilitato per impostazione predefinita per mostrare immagini nuove e vecchie.

La funzione Lambda verrà archiviata nella cartella `lambda` nel file `app.py`. Questo file verrà creato in seguito. Comprenderà una variabile di ambiente `APP_TABLE_NAME`, che sarà il nome della tabella Amazon DynamoDB creata da questo stack. Nella stessa funzione concederemo alla funzione Lambda le autorizzazioni di lettura del flusso. Infine, verrà effettuata la sottoscrizione a flussi DynamoDB come origine degli eventi per la funzione Lambda. 

Alla fine del file nel metodo `__init__`, richiamerai i rispettivi costrutti per inizializzarli nello stack. Per progetti più grandi che richiedono componenti e servizi aggiuntivi, potrebbe essere meglio definire questi costrutti al di fuori dello stack di base. 

```
import os
import json

import aws_cdk as cdk
from aws_cdk import (
    Stack,
    aws_lambda as _lambda,
    aws_dynamodb as dynamodb,
)
from constructs import Construct


class DdbFiltersStack(Stack):

    def _create_ddb_table(self):
        dynamodb_table = dynamodb.Table(
            self,
            "AppTable",
            partition_key=dynamodb.Attribute(
                name="PK", type=dynamodb.AttributeType.STRING
            ),
            sort_key=dynamodb.Attribute(
                name="SK", type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            stream=dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
            removal_policy=cdk.RemovalPolicy.DESTROY,
        )

        cdk.CfnOutput(self, "AppTableName", value=dynamodb_table.table_name)
        return dynamodb_table

    def _set_ddb_trigger_function(self, ddb_table):
        events_lambda = _lambda.Function(
            self,
            "LambdaHandler",
            runtime=_lambda.Runtime.PYTHON_3_9,
            code=_lambda.Code.from_asset("lambda"),
            handler="app.handler",
            environment={
                "APP_TABLE_NAME": ddb_table.table_name,
            },
        )

        ddb_table.grant_stream_read(events_lambda)

        event_subscription = _lambda.CfnEventSourceMapping(
            scope=self,
            id="companyInsertsOnlyEventSourceMapping",
            function_name=events_lambda.function_name,
            event_source_arn=ddb_table.table_stream_arn,
            maximum_batching_window_in_seconds=1,
            starting_position="LATEST",
            batch_size=1,
        )

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        ddb_table = self._create_ddb_table()
        self._set_ddb_trigger_function(ddb_table)
```

Ora creeremo una funzione lambda molto semplice che stamperà i log in Amazon. CloudWatch Per farlo, crea una nuova cartella denominata `lambda`.

```
mkdir lambda
touch app.py
```

Usando l'editor di testo preferito, aggiungi il seguente contenuto al file `app.py`:

```
import logging

LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)


def handler(event, context):
    LOGGER.info('Received Event: %s', event)
    for rec in event['Records']:
        LOGGER.info('Record: %s', rec)
```

Assicurati di essere nella cartella `/ddb_filters/`, digita il seguente comando per creare l'applicazione di esempio:

```
cdk deploy
```

A un certo punto ti verrà chiesto di confermare se desideri implementare la soluzione. Accetta le modifiche digitando `Y`.

```
├───┼──────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${LambdaHandler/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴──────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘

Do you wish to deploy these changes (y/n)? y

...

✨  Deployment time: 67.73s

Outputs:
DdbFiltersStack.AppTableName = DdbFiltersStack-AppTable815C50BC-1M1W7209V5YPP
Stack ARN:
arn:aws:cloudformation:us-east-2:111122223333:stack/DdbFiltersStack/66873140-40f3-11ed-8e93-0a74f296a8f6
```

Una volta implementate le modifiche, apri la AWS console e aggiungi un elemento alla tabella. 

```
{
 "PK": "COMPANY#1000",
 "SK": "PRODUCT#CHOCOLATE#DARK",
 "company_id": "1000",
 "type": "",
 "state": "FL",
 "stores": 5,
 "price": 15,
 "quantity": 50,
 "fabric": "Florida Chocolates"
}
```

I CloudWatch log dovrebbero ora contenere tutte le informazioni di questa voce. 

**Esempi di filtri**
+ **Solo prodotti che corrispondono a un determinato stato**

Apri il file `ddb_filters/ddb_filters/ddb_filters_stack.py` e modificalo per includere il filtro che corrisponde a tutti i prodotti equivalenti a "FL". Questo può essere modificato appena sotto `event_subscription` nella riga 45.

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {"dynamodb": {"NewImage": {"state": {"S": ["FL"]}}}}
                )
            },
        ]
    },
)
```
+ **Solo gli elementi che iniziano con alcuni valori in PK e SK**

Modifica lo script Python per includere la seguente condizione:

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {
                        {
                            "dynamodb": {
                                "Keys": {
                                    "PK": {"S": [{"prefix": "COMPANY"}]},
                                    "SK": {"S": [{"prefix": "PRODUCT"}]},
                                }
                            }
                        }
                    }
                )
            },
        ]
    },
```
+ **O inizia con alcuni valori su PK e SK o proviene da un determinato stato.**

Modifica lo script Python per includere le seguenti condizioni:

```
event_subscription.add_property_override(
    property_path="FilterCriteria",
    value={
        "Filters": [
            {
                "Pattern": json.dumps(
                    {
                        {
                            "dynamodb": {
                                "Keys": {
                                    "PK": {"S": [{"prefix": "COMPANY"}]},
                                    "SK": {"S": [{"prefix": "PRODUCT"}]},
                                }
                            }
                        }
                    }
                )
            },
            {
                "Pattern": json.dumps(
                    {"dynamodb": {"NewImage": {"state": {"S": ["FL"]}}}}
                )
            },
        ]
    },
)
```

Si noti che la condizione OR viene aggiunta aggiungendo altri elementi all'array Filters.

**Pulizia**

Individua lo stack di filtri nella base della tua directory di lavoro ed esegui `cdk destroy`. Ti verrà chiesto di confermare l'eliminazione della risorsa:

```
cdk destroy
Are you sure you want to delete: DdbFiltersStack (y/n)? y
```

# Best practice per l’utilizzo dei flussi DynamoDB con Lambda
<a name="Streams.Lambda.BestPracticesWithDynamoDB"></a>

Una AWS Lambda funzione viene eseguita all'interno di un *contenitore*, un ambiente di esecuzione isolato da altre funzioni. Quando esegui una funzione per la prima volta, AWS Lambda crea un nuovo contenitore e inizia a eseguire il codice della funzione.

Una funzione Lambda dispone di un *gestore* che viene eseguito a ogni richiamo. Il gestore contiene la logica di business principale della funzione. Ad esempio, la funzione Lambda illustrata in [Fase 4: creazione e test di una funzione Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) dispone di un gestore in grado di elaborare record in un flusso DynamoDB. 

Puoi anche fornire un codice di inizializzazione che venga eseguito una sola volta, dopo la creazione del contenitore, ma prima che il gestore venga AWS Lambda eseguito per la prima volta. La funzione Lambda mostrata in [Fase 4: creazione e test di una funzione Lambda](Streams.Lambda.Tutorial.md#Streams.Lambda.Tutorial.LambdaFunction) ha un codice di inizializzazione che importa l'SDK per JavaScript Node.js e crea un client per Amazon SNS. Questi oggetti dovrebbero essere definiti una sola volta, esternamente al gestore.

Dopo l'esecuzione della funzione, AWS Lambda potrebbe scegliere di riutilizzare il contenitore per le successive chiamate della funzione. In questo caso, il gestore della funzione potrebbe essere in grado di utilizzare nuovamente le risorse definite nel codice di inizializzazione. (Non puoi controllare per quanto tempo AWS Lambda conserva il container, né se questo verrà nuovamente utilizzato o meno).

Per l' AWS Lambda utilizzo dei trigger DynamoDB, consigliamo quanto segue:
+ AWS i client di servizio devono essere istanziati nel codice di inizializzazione, non nel gestore. Ciò consente di AWS Lambda riutilizzare le connessioni esistenti, per tutta la durata del contenitore.
+ In generale, non è necessario gestire in modo esplicito le connessioni o implementare il pool di connessioni perché lo AWS Lambda gestisce per te.

Un consumer Lambda per un flusso DynamoDB non garantisce una consegna esatta di una sola volta e può portare a duplicati occasionali. Assicurati che il codice della funzione Lambda sia idempotente per evitare che si verifichino problemi imprevisti dovuti all’elaborazione duplicata.

Per ulteriori informazioni, consulta [Best practice per l'utilizzo delle AWS Lambda funzioni](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html) nella *AWS Lambda Developer* Guide.

# Flussi DynamoDB e Apache Flink
<a name="StreamsApacheFlink.xml"></a>

È possibile utilizzare i record dei flussi Amazon DynamoDB con Apache Flink. Con il [Servizio gestito da Amazon per Apache Flink](https://aws.amazon.com/managed-service-apache-flink/) è possibile trasformare e analizzare i dati in streaming in tempo reale con Apache Flink. Apache Flink è un framework di elaborazione di flussi open source per l’elaborazione di dati in tempo reale. Il connettore dei flussi Amazon DynamoDB per Apache Flink semplifica la creazione e la gestione dei carichi di lavoro Apache Flink e consente di integrare le applicazioni con altri Servizi AWS.

Amazon Managed Service for Apache Flink ti aiuta a creare rapidamente applicazioni di elaborazione dei end-to-end flussi per l'analisi dei log, l'analisi dei clickstream, l'Internet of Things (IoT), la tecnologia pubblicitaria, i giochi e altro ancora. I quattro casi d'uso più comuni sono lo streaming extract-transform-load (ETL), le applicazioni basate sugli eventi, l'analisi reattiva in tempo reale e l'interrogazione interattiva dei flussi di dati. Per ulteriori informazioni sulla scrittura in Apache Flink dai flussi Amazon DynamoDB, consulta [Amazon DynamoDB Streams Connector](https://nightlies.apache.org/flink/flink-docs-master/docs/connectors/datastream/dynamodb/).