

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# DynamoDB 中的遊戲設定檔結構描述設計
<a name="data-modeling-schema-gaming-profile"></a>

## 遊戲設定檔商業使用案例
<a name="data-modeling-schema-gaming-profile-use-case"></a>

本使用案例討論如何使用 DynamoDB 儲存遊戲系統的玩家設定檔。使用者 (在本案例中為玩家) 需要先建立設定檔，然後才能與許多現代遊戲 (尤其是線上遊戲) 進行互動。遊戲設定檔通常包括下列項目：
+ 基本資訊，例如使用者名稱
+ 遊戲資料，例如物品和裝備
+ 遊戲記錄，例如任務和活動
+ 朋友清單等社交資訊

為了滿足此應用程式的精細資料查詢存取要求，主索引鍵 (分割區索引鍵和排序索引鍵) 將使用通用名稱 (PK 和 SK)，因此它們可以用各種類型的值進行過載，如下所示。

此結構描述設計的存取模式為：
+ 取得使用者的好友清單
+ 取得玩家的所有資訊
+ 取得使用者的物品清單
+ 從使用者的物品清單中取得特定項目
+ 更新使用者的角色
+ 更新使用者的物品計數

遊戲設定檔的大小在不同的遊戲中會有所不同。[壓縮大型屬性值](bp-use-s3-too.md)可以讓它們符合 DynamoDB 中的項目限制並減少成本。輸送量管理策略取決於各種因素，例如：玩家數量，每秒遊戲遊玩數量，以及工作負載的季節性。通常對於新推出的遊戲而言，玩家數量和受歡迎程度未知，因此我們將從[隨需輸送量模式](capacity-mode.md#capacity-mode-on-demand)開始。

## 遊戲設定檔實體關係圖
<a name="data-modeling-schema-gaming-profile-erd"></a>

這是我們將用於遊戲設定檔架構設計的實體關係圖 (ERD)。

![\[遊戲設定檔的 ER 圖表，顯示實體之間的關係，例如使用者、遊戲和分數。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfileERD.png)


## 遊戲設定檔存取模式
<a name="data-modeling-schema-gaming-profile-access-patterns"></a>

這些是我們針對社交網路結構描述設計考量的存取模式。
+ `getPlayerFriends`
+ `getPlayerAllProfile`
+ `getPlayerAllItems`
+ `getPlayerSpecificItem`
+ `updateCharacterAttributes`
+ `updateItemCount`

## 遊戲設定檔結構描述設計演進
<a name="data-modeling-schema-social-network-design-evolution"></a>

從上面的 ERD 我們可以看到，這是一個一對多關係類型的資料建模。在 DynamoDB 中，一對多資料模型可以組織成項目集合，這與傳統建立多資料表並透過外部索引鍵建立連結的關聯式資料庫不同。[項目集合](WorkingWithItemCollections.md)是一組項目，共用相同的分割區索引鍵值，但具有不同的排序索引鍵值。在項目集合中，每個項目都有唯一的排序索引鍵值，可將其與其他項目區分開來。考量這一點，讓我們對每種實體類型的 `HASH` 和 `RANGE` 值使用以下模式。

首先，我們使用通用名稱 (如 `PK` 和 `SK`) 將不同類型的實體儲存在同一個資料表中，以打造前瞻性的模型。為了更好的可讀性，我們可以包括字首來表示資料的類型或包含名為 `Entity_type` 或 `Type` 的任意屬性。在目前範例中，我們使用以 `player` 開頭的字串將 `player_ID` 儲存為 `PK`；使用 `entity name#` 作為 `SK` 的字首，並新增一個 `Type` 屬性來指示這筆資料是哪種實體類型。這使我們能夠支援將來儲存更多實體類型，並使用例如 GSI 超載和稀疏 GSI 等先進技術來滿足更多存取模式。

讓我們開始實作存取模式。新增玩家、新增裝備等存取模式，都可以透過 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) 操作來實現，所以我們可以忽略它們。在本文件中，我們將著重於上面列出的典型存取模式。

**步驟 1：位址存取模式 1 (`getPlayerFriends`)**

我們會透過此步驟解決存取模式 1 (`getPlayerFriends`)。在我們目前的設計中，朋友關係很簡單，遊戲中的朋友數量也很少。為簡單起見，我們使用清單資料類型來儲存朋友清單 (1:1 模型建置)。在這種設計中，我們使用 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) 來滿足這種存取模式。在 `GetItem` 操作中，我們明確提供了分割區索引鍵和排序索引鍵值以取得特定項目。

