Seleziona le tue preferenze relative ai cookie

Utilizziamo cookie essenziali e strumenti simili necessari per fornire il nostro sito e i nostri servizi. Utilizziamo i cookie prestazionali per raccogliere statistiche anonime in modo da poter capire come i clienti utilizzano il nostro sito e apportare miglioramenti. I cookie essenziali non possono essere disattivati, ma puoi fare clic su \"Personalizza\" o \"Rifiuta\" per rifiutare i cookie prestazionali.

Se sei d'accordo, AWS e le terze parti approvate utilizzeranno i cookie anche per fornire utili funzionalità del sito, ricordare le tue preferenze e visualizzare contenuti pertinenti, inclusa la pubblicità pertinente. Per continuare senza accettare questi cookie, fai clic su \"Continua\" o \"Rifiuta\". Per effettuare scelte più dettagliate o saperne di più, fai clic su \"Personalizza\".

Fase 2: esame del modello di dati e dei dettagli di implementazione

Modalità Focus
Fase 2: esame del modello di dati e dei dettagli di implementazione - Amazon DynamoDB

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

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

2.1: Modello di dati di base

Questa applicazione di esempio mette in evidenza i concetti seguenti relativi al modello di dati di DynamoDB:

  • Tabella: in DynamoDB, una tabella è una raccolta di elementi (ovvero record) e ogni elemento è una raccolta di coppie nome-valore denominate attributi.

    In questo Tic-Tac-Toe esempio, l'applicazione memorizza tutti i dati di gioco in una tabella,. Games L'applicazione crea una item nella tabella per ogni partita e archivia tutti i dati di gioco come attributi. Una tic-tac-toe partita può avere fino a nove mosse. Poiché le tabelle DynamoDB non hanno uno schema nei casi in cui l'attributo richiesto è solo la chiave primaria, l'applicazione può archiviare un numero variabile di attributi per elemento di gioco.

    La tabella Games ha una chiave primaria semplice costituita da un attributo, GameId, di tipo stringa. L'applicazione assegna un ID univoco a ogni partita. Per ulteriori informazioni sulle chiavi primarie di DynamoDB, vedi Chiave primaria.

    Quando un utente inizia una tic-tac-toe partita invitando un altro utente a giocare, l'applicazione crea un nuovo elemento nella Games tabella con attributi che memorizzano i metadati del gioco, come i seguenti:

    • HostId, l'utente che ha avviato la partita.

    • Opponent, l'utente che è stato invitato a giocare.

    • Utente che deve giocare il turno successivo. L'utente che avvia la partita gioca per primo.

    • Utente che usa il simbolo O sulla griglia di gioco. L'utente che avvia la partita usa il simbolo O.

    L'applicazione crea anche un attributo concatenato StatusDate, contrassegnando lo stato iniziale della partita come PENDING. Lo screenshot seguente mostra un elemento di esempio come appare nella console DynamoDB:

    Schermata della console della tabella degli attributi.

    Man mano che la partita procede, l'applicazione aggiunge un attributo alla tabella per ogni mossa nel gioco. Il nome dell'attributo è costituito dalla posizione sulla griglia, ad esempio TopLeft o BottomRight. Una mossa, ad esempio, può avere un attributo TopLeft con il valore O, un attributo TopRight con il valore O e un attributo BottomRight con il valore X. Il valore dell'attributo è O o X, a seconda dell'utente che ha fatto la mossa. Considera, ad esempio, la griglia seguente.

    Schermata che mostra una tic-tac-toe partita finita che si è conclusa in parità.
  • Attributi dei valori concatenati: l'attributo StatusDateillustra un attributo valore concatenato. In base a questo approccio, anziché creare attributi separati per archiviare lo stato della partita (PENDING, IN_PROGRESS e FINISHED) e la data (dell'ultima mossa), i valori vengono combinati in un unico attributo, ad esempio IN_PROGRESS_2014-04-30 10:20:32.

    L'applicazione usa quindi l'attributo StatusDate per la creazione di indici secondari specificando StatusDate come chiave di ordinamento per l'indice. Il vantaggio dell'uso dell'attributo con valori concatenati StatusDate è spiegato ulteriormente negli indici illustrati più avanti.

  • Indici secondari globali: è possibile utilizzare la chiave primaria della tabella, GameId, per interrogare in modo efficiente la tabella per trovare un oggetto di gioco. Per eseguire query sulla tabella in base ad attributi diversi da quelli della chiave primaria, DynamoDB supporta la creazione di indici secondari. In questa applicazione di esempio vengono creati i due indici secondari seguenti:

    Schermata che mostra hostStatusDate gli indici secondari oppStatusDate globali creati nell'applicazione di esempio.
    • HostId- -indice. StatusDate Questo indice ha HostId come chiave di partizione e StatusDate come chiave di ordinamento. Puoi usare l'indice per eseguire query su HostId, ad esempio per trovare le partite ospitate da un utente specifico.

    • OpponentId- StatusDate -indice. Questo indice ha OpponentId come chiave di partizione e StatusDate come chiave di ordinamento. Puoi usare l'indice per eseguire query su Opponent, ad esempio per trovare le partite in cui un utente specifico è l'avversario.

    Questi indici vengono detti indici secondari globali perché la loro chiave di partizione non corrisponde alla chiave di partizione (GameId) usata nella chiave primaria della tabella.

    Entrambi gli indici hanno StatusDate come chiave di ordinamento. Ciò permette quanto segue:

    • Puoi eseguire query usando l'operatore di confronto BEGINS_WITH. Puoi ad esempio trovare tutte le partite con l'attributo IN_PROGRESS ospitate da un utente specifico. In questo caso, l'operatore BEGINS_WITH cerca il valore StatusDate che inizia con IN_PROGRESS.

    • DynamoDB archivia gli elementi nell'indice ordinandoli in base al valore della chiave di ordinamento. Quindi, se tutti i prefissi di stato sono uguali (ad esempio,IN_PROGRESS), il ISO formato utilizzato per la parte relativa alla data avrà gli elementi ordinati dal più vecchio al più recente. Questo approccio permette di eseguire in modo efficace determinate query, come le seguenti:

      • Recupera fino a 10 partite IN_PROGRESS più recenti ospitate dall'utente che ha eseguito l'accesso. Per questa query, specifica l'indice HostId-StatusDate-index.

      • Recupera fino a 10 partite IN_PROGRESS più recenti in cui l'utente che ha eseguito l'accesso è l'avversario. Per questa query, specifica l'indice OpponentId-StatusDate-index.

