DynamoDB 快速指南



DynamoDB - 概覽

DynamoDB 允許使用者建立能夠儲存和檢索任意數量資料併為任意數量流量提供服務的資料庫。它會自動將資料和流量分佈在伺服器上以動態管理每個客戶的請求,並保持快速效能。

DynamoDB 與 RDBMS 的比較

DynamoDB 使用 NoSQL 模型,這意味著它使用非關係型系統。下表重點介紹了 DynamoDB 和 RDBMS 之間的區別 -

常見任務 RDBMS DynamoDB
連線到源 它使用持久連線和 SQL 命令。 它使用 HTTP 請求和 API 操作
建立表 其基本結構是表,並且必須定義。 它僅使用主鍵,建立時沒有模式。它使用各種資料來源。
獲取表資訊 所有表資訊仍然可訪問 僅顯示主鍵。
載入表資料 它使用由列組成的行。 在表中,它使用由屬性組成的專案
讀取表資料 它使用 SELECT 語句和過濾語句。 它使用 GetItem、Query 和 Scan。
管理索引 它使用透過 SQL 語句建立的標準索引。對其進行的修改會在表更改時自動發生。 它使用二級索引來實現相同的功能。它需要規範(分割槽鍵和排序鍵)。
修改表資料 它使用 UPDATE 語句。 它使用 UpdateItem 操作。
刪除表資料 它使用 DELETE 語句。 它使用 DeleteItem 操作。
刪除表 它使用 DROP TABLE 語句。 它使用 DeleteTable 操作。

優勢

DynamoDB 的兩個主要優勢是可擴充套件性和靈活性。它不要求使用特定的資料來源和結構,允許使用者以統一的方式處理幾乎任何內容。

其設計還支援從較輕的任務和操作到苛刻的企業功能的廣泛用途。它還允許簡單地使用多種語言:Ruby、Java、Python、C#、Erlang、PHP 和 Perl。

侷限性

然而,DynamoDB 確實存在某些侷限性,但這些侷限性不一定造成重大問題或阻礙可靠的開發。

您可以從以下幾點回顧它們 -

  • 容量單位大小 - 讀取容量單位是每秒對不大於 4KB 的專案進行一次一致讀取。寫入容量單位是每秒對不大於 1KB 的專案進行一次寫入。

  • 預置吞吐量最小值/最大值 - 所有表和全域性二級索引的讀取和寫入容量單位至少為一個。最大值取決於區域。在美國,每個表的讀取和寫入上限為 40K(每個帳戶 80K),其他區域每個表的讀取和寫入上限為 10K,每個帳戶的讀取和寫入上限為 20K。

  • 預置吞吐量的增加和減少 - 您可以根據需要隨時增加它,但減少每天每個表最多僅限四次。

  • 每個帳戶的表大小和數量 - 表大小沒有限制,但除非您請求更高的上限,否則帳戶的表限制為 256 個。

  • 每個表的二級索引 - 允許五個本地索引和五個全域性索引。

  • 每個表的投影二級索引屬性 - DynamoDB 允許 20 個屬性。

  • 分割槽鍵長度和值 - 它們的最小長度為 1 位元組,最大長度為 2048 位元組,但是,DynamoDB 對值沒有限制。

  • 排序鍵長度和值 - 其最小長度為 1 位元組,最大長度為 1024 位元組,除非其表使用本地二級索引,否則對值沒有限制。

  • 表和二級索引名稱 - 名稱的最小長度必須為 3 個字元,最大長度為 255 個字元。它們使用以下字元:AZ、a-z、0-9、“_”、“-” 和“.”。

  • 屬性名稱 - 最小為一個字元,最大為 64KB,但鍵和某些屬性除外。

  • 保留字 - DynamoDB 不阻止將保留字用作名稱。

  • 表示式長度 - 表示式字串長度限制為 4KB。屬性表示式的長度限制為 255 位元組。表示式的替換變數長度限制為 2MB。

DynamoDB - 基本概念

在使用 DynamoDB 之前,您必須熟悉其基本元件和生態系統。在 DynamoDB 生態系統中,您使用表、屬性和專案進行操作。表包含一組專案,專案包含一組屬性。屬性是資料的基本元素,不需要進一步分解,即欄位。

主鍵

主鍵充當表專案唯一標識的方法,二級索引提供查詢靈活性。DynamoDB 透過修改表資料來記錄事件。

表建立不僅需要設定名稱,還需要設定主鍵;它標識表專案。沒有兩個專案共享一個鍵。DynamoDB 使用兩種型別的主鍵 -

  • 分割槽鍵 - 此簡單主鍵由一個稱為“分割槽鍵”的單個屬性組成。在內部,DynamoDB 使用鍵值作為雜湊函式的輸入來確定儲存位置。

  • 分割槽鍵和排序鍵 - 此鍵稱為“複合主鍵”,由兩個屬性組成。

    • 分割槽鍵和

    • 排序鍵。

    DynamoDB 將第一個屬性應用於雜湊函式,並將具有相同分割槽鍵的專案儲存在一起;其順序由排序鍵確定。專案可以共享分割槽鍵,但不能共享排序鍵。

主鍵屬性僅允許標量(單個)值;以及字串、數字或二進位制資料型別。非鍵屬性沒有這些約束。

二級索引

這些索引允許您使用備用鍵查詢表資料。儘管 DynamoDB 不要求使用它們,但它們可以最佳化查詢。

DynamoDB 使用兩種型別的二級索引 -

  • 全域性二級索引 - 此索引擁有分割槽鍵和排序鍵,它們可能與表鍵不同。

  • 本地二級索引 - 此索引擁有與表相同的分割槽鍵,但其排序鍵不同。

API

DynamoDB 提供的 API 操作包括控制平面、資料平面(例如建立、讀取、更新和刪除)和流的操作。在控制平面操作中,您可以使用以下工具建立和管理表 -

  • CreateTable
  • DescribeTable
  • ListTables
  • UpdateTable
  • DeleteTable

在資料平面中,您可以使用以下工具執行 CRUD 操作 -

建立 讀取 更新 刪除

PutItem

BatchWriteItem

GetItem

BatchGetItem

Query

Scan

UpdateItem

DeleteItem

BatchWriteItem

流操作控制表流。您可以檢視以下流工具 -

  • ListStreams
  • DescribeStream
  • GetShardIterator
  • GetRecords

預置吞吐量

在表建立中,您指定預置吞吐量,它保留讀取和寫入的資源。您使用容量單位來衡量和設定吞吐量。

當應用程式超出設定的吞吐量時,請求會失敗。DynamoDB GUI 控制檯允許監控設定和使用的吞吐量,以便更好地進行動態配置。

讀取一致性

DynamoDB 使用最終一致性強一致性讀取來支援動態應用程式需求。最終一致性讀取並不總是提供當前資料。

強一致性讀取始終提供當前資料(裝置故障或網路問題除外)。最終一致性讀取用作預設設定,需要在ConsistentRead引數中設定為 true 才能更改它。

分割槽

DynamoDB 使用分割槽進行資料儲存。這些表的儲存分配具有 SSD 支援,並在區域之間自動複製。DynamoDB 管理所有分割槽任務,無需使用者參與。

在表建立中,表進入 CREATING 狀態,該狀態分配分割槽。當它達到 ACTIVE 狀態時,您可以執行操作。當其容量達到最大值或您更改吞吐量時,系統會更改分割槽。

DynamoDB - 環境

DynamoDB 環境僅包括使用您的 Amazon Web Services 帳戶訪問 DynamoDB GUI 控制檯,但是,您也可以執行本地安裝。

導航到以下網站 - https://aws.amazon.com/dynamodb/

點選“開始使用 Amazon DynamoDB”按鈕,如果您沒有 Amazon Web Services 帳戶,則點選“建立 AWS 帳戶”按鈕。簡單的引導流程將告知您所有相關的費用和要求。

完成流程的所有必要步驟後,您將獲得訪問許可權。只需登入 AWS 控制檯,然後導航到 DynamoDB 控制檯。

請務必刪除未使用的或不必要的材料,以避免相關費用。

本地安裝

AWS(Amazon Web Service)提供了一個用於本地安裝的 DynamoDB 版本。它支援在沒有 Web 服務或連線的情況下建立應用程式。它還可以透過允許本地資料庫來減少預置吞吐量、資料儲存和傳輸費用。本指南假定進行了本地安裝。

準備好部署時,您可以對應用程式進行一些小的調整以將其轉換為 AWS 使用。

安裝檔案是一個.jar 可執行檔案。它可以在 Linux、Unix、Windows 和任何其他支援 Java 的作業系統上執行。使用以下連結之一下載檔案 -

注意 − 其他儲存庫也提供此檔案,但不一定是最新版本。請使用以上鍊接獲取最新的安裝檔案。此外,請確保您已安裝 Java 執行時環境 (JRE) 6.x 或更高版本。DynamoDB 無法在較舊的版本上執行。

下載相應的壓縮包後,解壓其目錄(DynamoDBLocal.jar)並將其放置在所需位置。

然後,您可以透過開啟命令提示符,導航到包含 DynamoDBLocal.jar 的目錄,並輸入以下命令來啟動 DynamoDB −

java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb

您也可以透過關閉用於啟動它的命令提示符來停止 DynamoDB。

工作環境

您可以使用 JavaScript Shell、GUI 控制檯和多種語言來使用 DynamoDB。可用的語言包括 Ruby、Java、Python、C#、Erlang、PHP 和 Perl。

在本教程中,我們使用 Java 和 GUI 控制檯示例來提高概念和程式碼的清晰度。安裝 Java IDE、AWS SDK for Java,併為 Java SDK 設定 AWS 安全憑證以使用 Java。

從本地到 Web 服務程式碼的轉換

準備好部署時,您需要更改程式碼。調整取決於程式碼語言和其他因素。主要更改僅包括將端點從本地點更改為 AWS 區域。其他更改需要更深入地分析您的應用程式。

本地安裝在許多方面都不同於 Web 服務,包括但不限於以下關鍵區別 −

  • 本地安裝會立即建立表,但服務需要更長時間。

  • 本地安裝會忽略吞吐量。

  • 本地安裝中刪除操作會立即發生。

  • 由於沒有網路開銷,本地安裝中的讀/寫操作會很快。

DynamoDB - 操作工具

DynamoDB 提供三種執行操作的選項:基於 Web 的 GUI 控制檯、JavaScript Shell 和您選擇的程式語言。

在本教程中,我們將重點介紹使用 GUI 控制檯和 Java 語言,以提高畫質晰度和概念理解。

GUI 控制檯

可以在以下地址找到 GUI 控制檯或 Amazon DynamoDB 的 AWS 管理控制檯 − https://console.aws.amazon.com/dynamodb/home

它允許您執行以下任務 −

  • CRUD 操作
  • 查看錶項
  • 執行表查詢
  • 設定表容量監控的警報
  • 即時查看錶指標
  • 查看錶警報
GUI Console

如果您的 DynamoDB 帳戶沒有表,則在訪問時,它會指導您建立表。其主螢幕提供了三個執行常見操作的快捷方式 −

  • 建立表
  • 新增和查詢表
  • 監控和管理表

JavaScript Shell

DynamoDB 包含一個互動式 JavaScript Shell。Shell 在 Web 瀏覽器中執行,推薦的瀏覽器包括 Firefox 和 Chrome。

JavaScript Shell

注意 − 使用其他瀏覽器可能會導致錯誤。

透過開啟 Web 瀏覽器並輸入以下地址來訪問 Shell −https://:8000/shell

透過在左側窗格中輸入 JavaScript 並單擊左側窗格右上角的“播放”圖示按鈕來使用 Shell,這將執行程式碼。程式碼結果顯示在右側窗格中。

DynamoDB 和 Java

透過使用 Java 開發環境,在 DynamoDB 中使用 Java。操作符合正常的 Java 語法和結構。

DynamoDB - 資料型別

DynamoDB 支援的資料型別包括特定於屬性、操作和您選擇的編碼語言的資料型別。

屬性資料型別

DynamoDB 支援大量用於表屬性的資料型別。每種資料型別都屬於以下三類之一 −

  • 標量 − 這些型別表示單個值,包括數字、字串、二進位制、布林值和空值。

  • 文件 − 這些型別表示具有巢狀屬性的複雜結構,包括列表和對映。

  • 集合 − 這些型別表示多個標量,包括字串集合、數字集合和二進位制集合。

請記住,DynamoDB 作為一種無模式 NoSQL 資料庫,在建立表時不需要屬性或資料型別定義。它只需要一個主鍵屬性資料型別,這與需要在表建立時指定列資料型別的 RDBMS 形成對比。

標量

  • 數字 − 限制為 38 位數字,可以是正數、負數或零。

  • 字串 − 使用 UTF-8 的 Unicode,最小長度 >0,最大長度為 400KB。

  • 二進位制 − 儲存任何二進位制資料,例如加密資料、影像和壓縮文字。DynamoDB 將其位元組視為無符號。

  • 布林值 − 儲存真或假。

  • 空值 − 表示未知或未定義的狀態。

文件

  • 列表 − 儲存有序的值集合,並使用方括號 ([...])。

  • 對映 − 儲存無序的名稱-值對集合,並使用花括號 ({...})。

集合

集合必須包含相同型別(數字、字串或二進位制)的元素。對集合施加的唯一限制包括 400KB 的專案大小限制,並且每個元素都必須是唯一的。

操作資料型別

DynamoDB API 包含操作使用各種資料型別。您可以檢視以下關鍵型別的選擇 −

  • AttributeDefinition − 表示鍵表和索引模式。

  • Capacity − 表示表或索引消耗的吞吐量數量。

  • CreateGlobalSecondaryIndexAction − 表示新增到表的新的全域性二級索引。

  • LocalSecondaryIndex − 表示本地二級索引屬性。

  • ProvisionedThroughput − 表示索引或表的預置吞吐量。

  • PutRequest − 表示 PutItem 請求。

  • TableDescription − 表示表屬性。

支援的 Java 資料型別

DynamoDB 為 Java 提供對基本資料型別、Set 集合和任意型別的支援。

DynamoDB - 建立表

建立表通常包括生成表、命名錶、建立其主鍵屬性以及設定屬性資料型別。

使用 GUI 控制檯、Java 或其他選項來執行這些任務。

使用 GUI 控制檯建立表

透過訪問控制檯 https://console.aws.amazon.com/dynamodb 建立表。然後選擇“建立表”選項。

GUI Console

我們的示例生成一個填充產品資訊的表,其中產品透過 ID 號(數字屬性)識別唯一屬性。在建立表螢幕中,在表名稱欄位中輸入表名稱;在分割槽鍵欄位中輸入主鍵(ID);併為資料型別輸入“Number”。

Create Table

輸入所有資訊後,選擇建立

使用 Java 建立表

使用 Java 建立相同的表。其主鍵包含以下兩個屬性 −

  • ID − 使用分割槽鍵和 ScalarAttributeType N,表示數字。

  • Nomenclature − 使用排序鍵和 ScalarAttributeType S,表示字串。

Java 使用createTable 方法生成表;並在呼叫中指定表名稱、主鍵屬性和屬性資料型別。

您可以檢視以下示例 −

import java.util.Arrays;
 
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; 
import com.amazonaws.services.dynamodbv2.document.DynamoDB; 
import com.amazonaws.services.dynamodbv2.document.Table; 

import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; 
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; 
import com.amazonaws.services.dynamodbv2.model.KeyType; 
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; 
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
 
public class ProductsCreateTable {  
   public static void main(String[] args) throws Exception { 
      AmazonDynamoDBClient client = new AmazonDynamoDBClient() 
         .withEndpoint("https://:8000");  
      
      DynamoDB dynamoDB = new DynamoDB(client); 
      String tableName = "Products";  
      try { 
         System.out.println("Creating the table, wait..."); 
         Table table = dynamoDB.createTable (tableName, 
            Arrays.asList ( 
               new KeySchemaElement("ID", KeyType.HASH), // the partition key 
                                                         // the sort key 
               new KeySchemaElement("Nomenclature", KeyType.RANGE)
            ),
            Arrays.asList ( 
               new AttributeDefinition("ID", ScalarAttributeType.N), 
               new AttributeDefinition("Nomenclature", ScalarAttributeType.S)
            ),
            new ProvisionedThroughput(10L, 10L)
         );
         table.waitForActive(); 
         System.out.println("Table created successfully.  Status: " + 
            table.getDescription().getTableStatus());
            
      } catch (Exception e) {
         System.err.println("Cannot create the table: "); 
         System.err.println(e.getMessage()); 
      } 
   } 
}

在上述示例中,請注意端點:.withEndpoint

它表示透過使用 localhost 使用本地安裝。此外,請注意所需的ProvisionedThroughput 引數,本地安裝會忽略此引數。

DynamoDB - 載入表

載入表通常包括建立原始檔、確保原始檔符合與 DynamoDB 相容的語法、將原始檔傳送到目標,然後確認成功填充。

使用 GUI 控制檯、Java 或其他選項來執行此任務。

使用 GUI 控制檯載入表

使用命令列和控制檯的組合載入資料。您可以透過多種方式載入資料,其中一些如下 −

  • 控制檯
  • 命令列
  • 程式碼以及
  • 資料管道(本教程後面將討論的功能)

但是,為了提高速度,此示例同時使用 Shell 和控制檯。首先,使用以下語法將源資料載入到目標中 −

aws dynamodb batch-write-item -–request-items file://[filename]

例如 −

aws dynamodb batch-write-item -–request-items file://MyProductData.json

透過訪問以下控制檯來驗證操作是否成功 −

https://console.aws.amazon.com/dynamodb

從導航窗格中選擇,然後從表列表中選擇目標表。

選擇專案選項卡以檢查用於填充表的資料。選擇取消以返回到表列表。

使用 Java 載入表

首先建立原始檔,然後使用 Java。我們的原始檔使用 JSON 格式。每個產品具有兩個主鍵屬性(ID 和 Nomenclature)和一個 JSON 對映(Stat)−

[ 
   { 
      "ID" : ... , 
      "Nomenclature" : ... , 
      "Stat" : { ... }
   }, 
   { 
      "ID" : ... , 
      "Nomenclature" : ... , 
      "Stat" : { ... } 
   }, 
    ... 
] 

您可以檢視以下示例 −

{ 
   "ID" : 122, 
   "Nomenclature" : "Particle Blaster 5000", 
   "Stat" : { 
      "Manufacturer" : "XYZ Inc.", 
      "sales" : "1M+", 
      "quantity" : 500, 
      "img_src" : "http://www.xyz.com/manuals/particleblaster5000.jpg", 
      "description" : "A laser cutter used in plastic manufacturing." 
   } 
}