但是，如果一個遊戲有大量的朋友，並且他們之間的關係很複雜 (例如朋友關係是雙向的，具有邀請和接受元件)，則必須使用多對多關係來單獨儲存每個朋友，以便擴展到無限的朋友清單大小。而且，如果朋友關係變更涉及同時對多個項目進行操作，則 DynamoDB 交易可用於將多個動作分組在一起，並將它們提交為單一「全有或全無」[https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) 或 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html) 操作。

![\[朋友實體遊戲設定檔的複雜多對多關係圖。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile1.png)


**步驟 2：位址存取模式 2 (`getPlayerAllProfile`)、3 (`getPlayerAllItems`) 和 4 (`getPlayerSpecificItem`)**

我們使用此步驟解決存取模式 2 (`getPlayerAllProfile`)、3 (`getPlayerAllItems`) 和 4 (`getPlayerSpecificItem`)。這三種存取模式的共同點是使用 [`Query`](Query.md) 操作的範圍查詢。根據查詢的範圍，會使用[索引鍵條件](Query.KeyConditionExpressions.md)和[篩選條件表達式](Query.FilterExpression.md)，這些表達式通常在實際開發中使用。

在查詢操作中，我們為分割區索引鍵提供單一值，並取得具有該分割區索引鍵值的所有項目。存取模式 2 (`getPlayerAllProfile`) 是以這種方式實現。或者，我們可以新增一個排序索引鍵條件表達式 - 確定要從資料表中讀取項目的字串。存取模式 3 (`getPlayerAllItems`) 是透過新增排序索引鍵 begins\$1with `ITEMS#` 的索引鍵條件來實現。此外，為了簡化應用程式端的開發，我們可以使用篩選條件表達式來實現存取模式 4 (`getPlayerSpecificItem`)。

以下是使用篩選條件表達式來篩選 `Weapon` 類別項目的虛擬程式碼範例：

```
filterExpression: "ItemType = :itemType"
expressionAttributeValues: {":itemType": "Weapon"}
```

![\[以分割區索引鍵和排序索引鍵條件進行查詢操作，以實作不同的存取模式。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile2.png)


**注意**  
篩選條件表達式會在查詢完成之後，結果傳回給用戶端之前進行套用。因此，無論是否有篩選條件表達式，查詢都會使用相同數量的讀取容量。

如果存取模式是查詢大型資料集並篩選出大量資料以僅保留一小部分資料，則適當的方法是更有效地設計 DynamoDB 分割區索引鍵和排序索引鍵。例如，在上面的範例中取得特定 `ItemType`，如果每個玩家都有很多物品並且查詢特定 `ItemType` 是典型的存取模式，將 `ItemType` 作為複合索引鍵帶入 `SK` 會更有效。資料模型看起來會像這樣：`ITEMS#ItemType#ItemId`。

**步驟 3：位址存取模式 5 (`updateCharacterAttributes`)、和 6 (`updateItemCount`)**

我們使用此步驟解決存取模式 5 (`updateCharacterAttributes`) 和 6 (`updateItemCount`)。當玩家需要修改角色時，例如減少貨幣，或者修改物品中某種武器數量時，可使用 [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) 以實現這些存取模式。如要更新玩家的貨幣，但確保它永遠不會低於最低金額，僅在餘額大於或等於最小金額時，我們才可以新增 [DynamoDB 條件表達式 CLI 範例](Expressions.ConditionExpressions.md) 來減少餘額。此為一個虛擬程式碼範例：

```
UpdateExpression: "SET currency = currency - :amount"
ConditionExpression: "currency >= :minAmount"
```

![\[使用 UpdateItem 搭配條件表達式來修改玩家貨幣，確保其絕不會小於設定金額。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile4-Update-player-Currency.png)


使用 DynamoDB 進行開發並使用[原子計數器](WorkingWithItems.md#WorkingWithItems.AtomicCounters)減少庫存時，我們可以透過使用樂觀鎖定來確保冪等性。以下是原子計數器的虛擬程式碼範例：

```
UpdateExpression: "SET ItemCount = ItemCount - :incr"
expression-attribute-values: '{":incr":{"N":"1"}}'
```

![\[使用原子計數器將 ItemCount 屬性值從 5 遞減至 4。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile5-Update-Item-Count.png)


此外，在玩家用貨幣購買物品的情況下，整個過程需要扣除貨幣並同時新增一個物品。我們可以使用 DynamoDB 交易將多個動作分組在一起，並將它們作為單一「全有或全無」`TransactWriteItems` 或 `TransactGetItems` 操作來提交。`TransactWriteItems` 是一種同步且冪等性的寫入操作，在單一「全有或全無」操作中分成多達 100 個群組的寫入操作。這些動作的完成具有不可分割性，也就是全部成功或全部失敗。交易有助於消除貨幣重複或消失的風險。如需交易的詳細資訊，請參閱 [DynamoDB 交易範例](transaction-example.md)。

下表摘要整理了所有存取模式，以及結構描述設計處理這些模式的方式：


| 存取模式 | 基礎資料表/GSI/LSI | 作業 | 分割區索引鍵值 | 排序索引鍵值 | 其他條件/篩選條件 | 
| --- | --- | --- | --- | --- | --- | 
| getPlayerFriends | 基礎資料表 | GetItem | PK=PlayerID | SK=“FRIENDS\$1playerID” |  | 
| getPlayerAllProfile | 基礎資料表 | Query | PK=PlayerID |  |  | 
| getPlayerAllItems | 基礎資料表 | Query | PK=PlayerID | SK begins\$1with “ITEMS\$1” |  | 
| getPlayerSpecificItem | 基礎資料表 | Query | PK=PlayerID | SK begins\$1with “ITEMS\$1” | filterExpression: "ItemType = :itemType" expressionAttributeValues: \$1 ":itemType": "Weapon" \$1 | 
| updateCharacterAttributes | 基礎資料表 | UpdateItem | PK=PlayerID | SK=“\$1METADATA\$1playerID” | UpdateExpression: "SET currency = currency - :amount" ConditionExpression: "currency >= :minAmount" | 
| updateItemCount | 基礎資料表 | UpdateItem | PK=PlayerID | SK =“ITEMS\$1ItemID” | update-expression: "SET ItemCount = ItemCount - :incr" expression-attribute-values: '\$1":incr":\$1"N":"1"\$1\$1' | 

## 遊戲設定檔最終結構描述
<a name="data-modeling-schema-gaming-profile-final-schema"></a>

這是最終的結構描述設計。若要將此結構描述設計下載為 JSON 檔案，請參閱 GitHub 上的 [DynamoDB 範例](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/GamingPlayerProfiles/GamePlayerProfilesSchema.json)。

**基礎資料表：**

![\[資料表的最終結構描述設計，其中包含先前存取模式實作結果。\]](http://docs.aws.amazon.com/zh_tw/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile6-FinalSchema.png)


## 使用 NoSQL Workbench 與此結構描述設計
<a name="data-modeling-schema-gaming-profile-nosql"></a>

您可以將此最終結構描述匯入 [NoSQL Workbench](workbench.md)，這是為 DynamoDB 提供資料建模、資料視覺化，和查詢開發功能的視覺化工具，以進一步探索和編輯新專案。請依照下列步驟以開始使用：

1. 下載 NoSQL Workbench。如需詳細資訊，請參閱[下載 DynamoDB 專用 NoSQL Workbench](workbench.settingup.md)。

1. 下載上面列出的 JSON 結構描述檔案，該檔案已經是 NoSQL Workbench 模型格式。

1. 將 JSON 結構描述檔案匯入到 NoSQL Workbench。如需詳細資訊，請參閱[匯入現有的資料模型](workbench.Modeler.ImportExisting.md)。

1. 一旦您匯入到 NOSQL Workbench 後，便可以編輯資料模型。如需詳細資訊，請參閱[編輯現有的資料模型](workbench.Modeler.Edit.md)。