Per ulteriori informazioni sugli indici secondari, consulta Miglioramento dell'accesso ai dati con indici secondari in DynamoDB.

2.2: Funzionamento dell'applicazione (procedura guidata per il codice)

Questa applicazione ha due pagine principali:

  • Pagina iniziale: questa pagina fornisce all'utente un accesso semplice, un CREATEpulsante per creare una nuova tic-tac-toe partita, un elenco delle partite in corso, la cronologia delle partite e tutti gli inviti a giocare attivi in sospeso.

    La home page non si aggiorna automaticamente, ma deve essere aggiornata manualmente per aggiornare gli elenchi.

  • Pagina del gioco: questa pagina mostra la tic-tac-toe griglia in cui giocano gli utenti.

    L'applicazione aggiorna la pagina del gioco automaticamente ogni secondo. JavaScript Nel tuo browser richiama il server web Python ogni secondo per chiedere alla tabella Giochi se gli elementi del gioco nella tabella sono cambiati. In caso affermativo, JavaScript attiva un aggiornamento della pagina in modo che l'utente veda la bacheca aggiornata.

Analizziamo nel dettaglio il funzionamento dell'applicazione.

Home page

Dopo l'accesso dell'utente, l'applicazione visualizza i tre elenchi di informazioni seguenti.

Screenshot che mostra la home page dell'applicazione con 3 elenchi: inviti in sospeso, partite in corso e cronologia recente.
  • Inviti: in questo elenco vengono visualizzati fino a 10 inviti più recenti da altri che sono in attesa di accettazione da parte dell'utente che ha eseguito l'accesso. Nello screenshot precedente l'utente user1 ha inviti in attesa da user5 e user2.

  • Giochi in corso: questo elenco mostra fino ai 10 giochi più recenti in corso. Si tratta delle partite a cui l'utente sta giocando, che hanno stato IN_PROGRESS. Nello screenshot, l'utente1 sta giocando attivamente con user3 e tic-tac-toe user4.

  • Cronologia recente: questo elenco mostra fino ai 10 giochi più recenti che l'utente ha terminato, che hanno lo stato FINISHED. Nello screenshot user1 ha giocato in precedenza con user2. Per ogni partita completata viene indicato il risultato.

Nel codice la funzione index (in application.py) esegue le tre chiamate seguenti per recuperare informazioni sullo stato della partita:

