

# 处理全局二级索引：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 文档 API 创建具有全局二级索引的表的步骤。

1. 创建 `DynamoDB` 类的实例。

1. 创建 `CreateTableRequest` 类实例，以提供请求信息。

   您必须提供表名称、主键以及预配置吞吐量值。对于全局二级索引，您必须提供索引名称、其预置吞吐量设置、索引排序键的属性定义、索引的键架构以及属性投影。

1. 以参数形式提供请求对象，以调用 `createTable` 方法。

以下 Java 代码示例演示了上述步骤。创建具有全局二级索引 (`PrecipIndex`) 的表 (`WeatherData`)。索引分区键为 `Date`，排序键为 `Precipitation`。所有表属性都投影到索引中。用户可以查询此索引以获取特定日期的天气数据，也可以选择按降水量对数据进行排序。

由于 `Precipitation` 不是表的键属性，它不是必需的。然而,`WeatherData` 项目不包含 `Precipitation`，不会显示在 `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. 调用 `describe` 对象上的 `Table` 方法。

以下 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. 调用 `query` 对象上的 `Index` 方法。

属性名称 `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());
}
```