下一步是將檔案放在應用程式使用的目錄中。

Java 主要使用putItempath 方法來執行載入。

您可以檢視以下程式碼示例以處理檔案並載入它 −

import java.io.File;
import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ProductsLoadData {  
   public static void main(String[] args) throws Exception {  
      AmazonDynamoDBClient client = new AmazonDynamoDBClient() 
         .withEndpoint("https://:8000");  
      
      DynamoDB dynamoDB = new DynamoDB(client);  
      Table table = dynamoDB.getTable("Products");  
      JsonParser parser = new JsonFactory() 
         .createParser(new File("productinfo.json"));  
      
      JsonNode rootNode = new ObjectMapper().readTree(parser); 
      Iterator<JsonNode> iter = rootNode.iterator();  
      ObjectNode currentNode;  
      
      while (iter.hasNext()) { 
         currentNode = (ObjectNode) iter.next();  
         int ID = currentNode.path("ID").asInt(); 
         String Nomenclature = currentNode.path("Nomenclature").asText();  
         
         try { 
            table.putItem(new Item() 
               .withPrimaryKey("ID", ID, "Nomenclature", Nomenclature) 
               .withJSON("Stat", currentNode.path("Stat").toString()));
            System.out.println("Successful load: " + ID + " " + Nomenclature);  
         } catch (Exception e) {
            System.err.println("Cannot add product: " + ID + " " + Nomenclature);
            System.err.println(e.getMessage()); 
            break; 
         } 
      } 
      parser.close(); 
   } 
} 

DynamoDB - 查詢表

查詢表主要需要選擇表、指定分割槽鍵並執行查詢;可以選擇使用二級索引並透過掃描操作執行更深入的過濾。

使用 GUI 控制檯、Java 或其他選項來執行此任務。

使用 GUI 控制檯查詢表

使用先前建立的表執行一些簡單的查詢。首先,在 https://console.aws.amazon.com/dynamodb 中開啟控制檯

從導航窗格中選擇,然後從表列表中選擇Reply。然後選擇專案選項卡以檢視載入的資料。

選擇建立專案按鈕下方的資料過濾連結(“掃描:[表] Reply”)。

Query Table using the GUI Console

在過濾螢幕中,為操作選擇查詢。輸入相應的分割槽鍵值,然後單擊開始

然後,Reply 表將返回匹配的專案。

Reply Table

使用 Java 查詢表

在 Java 中使用 query 方法執行資料檢索操作。它需要指定分割槽鍵值,排序鍵為可選。

透過首先建立描述引數的querySpec 物件來編寫 Java 查詢。然後將物件傳遞給 query 方法。我們使用先前示例中的分割槽鍵。

您可以檢視以下示例 −

import java.util.HashMap;
import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;

public class ProductsQuery {  
   public static void main(String[] args) throws Exception {  
      AmazonDynamoDBClient client = new AmazonDynamoDBClient() 
         .withEndpoint("https://:8000");  
      
      DynamoDB dynamoDB = new DynamoDB(client);  
      Table table = dynamoDB.getTable("Products");  
      HashMap<String, String> nameMap = new HashMap<String, String>(); 
      nameMap.put("#ID", "ID");  
      HashMap<String, Object> valueMap = new HashMap<String, Object>(); 
      valueMap.put(":xxx", 122);
      QuerySpec querySpec = new QuerySpec() 
         .withKeyConditionExpression("#ID = :xxx") 
         .withNameMap(new NameMap().with("#ID", "ID")) 
         .withValueMap(valueMap);  
      
      ItemCollection<QueryOutcome> items = null; 
      Iterator<Item> iterator = null; 
      Item item = null;  
      try { 
         System.out.println("Product with the ID 122"); 
         items = table.query(querySpec);  
         iterator = items.iterator(); 
         
         while (iterator.hasNext()) { 
            item = iterator.next(); 
            System.out.println(item.getNumber("ID") + ": " 
               + item.getString("Nomenclature")); 
         } 
      } catch (Exception e) { 
         System.err.println("Cannot find products with the ID number 122"); 
         System.err.println(e.getMessage()); 
      } 
   } 
}

請注意,查詢使用了分割槽鍵,但是,二級索引提供了另一種查詢選項。它們的靈活性允許查詢非鍵屬性,本教程稍後將討論此主題。

掃描方法還支援透過收集所有表資料來執行檢索操作。可選的 .withFilterExpression 可防止指定條件之外的項出現在結果中。

在本教程的後面,我們將詳細討論掃描。現在,請檢視以下示例 -

import java.util.Iterator;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.ScanOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.ScanSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;

public class ProductsScan {  
   public static void main(String[] args) throws Exception {  
      AmazonDynamoDBClient client = new AmazonDynamoDBClient() 
         .withEndpoint("https://:8000");  
      
      DynamoDB dynamoDB = new DynamoDB(client);  
      Table table = dynamoDB.getTable("Products");  
      ScanSpec scanSpec = new ScanSpec() 
         .withProjectionExpression("#ID, Nomenclature , stat.sales") 
         .withFilterExpression("#ID between :start_id and :end_id") 
         .withNameMap(new NameMap().with("#ID",  "ID")) 
         .withValueMap(new ValueMap().withNumber(":start_id", 120)
         .withNumber(":end_id", 129));  
      
      try { 
         ItemCollection<ScanOutcome> items = table.scan(scanSpec);  
         Iterator<Item> iter = items.iterator(); 
        
         while (iter.hasNext()) {
            Item item = iter.next(); 
            System.out.println(item.toString()); 
         } 
      } catch (Exception e) { 
         System.err.println("Cannot perform a table scan:"); 
         System.err.println(e.getMessage()); 
      } 
   } 
} 

DynamoDB - 刪除表

在本章中,我們將討論如何刪除表以及刪除表的不同方法。

表刪除是一個簡單的操作,只需要表名即可。可以使用 GUI 控制檯、Java 或任何其他選項來執行此任務。

使用 GUI 控制檯刪除表

首先訪問以下控制檯,執行刪除操作 -

https://console.aws.amazon.com/dynamodb.

從導航窗格中選擇,然後從表列表中選擇要刪除的表,如下面的螢幕截圖所示。

Delete Table using the GUI Console

最後,選擇刪除表。選擇“刪除表”後,將顯示一個確認訊息。然後您的表將被刪除。

使用 Java 刪除表

使用delete方法刪除表。下面給出一個示例來更好地解釋這個概念。

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient; 
import com.amazonaws.services.dynamodbv2.document.DynamoDB; 
import com.amazonaws.services.dynamodbv2.document.Table;  

public class ProductsDeleteTable {  
   public static void main(String[] args) throws Exception {  
      AmazonDynamoDBClient client = new AmazonDynamoDBClient() 
         .withEndpoint("https://:8000"); 
      
      DynamoDB dynamoDB = new DynamoDB(client);  
      Table table = dynamoDB.getTable("Products");  
      try { 
         System.out.println("Performing table delete, wait..."); 
         table.delete(); 
         table.waitForDelete(); 
         System.out.print("Table successfully deleted.");  
      } catch (Exception e) { 
         System.err.println("Cannot perform table delete: "); 
         System.err.println(e.getMessage()); 
      } 
   } 
}   

DynamoDB - API 介面

DynamoDB 提供了一套廣泛且強大的 API 工具,用於表操作、資料讀取和資料修改。

Amazon 建議使用AWS SDK(例如,Java SDK)而不是呼叫低階 API。這些庫使直接與低階 API 互動變得不必要。這些庫簡化了身份驗證、序列化和連線等常見任務。

操作表

DynamoDB 提供了五個用於表管理的低階操作 -

  • CreateTable - 此操作建立表,幷包含使用者設定的吞吐量。它要求您設定主鍵,無論是複合鍵還是簡單鍵。它還允許一個或多個二級索引。

  • ListTables - 此操作提供當前 AWS 使用者帳戶中與其端點關聯的所有表的列表。

  • UpdateTable - 此操作更改吞吐量和全域性二級索引吞吐量。

  • DescribeTable - 此操作提供表元資料;例如,狀態、大小和索引。

  • DeleteTable - 此操作簡單地擦除表及其索引。

讀取資料

DynamoDB 提供了四個用於資料讀取的低階操作 -

  • GetItem - 它接受主鍵並返回關聯項的屬性。它允許更改其預設的最終一致讀取設定。

  • BatchGetItem - 它透過主鍵對多個項執行多個 GetItem 請求,並可以選擇一個或多個表。它的返回項不超過 100 個,並且必須保持在 16MB 以內。它允許最終一致讀取和強一致讀取。

  • Scan - 它讀取所有表項並生成最終一致的結果集。您可以透過條件過濾結果。它避免使用索引並掃描整個表,因此不要將其用於需要可預測性的查詢。

  • Query - 它返回單個或多個表項或二級索引項。它使用分割槽鍵的指定值,並允許使用比較運算子縮小範圍。它支援兩種一致性型別,並且每個響應的大小都受 1MB 的限制。

修改資料

DynamoDB 提供了四個用於資料修改的低階操作 -

  • PutItem - 此操作建立新項或替換現有項。如果發現相同的主鍵,則預設情況下,它會替換該項。條件運算子允許您繞過預設值,並且僅在某些條件下替換項。

  • BatchWriteItem - 此操作執行多個 PutItem 和 DeleteItem 請求,以及多個表上的請求。如果一個請求失敗,它不會影響整個操作。它的上限為 25 個專案,大小為 16MB。

  • UpdateItem - 它更改現有項的屬性,並允許使用條件運算子僅在某些條件下執行更新。

  • DeleteItem - 它使用主鍵擦除項,並且還允許使用條件運算子指定刪除條件。

DynamoDB - 建立專案

在 DynamoDB 中建立項主要包括項和屬性規範,以及指定條件的選項。每個項都作為一組屬性存在,每個屬性都有名稱並分配某個型別的值。

值型別包括標量、文件或集合。項的大小限制為 400KB,並且可以包含任何數量的屬性,只要它們適合該限制即可。名稱和值的大小(二進位制和 UTF-8 長度)決定了項的大小。使用短屬性名稱有助於最小化項的大小。

注意 - 您必須指定所有主鍵屬性,其中主鍵僅需要分割槽鍵;複合鍵需要分割槽鍵和排序鍵。

另外,請記住表沒有預定義的架構。您可以在一個表中儲存截然不同的資料集。

可以使用 GUI 控制檯、Java 或其他工具來執行此任務。

如何使用 GUI 控制檯建立項?

導航到控制檯。在左側的導航窗格中,選擇。選擇用作目標的表名,然後選擇選項卡,如下面的螢幕截圖所示。

Create Item

選擇建立項。建立項螢幕提供了一個介面,用於輸入所需的屬性值。還必須輸入任何二級索引。

Select Create Item

如果您需要更多屬性,請選擇訊息左側的操作選單。然後選擇追加和所需的資料型別。

Message

輸入所有必要資訊後,選擇儲存以新增項。

如何在項建立中使用 Java?

在項建立操作中使用 Java 包括建立 DynamoDB 類例項、Table 類例項、Item 類例項,並指定您要建立的項的主鍵和屬性。然後使用 putItem 方法新增新項。

示例

DynamoDB dynamoDB = new DynamoDB (new AmazonDynamoDBClient(
   new ProfileCredentialsProvider()));
Table table = dynamoDB.getTable("ProductList");
   
// Spawn a related items list 
List<Number> RELItems = new ArrayList<Number>(); 
RELItems.add(123); 
RELItems.add(456); 
RELItems.add(789);  
   
//Spawn a product picture map  
Map<String, String> photos = new HashMap<String, String>(); 
photos.put("Anterior", "http://xyz.com/products/101_front.jpg"); 
photos.put("Posterior", "http://xyz.com/products/101_back.jpg"); 
photos.put("Lateral", "http://xyz.com/products/101_LFTside.jpg");  

//Spawn a product review map 
Map<String, List<String>> prodReviews = new HashMap<String, List<String>>();  
List<String> fiveStarRVW = new ArrayList<String>(); 
fiveStarRVW.add("Shocking high performance."); 
fiveStarRVW.add("Unparalleled in its market."); 
prodReviews.put("5 Star", fiveStarRVW);  
List<String> oneStarRVW = new ArrayList<String>(); 
oneStarRVW.add("The worst offering in its market."); 
prodReviews.put("1 Star", oneStarRVW);  

// Generate the item 
Item item = new Item()
   .withPrimaryKey("Id", 101) 
   .withString("Nomenclature", "PolyBlaster 101") 
   .withString("Description", "101 description") 
   .withString("Category", "Hybrid Power Polymer Cutter")  
   .withString("Make", "Brand – XYZ") 
   .withNumber("Price", 50000) 
   .withString("ProductCategory", "Laser Cutter") 
   .withBoolean("Availability", true) 
   .withNull("Qty") 
   .withList("ItemsRelated", RELItems) 
   .withMap("Images", photos) 
   .withMap("Reviews", prodReviews);

// Add item to the table  
PutItemOutcome outcome = table.putItem(item);

您還可以檢視以下更大的示例。

注意 - 以下示例可能假設之前已建立資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

以下示例還使用了 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;

import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class CreateItemOpSample { 
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
      new ProfileCredentialsProvider()));  
   static String tblName = "ProductList";  
      
   public static void main(String[] args) throws IOException {  
      createItems();  
      retrieveItem();  
         
      // Execute updates 
      updateMultipleAttributes(); 
      updateAddNewAttribute(); 
      updateExistingAttributeConditionally();  
         
      // Item deletion 
      deleteItem();  
   }
   private static void createItems() {  
      Table table = dynamoDB.getTable(tblName); 
      try {  
         Item item = new Item() 
            .withPrimaryKey("ID", 303)
            .withString("Nomenclature", "Polymer Blaster 4000") 
            .withStringSet( "Manufacturers", 
            new HashSet<String>(Arrays.asList("XYZ Inc.", "LMNOP Inc.")))  
            .withNumber("Price", 50000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Laser Cutter"); 
         
         table.putItem(item);  
         item = new Item() 
            .withPrimaryKey("ID", 313) 
            .withString("Nomenclature", "Agitatatron 2000") 
            .withStringSet( "Manufacturers", 
            new HashSet<String>(Arrays.asList("XYZ Inc,", "CDE Inc."))) 
            .withNumber("Price", 40000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Agitator"); 
         
         table.putItem(item);  
      } catch (Exception e) { 
         System.err.println("Cannot create items."); 
         System.err.println(e.getMessage()); 
      } 
   }   
}

DynamoDB - 獲取專案

在 DynamoDB 中檢索項需要使用 GetItem,並指定表名和項主鍵。請確保包含完整的主鍵,而不是省略部分主鍵。

例如,省略複合鍵的排序鍵。

GetItem 的行為符合三個預設值 -

  • 它作為最終一致讀取執行。
  • 它提供所有屬性。
  • 它沒有詳細說明其容量單位消耗。

這些引數允許您覆蓋預設的 GetItem 行為。

檢索項

DynamoDB 透過在多個伺服器上維護項的多個副本確保可靠性。每次成功的寫入都會建立這些副本,但需要大量時間來執行;這意味著最終一致性。這意味著您不能在寫入項後立即嘗試讀取。

您可以更改 GetItem 的預設最終一致讀取,但是,獲取更最新資料所需的成本仍然是消耗更多容量單位;具體來說,是兩倍。請注意,DynamoDB 通常在一秒鐘內實現所有副本之間的一致性。

您可以使用 GUI 控制檯、Java 或其他工具來執行此任務。

使用 Java 檢索項

在項檢索操作中使用 Java 需要建立 DynamoDB 類例項、Table 類例項,並呼叫 Table 例項的 getItem 方法。然後指定項的主鍵。

您可以檢視以下示例 −

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));  
Table table = dynamoDB.getTable("ProductList");  
Item item = table.getItem("IDnum", 109);

在某些情況下,您需要為此操作指定引數。

以下示例使用.withProjectionExpressionGetItemSpec進行檢索規範 -

GetItemSpec spec = new GetItemSpec() 
   .withPrimaryKey("IDnum", 122) 
   .withProjectionExpression("IDnum, EmployeeName, Department") 
   .withConsistentRead(true);

Item item = table.getItem(spec);
System.out.println(item.toJSONPretty());

您還可以檢視以下更大的示例以更好地理解。

注意 - 以下示例可能假設之前已建立資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用了 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;

import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class GetItemOpSample {
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient(
      new ProfileCredentialsProvider()));
   
   static String tblName = "ProductList";
   public static void main(String[] args) throws IOException {
      createItems();
      retrieveItem();
      
      // Execute updates
      updateMultipleAttributes();
      updateAddNewAttribute();
      updateExistingAttributeConditionally();
      
      // Item deletion
      deleteItem();
   }
   private static void createItems() {
      Table table = dynamoDB.getTable(tblName);
      try {
         Item item = new Item()
            .withPrimaryKey("ID", 303)
            .withString("Nomenclature", "Polymer Blaster 4000")
            .withStringSet( "Manufacturers",
            new HashSet<String>(Arrays.asList("XYZ Inc.", "LMNOP Inc.")))
            .withNumber("Price", 50000)
            .withBoolean("InProduction", true)
            .withString("Category", "Laser Cutter");
            table.putItem(item);
            
         item = new Item()
            .withPrimaryKey("ID", 313)
            .withString("Nomenclature", "Agitatatron 2000")
            .withStringSet( "Manufacturers",
            new HashSet<String>(Arrays.asList("XYZ Inc,", "CDE Inc.")))
            .withNumber("Price", 40000)
            .withBoolean("InProduction", true)
            .withString("Category", "Agitator");
         
         table.putItem(item);
      } catch (Exception e) {
         System.err.println("Cannot create items.");
         System.err.println(e.getMessage());
      }
   }
   private static void retrieveItem() {
      Table table = dynamoDB.getTable(tableName);
      try {
         Item item = table.getItem("ID", 303, "ID, Nomenclature, Manufacturers", null);
         System.out.println("Displaying retrieved items...");
         System.out.println(item.toJSONPretty());
      } catch (Exception e) {
         System.err.println("Cannot retrieve items.");
         System.err.println(e.getMessage());
      }
   }
}

DynamoDB - 更新專案

在 DynamoDB 中更新項主要包括為項指定完整的主鍵和表名。它需要您要修改的每個屬性的新值。此操作使用UpdateItem,它修改現有項或在發現缺少項時建立它們。

