

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

# 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"} }'
```