inviteGames = controller.getGameInvites(session["username"]) inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS") finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")

Ognuna di queste chiamate restituisce un elenco di elementi di DynamoDB inclusi in oggetti Game. È possibile estrarre i dati da questi oggetti nella vista in modo semplice. La funzione index passa questi elenchi di oggetti alla vista per renderizzare. HTML

return render_template("index.html", user=session["username"], invites=inviteGames, inprogress=inProgressGames, finished=finishedGames)

L' Tic-Tac-Toeapplicazione definisce la Game classe principalmente per archiviare i dati di gioco recuperati da DynamoDB. Queste funzioni restituiscono elenchi di oggetti Game che permettono di isolare il resto dell'applicazione dal codice correlato agli elementi Amazon DynamoDB. Queste funzioni aiutano quindi a separare il codice dell'applicazione dai dettagli del livello datastore.

Il pattern architettonico qui descritto viene anche chiamato pattern model-view-controller (MVC) UI. In questo caso, le istanze Game dell'oggetto (che rappresentano i dati) sono il modello e la HTML pagina è la vista. Il controller è diviso in due file. Il file application.py ha la logica del controller per il framework Flask e la logica di business è isolata nel file gameController.py. Cioè, l'applicazione archivia tutto ciò che ha a che fare con SDK DynamoDB in un file separato all'interno della cartella. dynamodb

Esaminiamo le tre funzioni e come eseguono query sulla tabella Games usando gli indici secondari globali per recuperare i dati rilevanti.

Si usa getGameInvites per ottenere l'elenco degli inviti alle partite in sospeso

La funzione getGameInvites restituisce l'elenco dei 10 inviti in attesa più recenti. Queste partite sono state create dagli utenti, ma gli avversari non hanno accettato l'invito. Per queste partite, lo stato rimane PENDING fino a quando l'avversario non accetta l'invito. Se l'avversario rifiuta l'invito, l'applicazione rimuove l'item corrispondente dalla tabella.

La funzione specifica la query come segue:

  • Specifica l'indice OpponentId-StatusDate-index da usare con i valori delle chiavi di indice e gli operatori di confronto seguenti:

    • La chiave di partizione è OpponentId e accetta la chiave di indice user ID.

    • La chiave di ordinamento è StatusDate e accetta l'operatore di confronto e il valore della chiave di indice beginswith="PENDING_".

    È possibile utilizzare l'indice OpponentId-StatusDate-index per recuperare i giochi a cui è invitato l'utente connesso, ovvero dove l'utente connesso è l'avversario.

  • La query prevede un limite di 10 item nel risultato.

gameInvitesIndex = self.cm.getGamesTable().query( Opponent__eq=user, StatusDate__beginswith="PENDING_", index="OpponentId-StatusDate-index", limit=10)

Nell'indice, per ogni valore OpponentId (la chiave di partizione) DynamoDB mantiene gli elementi ordinati in base a StatusDate (la chiave di ordinamento). Le partite restituite dalla query saranno quindi le 10 più recenti.

Utilizzo di getGamesWith Status per ottenere l'elenco dei giochi con uno stato specifico

Quando un avversario accetta un invito a una partita, lo stato diventa IN_PROGRESS. Al termine della partita, lo stato cambia in FINISHED.

Le query per trovare le partite in corso o terminate sono uguali, ad eccezione del valore di stato diverso. L'applicazione definisce quindi la funzione getGamesWithStatus, che accetta un valore di stato come parametro.

inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS") finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")

La sezione seguente si riferisce alle partite in corso, ma la stessa descrizione si applica alle partite terminate.

Un elenco delle partite in corso per un utente specifico include entrambi i tipi seguenti:

  • Partite in corso ospitate dall'utente

  • Partite in corso in cui l'utente è l'avversario

La funzione getGamesWithStatus esegue le due query seguenti, ogni volta usando l'indice secondario appropriato.

  • La funzione esegue una query sulla tabella Games usando l'indice HostId-StatusDate-index. Per l'indice, la query specifica i valori della chiave primaria, sia la chiave di partizione (HostId) che la chiave di ordinamento (StatusDate), insieme agli operatori di confronto.

    hostGamesInProgress = self.cm.getGamesTable ().query(HostId__eq=user, StatusDate__beginswith=status, index="HostId-StatusDate-index", limit=10)

    Ecco la sintassi Python per gli operatori di confronto:

    • HostId__eq=user specifica l'operatore di confronto di uguaglianza.

    • StatusDate__beginswith=status specifica l'operatore di confronto BEGINS_WITH.

  • La funzione esegue una query sulla tabella Games usando l'indice OpponentId-StatusDate-index.

    oppGamesInProgress = self.cm.getGamesTable().query(Opponent__eq=user, StatusDate__beginswith=status, index="OpponentId-StatusDate-index", limit=10)
  • La funzione combina quindi i due elenchi, li ordina, crea un elenco di oggetti Game per i primi da 0 a 10 item e restituisce l'elenco alla funzione chiamante, ovvero all'indice.

    games = self.mergeQueries(hostGamesInProgress, oppGamesInProgress) return games