在更新中,您可能希望透過在操作之前和之後顯示原始值和新值來跟蹤更改。UpdateItem 使用ReturnValues引數來實現此目的。

注意 - 此操作不報告容量單位消耗,但您可以使用ReturnConsumedCapacity引數。

可以使用 GUI 控制檯、Java 或任何其他工具來執行此任務。

如何使用 GUI 工具更新項?

導航到控制檯。在左側的導航窗格中,選擇。選擇所需的表,然後選擇選項卡。

Update Items Using GUI Tools

選擇要更新的項,然後選擇操作 | 編輯

Choose Item

編輯項視窗中修改任何必要的屬性或值。

使用 Java 更新項

在項更新操作中使用 Java 需要建立一個 Table 類例項,並呼叫其updateItem方法。然後您指定項的主鍵,並提供一個UpdateExpression,詳細說明屬性修改。

以下是相同的示例 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient(
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ProductList");

Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#M", "Make");
expressionAttributeNames.put("#P", "Price
expressionAttributeNames.put("#N", "ID");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1",
   new HashSet<String>(Arrays.asList("Make1","Make2")));
expressionAttributeValues.put(":val2", 1);       //Price

UpdateItemOutcome outcome =  table.updateItem(
   "internalID",                                 // key attribute name
   111,                                          // key attribute value
   "add #M :val1 set #P = #P - :val2 remove #N", // UpdateExpression
   expressionAttributeNames,
   expressionAttributeValues);

updateItem方法還允許指定條件,這可以在以下示例中看到 -

Table table = dynamoDB.getTable("ProductList");
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#P", "Price");

Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", 44);  // change Price to 44
expressionAttributeValues.put(":val2", 15);  // only if currently 15

UpdateItemOutcome outcome = table.updateItem (new PrimaryKey("internalID",111),
   "set #P = :val1",                        // Update
   "#P = :val2",                            // Condition 
   expressionAttributeNames,
   expressionAttributeValues);

使用計數器更新項

DynamoDB 允許原子計數器,這意味著使用 UpdateItem 增加/減少屬性值而不影響其他請求;此外,計數器始終更新。

以下是一個解釋如何執行此操作的示例。

注意 - 以下示例可能假設之前已建立資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用了 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;

import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class UpdateItemOpSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
      new ProfileCredentialsProvider()));  
   static String tblName = "ProductList";  
   
   public static void main(String[] args) throws IOException {  
      createItems();  
      retrieveItem();  
      
      // Execute updates 
      updateMultipleAttributes(); 
      updateAddNewAttribute();
      updateExistingAttributeConditionally();  
      
      // Item deletion 
      deleteItem(); 
   }
   private static void createItems() {  
      Table table = dynamoDB.getTable(tblName); 
      try { 
         Item item = new Item() 
            .withPrimaryKey("ID", 303) 
            .withString("Nomenclature", "Polymer Blaster 4000") 
            .withStringSet( "Manufacturers",
            new HashSet<String>(Arrays.asList("XYZ Inc.", "LMNOP Inc."))) 
            .withNumber("Price", 50000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Laser Cutter"); 
            table.putItem(item);  
         
         item = new Item() 
            .withPrimaryKey("ID", 313) 
            .withString("Nomenclature", "Agitatatron 2000") 
            .withStringSet( "Manufacturers", 
            new HashSet<String>(Arrays.asList("XYZ Inc,", "CDE Inc."))) 
            .withNumber("Price", 40000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Agitator");  
            table.putItem(item);  
      } catch (Exception e) { 
         System.err.println("Cannot create items."); 
         System.err.println(e.getMessage()); 
      } 
   }
   private static void updateAddNewAttribute() { 
      Table table = dynamoDB.getTable(tableName);  
      try {  
         Map<String, String> expressionAttributeNames = new HashMap<String, String>(); 
         expressionAttributeNames.put("#na", "NewAttribute");  
         UpdateItemSpec updateItemSpec = new UpdateItemSpec() 
            .withPrimaryKey("ID", 303) 
            .withUpdateExpression("set #na = :val1") 
            .withNameMap(new NameMap() 
            .with("#na", "NewAttribute")) 
            .withValueMap(new ValueMap() 
            .withString(":val1", "A value")) 
            .withReturnValues(ReturnValue.ALL_NEW);  
            UpdateItemOutcome outcome =  table.updateItem(updateItemSpec);  
         
         // Confirm 
         System.out.println("Displaying updated item..."); 
         System.out.println(outcome.getItem().toJSONPretty());             
      } catch (Exception e) { 
         System.err.println("Cannot add an attribute in " + tableName); 
         System.err.println(e.getMessage()); 
      }         
   } 
}

DynamoDB - 刪除專案

在 DynamoDB 中刪除項只需要提供表名和項鍵。還強烈建議使用條件表示式,這對於避免刪除錯誤的項將是必要的。

像往常一樣,您可以使用 GUI 控制檯、Java 或任何其他所需的工具來執行此任務。

使用 GUI 控制檯刪除項

導航到控制檯。在左側的導航窗格中,選擇。然後選擇表名和選項卡。

Delete Items Using the GUI Console

選擇要刪除的項,然後選擇操作 | 刪除

Select Actions

然後會出現一個刪除專案(s)對話方塊,如下面的螢幕截圖所示。選擇“刪除”以確認。

Delete Item

如何使用 Java 刪除專案?

在專案刪除操作中使用 Java 只需建立 DynamoDB 客戶端例項,並透過使用專案的鍵呼叫deleteItem方法。

您可以檢視以下示例,其中已詳細說明。

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ProductList");
DeleteItemOutcome outcome = table.deleteItem("IDnum", 151);

您還可以指定引數以防止錯誤刪除。只需使用ConditionExpression

例如 −

Map<String,Object> expressionAttributeValues = new HashMap<String,Object>(); 
expressionAttributeValues.put(":val", false);
  
DeleteItemOutcome outcome = table.deleteItem("IDnum",151, 
   "Ship = :val",  
   null,                   // doesn't use ExpressionAttributeNames  
   expressionAttributeValues);

以下是一個更大的示例,以便更好地理解。

注意 - 以下示例可能假設之前已建立資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用了 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;

import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.UpdateItemSpec;
import com.amazonaws.services.dynamodbv2.document.utils.NameMap;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;

public class DeleteItemOpSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
      new ProfileCredentialsProvider()));  
   
   static String tblName = "ProductList";  
   public static void main(String[] args) throws IOException { 
      createItems(); 
      retrieveItem();  
      
      // Execute updates 
      updateMultipleAttributes(); 
      updateAddNewAttribute(); 
      updateExistingAttributeConditionally();  
      
      // Item deletion 
      deleteItem();  
   }  
   private static void createItems() {  
      Table table = dynamoDB.getTable(tblName); 
      try {  
         Item item = new Item()  
            .withPrimaryKey("ID", 303) 
            .withString("Nomenclature", "Polymer Blaster 4000")
            .withStringSet( "Manufacturers",
            new HashSet<String>(Arrays.asList("XYZ Inc.", "LMNOP Inc."))) 
            .withNumber("Price", 50000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Laser Cutter"); 
            table.putItem(item);  
         
         item = new Item() 
            .withPrimaryKey("ID", 313) 
            .withString("Nomenclature", "Agitatatron 2000") 
            .withStringSet( "Manufacturers", 
            new HashSet<String>(Arrays.asList("XYZ Inc,", "CDE Inc."))) 
            .withNumber("Price", 40000) 
            .withBoolean("InProduction", true) 
            .withString("Category", "Agitator"); 
            table.putItem(item);  
      } catch (Exception e) { 
         System.err.println("Cannot create items."); 
         System.err.println(e.getMessage());  
      } 
   }  
   private static void deleteItem() {  
      Table table = dynamoDB.getTable(tableName);  
      try {  
         DeleteItemSpec deleteItemSpec = new DeleteItemSpec() 
            .withPrimaryKey("ID", 303)  
            .withConditionExpression("#ip = :val") 
            .withNameMap(new NameMap() 
            .with("#ip", "InProduction"))
            .withValueMap(new ValueMap() 
            .withBoolean(":val", false)) 
            .withReturnValues(ReturnValue.ALL_OLD);  
         DeleteItemOutcome outcome = table.deleteItem(deleteItemSpec);  
         
         // Confirm 
         System.out.println("Displaying deleted item..."); 
         System.out.println(outcome.getItem().toJSONPretty());  
      } catch (Exception e) { 
         System.err.println("Cannot delete item in " + tableName); 
         System.err.println(e.getMessage()); 
      } 
   } 
}

DynamoDB - 批次寫入

批次寫入透過建立或刪除多個專案來操作多個專案。這些操作利用BatchWriteItem,其限制為不超過 16MB 寫入和 25 個請求。每個專案都遵守 400KB 的大小限制。批次寫入也不能執行專案更新。

什麼是批次寫入?

批次寫入可以操作多個表中的專案。每個單獨的請求都會發生操作呼叫,這意味著操作不會相互影響,並且允許異構混合;例如,在一個批次中有一個PutItem和三個DeleteItem請求,而 PutItem 請求的失敗不會影響其他請求。失敗的請求會導致操作返回與每個失敗請求相關的資訊(鍵和資料)。

注意 - 如果 DynamoDB 返回任何未經處理的專案,請重試;但是,使用回退方法以避免基於過載的另一個請求失敗。

當以下一個或多個語句被證明為真時,DynamoDB 會拒絕批次寫入操作 -

  • 請求超過了預置的吞吐量。

  • 請求嘗試使用BatchWriteItems更新專案。

  • 請求對單個專案執行多個操作。

  • 請求的表不存在。

  • 請求中的專案屬性與目標不匹配。

  • 請求超過大小限制。

批次寫入需要某些RequestItem引數 -

  • 刪除操作需要DeleteRequest子元素,即屬性名稱和值。

  • PutRequest專案需要一個Item 子元素,即屬性和屬性值對映。

響應 - 成功操作將導致 HTTP 200 響應,這表示諸如消耗的容量單位、表處理指標和任何未處理的專案等特徵。

使用 Java 進行批次寫入

透過建立 DynamoDB 類例項、描述所有操作的TableWriteItems類例項以及呼叫batchWriteItem方法來使用 TableWriteItems 物件來執行批次寫入。

注意 - 必須為批次寫入到多個表中的每個表建立一個 TableWriteItems 例項。此外,檢查您的請求響應中是否存在任何未處理的請求。

您可以檢視以下批次寫入示例 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));  

TableWriteItems forumTableWriteItems = new TableWriteItems("Forum") 
   .withItemsToPut( 
   new Item() 
   .withPrimaryKey("Title", "XYZ CRM") 
   .withNumber("Threads", 0));  

TableWriteItems threadTableWriteItems = new TableWriteItems(Thread) 
   .withItemsToPut( 
   new Item() 
   .withPrimaryKey("ForumTitle","XYZ CRM","Topic","Updates") 
   .withHashAndRangeKeysToDelete("ForumTitle","A partition key value", 
   "Product Line 1", "A sort key value"));

BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem (
   forumTableWriteItems, threadTableWriteItems);

以下程式是另一個更大的示例,以便更好地瞭解如何使用 Java 進行批次寫入。

注意 - 以下示例可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.BatchWriteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableWriteItems;
import com.amazonaws.services.dynamodbv2.model.WriteRequest;

public class BatchWriteOpSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
      new ProfileCredentialsProvider()));  
   static String forumTableName = "Forum"; 
   static String threadTableName = "Thread";  
      
   public static void main(String[] args) throws IOException { 
      batchWriteMultiItems();   
   }
   private static void batchWriteMultiItems() { 
      try {
         // Place new item in Forum 
         TableWriteItems forumTableWriteItems = new TableWriteItems(forumTableName) 
                                                                       //Forum 
            .withItemsToPut(new Item() 
            .withPrimaryKey("Name", "Amazon RDS") 
            .withNumber("Threads", 0));  
            
         // Place one item, delete another in Thread 
         // Specify partition key and range key 
         TableWriteItems threadTableWriteItems = new TableWriteItems(threadTableName) 
            .withItemsToPut(new Item() 
            .withPrimaryKey("ForumName","Product  
            Support","Subject","Support Thread 1") 
            .withString("Message", "New OS Thread 1 message")
            .withHashAndRangeKeysToDelete("ForumName","Subject", "Polymer Blaster", 
            "Support Thread 100"));  
            
         System.out.println("Processing request..."); 
         BatchWriteItemOutcome outcome = dynamoDB.batchWriteItem (
               forumTableWriteItems, threadTableWriteItems);
         do {  
            // Confirm no unprocessed items 
            Map<String, List<WriteRequest>> unprocessedItems 
               = outcome.getUnprocessedItems();  
                  
            if (outcome.getUnprocessedItems().size() == 0) { 
               System.out.println("All items processed."); 
            } else { 
               System.out.println("Gathering unprocessed items..."); 
               outcome = dynamoDB.batchWriteItemUnprocessed(unprocessedItems); 
            }  
         } while (outcome.getUnprocessedItems().size() > 0);  
      } catch (Exception e) { 
         System.err.println("Could not get items: "); 
         e.printStackTrace(System.err); 
      }   
   } 
}

DynamoDB - 批次檢索

批次檢索操作返回一個或多個專案的屬性。這些操作通常包括使用主鍵來識別所需的專案(s)。BatchGetItem操作受單個操作的限制及其自身唯一約束的限制。

批次檢索操作中的以下請求會導致拒絕 -

  • 請求超過 100 個專案。
  • 發出超過吞吐量的請求。

批次檢索操作對可能超出限制的請求執行部分處理。

例如 - 檢索大小足以超出限制的多個專案的請求會導致部分請求處理,以及一條說明未處理部分的錯誤訊息。在返回未處理的專案時,建立回退演算法解決方案來管理此問題,而不是限制表。

BatchGet操作最終使用一致讀取執行,需要修改才能使其成為強一致讀取。它們還並行執行檢索。

注意 - 返回專案的順序。DynamoDB 不會對專案進行排序。它也不會指示請求的專案不存在。此外,這些請求會消耗容量單位。

所有 BatchGet 操作都需要RequestItems引數,例如讀取一致性、屬性名稱和主鍵。

響應 - 成功操作將導致 HTTP 200 響應,這表示諸如消耗的容量單位、表處理指標和任何未處理的專案等特徵。

使用 Java 進行批次檢索

在 BatchGet 操作中使用 Java 需要建立一個 DynamoDB 類例項、描述專案的 Primary Key 值列表的TableKeysAndAttributes類例項,並將 TableKeysAndAttributes 物件傳遞給BatchGetItem方法。

以下是一個 BatchGet 操作的示例 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));  

TableKeysAndAttributes forumTableKeysAndAttributes = new TableKeysAndAttributes 
   (forumTableName);
   
forumTableKeysAndAttributes.addHashOnlyPrimaryKeys (
   "Title",
   "Updates",  
   "Product Line 1"
); 
TableKeysAndAttributes threadTableKeysAndAttributes = new TableKeysAndAttributes (
   threadTableName);
      
threadTableKeysAndAttributes.addHashAndRangePrimaryKeys (
   "ForumTitle",
   "Topic",  
   "Product Line 1",
   "P1 Thread 1", 
   "Product Line 1",
   "P1 Thread 2", 
   "Product Line 2",
   "P2 Thread 1"
); 
BatchGetItemOutcome outcome = dynamoDB.batchGetItem ( 
   forumTableKeysAndAttributes, threadTableKeysAndAttributes);
      
for (String tableName : outcome.getTableItems().keySet()) { 
   System.out.println("Table items " + tableName); 
   List<Item> items = outcome.getTableItems().get(tableName); 
   for (Item item : items) { 
      System.out.println(item); 
   } 
}

您可以檢視以下更大的示例。

注意 - 以下程式可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此程式還使用 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.BatchGetItemOutcome;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.TableKeysAndAttributes;
import com.amazonaws.services.dynamodbv2.model.KeysAndAttributes;

public class BatchGetOpSample { 
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
      new ProfileCredentialsProvider())); 
      
   static String forumTableName = "Forum"; 
   static String threadTableName = "Thread"; 
     
   public static void main(String[] args) throws IOException { 
      retrieveMultipleItemsBatchGet(); 
   }
   private static void retrieveMultipleItemsBatchGet() {         
      try { 
         TableKeysAndAttributes forumTableKeysAndAttributes = 
            new TableKeysAndAttributes(forumTableName); 
         
         //Create partition key 
         forumTableKeysAndAttributes.addHashOnlyPrimaryKeys (
            "Name", 
            "XYZ Melt-O-tron", 
            "High-Performance Processing"
         ); 
         TableKeysAndAttributes threadTableKeysAndAttributes = 
            new TableKeysAndAttributes(threadTableName); 
         
         //Create partition key and sort key 
         threadTableKeysAndAttributes.addHashAndRangePrimaryKeys (
            "ForumName",
            "Subject",  
            "High-Performance Processing",
            "HP Processing Thread One", 
            "High-Performance Processing",
            "HP Processing Thread Two", 
            "Melt-O-Tron",
            "MeltO Thread One"
         );
         System.out.println("Processing..."); 
         BatchGetItemOutcome outcome = dynamoDB.batchGetItem(forumTableKeysAndAttributes,
            threadTableKeysAndAttributes); 
              
         Map<String, KeysAndAttributes> unprocessed = null;    
         do { 
            for (String tableName : outcome.getTableItems().keySet()) { 
               System.out.println("Table items for " + tableName); 
               List<Item> items = outcome.getTableItems().get(tableName); 
               
               for (Item item : items) { 
                  System.out.println(item.toJSONPretty()); 
               } 
            } 
            // Confirm no unprocessed items 
            unprocessed = outcome.getUnprocessedKeys(); 
                 
            if (unprocessed.isEmpty()) { 
               System.out.println("All items processed."); 
            } else { 
               System.out.println("Gathering unprocessed items..."); 
               outcome = dynamoDB.batchGetItemUnprocessed(unprocessed); 
            } 
         } while (!unprocessed.isEmpty()); 
      } catch (Exception e) { 
         System.err.println("Could not get items."); 
         System.err.println(e.getMessage()); 
      }   
   } 
}

DynamoDB - 查詢

查詢透過主鍵查詢專案或二級索引。執行查詢需要分割槽鍵和特定值,或排序鍵和值;可以選擇使用比較進行過濾。查詢的預設行為包括返回與提供的 Primary Key 關聯的每個專案的每個屬性。但是,您可以使用ProjectionExpression引數指定所需的屬性。

