

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

# Utilizzo di indici secondari globali per query di aggregazione materializzate in DynamoDB
<a name="bp-gsi-aggregation"></a>

Il mantenimento di aggregazioni quasi in tempo reale e parametri chiave oltre a dati in rapida evoluzione sta acquisendo sempre più valore per permettere alle aziende di prendere decisioni in maniera veloce. Ad esempio, una libreria musicale potrebbe voler mostrare i brani più scaricati quasi in tempo reale, oppure una piattaforma di e-commerce potrebbe dover mostrare i prodotti di tendenza per categoria.

Poiché DynamoDB non supporta nativamente operazioni di aggregazione `SUM` simili `COUNT` o tra elementi, il calcolo di questi valori in fase di lettura richiederebbe la scansione di un gran numero di elementi, il che può essere lento e costoso. È invece possibile *precalcolare* le aggregazioni man mano che i dati cambiano e archiviare i risultati come normali elementi della tabella. *Questo modello è chiamato aggregazione materializzata.*

**Topics**
+ [Scenario di esempio e modelli di accesso](#bp-gsi-aggregation-scenario)
+ [Perché precalcolare le aggregazioni](#bp-gsi-aggregation-why)
+ [Progettazione di tabelle](#bp-gsi-aggregation-table-design)
+ [Pipeline di aggregazione con Streams e AWS Lambda](#bp-gsi-aggregation-pipeline)
+ [Design GSI sparso](#bp-gsi-aggregation-sparse-gsi)
+ [Interrogazione del GSI](#bp-gsi-aggregation-querying)
+ [Considerazioni](#bp-gsi-aggregation-considerations)

## Scenario di esempio e modelli di accesso
<a name="bp-gsi-aggregation-scenario"></a>

Prendi in considerazione un'applicazione di libreria musicale con i seguenti requisiti:
+ L'applicazione registra i download di singoli brani ad alto volume (migliaia al secondo).
+ Gli utenti devono vedere i brani più scaricati in un determinato mese con una latenza di un millisecondo.
+ L'applicazione deve inoltre supportare query come «le 10 migliori canzoni del mese» e «tutte le canzoni scaricate in un determinato mese».

Calcolare il conteggio dei download in fase di lettura mediante la scansione di tutti i record di download può essere costoso su questa scala. È invece possibile mantenere un conteggio costante che si aggiorna a ogni download e archiviarlo in un modo che supporti l'esecuzione di query efficienti.

## Perché precalcolare le aggregazioni
<a name="bp-gsi-aggregation-why"></a>

Esistono diversi approcci al calcolo delle aggregazioni. La tabella seguente mette a confronto le alternative più comuni e spiega perché l'aggregazione materializzata in DynamoDB è spesso la soluzione migliore per questo tipo di casi d'uso.


| Approccio | Compromessi | Quando utilizzare | 
| --- | --- | --- | 
| Scansiona e conta in fase di lettura | Richiede la lettura di tutti i record di download per ogni query. La latenza aumenta con il volume dei dati e consuma una notevole capacità di lettura. | Adatto solo per set di dati molto piccoli in cui la latenza non è un problema. | 
| Archivio di aggregazione esterno (ad esempio, Amazon ElastiCache) | Aggiunge complessità operativa con un servizio separato da gestire. Richiede la logica di sincronizzazione tra DynamoDB e la cache. | Quando sono necessarie letture inferiori al millisecondo o una logica di aggregazione complessa che vada oltre i semplici conteggi. | 
| Aggregazione a livello di applicazione in fase di scrittura | Associa la logica di aggregazione al percorso di scrittura. Se l'applicazione fallisce dopo aver registrato il download ma prima di aggiornare il conteggio, l'aggregazione diventa incoerente. | Quando è necessaria un'aggregazione sincrona e fortemente coerente e si può tollerare una maggiore latenza di scrittura. | 
| Aggregazione materializzata con Streams e Lambda | Disaccoppia l'aggregazione dal percorso di scrittura. L'aggregazione alla fine è coerente (in genere con pochi secondi di ritardo). Aggiunge i costi di chiamata Lambda. | Quando hai bisogno di aggregazioni quasi in tempo reale con bassa latenza di lettura e puoi tollerare una eventuale coerenza. Questo è l'approccio descritto in questa pagina. | 

L'approccio di aggregazione materializzata semplifica il percorso di scrittura (basta registrare il download), trasferisce l'aggregazione su un processo asincrono e archivia il risultato in DynamoDB dove può essere interrogato con una latenza di un millisecondo.

## Progettazione di tabelle
<a name="bp-gsi-aggregation-table-design"></a>

Questo design utilizza una singola tabella con due tipi di elementi che condividono la stessa chiave di partizione () ma utilizzano schemi di chiave di ordinamento diversi per distinguerli: `songID`
+ **Record di download**: eventi di download individuali. La chiave di ordinamento è la `DownloadID` (un identificatore univoco per ogni download).
+ **Elementi di aggregazione mensili**: conteggi di download precalcolati per brano al mese. La chiave di ordinamento è il `YYYY-MM` formato del mese (ad esempio,). `2018-01` Questi elementi contengono anche un `DownloadCount` attributo con il totale corrente.

Solo gli elementi di aggregazione mensili contengono l'`Month`attributo. Questa distinzione è importante per la progettazione sparsa del GSI descritta più avanti.

Il diagramma seguente mostra il layout della tabella con entrambi i tipi di elementi:

![\[Layout della tabella della libreria musicale che mostra i record di download e gli elementi di aggregazione mensili che condividono la stessa chiave di partizione (SongID).\]](http://docs.aws.amazon.com/it_it/amazondynamodb/latest/developerguide/images/AggregationQueries.png)



| Tipo di elemento | Chiave di partizione (SongID) | Chiave di ordinamento | Attributi aggiuntivi | 
| --- | --- | --- | --- | 
| Scarica il record | song1 | download-abc123 | UserID, Timestamp | 
| Aggregazione mensile | song1 | 2018-01 | Month=2018-01, DownloadCount=1,746,992 | 

## Pipeline di aggregazione con Streams e AWS Lambda
<a name="bp-gsi-aggregation-pipeline"></a>

La pipeline di aggregazione funziona come segue:

1. Quando viene scaricato un brano, l'applicazione scrive un nuovo elemento nella tabella con `Partition-Key=songID` e. `Sort-Key=DownloadID`

1. DynamoDB Streams acquisisce questa scrittura come record di flusso.

1. Una funzione Lambda, collegata allo stream, elabora il nuovo record. Identifica il mese `songID` e il mese corrente, quindi aggiorna l'elemento di aggregazione mensile corrispondente incrementando l'attributo. `DownloadCount`

1. L'elemento di aggregazione aggiornato è quindi disponibile per l'interrogazione tramite il GSI sparso.

La funzione Lambda utilizza una `UpdateItem` chiamata con un'`ADD`espressione per incrementare atomicamente il numero di download. In questo modo si read-modify-write evitano le condizioni di gara:

```
import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('MusicLibrary')

def handler(event, context):
    for record in event['Records']:
        if record['eventName'] == 'INSERT':
            new_image = record['dynamodb']['NewImage']
            song_id = new_image['songID']['S']
            # Derive the month from the download timestamp
            timestamp = new_image['Timestamp']['S']
            month = timestamp[:7]  # Extract YYYY-MM

            table.update_item(
                Key={
                    'songID': song_id,
                    'SK': month
                },
                UpdateExpression='ADD DownloadCount :inc SET #m = :month',
                ExpressionAttributeNames={
                    '#m': 'Month'
                },
                ExpressionAttributeValues={
                    ':inc': 1,
                    ':month': month
                }
            )
```

**Nota**  
Se un'esecuzione Lambda fallisce dopo aver scritto il valore di aggregazione aggiornato, è possibile ritentare il record dello stream. *Poiché l'`ADD`operazione incrementa il conteggio ogni volta che viene eseguita, un nuovo tentativo incrementerebbe il conteggio più di una volta per lo stesso download, lasciandoti con un valore approssimativo.* Per la maggior parte dei casi d'uso relativi all'analisi e alla classificazione, questo piccolo margine di errore è accettabile. Se hai bisogno di conteggi esatti, prendi in considerazione l'aggiunta di una logica di idempotenza, ad esempio utilizzando un'espressione di condizione che verifichi se lo specifico è già stato elaborato. `DownloadID`

## Design GSI sparso
<a name="bp-gsi-aggregation-sparse-gsi"></a>

Per interrogare in modo efficiente i risultati aggregati, crea un indice secondario globale con il seguente schema chiave:
+ **Chiave di partizione GSI:** `Month` (String)
+ **Chiave di ordinamento GSI:** `DownloadCount` (Numero)

Questo GSI è *scarso* perché solo gli elementi di aggregazione mensili contengono l'attributo. `Month` I singoli record di download non hanno questo attributo, quindi vengono automaticamente esclusi dall'indice. Ciò significa che il GSI contiene solo gli elementi di aggregazione precalcolati, una piccola frazione del totale degli elementi della tabella.

Un GSI scarso offre due vantaggi principali:
+ **Costo inferiore**: poiché nell'indice vengono replicati solo gli elementi di aggregazione, si consumano molta meno capacità di scrittura e storage rispetto a un indice che include tutti gli elementi della tabella.
+ **Query più veloci: l'indice contiene solo i dati necessari per eseguire le query, quindi le letture sono efficienti e restituiscono risultati con una latenza di un millisecondo**.

Per ulteriori informazioni sul funzionamento degli indici sparsi, consulta. [Trai vantaggio degli indici di tipo sparse](bp-indexes-general-sparse-indexes.md)

## Interrogazione del GSI
<a name="bp-gsi-aggregation-querying"></a>

Con un GSI sparso, puoi rispondere in modo efficiente a diversi tipi di domande:

**Ottieni la canzone più scaricata in un determinato mese:**

```
aws dynamodb query \
    --table-name "MusicLibrary" \
    --index-name "MonthDownloadsIndex" \
    --key-condition-expression "#m = :month" \
    --expression-attribute-names '{"#m": "Month"}' \
    --expression-attribute-values '{":month": {"S": "2018-01"}}' \
    --scan-index-forward false \
    --limit 1
```

Se `ScanIndexForward` si imposta su, `false` i risultati vengono ordinati `DownloadCount` in ordine decrescente e viene `Limit=1` restituito solo il brano migliore.

**Visualizza le 10 migliori canzoni di un determinato mese:**

```
aws dynamodb query \
    --table-name "MusicLibrary" \
    --index-name "MonthDownloadsIndex" \
    --key-condition-expression "#m = :month" \
    --expression-attribute-names '{"#m": "Month"}' \
    --expression-attribute-values '{":month": {"S": "2018-01"}}' \
    --scan-index-forward false \
    --limit 10
```

**Scarica tutti i brani in un determinato mese** (ordinati per numero di download):

```
aws dynamodb query \
    --table-name "MusicLibrary" \
    --index-name "MonthDownloadsIndex" \
    --key-condition-expression "#m = :month" \
    --expression-attribute-names '{"#m": "Month"}' \
    --expression-attribute-values '{":month": {"S": "2018-01"}}' \
    --scan-index-forward false
```

## Considerazioni
<a name="bp-gsi-aggregation-considerations"></a>

Tieni presente quanto segue quando implementi questo modello:
+ **Coerenza finale**: i valori di aggregazione vengono aggiornati in modo asincrono tramite DynamoDB Streams e Lambda. In genere c'è un ritardo di alcuni secondi tra la registrazione di un download e l'aggiornamento dell'aggregazione. Ciò significa che il GSI riflette dati quasi in tempo reale, non dati in tempo reale.
+ **Concorrenza Lambda**: se la tabella ha un volume di scrittura elevato, più chiamate Lambda possono tentare di aggiornare lo stesso elemento di aggregazione contemporaneamente. L'`ADD`operazione atomica lo gestisce in modo sicuro, ma è necessario monitorare la concorrenza Lambda e le metriche di limitazione per garantire che la funzione possa tenere il passo con il flusso.
+ **Capacità di scrittura GSI**: poiché il GSI sparso contiene solo elementi di aggregazione, richiede una capacità di scrittura significativamente inferiore rispetto alla tabella base. Tuttavia, è comunque necessario fornire una capacità sufficiente (o utilizzare la modalità on-demand) per gestire la frequenza degli aggiornamenti di aggregazione.
+ **Conteggi approssimativi**: come notato in precedenza, i nuovi tentativi Lambda possono far sì che i conteggi vengano leggermente sovrastimati. Per i casi d'uso che richiedono conteggi esatti, implementa i controlli di idempotenza nella funzione Lambda.