

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

# 使用本機次要索引：Java
<a name="LSIJavaDocumentAPI"></a>

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

以下是使用 適用於 Java 的 AWS SDK 文件 API 進行資料表操作的常見步驟。

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

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

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

**Topics**
+ [使用本機次要索引建立資料表](#LSIJavaDocumentAPI.CreateTableWithIndex)
+ [使用本機次要索引描述資料表](#LSIJavaDocumentAPI.DescribeTableWithIndex)
+ [查詢本機次要索引](#LSIJavaDocumentAPI.QueryAnIndex)
+ [範例：使用 Java Document API 的本機次要索引](LSIJavaDocumentAPI.Example.md)

## 使用本機次要索引建立資料表
<a name="LSIJavaDocumentAPI.CreateTableWithIndex"></a>

您必須同時建立資料表和本機次要索引。若要執行這項操作，請使用 `createTable` 方法，並提供一或多個本機次要索引的規格。以下 Java 程式碼範例會建立資料表來保存音樂收藏中歌曲的相關資訊。分割區索引鍵為 `Artist`，而排序索引鍵為 `SongTitle`。次要索引 `AlbumTitleIndex` 有助於依照專輯標題查詢。

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

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

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

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

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

下列 Java 程式碼範例示範上述步驟。程式碼會建立一個資料表 (`Music`) 與次要索引 `AlbumTitle` 屬性。資料表分割區索引鍵和排序索引鍵以及索引排序索引鍵，是唯一投影到索引的屬性。

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

String tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName);

//ProvisionedThroughput
createTableRequest.setProvisionedThroughput(new ProvisionedThroughput().withReadCapacityUnits((long)5).withWriteCapacityUnits((long)5));

//AttributeDefinitions
ArrayList<AttributeDefinition> attributeDefinitions= new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition().withAttributeName("Artist").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("SongTitle").withAttributeType("S"));
attributeDefinitions.add(new AttributeDefinition().withAttributeName("AlbumTitle").withAttributeType("S"));

createTableRequest.setAttributeDefinitions(attributeDefinitions);

//KeySchema
ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
tableKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
tableKeySchema.add(new KeySchemaElement().withAttributeName("SongTitle").withKeyType(KeyType.RANGE));  //Sort key

createTableRequest.setKeySchema(tableKeySchema);

ArrayList<KeySchemaElement> indexKeySchema = new ArrayList<KeySchemaElement>();
indexKeySchema.add(new KeySchemaElement().withAttributeName("Artist").withKeyType(KeyType.HASH));  //Partition key
indexKeySchema.add(new KeySchemaElement().withAttributeName("AlbumTitle").withKeyType(KeyType.RANGE));  //Sort key

Projection projection = new Projection().withProjectionType(ProjectionType.INCLUDE);
ArrayList<String> nonKeyAttributes = new ArrayList<String>();
nonKeyAttributes.add("Genre");
nonKeyAttributes.add("Year");
projection.setNonKeyAttributes(nonKeyAttributes);

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
    .withIndexName("AlbumTitleIndex").withKeySchema(indexKeySchema).withProjection(projection);

ArrayList<LocalSecondaryIndex> localSecondaryIndexes = new ArrayList<LocalSecondaryIndex>();
localSecondaryIndexes.add(localSecondaryIndex);
createTableRequest.setLocalSecondaryIndexes(localSecondaryIndexes);

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

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

## 使用本機次要索引描述資料表
<a name="LSIJavaDocumentAPI.DescribeTableWithIndex"></a>

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

以下是使用 適用於 Java 的 AWS SDK Document API 存取資料表的本機次要索引資訊的步驟。

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

1. 建立 `Table` 類別的執行個體。您必須提供資料表名稱。

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

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

**Example**  

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

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);

TableDescription tableDescription = table.describe();

List<LocalSecondaryIndexDescription> localSecondaryIndexes 
    = tableDescription.getLocalSecondaryIndexes();

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.

Iterator<LocalSecondaryIndexDescription> lsiIter = localSecondaryIndexes.iterator();
while (lsiIter.hasNext()) {

    LocalSecondaryIndexDescription lsiDescription = lsiIter.next();
    System.out.println("Info for index " + 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("\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="LSIJavaDocumentAPI.QueryAnIndex"></a>

您可以依照與 `Query` 資料表大致相同的方式在本機次要索引上使用 `Query` 操作。您必須指定索引名稱、索引排序索引鍵的查詢準則，以及您要傳回的屬性。在本例中，索引是 `AlbumTitleIndex`，而索引排序索引鍵為 `AlbumTitle`。

傳回的唯一屬性是已投影到索引的屬性。您也可以修改此查詢來選擇非索引鍵屬性，但這需要相對昂貴的資料表擷取活動。如需資料表擷取的詳細資訊，請參閱 [屬性投影](LSI.md#LSI.Projections)。

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

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

1. 建立 `Table` 類別的執行個體。您必須提供資料表名稱。

1. 建立 `Index` 類別的執行個體。您必須提供索引名稱。

1. 呼叫 `Index` 類別的 `query` 方法。

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

**Example**  

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

String tableName = "Music";

Table table = dynamoDB.getTable(tableName);
Index index = table.getIndex("AlbumTitleIndex");

QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"));

ItemCollection<QueryOutcome> items = index.query(spec);

Iterator<Item> itemsIter = items.iterator();

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

### 本機次要索引上的一致讀取
<a name="LSIJavaDocumentAPI.ConsistentReads"></a>

與僅支援最終一致讀取的全域次要索引不同，本機次要索引支援最終一致和強烈一致讀取。來自本機次要索引的高度一致性讀取一律會傳回最新的更新值。如果查詢需要從基礎資料表擷取其他屬性，則這些擷取的屬性也與索引一致。

根據預設， `Query`會使用最終一致讀取。若要請求強式一致讀取，請在 `true`中將 `ConsistentRead`設定為 `QuerySpec`。下列範例查詢`AlbumTitleIndex`使用強式一致讀取：

**Example**  

```
QuerySpec spec = new QuerySpec()
    .withKeyConditionExpression("Artist = :v_artist and AlbumTitle = :v_title")
    .withValueMap(new ValueMap()
        .withString(":v_artist", "Acme Band")
        .withString(":v_title", "Songs About Life"))
    .withConsistentRead(true);
```

**注意**  
強式一致讀取每傳回 4 KB 的資料會耗用一個讀取容量單位 （四捨五入），而最終一致讀取則會耗用一半。例如，傳回 9 KB 資料的強式一致讀取耗用 3 個讀取容量單位 (9 KB/4 KB = 2.25，四捨五入至 3)，而使用最終一致讀取的相同查詢耗用 1.5 個讀取容量單位。如果您的應用程式可以容忍讀取可能稍微過時的資料，請使用最終一致讀取來減少讀取容量用量。如需詳細資訊，請參閱[讀取容量單位](LSI.md#LSI.ThroughputConsiderations.Reads)。