查詢利用KeyConditionExpression引數選擇專案,這需要以等式條件的形式提供分割槽鍵名稱和值。您還可以選擇為任何存在的排序鍵提供附加條件。

排序鍵條件的一些示例如下 -

序號 條件和描述
1

x = y

如果屬性 x 等於 y,則其計算結果為真。

2

x < y

如果 x 小於 y,則其計算結果為真。

3

x <= y

如果 x 小於或等於 y,則其計算結果為真。

4

x > y

如果 x 大於 y,則其計算結果為真。

5

x >= y

如果 x 大於或等於 y,則其計算結果為真。

6

x BETWEEN y AND z

如果 x 大於或等於 y 且小於或等於 z,則其計算結果為真。

DynamoDB 還支援以下函式:begins_with (x, substr)

如果屬性 x 以指定的字串開頭,則其計算結果為真。

以下條件必須符合某些要求 -

  • 屬性名稱必須以 a-z 或 A-Z 集合中的字元開頭。

  • 屬性名稱的第二個字元必須位於 a-z、A-Z 或 0-9 集合中。

  • 屬性名稱不能使用保留字。

不符合上述約束的屬性名稱可以定義一個佔位符。

查詢透過按排序鍵順序執行檢索以及使用任何存在的條件和過濾器表示式來處理。查詢始終返回結果集,如果沒有任何匹配項,則返回空結果集。

結果始終按排序鍵順序返回,並根據資料型別進行排序,可修改的預設值為升序。

使用 Java 進行查詢

Java 中的查詢允許您查詢表和二級索引。它們需要指定分割槽鍵和等式條件,可以選擇指定排序鍵和條件。

Java 中查詢的一般必需步驟包括建立 DynamoDB 類例項、目標表的 Table 類例項,以及呼叫 Table 例項的 query 方法以接收查詢物件。

查詢的響應包含一個ItemCollection物件,該物件提供所有返回的專案。

以下示例演示了詳細的查詢 -

DynamoDB dynamoDB = new DynamoDB (
   new AmazonDynamoDBClient(new ProfileCredentialsProvider()));

Table table = dynamoDB.getTable("Response");  
   QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("ID = :nn") 
.withValueMap(new ValueMap() 
   .withString(":nn", "Product Line 1#P1 Thread 1"));
   
ItemCollection<QueryOutcome> items = table.query(spec);  
Iterator<Item> iterator = items.iterator(); 
Item item = null; 

while (iterator.hasNext()) { 
   item = iterator.next(); 
   System.out.println(item.toJSONPretty());
}

query 方法支援各種可選引數。以下示例演示瞭如何利用這些引數 -

Table table = dynamoDB.getTable("Response");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("ID = :nn and ResponseTM > :nn_responseTM")  
   .withFilterExpression("Author = :nn_author") 
   .withValueMap(new ValueMap()
   .withString(":nn", "Product Line 1#P1 Thread 1") 
   .withString(":nn_responseTM", twoWeeksAgoStr) 
   .withString(":nn_author", "Member 123"))
   .withConsistentRead(true);
   
ItemCollection<QueryOutcome> items = table.query(spec);  
Iterator<Item> iterator = items.iterator(); 

while (iterator.hasNext()) { 
   System.out.println(iterator.next().toJSONPretty()); 
}

您還可以檢視以下更大的示例。

注意 - 以下程式可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

package com.amazonaws.codesamples.document;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;

import com.amazonaws.services.dynamodbv2.document.Page;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;

public class QueryOpSample {
   static DynamoDB dynamoDB = new DynamoDB(
      new AmazonDynamoDBClient(new ProfileCredentialsProvider()));
   static String tableName = "Reply";  
   
   public static void main(String[] args) throws Exception { 
      String forumName = "PolyBlaster"; 
      String threadSubject = "PolyBlaster Thread 1";  
      getThreadReplies(forumName, threadSubject); 
   } 
   private static void getThreadReplies(String forumName, String threadSubject) {  
      Table table = dynamoDB.getTable(tableName);  
      String replyId = forumName + "#" + threadSubject; 
      QuerySpec spec = new QuerySpec() 
         .withKeyConditionExpression("Id = :v_id") 
         .withValueMap(new ValueMap() 
         .withString(":v_id", replyId)); 
         
      ItemCollection<QueryOutcome> items = table.query(spec); 
      System.out.println("\ngetThreadReplies results:"); 
      Iterator<Item> iterator = items.iterator(); 
      
      while (iterator.hasNext()) { 
         System.out.println(iterator.next().toJSONPretty()); 
      } 
   } 
}

DynamoDB - 掃描

掃描操作讀取所有表專案或二級索引。其預設功能會導致返回索引或表中所有專案的所有資料屬性。使用ProjectionExpression引數過濾屬性。

每次掃描都會返回結果集,即使在找不到匹配項的情況下也會返回結果集,這會導致返回空集。掃描最多檢索 1MB,可以選擇過濾資料。

注意 - 掃描的引數和過濾也適用於查詢。

掃描操作的型別

過濾 - 掃描操作透過過濾器表示式提供精細過濾,這些表示式在掃描或查詢之後修改資料;在返回結果之前。表示式使用比較運算子。它們的語法類似於條件表示式,除了鍵屬性,過濾器表示式不允許鍵屬性。您不能在過濾器表示式中使用分割槽鍵或排序鍵。

注意 - 1MB 限制適用於任何過濾應用之前。

吞吐量規範 - 掃描會消耗吞吐量,但是,消耗重點在於專案大小而不是返回的資料。無論您請求每個屬性還是僅請求幾個屬性,消耗都保持不變,使用或不使用過濾器表示式也不會影響消耗。

分頁 - DynamoDB 對結果進行分頁,導致結果被劃分為特定的頁面。1MB 限制適用於返回的結果,當您超過它時,需要進行另一次掃描以收集其餘資料。LastEvaluatedKey值允許您執行此後續掃描。只需將該值應用於ExclusiveStartkey。當LastEvaluatedKey值變為 null 時,操作已完成所有資料頁面。但是,非 null 值並不自動意味著還有更多資料。只有 null 值表示狀態。

Limit 引數 - limit 引數管理結果大小。DynamoDB 使用它來建立在返回資料之前要處理的專案數量,並且不超出範圍。如果您設定了 x 值,DynamoDB 將返回前 x 個匹配專案。

LastEvaluatedKey 值也適用於 limit 引數產生部分結果的情況。使用它來完成掃描。

結果計數 - 查詢和掃描的響應還包括與ScannedCount和 Count 相關的資訊,這些資訊量化了掃描/查詢的專案和返回的專案。如果您不進行過濾,則它們的值相同。當您超過 1MB 時,計數僅表示已處理的部分。

一致性 - 查詢結果和掃描結果是一致讀取,但是,您也可以設定強一致讀取。使用ConsistentRead引數更改此設定。

注意 - 一致讀取設定會透過在設定為強一致時使用兩倍的容量單位來影響消耗。

效能 - 查詢比掃描提供更好的效能,因為掃描會爬取整個表或二級索引,導致響應緩慢和吞吐量消耗過大。掃描最適合小型表和過濾器較少的搜尋,但是,您可以透過遵循一些最佳實踐來設計精簡掃描,例如避免突然加速的讀取活動並利用並行掃描。

查詢查詢滿足給定條件的特定鍵範圍,其效能由它檢索的資料量而不是鍵的數量決定。操作的引數和匹配項的數量會特別影響效能。

並行掃描

掃描操作預設情況下按順序執行處理。然後,它們以 1MB 部分返回資料,這會提示應用程式獲取下一部分。這會導致大型表和索引的掃描時間過長。

這種特性也意味著掃描可能無法始終充分利用可用的吞吐量。DynamoDB 將表資料分佈在多個分割槽中;並且由於其單分割槽操作,掃描吞吐量仍然限制在單個分割槽。

此問題的解決方案來自將表或索引邏輯地劃分為段。然後,“工作器”並行(併發)掃描段。它使用 Segment 和 **TotalSegments** 引數來指定某些工作器掃描的段,並指定處理的段的總數。

工作器數量

您必須嘗試使用工作器值(Segment 引數)以實現最佳的應用程式效能。

**注意** - 使用大量工作器進行並行掃描會透過可能消耗所有吞吐量來影響吞吐量。使用 Limit 引數管理此問題,您可以使用它來阻止單個工作器消耗所有吞吐量。

以下是深度掃描示例。

注意 - 以下程式可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.ScanOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;

public class ScanOpSample {  
   static DynamoDB dynamoDB = new DynamoDB(
      new AmazonDynamoDBClient(new ProfileCredentialsProvider())); 
   static String tableName = "ProductList";  
   
   public static void main(String[] args) throws Exception { 
      findProductsUnderOneHun();                       //finds products under 100 dollars
   }  
   private static void findProductsUnderOneHun() { 
      Table table = dynamoDB.getTable(tableName);
      Map<String, Object> expressionAttributeValues = new HashMap<String, Object>(); 
      expressionAttributeValues.put(":pr", 100); 
         
      ItemCollection<ScanOutcome> items = table.scan ( 
         "Price < :pr",                                  //FilterExpression 
         "ID, Nomenclature, ProductCategory, Price",     //ProjectionExpression 
         null,                                           //No ExpressionAttributeNames  
         expressionAttributeValues);
         
      System.out.println("Scanned " + tableName + " to find items under $100."); 
      Iterator<Item> iterator = items.iterator(); 
         
      while (iterator.hasNext()) { 
         System.out.println(iterator.next().toJSONPretty()); 
      }     
   } 
}

DynamoDB - 索引

DynamoDB 使用索引來訪問主鍵屬性以改進訪問。它們可以加速應用程式訪問和資料檢索,並透過減少應用程式延遲來支援更好的效能。

二級索引

二級索引包含屬性子集和備用鍵。您可以透過針對索引的查詢或掃描操作來使用它。

其內容包括您投影或複製的屬性。在建立過程中,您為索引定義備用鍵,以及您希望在索引中投影的任何屬性。然後,DynamoDB 將屬性複製到索引中,包括來自表的自主鍵屬性。執行這些任務後,您只需像在表上執行一樣使用查詢/掃描即可。

DynamoDB 自動維護所有二級索引。在專案操作(例如新增或刪除)上,它會更新目標表上的任何索引。

DynamoDB 提供兩種型別的二級索引 -

  • **全域性二級索引** - 此索引包含分割槽鍵和排序鍵,它們可能與源表不同。由於索引上的查詢/掃描能夠跨越所有表資料和所有分割槽,因此它使用“全域性”標籤。

  • **本地二級索引** - 此索引與表共享分割槽鍵,但使用不同的排序鍵。它的“本地”性質源於其所有分割槽都作用域到具有相同分割槽鍵值的表分割槽。

要使用的最佳索引型別取決於應用程式需求。請考慮下表中介紹的兩種型別之間的差異 -

質量 全域性二級索引 本地二級索引
鍵架構 它使用簡單或複合主鍵。 它始終使用複合主鍵。
鍵屬性 索引分割槽鍵和排序鍵可以由字串、數字或二進位制表屬性組成。 索引的分割槽鍵是與表分割槽鍵共享的屬性。排序鍵可以是字串、數字或二進位制表屬性。
每個分割槽鍵值的尺寸限制 它們沒有尺寸限制。 它對與分割槽鍵值關聯的已索引專案的總大小施加 10GB 的最大限制。
線上索引操作 您可以在表建立時生成它們,將它們新增到現有表中,或刪除現有的表。 您必須在表建立時建立它們,但不能刪除它們或將它們新增到現有表中。
查詢 它允許覆蓋整個表和每個分割槽的查詢。 它們透過查詢中提供的分割槽鍵值來解決單個分割槽。
一致性 這些索引的查詢僅提供最終一致性選項。 這些查詢提供最終一致性或強一致性選項。
吞吐量成本 它包括讀取和寫入的吞吐量設定。查詢/掃描消耗索引的容量,而不是表的容量,這也適用於表寫入更新。 查詢/掃描消耗表讀取容量。表寫入更新本地索引,並消耗表容量單元。
投影 查詢/掃描只能請求投影到索引中的屬性,而不能檢索表屬性。 查詢/掃描可以請求未投影的那些屬性;此外,還會自動獲取它們。

在建立具有二級索引的多個表時,請按順序進行;這意味著建立一個表並等待它達到 ACTIVE 狀態,然後再建立另一個表並再次等待。DynamoDB 不允許併發建立。

每個二級索引都需要某些規範 -

  • **型別** - 指定本地或全域性。

  • **名稱** - 它使用與表相同的命名規則。

  • **鍵架構** - 僅允許頂級字串、數字或二進位制型別,索引型別決定其他要求。

  • **投影屬性** - DynamoDB 自動投影它們,並允許任何資料型別。

  • **吞吐量** - 為全域性二級索引指定讀取/寫入容量。

每個表的索引限制仍然是 5 個全域性索引和 5 個本地索引。

您可以使用 **DescribeTable** 訪問有關索引的詳細資訊。它返回名稱、大小和專案計數。

**注意** - 這些值每 6 小時更新一次。

在用於訪問索引資料的查詢或掃描中,提供表和索引名稱、結果所需的屬性以及任何條件語句。DynamoDB 提供了以升序或降序返回結果的選項。

**注意** - 刪除表也會刪除所有索引。

DynamoDB - 全域性二級索引

需要使用不同屬性執行各種查詢型別的應用程式可以使用一個或多個全域性二級索引來執行這些詳細查詢。

**例如** - 一個系統跟蹤使用者、他們的登入狀態以及他們的登入時間。先前示例的增長會減慢其資料上的查詢速度。

全域性二級索引透過組織表中選擇的屬性來加速查詢。它們使用主鍵對資料進行排序,並且不需要鍵表屬性或與表相同的鍵架構。

所有全域性二級索引都必須包含分割槽鍵,可以選擇排序鍵。索引鍵架構可以與表不同,索引鍵屬性可以使用任何頂級字串、數字或二進位制表屬性。

在投影中,您可以使用其他表屬性,但是,查詢不會從父表中檢索。

屬性投影

投影由從表複製到二級索引的一組屬性組成。投影始終與表分割槽鍵和排序鍵一起發生。在查詢中,投影允許 DynamoDB 訪問投影的任何屬性;它們本質上存在於自己的表中。

在建立二級索引時,您必須指定投影屬性。DynamoDB 提供三種執行此任務的方法 -

  • **KEYS_ONLY** - 所有索引專案都包含表分割槽和排序鍵值以及索引鍵值。這將建立最小的索引。

  • **INCLUDE** - 它包含 KEYS_ONLY 屬性和指定的非鍵屬性。

  • **ALL** - 它包含所有源表屬性,建立最大的索引。

請注意將屬性投影到全域性二級索引中的權衡,這些權衡與吞吐量和儲存成本相關。

請考慮以下幾點 -

  • 如果您只需要訪問少數幾個屬性並且延遲很低,則僅投影您需要的屬性。這可以降低儲存和寫入成本。

  • 如果應用程式經常訪問某些非鍵屬性,請投影它們,因為儲存成本與掃描消耗相比微不足道。

  • 您可以投影經常訪問的大量屬性集,但是,這會產生高昂的儲存成本。

  • 對於不頻繁的表查詢和頻繁的寫入/更新,請使用 KEYS_ONLY。這可以控制大小,但仍然可以在查詢上提供良好的效能。

全域性二級索引查詢和掃描

您可以利用查詢訪問索引中的單個或多個專案。您必須指定索引和表名稱、所需的屬性以及條件;可以選擇以升序或降序返回結果。

您還可以利用掃描獲取所有索引資料。它需要表和索引名稱。您可以使用篩選器表示式來檢索特定資料。

表和索引資料同步

DynamoDB 自動執行索引與其父表的同步。專案上的每個修改操作都會導致非同步更新,但是,應用程式不會直接寫入索引。

您需要了解 DynamoDB 維護對索引的影響。在建立索引時,您指定鍵屬性和資料型別,這意味著在寫入時,這些資料型別必須與鍵架構資料型別匹配。

在專案建立或刪除時,索引會以最終一致的方式更新,但是,資料更新會在幾分之一秒內傳播(除非發生某種型別的系統故障)。您必須在應用程式中考慮此延遲。

**全域性二級索引中的吞吐量注意事項** - 多個全域性二級索引會影響吞吐量。索引建立需要容量單元規範,這些規範獨立於表存在,導致操作消耗索引容量單元而不是表單元。

如果查詢或寫入超過預配的吞吐量,這可能會導致節流。使用 **DescribeTable** 檢視吞吐量設定。

**讀取容量** - 全域性二級索引提供最終一致性。在查詢中,DynamoDB 執行與表相同的預配計算,唯一的區別是使用索引條目大小而不是專案大小。查詢返回的限制仍然是 1MB,其中包括每個返回專案中屬性名稱的大小和值。

寫入容量

當寫入操作發生時,受影響的索引會消耗寫入單元。寫入吞吐量成本是表寫入中消耗的寫入容量單元和索引更新中消耗的單元的總和。成功的寫入操作需要足夠的容量,否則會導致節流。

寫入成本也仍然取決於某些因素,其中一些如下 -

  • 定義索引屬性的新專案或定義未定義索引屬性的專案更新使用單個寫入操作將專案新增到索引中。

  • 更改索引鍵屬性值的更新使用兩次寫入來刪除專案並寫入新專案。

  • 觸發索引屬性刪除的表寫入使用單個寫入來擦除索引中的舊專案投影。

  • 在更新操作之前和之後索引中不存在的專案不使用寫入。

  • 僅更改索引鍵架構中投影屬性值而不是索引鍵屬性值的更新使用一次寫入將投影屬性的值更新到索引中。

所有這些因素都假設專案大小小於或等於 1KB。

全域性二級索引儲存

在專案寫入時,DynamoDB 會自動將正確的屬性集複製到必須存在屬性的任何索引中。這會影響您的帳戶,因為它會對錶專案儲存和屬性儲存收費。使用的空間是這些數量的總和 -

  • 表主鍵的位元組大小
  • 索引鍵屬性的位元組大小
  • 投影屬性的位元組大小

  • 每個索引項的開銷為 100 位元組。

您可以透過估算平均專案大小並乘以具有全域性二級索引鍵屬性的表專案的數量來估算儲存需求。

DynamoDB 不會為表項寫入資料,其中未定義的屬性被定義為索引分割槽或排序鍵。