Pagina del gioco

La pagina del gioco è dove l'utente tic-tac-toe gioca. In questa pagina sono presenti la griglia di gioco e informazioni sulla partita. Lo screenshot seguente mostra una partita di esempio in corso:

Schermata che mostra una tic-tac-toe partita in corso.

L'applicazione visualizza la pagina del gioco nelle situazioni seguenti:

  • L'utente crea una partita invitando un altro utente a giocare.

    In questo caso, la pagina mostra l'utente come host e lo stato della partita come PENDING, in attesa che l'avversario accetti l'invito.

  • L'utente accetta uno degli inviti in attesa nella home page.

    In questo caso, la pagina mostra l'utente come avversario e lo stato della partita come IN_PROGRESS.

Quando l'utente effettua una selezione sulla griglia, viene generata una richiesta POST per l'applicazione. Cioè, Flask chiama la selectSquare funzione (inapplication.py) con i dati del HTML modulo. Questa funzione, a sua volta, chiama la funzione updateBoardAndTurn (in gameController.py) per aggiornare l'item di gioco come indicato di seguito:

  • Aggiunge un nuovo attributo specifico della mossa.

  • Aggiorna il valore dell'attributo Turn in base all'utente che deve giocare il turno successivo.

controller.updateBoardAndTurn(item, value, session["username"])

La funzione restituisce true se l'aggiornamento dell'item è stato eseguito correttamente, altrimenti restituisce false. Tieni presente quanto segue in relazione alla funzione updateBoardAndTurn:

  • La funzione chiama la update_item funzione di SDK for Python per apportare un insieme finito di aggiornamenti a un elemento esistente. La funzione è mappata all'operazione UpdateItem in DynamoDB. Per ulteriori informazioni, consulta UpdateItem.

    Nota

    La differenza tra le operazioni UpdateItem e PutItem è legata al fatto che PutItem sostituisce l'intero item. Per ulteriori informazioni, consulta PutItem.

Per la chiamata di update_item, il codice identifica quanto segue:

  • La chiave primaria della tabella Games, ovvero ItemId.

    key = { "GameId" : { "S" : gameId } }
  • Il nuovo attributo da aggiungere, specifico della mossa dell'utente corrente, e il relativo valore (ad esempio TopLeft="X").

    attributeUpdates = { position : { "Action" : "PUT", "Value" : { "S" : representation } } }
  • Le condizioni che devono essere soddisfatte affinché venga eseguito l'aggiornamento:

    • La partita deve essere in corso. Ciò significa che il valore dell'attributo StatusDate deve iniziare con IN_PROGRESS.

    • Il turno corrente deve essere un turno utente valido come specificato dall'attributo Turn.

    • Il quadrato della griglia scelto dall'utente deve essere disponibile. Ciò significa che l'attributo corrispondente al quadrato non deve esistere.

    expectations = {"StatusDate" : {"AttributeValueList": [{"S" : "IN_PROGRESS_"}], "ComparisonOperator": "BEGINS_WITH"}, "Turn" : {"Value" : {"S" : current_player}}, position : {"Exists" : False}}

La funzione chiama ora update_item per aggiornare l'item.

self.cm.db.update_item("Games", key=key, attribute_updates=attributeUpdates, expected=expectations)

Dopo che la funzione restituisce il risultato, la funzione selectSquare chiama il metodo redirect, come illustrato nell'esempio seguente.

redirect("/game="+gameId)

Questa chiamata causa l'aggiornamento del browser. Nel corso di questo aggiornamento, l'applicazione verifica se la partita si è conclusa con una vittoria o un pareggio. In caso affermativo, l'applicazione aggiorna l'item di gioco di conseguenza.

PrivacyCondizioni del sitoPreferenze cookie
© 2025, Amazon Web Services, Inc. o società affiliate. Tutti i diritti riservati.