

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

# 使用全域次要索引：Java
<a name="GSIJavaDocumentAPI"></a>

您可以使用 適用於 Java 的 AWS SDK 文件 API 建立具有一或多個全域次要索引的 Amazon DynamoDB 資料表、描述資料表上的索引，並使用索引執行查詢。

下列是資料表操作的常用步驟。

1. 建立 `DynamoDB` 類別的執行個體。

1. 透過建立對應的請求物件，為操作提供必要及選用的參數。

1. 呼叫您在前一步驟中建立之用戶端所提供的適當方法。

**Topics**
+ [建立具有全域次要索引的資料表](#GSIJavaDocumentAPI.CreateTableWithIndex)
+ [使用全域次要索引描述資料表](#GSIJavaDocumentAPI.DescribeTableWithIndex)
+ [查詢全域次要索引](#GSIJavaDocumentAPI.QueryAnIndex)
+ [範例：使用 適用於 Java 的 AWS SDK 文件 API 的全域次要索引](GSIJavaDocumentAPI.Example.md)

## 建立具有全域次要索引的資料表
<a name="GSIJavaDocumentAPI.CreateTableWithIndex"></a>

您可在建立資料表的同時建立全域次要索引。若要執行這項操作，請使用 `CreateTable`，並提供一或多個全域次要索引的規格。以下 Java 程式碼範例會建立資料表來保存天氣資料的相關資訊。分割區索引鍵為 `Location`，而排序索引鍵為 `Date`。名為 `PrecipIndex` 的全域次要索引允許快速存取各個地點的降水資料。

以下是使用 DynamoDB Document API 建立具有全域次要索引的資料表的步驟。

1. 建立 `DynamoDB` 類別的執行個體。

1. 建立 `CreateTableRequest` 類別的執行個體，以提供請求資訊。

   您必須提供資料表名稱、其主索引鍵，以及佈建的輸送量數值。對於全域次要索引，您必須提供索引名稱、其佈建的輸送量設定值、索引排序索引鍵的屬性定義、索引的索引鍵結構描述以及屬性投影。

1. 以參數形式提供請求物件，以便呼叫 `createTable` 方法。

下列 Java 程式碼範例示範上述步驟。程式碼會建立具有全域次要索引 (`PrecipIndex`) 的資料表 (`WeatherData`)。索引分割區索引鍵是 `Date`，而其排序索引鍵是 `Precipitation`。所有的資料表屬性都會投影到索引。使用者可以查詢此索引以取得特定日期的天氣資料，可選擇依降水量排序資料。

因為 `Precipitation` 不是資料表的索引鍵屬性，所以其並非必要項目。不過，沒有 `Precipitation` 的 `WeatherData` 項目不會在 `PrecipIndex` 中顯示。

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

// Attribute definitions
ArrayList<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();

attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Location")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Date")
    .withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition()
    .withAttributeName("Precipitation")
    .withAttributeType("N"));

// Table key schema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Location")
    .withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement()
    .withAttributeName("Date")
    .withKeyType(KeyType.RANGE));  //Sort key

// PrecipIndex
GlobalSecondaryIndex precipIndex = new GlobalSecondaryIndex()
    .withIndexName("PrecipIndex")
    .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("Precipitation")
    .withKeyType(KeyType.RANGE));  //Sort key

precipIndex.setKeySchema(indexKeySchema);

CreateTableRequest createTableRequest = new CreateTableRequest()
    .withTableName("WeatherData")
    .withProvisionedThroughput(new ProvisionedThroughput()
        .withReadCapacityUnits((long) 5)
        .withWriteCapacityUnits((long) 1))
    .withAttributeDefinitions(attributeDefinitions)
    .withKeySchema(tableKeySchema)
    .withGlobalSecondaryIndexes(precipIndex);

Table table = dynamoDB.createTable(createTableRequest);
System.out.println(table.getDescription());
```

您必須等到 DynamoDB 建立資料表，並將資料表狀態設定為 `ACTIVE`。之後，您可以開始將資料項目放入資料表中。

## 使用全域次要索引描述資料表
<a name="GSIJavaDocumentAPI.DescribeTableWithIndex"></a>

若要取得資料表上全域次要索引的資訊，請使用 `DescribeTable`。對於每個索引，您可以存取其名稱、索引鍵結構描述和投影屬性。

以下是存取資料表的全域次要索引資訊的步驟。

1. 建立 `DynamoDB` 類別的執行個體。

1. 建立 `Table` 類別的執行個體，代表您要進行作業的索引。

1. 在 `Table` 物件上呼叫 `describe` 方法。

下列 Java 程式碼範例示範上述步驟。

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
TableDescription tableDesc = table.describe();
    

Iterator<GlobalSecondaryIndexDescription> gsiIter = tableDesc.getGlobalSecondaryIndexes().iterator();
while (gsiIter.hasNext()) {
    GlobalSecondaryIndexDescription gsiDesc = gsiIter.next();
    System.out.println("Info for index "
         + gsiDesc.getIndexName() + ":");

    Iterator<KeySchemaElement> kseIter = 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("\tThe projection type is: "
        + projection.getProjectionType());
    if (projection.getProjectionType().toString().equals("INCLUDE")) {
        System.out.println("\t\tThe non-key projected attributes are: "
            + projection.getNonKeyAttributes());
    }
}
```

## 查詢全域次要索引
<a name="GSIJavaDocumentAPI.QueryAnIndex"></a>

您可以在全域次要索引上使用 `Query`，與 `Query` 資料表的方式相同。您需要指定索引名稱、索引分割區索引鍵和排序索引鍵的查詢條件 (如存在)，以及要傳回的屬性。在本例中，索引為 `PrecipIndex`，其分割區索引鍵為 `Date`，排序索引鍵為 `Precipitation`。索引查詢會傳回特定日期的所有天氣資料，其中降水量大於零。

以下是使用 適用於 Java 的 AWS SDK 文件 API 查詢全域次要索引的步驟。

1. 建立 `DynamoDB` 類別的執行個體。

1. 建立 `Table` 類別的執行個體，代表您要進行作業的索引。

1. 針對您想要查詢的索引建立 `Index` 類別的執行個體。

1. 在 `Index` 物件上呼叫 `query` 方法。

屬性名稱 `Date` 是 DynamoDB 保留字。因此，您必須使用表達式屬性名稱作為 `KeyConditionExpression` 中的預留位置。

下列 Java 程式碼範例示範上述步驟。

**Example**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);

Table table = dynamoDB.getTable("WeatherData");
Index index = table.getIndex("PrecipIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("#d = :v_date and Precipitation = :v_precip")
    .withNameMap(new NameMap()
        .with("#d", "Date"))
    .withValueMap(new ValueMap()
        .withString(":v_date","2013-08-10")
        .withNumber(":v_precip",0));

ItemCollection<QueryOutcome> items = index.query(spec);
Iterator<Item> iter = items.iterator(); 
while (iter.hasNext()) {
    System.out.println(iter.next().toJSONPretty());
}
```