全域性二級索引 CRUD

使用 **CreateTable** 操作與 **GlobalSecondaryIndexes** 引數配對,建立具有全域性二級索引的表。您必須指定一個屬性作為索引分割槽鍵,或使用另一個屬性作為索引排序鍵。所有索引鍵屬性必須是字串、數字或二進位制標量。您還必須提供吞吐量設定,包括 **ReadCapacityUnits** 和 **WriteCapacityUnits**。

使用 **UpdateTable** 透過再次使用 GlobalSecondaryIndexes 引數向現有表新增全域性二級索引。

在此操作中,您必須提供以下輸入 -

  • 索引名稱
  • 鍵架構
  • 投影屬性
  • 吞吐量設定

新增全域性二級索引可能會在大型表中花費大量時間,因為專案數量、投影屬性數量、寫入容量和寫入活動。使用 **CloudWatch** 指標監控此過程。

使用 **DescribeTable** 獲取全域性二級索引的狀態資訊。它為 GlobalSecondaryIndexes 返回四種 **IndexStatus** 之一 -

  • **CREATING** - 表示索引的構建階段及其不可用性。

  • **ACTIVE** - 表示索引已準備好使用。

  • **UPDATING** - 表示吞吐量設定的更新狀態。

  • **DELETING** - 表示索引的刪除狀態,以及它永久不可用。

在載入/回填階段更新全域性二級索引的預置吞吐量設定(DynamoDB 將屬性寫入索引並跟蹤新增/刪除/更新的專案)。使用 **UpdateTable** 執行此操作。

您應該記住,在回填階段不能新增/刪除其他索引。

使用 UpdateTable 刪除全域性二級索引。它允許每次操作僅刪除一個索引,但是,您可以同時執行多個操作,最多五個。刪除過程不會影響父表的讀/寫活動,但在操作完成之前,您不能新增/刪除其他索引。

使用 Java 處理全域性二級索引

透過 CreateTable 建立具有索引的表。只需建立一個 DynamoDB 類例項、一個 **CreateTableRequest** 類例項用於請求資訊,並將請求物件傳遞給 CreateTable 方法。

以下程式是一個簡短的示例 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
// Attributes 
ArrayList<AttributeDefinition> attributeDefinitions = new 
   ArrayList<AttributeDefinition>();  
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("City") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Date") 
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition() 
   .withAttributeName("Wind") 
   .withAttributeType("N"));
   
// Key schema of the table 
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>(); 
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("City") 
   .withKeyType(KeyType.HASH));              //Partition key
   
tableKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
// Wind index 
GlobalSecondaryIndex windIndex = new GlobalSecondaryIndex() 
   .withIndexName("WindIndex") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 10) 
   .withWriteCapacityUnits((long) 1)) 
   .withProjection(new Projection().withProjectionType(ProjectionType.ALL));
   
ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>(); 
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Date") 
   .withKeyType(KeyType.HASH));              //Partition key
   
indexKeySchema.add(new KeySchemaElement() 
   .withAttributeName("Wind") 
   .withKeyType(KeyType.RANGE));             //Sort key
   
windIndex.setKeySchema(indexKeySchema);  
CreateTableRequest createTableRequest = new CreateTableRequest() 
   .withTableName("ClimateInfo") 
   .withProvisionedThroughput(new ProvisionedThroughput() 
   .withReadCapacityUnits((long) 5) 
   .withWriteCapacityUnits((long) 1))
   .withAttributeDefinitions(attributeDefinitions) 
   .withKeySchema(tableKeySchema) 
   .withGlobalSecondaryIndexes(windIndex); 
Table table = dynamoDB.createTable(createTableRequest); 
System.out.println(table.getDescription());

使用 **DescribeTable** 檢索索引資訊。首先,建立一個 DynamoDB 類例項。然後建立一個 Table 類例項以定位索引。最後,將表傳遞給 describe 方法。

這是一個簡短的示例 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
TableDescription tableDesc = table.describe();  
Iterator<GlobalSecondaryIndexDescription> gsiIter = 
   tableDesc.getGlobalSecondaryIndexes().iterator(); 

while (gsiIter.hasNext()) { 
   GlobalSecondaryIndexDescription gsiDesc = gsiIter.next(); 
   System.out.println("Index data " + gsiDesc.getIndexName() + ":");  
   Iterator<KeySchemaElement> kse7Iter = gsiDesc.getKeySchema().iterator(); 
   
   while (kseIter.hasNext()) { 
      KeySchemaElement kse = kseIter.next(); 
      System.out.printf("\t%s: %s\n", kse.getAttributeName(), kse.getKeyType()); 
   }
   Projection projection = gsiDesc.getProjection(); 
   System.out.println("\tProjection type: " + projection.getProjectionType()); 
   
   if (projection.getProjectionType().toString().equals("INCLUDE")) { 
      System.out.println("\t\tNon-key projected attributes: " 
         + projection.getNonKeyAttributes()); 
   } 
}

使用 Query 對索引執行查詢,就像對錶執行查詢一樣。只需建立一個 DynamoDB 類例項、一個 Table 類例項用於目標索引、一個 Index 類例項用於特定索引,並將索引和查詢物件傳遞給 query 方法。

檢視以下程式碼以更好地理解 -

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
   new ProfileCredentialsProvider()));
   
Table table = dynamoDB.getTable("ClimateInfo"); 
Index index = table.getIndex("WindIndex");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("#d = :v_date and Wind = :v_wind") 
   .withNameMap(new NameMap() 
   .with("#d", "Date"))
   .withValueMap(new ValueMap() 
   .withString(":v_date","2016-05-15") 
   .withNumber(":v_wind",0));
   
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator();

while (iter.hasNext()) {
   System.out.println(iter.next().toJSONPretty()); 
}

以下程式是一個更大的示例,以便更好地理解 -

注意 - 以下程式可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

此示例還使用 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

import java.util.ArrayList;
import java.util.Iterator;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Index;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;

import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;

public class GlobalSecondaryIndexSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient ( 
      new ProfileCredentialsProvider()));  
   public static String tableName = "Bugs";   
   public static void main(String[] args) throws Exception {  
      createTable(); 
      queryIndex("CreationDateIndex"); 
      queryIndex("NameIndex"); 
      queryIndex("DueDateIndex"); 
   }
   public static void createTable() {  
      // Attributes 
      ArrayList<AttributeDefinition> attributeDefinitions = new 
         ArrayList<AttributeDefinition>();  
      attributeDefinitions.add(new AttributeDefinition()
         .withAttributeName("BugID") 
         .withAttributeType("S")); 
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("Name")
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("CreationDate")
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("DueDate") 
         .withAttributeType("S"));
         
      // Table Key schema
      ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>(); 
      tableKeySchema.add (new KeySchemaElement() 
         .withAttributeName("BugID") 
         .withKeyType(KeyType.HASH));              //Partition key 
      
      tableKeySchema.add (new KeySchemaElement() 
         .withAttributeName("Name") 
         .withKeyType(KeyType.RANGE));             //Sort key
         
      // Indexes' initial provisioned throughput
      ProvisionedThroughput ptIndex = new ProvisionedThroughput()
         .withReadCapacityUnits(1L)
         .withWriteCapacityUnits(1L);
         
      // CreationDateIndex 
      GlobalSecondaryIndex creationDateIndex = new GlobalSecondaryIndex() 
         .withIndexName("CreationDateIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement() 
         .withAttributeName("CreationDate") 
         .withKeyType(KeyType.HASH),               //Partition key 
         new KeySchemaElement()
         .withAttributeName("BugID") 
         .withKeyType(KeyType.RANGE))              //Sort key 
         .withProjection(new Projection() 
         .withProjectionType("INCLUDE") 
         .withNonKeyAttributes("Description", "Status"));
         
      // NameIndex 
      GlobalSecondaryIndex nameIndex = new GlobalSecondaryIndex() 
         .withIndexName("NameIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement()  
         .withAttributeName("Name")  
         .withKeyType(KeyType.HASH),                  //Partition key 
         new KeySchemaElement()  
         .withAttributeName("BugID")  
         .withKeyType(KeyType.RANGE))                 //Sort key 
         .withProjection(new Projection() 
         .withProjectionType("KEYS_ONLY"));
         
      // DueDateIndex 
      GlobalSecondaryIndex dueDateIndex = new GlobalSecondaryIndex() 
         .withIndexName("DueDateIndex") 
         .withProvisionedThroughput(ptIndex) 
         .withKeySchema(new KeySchemaElement() 
         .withAttributeName("DueDate") 
         .withKeyType(KeyType.HASH))               //Partition key 
         .withProjection(new Projection() 
         .withProjectionType("ALL"));
         
      CreateTableRequest createTableRequest = new CreateTableRequest() 
         .withTableName(tableName) 
         .withProvisionedThroughput( new ProvisionedThroughput() 
         .withReadCapacityUnits( (long) 1) 
         .withWriteCapacityUnits( (long) 1)) 
         .withAttributeDefinitions(attributeDefinitions)
         .withKeySchema(tableKeySchema)
         .withGlobalSecondaryIndexes(creationDateIndex, nameIndex, dueDateIndex);  
         System.out.println("Creating " + tableName + "..."); 
         dynamoDB.createTable(createTableRequest);  
      
      // Pause for active table state 
      System.out.println("Waiting for ACTIVE state of " + tableName); 
      try { 
         Table table = dynamoDB.getTable(tableName); 
         table.waitForActive(); 
      } catch (InterruptedException e) { 
         e.printStackTrace(); 
      } 
   }
   public static void queryIndex(String indexName) { 
      Table table = dynamoDB.getTable(tableName);  
      System.out.println 
      ("\n*****************************************************\n"); 
      System.out.print("Querying index " + indexName + "...");  
      Index index = table.getIndex(indexName);  
      ItemCollection<QueryOutcome> items = null; 
      QuerySpec querySpec = new QuerySpec();  
      
      if (indexName == "CreationDateIndex") { 
         System.out.println("Issues filed on 2016-05-22"); 
         querySpec.withKeyConditionExpression("CreationDate = :v_date and begins_with
            (BugID, :v_bug)") 
            .withValueMap(new ValueMap() 
            .withString(":v_date","2016-05-22")
            .withString(":v_bug","A-")); 
         items = index.query(querySpec); 
      } else if (indexName == "NameIndex") { 
         System.out.println("Compile error"); 
         querySpec.withKeyConditionExpression("Name = :v_name and begins_with
            (BugID, :v_bug)") 
            .withValueMap(new ValueMap() 
            .withString(":v_name","Compile error") 
            .withString(":v_bug","A-")); 
         items = index.query(querySpec); 
      } else if (indexName == "DueDateIndex") { 
         System.out.println("Items due on 2016-10-15"); 
         querySpec.withKeyConditionExpression("DueDate = :v_date") 
         .withValueMap(new ValueMap() 
         .withString(":v_date","2016-10-15")); 
         items = index.query(querySpec); 
      } else { 
         System.out.println("\nInvalid index name"); 
         return; 
      }  
      Iterator<Item> iterator = items.iterator(); 
      System.out.println("Query: getting result..."); 
      
      while (iterator.hasNext()) { 
         System.out.println(iterator.next().toJSONPretty()); 
      } 
   } 
}

DynamoDB - 本地二級索引

某些應用程式僅使用主鍵執行查詢,但某些情況下會從備用排序鍵中受益。透過建立單個或多個本地二級索引,允許您的應用程式進行選擇。

複雜的資料訪問需求,例如組合數百萬個專案,使得執行更有效的查詢/掃描成為必要。本地二級索引為分割槽鍵值提供備用排序鍵。它們還儲存所有或某些表屬性的副本。它們按表分割槽鍵組織資料,但使用不同的排序鍵。

使用本地二級索引無需進行整個表掃描,並允許使用排序鍵進行簡單快速的查詢。

所有本地二級索引必須滿足某些條件 -

  • 與源表分割槽鍵相同的分割槽鍵。
  • 僅一個標量屬性的排序鍵。
  • 作為非鍵屬性的源表排序鍵的投影。

所有本地二級索引都自動儲存來自父表的分割槽和排序鍵。在查詢中,這意味著有效地收集投影屬性,以及檢索未投影的屬性。

本地二級索引的儲存限制為每個分割槽鍵值 10GB,其中包括所有表項以及共享分割槽鍵值的索引項。

投影屬性

某些操作由於複雜性而需要額外的讀取/獲取。這些操作可能會消耗大量的吞吐量。透過隔離這些屬性,投影允許您避免代價高昂的獲取並執行豐富的查詢。請記住,投影包括複製到二級索引中的屬性。

建立二級索引時,您會指定投影的屬性。回想一下 DynamoDB 提供的三個選項:**KEYS_ONLY、INCLUDE 和 ALL**。

在選擇投影中的某些屬性時,請考慮相關的成本權衡 -

  • 如果您僅投影一小部分必要的屬性,則會大幅降低儲存成本。

  • 如果您投影經常訪問的非鍵屬性,則可以透過儲存成本抵消掃描成本。

  • 如果您投影大多數或所有非鍵屬性,這將最大限度地提高靈活性並降低吞吐量(無需檢索);但是,儲存成本會上升。

  • 如果您為頻繁寫入/更新和不頻繁查詢投影 KEYS_ONLY,它可以最小化大小,但保持查詢準備。

本地二級索引建立

使用 CreateTable 的 **LocalSecondaryIndex** 引數建立單個或多個本地二級索引。您必須為排序鍵指定一個非鍵屬性。在表建立時,您建立本地二級索引。在刪除時,您刪除這些索引。

具有本地二級索引的表必須遵守每個分割槽鍵值 10GB 的大小限制,但可以儲存任意數量的專案。

本地二級索引查詢和掃描

當索引中的多個專案共享排序鍵值時,本地二級索引上的查詢操作將返回所有具有匹配分割槽鍵值的專案。匹配的專案不會以特定順序返回。本地二級索引的查詢使用最終一致性或強一致性,強一致性讀取提供最新值。

掃描操作返回所有本地二級索引資料。掃描要求您提供表和索引名稱,並允許使用篩選表示式來丟棄資料。

專案寫入

在建立本地二級索引時,您會指定排序鍵屬性及其資料型別。當您寫入專案時,如果專案定義了索引鍵的屬性,則其型別必須與鍵架構的資料型別匹配。

DynamoDB 對錶項和本地二級索引項沒有施加一對一關係的要求。具有多個本地二級索引的表的寫入成本高於具有較少索引的表。

本地二級索引中的吞吐量注意事項

查詢的讀取容量消耗取決於資料訪問的性質。查詢使用最終一致性或強一致性,強一致性讀取使用一個單元,而最終一致性讀取使用半個單元。

結果限制包括最大 1MB 的大小。結果大小來自匹配索引專案大小(四捨五入到最接近的 4KB)和匹配表專案大小(也四捨五入到最接近的 4KB)的總和。

寫入容量消耗保持在預置單元內。透過查詢表寫入中消耗的單元和更新索引中消耗的單元的總和來計算總預置成本。

您還可以考慮影響成本的關鍵因素,其中一些可能是 -

  • 當您寫入定義索引屬性的專案或更新專案以定義未定義的索引屬性時,會發生一次寫入操作。

  • 當表更新更改索引鍵屬性值時,會發生兩次寫入以刪除然後新增專案。

  • 當寫入導致索引屬性的刪除時,會發生一次寫入以刪除舊的專案投影。

  • 當專案在更新之前或之後不存在於索引中時,不會發生寫入。

本地二級索引儲存

在表項寫入時,DynamoDB 會自動將正確的屬性集複製到所需的本地二級索引。這會向您的賬戶收費。使用的空間來自表主鍵位元組大小、索引鍵屬性位元組大小、任何存在的投影屬性位元組大小以及每個索引項 100 位元組開銷的總和。

估算儲存是透過估算平均索引專案大小並乘以表專案數量得到的。

使用 Java 處理本地二級索引

首先建立 DynamoDB 類例項來建立本地二級索引。然後,使用必要的請求資訊建立一個 CreateTableRequest 類例項。最後,使用 createTable 方法。

示例

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
String tableName = "Tools";  
CreateTableRequest createTableRequest = new 
   CreateTableRequest().withTableName(tableName);
   
//Provisioned Throughput
createTableRequest.setProvisionedThroughput (
   new ProvisionedThroughput()
   .withReadCapacityUnits((long)5)
   .withWriteCapacityUnits(( long)5));
   
//Attributes 
ArrayList<AttributeDefinition> attributeDefinitions = 
   new ArrayList<AttributeDefinition>();
   attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Make")
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Model")
   .withAttributeType("S"));
   
attributeDefinitions.add(new AttributeDefinition()
   .withAttributeName("Line")
   .withAttributeType("S"));
   
createTableRequest.setAttributeDefinitions(attributeDefinitions);

//Key Schema 
ArrayList<KeySchemaElement> tableKeySchema = new 
   ArrayList<KeySchemaElement>();
   
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("Make")
   .withKeyType(KeyType.HASH));                    //Partition key
   
tableKeySchema.add(new KeySchemaElement()
   .withAttributeName("Model")
   .withKeyType(KeyType.RANGE));                   //Sort key
   
createTableRequest.setKeySchema(tableKeySchema);
ArrayList<KeySchemaElement> indexKeySchema = new 
   ArrayList<KeySchemaElement>();
   
indexKeySchema.add(new KeySchemaElement()
   .withAttributeName("Make")
   .withKeyType(KeyType.HASH));                   //Partition key
   
indexKeySchema.add(new KeySchemaElement()
   .withAttributeName("Line")
   .withKeyType(KeyType.RANGE));                   //Sort key
   
Projection projection = new Projection()
   .withProjectionType(ProjectionType.INCLUDE);

ArrayList<String> nonKeyAttributes = new ArrayList<String>(); 
nonKeyAttributes.add("Type"); 
nonKeyAttributes.add("Year"); 
projection.setNonKeyAttributes(nonKeyAttributes);  

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex() 
   .withIndexName("ModelIndex")
   .withKeySchema(indexKeySchema)
   .withProjection(p rojection);  

ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new 
   ArrayList<LocalSecondaryIndex>(); 

localSecondaryIndexes.add(localSecondaryIndex); 
createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);  
Table table = dynamoDB.createTable(createTableRequest); 
System.out.println(table.getDescription());

使用 describe 方法檢索有關本地二級索引的資訊。只需建立一個 DynamoDB 類例項、建立一個 Table 類例項,並將表傳遞給 describe 方法。

示例

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
   
String tableName = "Tools";
Table table = dynamoDB.getTable(tableName);
TableDescription tableDescription = table.describe();

List<LocalSecondaryIndexDescription> localSecondaryIndexes = 
   tableDescription.getLocalSecondaryIndexes();
   
Iterator<LocalSecondaryIndexDescription> lsiIter = 
   localSecondaryIndexes.iterator();
   
while (lsiIter.hasNext()) {  
   LocalSecondaryIndexDescription lsiDescription = lsiIter.next(); 
   System.out.println("Index info " + 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("\tProjection type: " + projection.getProjectionType()); 
   
   if (projection.getProjectionType().toString().equals("INCLUDE")) { 
      System.out.println("\t\tNon-key projected attributes: " + 
         projection.getNonKeyAttributes()); 
   } 
}

透過使用與表查詢相同的步驟執行查詢。只需建立一個 DynamoDB 類例項、一個 Table 類例項、一個 Index 類例項、一個查詢物件,並使用 query 方法。

示例

DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
   new ProfileCredentialsProvider()));
   
String tableName = "Tools";  
Table table = dynamoDB.getTable(tableName); 
Index index = table.getIndex("LineIndex");  
QuerySpec spec = new QuerySpec() 
   .withKeyConditionExpression("Make = :v_make and Line = :v_line") 
   .withValueMap(new ValueMap() 
   .withString(":v_make", "Depault") 
   .withString(":v_line", "SuperSawz"));
      
ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> itemsIter = items.iterator();

while (itemsIter.hasNext()) { 
   Item item = itemsIter.next(); 
   System.out.println(item.toJSONPretty()); 
}

您還可以檢視以下示例。

注意 - 以下示例可能假設存在先前建立的資料來源。在嘗試執行之前,請獲取支援庫並建立必要的資料來源(具有所需特徵的表或其他引用的源)。

以下示例還使用了 Eclipse IDE、AWS 憑證檔案以及 Eclipse AWS Java 專案中的 AWS 工具包。

示例

import java.util.ArrayList;
import java.util.Iterator;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;

import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Index;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.PutItemOutcome;
import com.amazonaws.services.dynamodbv2.document.QueryOutcome;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.utils.ValueMap;

import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.LocalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.Projection;
import com.amazonaws.services.dynamodbv2.model.ProjectionType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ReturnConsumedCapacity;
import com.amazonaws.services.dynamodbv2.model.Select;

public class LocalSecondaryIndexSample {  
   static DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient( 
      new ProfileCredentialsProvider()));  
   public static String tableName = "ProductOrders";  
   
   public static void main(String[] args) throws Exception {  
      createTable();
      query(null); 
      query("IsOpenIndex"); 
      query("OrderCreationDateIndex"); 
   }
   public static void createTable() { 
      CreateTableRequest createTableRequest = new CreateTableRequest() 
         .withTableName(tableName) 
         .withProvisionedThroughput(new ProvisionedThroughput() 
         .withReadCapacityUnits((long) 1) 
         .withWriteCapacityUnits((long) 1));
         
      // Table partition and sort keys attributes 
      ArrayList<AttributeDefinition> attributeDefinitions = new 
         ArrayList<AttributeDefinition>(); 
      
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("CustomerID") 
         .withAttributeType("S"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OrderID") 
         .withAttributeType("N"));
         
      // Index primary key attributes 
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OrderDate") 
         .withAttributeType("N"));
         
      attributeDefinitions.add(new AttributeDefinition() 
         .withAttributeName("OpenStatus") 
         .withAttributeType("N"));  
      createTableRequest.setAttributeDefinitions(attributeDefinitions);
      
      // Table key schema 
      ArrayList<KeySchemaElement> tableKeySchema = new
         ArrayList<KeySchemaElement>(); 
      tableKeySchema.add(new KeySchemaElement()  
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                    //Partition key
         
      tableKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OrderID") 
         .withKeyType(KeyType.RANGE));                   //Sort key
         
      createTableRequest.setKeySchema(tableKeySchema);  
      ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new 
         ArrayList<LocalSecondaryIndex>();  
      
      // OrderDateIndex 
      LocalSecondaryIndex orderDateIndex = new LocalSecondaryIndex() 
         .withIndexName("OrderDateIndex");
         
      // OrderDateIndex key schema 
      ArrayList<KeySchemaElement> indexKeySchema = new 
         ArrayList<KeySchemaElement>(); 
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                   //Partition key
         
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OrderDate") 
         .withKeyType(KeyType.RANGE));                   //Sort key
      orderDateIndex.setKeySchema(indexKeySchema);
      
      // OrderCreationDateIndex projection w/attributes list 
      Projection projection = new Projection() 
         .withProjectionType(ProjectionType.INCLUDE); 
      
      ArrayList<String> nonKeyAttributes = new ArrayList<String>(); 
      nonKeyAttributes.add("ProdCat"); 
      nonKeyAttributes.add("ProdNomenclature"); 
      projection.setNonKeyAttributes(nonKeyAttributes);
      orderCreationDateIndex.setProjection(projection);  
      localSecondaryIndexes.add(orderDateIndex);  
      
      // IsOpenIndex 
      LocalSecondaryIndex isOpenIndex = new LocalSecondaryIndex() 
         .withIndexName("IsOpenIndex");  
      
      // OpenStatusIndex key schema 
      indexKeySchema = new ArrayList<KeySchemaElement>(); 
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("CustomerID") 
         .withKeyType(KeyType.HASH));                   //Partition key
         
      indexKeySchema.add(new KeySchemaElement() 
         .withAttributeName("OpenStatus") 
         .withKeyType(KeyType.RANGE));                   //Sort key
         
      // OpenStatusIndex projection 
      projection = new Projection() .withProjectionType(ProjectionType.ALL);  
      OpenStatusIndex.setKeySchema(indexKeySchema); 
      OpenStatusIndex.setProjection(projection);  
      localSecondaryIndexes.add(OpenStatusIndex);  
      
      // Put definitions in CreateTable request 
      createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);  
      System.out.println("Spawning table " + tableName + "..."); 
      System.out.println(dynamoDB.createTable(createTableRequest));  
      
      // Pause for ACTIVE status 
      System.out.println("Waiting for ACTIVE table:" + tableName); 
      try { 
         Table table = dynamoDB.getTable(tableName);
         table.waitForActive(); 
      } catch (InterruptedException e) { 
         e.printStackTrace(); 
      } 
   }
   public static void query(String indexName) {  
      Table table = dynamoDB.getTable(tableName);  
      System.out.println("\n*************************************************\n"); 
      System.out.println("Executing query on" + tableName);  
      QuerySpec querySpec = new QuerySpec() 
         .withConsistentRead(true) 
         .withScanIndexForward(true) 
         .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
      
      if (indexName == "OpenStatusIndex") {  
         System.out.println("\nEmploying index: '" + indexName 
            + "' open orders for this customer.");
            
         System.out.println( 
            "Returns only user-specified attribute list\n"); 
         Index index = table.getIndex(indexName); 
             
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid and 
            OpenStatus = :v_openstat") 
            .withValueMap(new ValueMap() 
            .withString(":v_custmid", "jane@sample.com") 
            .withNumber(":v_openstat", 1));  
         
         querySpec.withProjectionExpression( 
            "OrderDate, ProdCat, ProdNomenclature, OrderStatus"); 
            ItemCollection<QueryOutcome> items = index.query(querySpec); 
            Iterator<Item> iterator = items.iterator();  
            System.out.println("Printing query results...");  
            
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         }  
      } else if (indexName == "OrderDateIndex") { 
         System.out.println("\nUsing index: '" + indexName 
            + "': this customer's orders placed after 05/22/2016."); 
         System.out.println("Projected attributes are returned\n"); 
         Index index = table.getIndex(indexName); 
             
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid and OrderDate 
            >= :v_ordrdate") 
            .withValueMap(new ValueMap() 
            .withString(":v_custmid", "jane@sample.com") 
            .withNumber(":v_ordrdate", 20160522));
               
         querySpec.withSelect(Select.ALL_PROJECTED_ATTRIBUTES);  
         ItemCollection<QueryOutcome> items = index.query(querySpec); 
         Iterator<Item> iterator = items.iterator();  
         System.out.println("Printing query results...");  
            
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         }  
      } else { 
         System.out.println("\nNo index: All Jane's orders by OrderID:\n"); 
         querySpec.withKeyConditionExpression("CustomerID = :v_custmid") 
            .withValueMap(new ValueMap()
            .withString(":v_custmid", "jane@example.com"));  
         
         ItemCollection<QueryOutcome> items = table.query(querySpec); 
         Iterator<Item> iterator = items.iterator();  
         System.out.println("Printing query results...");  
         
         while (iterator.hasNext()) { 
            System.out.println(iterator.next().toJSONPretty()); 
         } 
      } 
   } 
}

DynamoDB - 聚合

DynamoDB 不提供聚合函式。您必須創造性地使用查詢、掃描、索引和各種工具來執行這些任務。在所有這些操作中,這些操作中查詢/掃描的吞吐量開銷可能很大。

您還可以選擇為首選的 DynamoDB 編碼語言使用庫和其他工具。在使用之前,請確保它們與 DynamoDB 相容。

計算最大值或最小值

利用結果的升序/降序儲存順序、Limit 引數以及設定順序的任何引數來查詢最高和最低值。

例如 −

Map<String, AttributeValue> eaval = new HashMap<>(); 
eaval.put(":v1", new AttributeValue().withS("hashval")); 
queryExpression = new DynamoDBQueryExpression<Table>() 
   .withIndexName("yourindexname") 
   .withKeyConditionExpression("HK = :v1") 
   .withExpressionAttributeValues(values) 
   .withScanIndexForward(false);                //descending order 

queryExpression.setLimit(1); 
QueryResultPage<Lookup> res = 
   dynamoDBMapper.queryPage(Table.class, queryExpression);

計算計數

使用 **DescribeTable** 獲取表項的計數,但是,請注意它提供的是陳舊資料。此外,使用 Java 的 **getScannedCount 方法**。

利用 **LastEvaluatedKey** 確保它提供所有結果。

例如 −

ScanRequest scanRequest = new ScanRequest().withTableName(yourtblName); 
ScanResult yourresult = client.scan(scanRequest); 
System.out.println("#items:" + yourresult.getScannedCount());

計算平均值和總和

利用索引和查詢/掃描在處理之前檢索和篩選值。然後,只需透過物件對這些值進行操作。

DynamoDB - 訪問控制

DynamoDB 使用您提供的憑證來驗證請求。這些憑證是必需的,並且必須包含對 AWS 資源訪問的許可權。這些許可權幾乎涵蓋了 DynamoDB 的各個方面,直至操作或功能的細微功能。

許可權型別

在本節中,我們將討論 DynamoDB 中的各種許可權和資源訪問。

驗證使用者

在註冊時,您提供了密碼和電子郵件,它們用作根憑證。DynamoDB 將此資料與您的 AWS 賬戶關聯,並使用它來授予對所有資源的完全訪問許可權。

AWS 建議您僅將根憑證用於建立管理賬戶。這使您可以建立具有較少許可權的 IAM 賬戶/使用者。IAM 使用者是由 IAM 服務生成的其它賬戶。它們的訪問許可權/特權包括訪問安全頁面和某些自定義許可權,例如表修改。

訪問金鑰提供了另一個用於新增賬戶和訪問許可權的選項。使用它們來授予訪問許可權,並在某些情況下避免手動授予訪問許可權。聯合使用者透過允許透過身份提供商進行訪問提供了另一個選項。

管理

AWS 資源仍然屬於某個賬戶所有。許可權策略控制授予的建立或訪問資源的許可權。管理員將許可權策略與 IAM 標識相關聯,即角色、組、使用者和服務。他們還將許可權附加到資源。

許可權指定使用者、資源和操作。請注意,管理員僅僅是擁有管理員許可權的賬戶。

操作和資源

表仍然是 DynamoDB 中的主要資源。子資源用作其他資源,例如流和索引。這些資源使用唯一的名稱,其中一些在以下表格中提到 -

型別 ARN(Amazon 資源名稱)
arn:aws:dynamodb:region:account-id:table/table-name/stream/stream-label
索引 arn:aws:dynamodb:region:account-id:table/table-name/index/index-name
arn:aws:dynamodb:region:account-id:table/table-name

所有權

資源所有者定義為建立該資源的 AWS 賬戶,或負責在資源建立中進行請求身份驗證的主體實體賬戶。考慮一下它在 DynamoDB 環境中的工作方式 -

  • 在使用根憑證建立表時,您的賬戶仍然是資源所有者。

  • 在建立 IAM 使用者並授予該使用者建立表的許可權時,您的賬戶仍然是資源所有者。

  • 在建立 IAM 使用者並授予該使用者以及任何能夠承擔該角色的使用者建立表的許可權時,您的賬戶仍然是資源所有者。

管理資源訪問

訪問管理主要需要關注描述使用者和資源訪問許可權的許可權策略。您可以將策略與 IAM 標識或資源關聯。但是,DynamoDB 僅支援 IAM/身份策略。

基於身份(IAM)的策略允許您透過以下方式授予許可權 -

  • 將許可權附加到使用者或組。
  • 將許可權附加到角色以進行跨賬戶許可權。

其他 AWS 允許基於資源的策略。這些策略允許訪問諸如 S3 儲存桶之類的內容。

策略元素

策略定義操作、效果、資源和主體;並授予執行這些操作的許可權。

注意 - API 操作可能需要多個操作的許可權。

仔細檢視以下策略元素 -

  • 資源 - ARN 標識此內容。

  • 操作 - 關鍵字標識這些資源操作,以及是允許還是拒絕。

  • 效果 - 它指定使用者對操作請求的效果,即允許或拒絕,其中拒絕為預設值。

  • 主體 - 這標識附加到策略的使用者。

條件

在授予許可權時,您可以指定策略何時生效的條件,例如在特定日期。使用條件鍵表達條件,其中包括 AWS 範圍內的鍵和 DynamoDB 鍵。這些鍵將在本教程的後面詳細討論。

控制檯許可權

使用者需要某些基本許可權才能使用控制檯。他們還需要其他標準服務中的控制檯許可權 -

  • CloudWatch
  • 資料管道
  • 身份和訪問管理
  • 通知服務
  • Lambda

如果 IAM 策略過於限制,則使用者無法有效地使用控制檯。此外,您無需擔心僅呼叫 CLI 或 API 的使用者的使用者許可權。

常用 IAM 策略

AWS 使用獨立的 IAM 託管策略涵蓋許可權中的常見操作。它們提供關鍵許可權,允許您避免深入調查必須授予的內容。

其中一些如下 -

  • AmazonDynamoDBReadOnlyAccess - 它透過控制檯提供只讀訪問許可權。

  • AmazonDynamoDBFullAccess - 它透過控制檯提供完全訪問許可權。

  • AmazonDynamoDBFullAccesswithDataPipeline - 它透過控制檯提供完全訪問許可權,並允許使用資料管道進行匯出/匯入。

您當然也可以建立自定義策略。

授予許可權:使用 Shell

您可以使用 Javascript shell 授予許可權。以下程式顯示了一個典型的許可權策略 -

{ 
   "Version": "2016-05-22", 
   "Statement": [ 
      { 
         "Sid": "DescribeQueryScanToolsTable", 
         "Effect": "Deny", 
         
         "Action": [ 
            "dynamodb:DescribeTable", 
            "dynamodb:Query", 
            "dynamodb:Scan" 
         ], 
         "Resource": "arn:aws:dynamodb:us-west-2:account-id:table/Tools" 
      } 
   ] 
}

您可以檢視以下三個示例 -

阻止使用者執行任何表操作。

{ 
   "Version": "2016-05-23", 
   "Statement": [ 
      { 
         "Sid": "AllAPIActionsOnTools", 
         "Effect": "Deny", 
         "Action": "dynamodb:*", 
         "Resource": "arn:aws:dynamodb:us-west-2:155556789012:table/Tools" 
      } 
   ] 
}

阻止訪問表及其索引。

{ 
   "Version": "2016-05-23", 
   "Statement": [ 
      { 
         "Sid": "AccessAllIndexesOnTools", 
         "Effect": "Deny", 
         "Action": [
            "dynamodb:*" 
         ], 
         "Resource": [ 
            "arn:aws:dynamodb:us-west-2:155556789012:table/Tools", 
            "arn:aws:dynamodb:us-west-2:155556789012:table/Tools/index/*" 
         ] 
      } 
   ] 
}

阻止使用者進行預留容量購買。

{ 
   "Version": "2016-05-23", 
   "Statement": [ 
      { 
         "Sid": "BlockReservedCapacityPurchases", 
         "Effect": "Deny", 
         "Action": "dynamodb:PurchaseReservedCapacityOfferings", 
         "Resource": "arn:aws:dynamodb:us-west-2:155556789012:*" 
      } 
   ] 
}

授予許可權:使用 GUI 控制檯

您還可以使用 GUI 控制檯建立 IAM 策略。首先,從導航窗格中選擇。在表列表中,選擇目標表並按照以下步驟操作。

步驟 1 - 選擇訪問控制選項卡。

步驟 2 - 選擇身份提供商、操作和策略屬性。輸入所有設定後,選擇建立策略

步驟 3 - 選擇附加策略說明,並完成每個必需步驟以將策略與相應的 IAM 角色關聯。

DynamoDB - 許可權 API

DynamoDB API 提供大量需要許可權的操作。在設定許可權時,您必須確定允許的操作、允許的資源以及每個條件。

您可以在策略的 Action 欄位中指定操作。在策略的 Resource 欄位中指定資源值。但請確保使用包含 Dynamodb: 字首和 API 操作的正確語法。

例如 - dynamodb:CreateTable

您還可以使用條件鍵來過濾許可權。

許可權和 API 操作

仔細檢視以下表格中給出的 API 操作和關聯許可權 -

API 操作 必要許可權
BatchGetItem dynamodb:BatchGetItem
BatchWriteItem dynamodb:BatchWriteItem
CreateTable dynamodb:CreateTable
DeleteItem dynamodb:DeleteItem
DeleteTable dynamodb:DeleteTable
DescribeLimits dynamodb:DescribeLimits
DescribeReservedCapacity dynamodb:DescribeReservedCapacity
DescribeReservedCapacityOfferings dynamodb:DescribeReservedCapacityOfferings
DescribeStream dynamodb:DescribeStream
DescribeTable dynamodb:DescribeTable
GetItem dynamodb:GetItem
GetRecords dynamodb:GetRecords
GetShardIterator dynamodb:GetShardIterator
ListStreams dynamodb:ListStreams
ListTables dynamodb:ListTables
PurchaseReservedCapacityOfferings dynamodb:PurchaseReservedCapacityOfferings
PutItem dynamodb:PutItem
Query dynamodb:Query
Scan dynamodb:Scan
UpdateItem dynamodb:UpdateItem
UpdateTable dynamodb:UpdateTable

資源

在以下表格中,您可以檢視與每個允許的 API 操作關聯的資源 -

API 操作 資源
BatchGetItem arn:aws:dynamodb:region:account-id:table/table-name
BatchWriteItem arn:aws:dynamodb:region:account-id:table/table-name
CreateTable arn:aws:dynamodb:region:account-id:table/table-name
DeleteItem arn:aws:dynamodb:region:account-id:table/table-name
DeleteTable arn:aws:dynamodb:region:account-id:table/table-name
DescribeLimits arn:aws:dynamodb:region:account-id:*
DescribeReservedCapacity arn:aws:dynamodb:region:account-id:*
DescribeReservedCapacityOfferings arn:aws:dynamodb:region:account-id:*
DescribeStream arn:aws:dynamodb:region:account-id:table/table-name/stream/stream-label
DescribeTable arn:aws:dynamodb:region:account-id:table/table-name
GetItem arn:aws:dynamodb:region:account-id:table/table-name
GetRecords arn:aws:dynamodb:region:account-id:table/table-name/stream/stream-label
GetShardIterator arn:aws:dynamodb:region:account-id:table/table-name/stream/stream-label
ListStreams arn:aws:dynamodb:region:account-id:table/table-name/stream/*
ListTables *
PurchaseReservedCapacityOfferings arn:aws:dynamodb:region:account-id:*
PutItem arn:aws:dynamodb:region:account-id:table/table-name
Query

arn:aws:dynamodb:region:account-id:table/table-name

arn:aws:dynamodb:region:account-id:table/table-name/index/index-name

Scan

arn:aws:dynamodb:region:account-id:table/table-name

arn:aws:dynamodb:region:account-id:table/table-name/index/index-name

UpdateItem arn:aws:dynamodb:region:account-id:table/table-name
UpdateTable arn:aws:dynamodb:region:account-id:table/table-name

DynamoDB - 條件

在授予許可權時,DynamoDB 允許透過具有條件鍵的詳細 IAM 策略為其指定條件。這支援諸如訪問特定專案和屬性之類的設定。

注意 - DynamoDB 不支援任何標籤。

詳細控制

一些條件允許具體到專案和屬性,例如根據使用者賬戶授予特定專案的只讀訪問許可權。使用條件 IAM 策略實現此級別的控制,該策略管理安全憑證。然後只需將策略應用於所需的使用者的、組和角色。稍後討論的 Web 身份聯合也提供了一種透過 Amazon、Facebook 和 Google 登入來控制使用者訪問許可權的方法。

IAM 策略的 condition 元素實現訪問控制。您只需將其新增到策略中即可。其使用示例包括拒絕或允許訪問表專案和屬性。condition 元素還可以使用條件鍵來限制許可權。

您可以檢視以下兩個條件鍵示例 -

  • dynamodb:LeadingKeys - 它阻止沒有與分割槽鍵值匹配的 ID 的使用者訪問專案。

  • dynamodb:Attributes - 它阻止使用者訪問或操作未列出的屬性之外的屬性。

在評估時,IAM 策略會產生真或假值。如果任何部分評估為假,則整個策略將評估為假,這將導致拒絕訪問。請確保在條件鍵中指定所有必需的資訊,以確保使用者擁有適當的訪問許可權。

預定義條件鍵

AWS 提供了一組預定義的條件鍵,這些鍵適用於所有服務。它們支援廣泛的用途並在檢查使用者和訪問許可權時提供精細的細節。

注意 - 條件鍵區分大小寫。

您可以檢視以下一些特定於服務的鍵 -

  • dynamodb:LeadingKey - 它表示表的第一個鍵屬性;分割槽鍵。在條件中使用 ForAllValues 修飾符。

  • dynamodb:Select - 它表示查詢/掃描請求 Select 引數。它必須是 ALL_ATTRIBUTES、ALL_PROJECTED_ATTRIBUTES、SPECIFIC_ATTRIBUTES 或 COUNT 值。

  • dynamodb:Attributes - 它表示請求中的屬性名稱列表,或從請求返回的屬性。其值及其功能類似於 API 操作引數,例如 BatchGetItem 使用 AttributesToGet。

  • dynamodb:ReturnValues - 它表示請求的 ReturnValues 引數,並且可以使用以下值:ALL_OLD、UPDATED_OLD、ALL_NEW、UPDATED_NEW 和 NONE。

  • dynamodb:ReturnConsumedCapacity - 它表示請求的 ReturnConsumedCapacity 引數,並且可以使用以下值:TOTAL 和 NONE。

DynamoDB - Web 身份聯合

Web 身份聯合允許您簡化對大型使用者組的身份驗證和授權。您可以跳過建立單個賬戶,並要求使用者登入到身份提供商以獲取臨時憑證或令牌。它使用 AWS 安全令牌服務 (STS) 來管理憑證。應用程式使用這些令牌與服務進行互動。

Web 身份聯合還支援其他身份提供商,例如 Amazon、Google 和 Facebook。

功能 - 在使用中,Web 身份聯合首先呼叫身份提供商進行使用者和應用程式身份驗證,並且提供商返回一個令牌。這會導致應用程式呼叫 AWS STS 並傳遞令牌作為輸入。STS 授權應用程式並向其授予臨時訪問憑證,這些憑證允許應用程式使用 IAM 角色並根據策略訪問資源。

實施 Web 身份聯合

在使用之前,您必須執行以下三個步驟 -

  • 使用受支援的第三方身份提供商註冊為開發者。

  • 向提供商註冊您的應用程式以獲取應用程式 ID。

  • 建立單個或多個 IAM 角色,包括策略附加。您必須為每個提供商每個應用程式使用一個角色。

假設您要使用 Web 身份聯合中的一個 IAM 角色。然後,您的應用程式必須執行一個三步過程 -

  • 身份驗證
  • 憑證獲取
  • 資源訪問

在第一步中,您的應用程式使用其自己的介面呼叫提供商,然後管理令牌過程。

然後第二步管理令牌,並要求您的應用程式向 AWS STS 傳送AssumeRoleWithWebIdentity請求。該請求包含第一個令牌、提供商應用程式 ID 和 IAM 角色的 ARN。然後 STS 提供設定為在特定時間段後過期的憑證。

在最後一步中,您的應用程式會收到來自 STS 的響應,其中包含 DynamoDB 資源的訪問資訊。它包括訪問憑證、過期時間、角色和角色 ID。

DynamoDB - 資料管道

資料管道允許將資料匯出和匯入到/從表、檔案或 S3 儲存桶。這當然在備份、測試以及類似的需求或場景中非常有用。

在匯出中,您使用資料管道控制檯,它會建立一個新的管道並啟動一個 Amazon EMR(Elastic MapReduce)叢集來執行匯出。EMR 從 DynamoDB 讀取資料並寫入目標。我們將在本教程的後面詳細討論 EMR。

在匯入操作中,您使用資料管道控制檯,它會建立一個管道並啟動 EMR 來執行匯入。它從源讀取資料並寫入目標。

注意 − 由於使用了 EMR 和 S3 等服務,匯出/匯入操作會產生費用。

使用資料管道

使用資料管道時,必須指定操作和資源許可權。您可以利用 IAM 角色或策略來定義它們。執行匯入/匯出操作的使用者應注意,他們需要一個有效的訪問金鑰 ID 和金鑰。

資料管道的 IAM 角色

使用資料管道需要兩個 IAM 角色 −

  • DataPipelineDefaultRole − 它包含您允許管道為您執行的所有操作。

  • DataPipelineDefaultResourceRole − 它包含您允許管道為您配置的資源。

如果您是資料管道的新手,則必須分別建立每個角色。所有以前的使用者都擁有這些角色,因為它們是現有角色。

使用 IAM 控制檯為資料管道建立 IAM 角色,並執行以下四個步驟 −

步驟 1 − 登入位於 https://console.aws.amazon.com/iam/ 的 IAM 控制檯

步驟 2 − 從儀表板中選擇角色

步驟 3 − 選擇建立新角色。然後在角色名稱欄位中輸入 DataPipelineDefaultRole,並選擇下一步。在角色型別面板中的AWS 服務角色列表中,導航到資料管道,然後選擇選擇。在審查面板中選擇建立角色

步驟 4 − 選擇建立新角色

DynamoDB - 資料備份

利用資料管道的匯入/匯出功能執行備份。執行備份的方式取決於您是使用 GUI 控制檯還是直接使用資料管道(API)。如果使用控制檯,則為每個表建立單獨的管道;如果使用直接選項,則在一個管道中匯入/匯出多個表。

匯出和匯入資料

在執行匯出之前,必須建立一個 Amazon S3 儲存桶。您可以從一個或多個表中匯出資料。

執行以下四個步驟過程來執行匯出 −

步驟 1 − 登入 AWS 管理控制檯並開啟位於 https://console.aws.amazon.com/datapipeline/ 的資料管道控制檯

步驟 2 − 如果您在使用的 AWS 區域中沒有管道,請選擇立即開始。如果您有一個或多個管道,請選擇建立新管道

步驟 3 − 在建立頁面上,輸入管道名稱。為源引數選擇使用模板構建。從列表中選擇將 DynamoDB 表匯出到 S3。在源 DynamoDB 表名稱欄位中輸入源表。

使用以下格式在輸出 S3 資料夾文字框中輸入目標 S3 儲存桶:s3://nameOfBucket/region/nameOfFolder。在日誌的 S3 位置文字框中輸入日誌檔案的 S3 目標。

步驟 4 − 輸入所有設定後,選擇啟用

管道可能需要幾分鐘才能完成建立過程。使用控制檯監控其狀態。透過檢視匯出的檔案,在 S3 控制檯中確認處理成功。

匯入資料

只有在滿足以下條件時,匯入才能成功:您建立了一個目標表,目標和源使用相同的名稱,以及目標和源使用相同的鍵架構。

您可以使用已填充的目標表,但是,匯入會替換與源項共享鍵的資料項,並將多餘的項新增到表中。目標還可以使用不同的區域。

雖然您可以匯出多個源,但每次操作只能匯入一個。您可以透過遵循以下步驟執行匯入 −

步驟 1 − 登入 AWS 管理控制檯,然後開啟資料管道控制檯。

步驟 2 − 如果您打算執行跨區域匯入,則應選擇目標區域。

步驟 3 − 選擇建立新管道

步驟 4 − 在名稱欄位中輸入管道名稱。為源引數選擇使用模板構建,並在模板列表中選擇從 S3 匯入 DynamoDB 備份資料

輸入 S3 資料夾文字框中輸入原始檔的位置。在目標 DynamoDB 表名稱欄位中輸入目標表名稱。然後在日誌的 S3 位置文字框中輸入日誌檔案的位置。

步驟 5 − 輸入所有設定後,選擇啟用

管道建立後立即開始匯入。管道可能需要幾分鐘才能完成建立過程。

錯誤

發生錯誤時,資料管道控制檯會將管道狀態顯示為錯誤。單擊出現錯誤的管道將帶您到其詳細資訊頁面,該頁面顯示了流程的每個步驟以及發生故障的點。內部日誌檔案也提供了一些見解。

您可以檢視錯誤的常見原因,如下所示 −

  • 匯入的目標表不存在,或者與源的鍵架構不相同。

  • S3 儲存桶不存在,或者您沒有對其進行讀/寫許可權。

  • 管道超時。

  • 您沒有必要的匯出/匯入許可權。

  • 您的 AWS 賬戶已達到其資源限制。

DynamoDB - 監控

Amazon 提供 CloudWatch 用於透過 CloudWatch 控制檯、命令列或 CloudWatch API 聚合和分析效能。您還可以使用它來設定警報和執行任務。它在某些事件上執行指定的動作。

CloudWatch 控制檯

透過訪問管理控制檯並開啟位於 https://console.aws.amazon.com/cloudwatch/ 的 CloudWatch 控制檯來使用 CloudWatch。

然後您可以執行以下步驟 −

  • 從導航窗格中選擇指標

  • 按類別劃分的 CloudWatch 指標窗格中的 DynamoDB 指標下,選擇表指標

  • 使用上窗格向下滾動並檢查表指標的完整列表。檢視列表提供了指標選項。

在結果介面中,您可以透過選中資源名稱和指標旁邊的複選框來選擇/取消選擇每個指標。然後您將能夠檢視每個專案的圖表。

API 整合

您可以使用查詢訪問 CloudWatch。使用指標值執行 CloudWatch 操作。請注意,DynamoDB 不會發送值為零的指標。它只是跳過這些指標在該值保持不變的時間段。

以下是一些最常用的指標 −

  • ConditionalCheckFailedRequests − 它跟蹤條件寫入(例如條件 PutItem 寫入)失敗嘗試的數量。在評估為假時,失敗的寫入會將此指標增加 1。它還會丟擲 HTTP 400 錯誤。

  • ConsumedReadCapacityUnits − 它量化了在特定時間段內使用的容量單位。您可以使用它來檢查單個表和索引的消耗。

  • ConsumedWriteCapacityUnits − 它量化了在特定時間段內使用的容量單位。您可以使用它來檢查單個表和索引的消耗。

  • ReadThrottleEvents − 它量化了表/索引讀取中超過預配容量單位的請求。它在每次節流時都會遞增,包括具有多個節流的批處理操作。

  • ReturnedBytes − 它量化了在特定時間段內檢索操作中返回的位元組數。

  • ReturnedItemCount − 它量化了在特定時間段內 Query 和 Scan 操作中返回的專案數。它僅解決返回的專案,而不是評估的專案,這些專案通常是完全不同的數字。

注意 − 還有許多其他指標存在,並且大多數指標允許您計算平均值、總和、最大值、最小值和計數。

DynamoDB - CloudTrail

DynamoDB 包括 CloudTrail 整合。它捕獲賬戶中來自或針對 DynamoDB 的低階 API 請求,並將日誌檔案傳送到指定的 S3 儲存桶。它針對控制檯或 API 的呼叫。您可以使用這些資料來確定所做的請求及其來源、使用者、時間戳等。

啟用後,它會在日誌檔案中跟蹤操作,其中包括其他服務記錄。它支援八個操作和兩個流 −

八個操作如下 −

  • CreateTable
  • DeleteTable
  • DescribeTable
  • ListTables
  • UpdateTable
  • DescribeReservedCapacity
  • DescribeReservedCapacityOfferings
  • PurchaseReservedCapacityOfferings

而兩個流是 −

  • DescribeStream
  • ListStreams

所有日誌都包含有關發出請求的賬戶的資訊。您可以確定詳細的資訊,例如根使用者或 IAM 使用者是否發出了請求,或者是否使用臨時憑證或聯合身份驗證。

日誌檔案將保留在儲存中您指定的時間,並設定存檔和刪除。預設情況下會建立加密日誌。您可以為新日誌設定警報。您還可以將跨區域和賬戶的多個日誌組織到一個儲存桶中。

解釋日誌檔案

每個檔案包含一個或多個條目。每個條目都包含多個 JSON 格式的事件。一個條目表示一個請求,幷包含相關資訊;不保證順序。

您可以檢視以下示例日誌檔案 −

{"Records": [ 
   { 
      "eventVersion": "5.05",  
      "userIdentity": {
         "type": "AssumedRole", 
         "principalId": "AKTTIOSZODNN8SAMPLE:jane", 
         "arn": "arn:aws:sts::155522255533:assumed-role/users/jane", 
         "accountId": "155522255533", 
         "accessKeyId": "AKTTIOSZODNN8SAMPLE", 
         
         "sessionContext": { 
            "attributes": { 
               "mfaAuthenticated": "false", 
               "creationDate": "2016-05-11T19:01:01Z" 
            },
            
            "sessionIssuer": { 
               "type": "Role", 
               "principalId": "AKTTI44ZZ6DHBSAMPLE", 
               "arn": "arn:aws:iam::499955777666:role/admin-role", 
               "accountId": "499955777666", 
               "userName": "jill" 
            } 
         } 
      },
      
      "eventTime": "2016-05-11T14:33:20Z", 
      "eventSource": "dynamodb.amazonaws.com", 
      "eventName": "DeleteTable", 
      "awsRegion": "us-west-2", 
      "sourceIPAddress": "192.0.2.0", 
      "userAgent": "console.aws.amazon.com", 
      "requestParameters": {"tableName": "Tools"}, 
      
      "responseElements": {"tableDescription": { 
         "tableName": "Tools", 
         "itemCount": 0, 
         
         "provisionedThroughput": { 
            "writeCapacityUnits": 25, 
            "numberOfDecreasesToday": 0, 
            "readCapacityUnits": 25 
         },
         "tableStatus": "DELETING", 
         "tableSizeBytes": 0
      }},
      "requestID": "4D89G7D98GF7G8A7DF78FG89AS7GFSO5AEMVJF66Q9ASUAAJG", 
      "eventID": "a954451c-c2fc-4561-8aea-7a30ba1fdf52", 
      "eventType": "AwsApiCall", 
      "apiVersion": "2013-04-22", 
      "recipientAccountId": "155522255533" 
   } 
]} 

DynamoDB - MapReduce

Amazon 的 Elastic MapReduce (EMR) 允許您快速有效地處理大資料。EMR 在 EC2 例項上執行 Apache Hadoop,但簡化了流程。您可以利用 Apache Hive 透過 HiveQL(一種類似於 SQL 的查詢語言)查詢 MapReduce 作業流。Apache Hive 作為最佳化查詢和應用程式的一種方式。

您可以使用管理控制檯的 EMR 選項卡、EMR CLI、API 或 SDK 來啟動作業流。您還可以選擇互動式執行 Hive 或使用指令碼。

EMR 的讀/寫操作會影響吞吐量的消耗,但是,在大型請求中,它會使用後退演算法的保護進行重試。此外,與其他操作和任務同時執行 EMR 可能會導致節流。

DynamoDB/EMR 整合不支援二進位制和二進位制集屬性。

DynamoDB/EMR 整合先決條件

在使用 EMR 之前,請檢視此必要專案清單 −

  • 一個 AWS 賬戶
  • 一個在 EMR 操作中使用的相同賬戶下的已填充表
  • 具有 DynamoDB 連線性的自定義 Hive 版本
  • DynamoDB 連線性支援
  • 一個 S3 儲存桶(可選)
  • 一個 SSH 客戶端(可選)
  • 一個 EC2 金鑰對(可選)

Hive 設定

在使用 EMR 之前,建立一個金鑰對以互動模式執行 Hive。金鑰對允許連線到作業流的 EC2 例項和主節點。

您可以按照以下步驟執行此操作 −

  • 登入管理控制檯,並開啟位於 https://console.aws.amazon.com/ec2/ 的 EC2 控制檯

  • 在控制檯的右上角選擇一個區域。確保該區域與 DynamoDB 區域匹配。

  • 在導航窗格中,選擇金鑰對

  • 選擇建立金鑰對

  • 金鑰對名稱欄位中,輸入名稱並選擇建立

  • 下載生成的私鑰檔案,該檔案使用以下格式:filename.pem。

注意 - 如果沒有金鑰對,則無法連線到 EC2 例項。

Hive 叢集

建立一個支援 Hive 的叢集來執行 Hive。它構建了 Hive 到 DynamoDB 連線所需的環境和基礎設施。

您可以透過以下步驟執行此任務:

  • 訪問 EMR 控制檯。

  • 選擇建立叢集

  • 在建立螢幕中,設定叢集配置,為叢集指定描述性名稱,為終止保護選擇,並選中日誌記錄的已啟用,為日誌資料夾 S3 位置選擇 S3 目標,併為除錯選擇已啟用

  • 在軟體配置螢幕中,確保欄位包含 Hadoop 發行版的Amazon,AMI 版本的最新版本,要安裝的應用程式 - Hive 的預設 Hive 版本,以及要安裝的應用程式 - Pig 的預設 Pig 版本。

  • 在硬體配置螢幕中,確保欄位包含網路的啟動到 EC2-Classic,EC2 可用區的無偏好,主節點 - Amazon EC2 例項型別的預設值,請求 Spot 例項的未選中狀態,核心節點 - Amazon EC2 例項型別的預設值,計數為2,請求 Spot 例項的未選中狀態,任務節點 - Amazon EC2 例項型別的預設值,計數為0,以及請求 Spot 例項的未選中狀態。

務必設定一個限制,提供足夠的容量來防止叢集故障。

  • 在安全和訪問螢幕中,確保欄位包含 EC2 金鑰對中的金鑰對,IAM 使用者訪問中的無其他 IAM 使用者,以及 IAM 角色中的無需角色繼續

  • 檢視引導操作螢幕,但不要修改它。

  • 檢視設定,完成後選擇建立叢集

叢集啟動時會顯示一個摘要窗格。

啟用 SSH 會話

您需要一個活動的 SSH 會話才能連線到主節點並執行 CLI 操作。透過在 EMR 控制檯中選擇叢集來查詢主節點。它將主節點列為主公有 DNS 名稱

如果您沒有 PuTTY,請安裝它。然後啟動 PuTTYgen 並選擇載入。選擇您的 PEM 檔案並開啟它。PuTTYgen 會通知您匯入成功。選擇儲存私鑰以儲存為 PuTTY 私鑰格式 (PPK),並選擇以在不使用密碼短語的情況下儲存。然後為 PuTTY 金鑰輸入一個名稱,點選儲存,然後關閉 PuTTYgen。

使用 PuTTY 透過首先啟動 PuTTY 來與主節點建立連線。從類別列表中選擇會話。在主機名欄位中輸入 hadoop@DNS。在類別列表中展開連線 > SSH,然後選擇身份驗證。在控制選項螢幕中,為身份驗證選擇瀏覽私鑰檔案。然後選擇您的私鑰檔案並開啟它。選擇以確認安全警報彈出視窗。

連線到主節點後,將出現 Hadoop 命令提示符,這意味著您可以開始互動式 Hive 會話。

Hive 表

Hive 充當資料倉庫工具,允許使用HiveQL在 EMR 叢集上執行查詢。之前的設定為您提供了一個可用的提示符。只需輸入“hive”,然後輸入您想要的任何命令即可互動式地執行 Hive 命令。有關Hive的更多資訊,請參閱我們的 Hive 教程。

DynamoDB - 表活動

DynamoDB 流使您能夠跟蹤和響應表項更改。利用此功能建立響應更改的應用程式,從而更新跨源的資訊。同步大型多使用者系統中數千使用者的的資料。使用它向用戶傳送更新通知。它的應用證明了多樣性和重要性。DynamoDB 流是實現此功能的主要工具。

流捕獲包含表中項修改的時間排序序列。它們最多儲存此資料 24 小時。應用程式使用它們來檢視原始項和修改後的項,幾乎是即時進行的。

為表啟用的流捕獲所有修改。對於任何 CRUD 操作,DynamoDB 都會建立一個流記錄,其中包含已修改項的主鍵屬性。您可以配置流以獲取其他資訊,例如前後影像。

流提供兩種保證:

  • 每個記錄在流中只出現一次,並且

  • 每個項修改都會導致流記錄的順序與修改的順序相同。

所有流都即時處理,以便您可以將它們用於應用程式中的相關功能。

管理流

在建立表時,您可以啟用流。現有表允許停用流或更改設定。流提供非同步操作功能,這意味著不會影響表效能。

利用 AWS 管理控制檯進行簡單的流管理。首先,導航到控制檯,然後選擇。在“概述”選項卡中,選擇管理流。在視窗中,選擇新增到表資料修改時流中的資訊。輸入所有設定後,選擇啟用

如果要停用任何現有流,請選擇管理流,然後選擇停用

您還可以利用 API CreateTable 和 UpdateTable 來啟用或更改流。使用引數 StreamSpecification 配置流。StreamEnabled 指定狀態,啟用為 true,停用為 false。

StreamViewType 指定新增到流中的資訊:KEYS_ONLY、NEW_IMAGE、OLD_IMAGE 和 NEW_AND_OLD_IMAGES。

流讀取

透過連線到端點併發出 API 請求來讀取和處理流。每個流都由流記錄組成,每個記錄都作為一個擁有流的單個修改存在。流記錄包含一個序列號,揭示釋出順序。記錄屬於稱為分片的組。分片充當多個記錄的容器,並且還儲存訪問和遍歷記錄所需的資訊。24 小時後,記錄會自動刪除。

這些分片根據需要生成和刪除,並且持續時間不長。它們還會自動劃分為多個新分片,通常是響應寫入活動峰值。在停用流時,開啟的分片會關閉。分片之間的層次關係意味著應用程式必須優先處理父分片以確保正確的處理順序。您可以使用 Kinesis 介面卡自動執行此操作。

注意 - 導致無更改的操作不會寫入流記錄。

訪問和處理記錄需要執行以下任務:

  • 確定目標流的 ARN。
  • 確定包含目標記錄的流的分片。
  • 訪問分片以檢索所需的記錄。

注意 - 最多應有兩個程序同時讀取一個分片。如果超過 2 個程序,則可能會限制源。

可用的流 API 操作包括

  • ListStreams
  • DescribeStream
  • GetShardIterator
  • GetRecords

您可以檢視以下流讀取示例:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsClient;

import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;

import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.DescribeStreamRequest;
import com.amazonaws.services.dynamodbv2.model.DescribeStreamResult;
import com.amazonaws.services.dynamodbv2.model.DescribeTableResult;

import com.amazonaws.services.dynamodbv2.model.GetRecordsRequest;
import com.amazonaws.services.dynamodbv2.model.GetRecordsResult;
import com.amazonaws.services.dynamodbv2.model.GetShardIteratorRequest;
import com.amazonaws.services.dynamodbv2.model.GetShardIteratorResult;

import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.Record;

import com.amazonaws.services.dynamodbv2.model.Shard;
import com.amazonaws.services.dynamodbv2.model.ShardIteratorType;
import com.amazonaws.services.dynamodbv2.model.StreamSpecification;
import com.amazonaws.services.dynamodbv2.model.StreamViewType;
import com.amazonaws.services.dynamodbv2.util.Tables;

public class StreamsExample {
   private static AmazonDynamoDBClient dynamoDBClient =  
      new AmazonDynamoDBClient(new ProfileCredentialsProvider());  
   private static AmazonDynamoDBStreamsClient streamsClient =  
      new AmazonDynamoDBStreamsClient(new ProfileCredentialsProvider());  

   public static void main(String args[]) {  
      dynamoDBClient.setEndpoint("InsertDbEndpointHere");   
      streamsClient.setEndpoint("InsertStreamEndpointHere");    
      
      // table creation 
      String tableName = "MyTestingTable";  
      ArrayList<AttributeDefinition> attributeDefinitions =  
         new ArrayList<AttributeDefinition>();  
      
      attributeDefinitions.add(new AttributeDefinition()
         .withAttributeName("ID") 
         .withAttributeType("N"));
         
      ArrayList<KeySchemaElement> keySchema = new 
         ArrayList<KeySchemaElement>(); 
      
      keySchema.add(new KeySchemaElement() 
         .withAttributeName("ID") 
         .withKeyType(KeyType.HASH));                       //Partition key

      StreamSpecification streamSpecification = new StreamSpecification(); 
      streamSpecification.setStreamEnabled(true); 
      streamSpecification.setStreamViewType(StreamViewType.NEW_AND_OLD_IMAGES);  
      CreateTableRequest createTableRequest = new CreateTableRequest() 
         .withTableName(tableName) 
         .withKeySchema(keySchema) 
         .withAttributeDefinitions(attributeDefinitions) 
         .withProvisionedThroughput(new ProvisionedThroughput() 
         .withReadCapacityUnits(1L) 
         .withWriteCapacityUnits(1L))
         .withStreamSpecification(streamSpecification);  
      
      System.out.println("Executing CreateTable for " + tableName); 
      dynamoDBClient.createTable(createTableRequest);  
      System.out.println("Creating " + tableName); 
      
      try { 
         Tables.awaitTableToBecomeActive(dynamoDBClient, tableName); 
      } catch (InterruptedException e) { 
         e.printStackTrace(); 
      } 
         
      // Get the table's stream settings 
      DescribeTableResult describeTableResult =
         dynamoDBClient.describeTable(tableName);  
      
      String myStreamArn = describeTableResult.getTable().getLatestStreamArn(); 
      StreamSpecification myStreamSpec =  
         describeTableResult.getTable().getStreamSpecification();  
      
      System.out.println("Current stream ARN for " + tableName + ": "+ myStreamArn);
      System.out.println("Stream enabled: "+ myStreamSpec.getStreamEnabled()); 
      System.out.println("Update view type: "+ myStreamSpec.getStreamViewType());  
      
      // Add an item 
      int numChanges = 0; 
      System.out.println("Making some changes to table data"); 
      Map<String, AttributeValue> item = new HashMap<String, AttributeValue>(); 
      item.put("ID", new AttributeValue().withN("222")); 
      item.put("Alert", new AttributeValue().withS("item!")); 
      dynamoDBClient.putItem(tableName, item); 
      numChanges++;  
      
      // Update the item         
      Map<String, AttributeValue> key = new HashMap<String, AttributeValue>(); 
      key.put("ID", new AttributeValue().withN("222")); 
      Map<String, AttributeValueUpdate> attributeUpdates =  
      new HashMap<String, AttributeValueUpdate>(); 
      
      attributeUpdates.put("Alert", new AttributeValueUpdate() 
         .withAction(AttributeAction.PUT) 
         .withValue(new AttributeValue().withS("modified item"))); 
      
      dynamoDBClient.updateItem(tableName, key, attributeUpdates); 
      numChanges++;   
      
      // Delete the item         
      dynamoDBClient.deleteItem(tableName, key);  
      numChanges++;
      
      // Get stream shards         
      DescribeStreamResult describeStreamResult =  
      streamsClient.describeStream(new DescribeStreamRequest() 
         .withStreamArn(myStreamArn)); 
      String streamArn =  
         describeStreamResult.getStreamDescription().getStreamArn(); 
      List<Shard> shards =  
         describeStreamResult.getStreamDescription().getShards();  
      
      // Process shards 
      for (Shard shard : shards) { 
         String shardId = shard.getShardId(); 
         System.out.println("Processing " + shardId + " in "+ streamArn);  
         
         // Get shard iterator 
         GetShardIteratorRequest getShardIteratorRequest = new 
            GetShardIteratorRequest() 
            .withStreamArn(myStreamArn) 
            .withShardId(shardId) 
            .withShardIteratorType(ShardIteratorType.TRIM_HORIZON); 
         
         GetShardIteratorResult getShardIteratorResult =  
            streamsClient.getShardIterator(getShardIteratorRequest); 
         String nextItr = getShardIteratorResult.getShardIterator();  
         
         while (nextItr != null && numChanges > 0) { 
            // Read data records with iterator                 
            GetRecordsResult getRecordsResult =  
               streamsClient.getRecords(new GetRecordsRequest(). 
               withShardIterator(nextItr));
               
            List<Record> records = getRecordsResult.getRecords(); 
            System.out.println("Pulling records...");  
               
            for (Record record : records) { 
               System.out.println(record); 
               numChanges--;
            } 
            nextItr = getRecordsResult.getNextShardIterator(); 
         } 
      } 
   } 
}

DynamoDB - 錯誤處理

如果請求處理失敗,DynamoDB 會丟擲一個錯誤。每個錯誤都包含以下元件:HTTP 狀態程式碼、異常名稱和訊息。錯誤管理取決於您的 SDK(它會傳播錯誤)或您自己的程式碼。

程式碼和訊息

異常屬於不同的 HTTP 標頭狀態程式碼。4xx 和 5xx 包含與請求問題和 AWS 相關的錯誤。

HTTP 4xx 類別中的一些異常如下:

  • AccessDeniedException - 客戶端未能正確簽名請求。

  • ConditionalCheckFailedException - 條件評估為 false。

  • IncompleteSignatureException - 請求包含不完整的簽名。

HTTP 5xx 類別中的異常如下:

  • 內部伺服器錯誤
  • 服務不可用

重試和回退演算法

錯誤來自各種來源,例如伺服器、交換機、負載均衡器以及其他結構和系統元件。常見的解決方案包括簡單的重試,它支援可靠性。所有 SDK 都自動包含此邏輯,您可以設定重試引數以滿足您的應用程式需求。

例如 - Java 提供了一個 maxErrorRetry 值來停止重試。

除了重試之外,Amazon 建議使用回退解決方案來控制流量。這包括逐步增加重試之間的等待時間,並在相當短的時間後最終停止。請注意,SDK 會執行自動重試,但不會執行指數回退。

以下程式是重試回退的示例:

public enum Results { 
   SUCCESS,  
   NOT_READY,  
   THROTTLED,  
   SERVER_ERROR 
}
public static void DoAndWaitExample() {  
   try {
      // asynchronous operation. 
      long token = asyncOperation();  
      int retries = 0; 
      boolean retry = false;  
      
      do { 
         long waitTime = Math.min(getWaitTime(retries), MAX_WAIT_INTERVAL);  
         System.out.print(waitTime + "\n");  
         
         // Pause for result 
         Thread.sleep(waitTime);  
         
         // Get result 
         Results result = getAsyncOperationResult(token);  
         
         if (Results.SUCCESS == result) { 
            retry = false; 
         } else if (Results.NOT_READY == result) { 
            retry = true; 
         } else if (Results.THROTTLED == result) { 
            retry = true; 
         } else if (Results.SERVER_ERROR == result) { 
            retry = true; 
         } else { 
            
            // stop on other error 
            retry = false; 
         }  
      } while (retry && (retries++ < MAX_RETRIES)); 
   }
   catch (Exception ex) { 
   } 
}
public static long getWaitTime(int retryCount) {  
   long waitTime = ((long) Math.pow(3, retryCount) * 100L);  
   return waitTime; 
}

DynamoDB - 最佳實踐

在處理各種來源和元素時,某些實踐可以最佳化程式碼、防止錯誤並最大程度地降低吞吐量成本。

以下是 DynamoDB 中一些最重要且最常用的最佳實踐。

表的分佈意味著最佳方法是將讀/寫活動均勻地分佈到所有表項中。

針對表項實現統一的資料訪問。最佳吞吐量使用取決於主鍵選擇和項工作負載模式。將工作負載均勻地分佈到分割槽鍵值中。避免少量高使用量的分割槽鍵值之類的情況。選擇更好的選擇,例如大量不同的分割槽鍵值。

瞭解分割槽行為。估計 DynamoDB 自動分配的分割槽。

DynamoDB 提供突發吞吐量使用,它會為“突發”功率保留未使用的吞吐量。避免大量使用此選項,因為突發會快速消耗大量吞吐量;此外,它並非可靠的資源。

在上傳時,分佈資料以獲得更好的效能。透過同時上傳到所有分配的伺服器來實現此目的。

快取常用項以將讀取活動從資料庫轉移到快取。

節流、效能、大小和訪問成本仍然是項方面最大的問題。選擇一對多表。刪除屬性並劃分表以匹配訪問模式。透過這種簡單的方法,您可以顯著提高效率。

在儲存大型值之前對其進行壓縮。利用標準壓縮工具。對大型屬性值(如 S3)使用備用儲存。您可以在 S3 中儲存物件,並在項中儲存識別符號。

透過虛擬項片段將大型屬性分佈到多個項中。這為項大小的限制提供瞭解決方案。

查詢和掃描

查詢和掃描主要面臨吞吐量消耗挑戰。避免突發,突發通常是由切換到強一致性讀取之類的情況引起的。以低資源的方式使用並行掃描(即沒有節流的後臺函式)。此外,僅在大型表中使用它們,並且在您未充分利用吞吐量或掃描操作效能較差的情況下使用它們。

本地二級索引

索引在吞吐量和儲存成本以及查詢效率方面存在問題。除非您經常查詢屬性,否則避免建立索引。在投影中謹慎選擇,因為它們會使索引膨脹。僅選擇那些大量使用的索引。

利用稀疏索引,這意味著排序鍵不會出現在所有表項中的索引。它們有利於查詢大多數表項中不存在的屬性。

注意項集合(所有表項及其索引)的擴充套件。新增/更新操作會導致表和索引都增長,集合限制為 10GB。

全域性二級索引

索引在吞吐量、儲存成本和查詢效率方面存在問題。建議選擇鍵屬性雜湊,類似於表中的讀/寫雜湊,提供工作負載均勻性。選擇能夠均勻雜湊資料的屬性。此外,利用稀疏索引。

利用全域性二級索引來快速搜尋查詢中請求少量資料的場景。

廣告