

# Como trabalhar com índices secundários globais: Java
<a name="GSIJavaDocumentAPI"></a>

Você pode usar a API de documentos do AWS SDK para Java para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários globais na tabela e executar consultas usando os índices. 

Veja a seguir as etapas comuns para as operações de tabela. 

1. Crie uma instância da classe `DynamoDB`.

1. Forneça os parâmetros obrigatórios e opcionais para a operação, criando os objetos de solicitação correspondentes. 

1. Chame o método apropriado fornecido pelo cliente que você criou na etapa anterior. 

**Topics**
+ [Criar uma tabela com um índice secundário global](#GSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário global](#GSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Consultar um índice secundário global](#GSIJavaDocumentAPI.QueryAnIndex)
+ [Exemplo: índices secundários globais que usam a API de documento do AWS SDK para Java](GSIJavaDocumentAPI.Example.md)

## Criar uma tabela com um índice secundário global
<a name="GSIJavaDocumentAPI.CreateTableWithIndex"></a>

Você pode criar índices secundários globais ao mesmo tempo em que cria uma tabela. Para fazer isso, use `CreateTable` e forneça suas especificações para um ou mais índices secundários globais. O exemplo de código Java a seguir cria uma tabela para armazenar informações sobre dados climáticos. A chave de partição é `Location` e a chave de classificação é `Date`. Um índice secundário global chamado `PrecipIndex` permite acesso rápido aos dados de precipitação de vários locais.

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário global usando a API de documentos do DynamoDB. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `CreateTableRequest` para fornecer as informações solicitadas.

   Você deve fornecer o nome da tabela, sua chave primária e os valores de throughput provisionado. Para o índice secundário global, você deve fornecer o nome do índice, suas configurações de throughput provisionado, as definições de atributo da chave de classificação do índice, o esquema de chaves do índice e a projeção do atributo.

1. Chame o método `createTable`, fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código Java a seguir demonstra as etapas anteriores. O código cria uma tabela (`WeatherData`) com um índice secundário global (`PrecipIndex`). A chave de partição do índice é `Date` e a chave de classificação é `Precipitation`. Todos os atributos da tabela estão projetados no índice. Os usuários podem consultar esse índice para obter dados climáticos de uma data específica, opcionalmente, classificar os dados por quantidade de precipitação. 

Como `Precipitation` não é um atributo de chave para a tabela, ele não é necessário. No entanto, os itens de `WeatherData` sem `Precipitation` não aparecem no `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());
```

Você deve aguardar até que o DynamoDB crie a tabela e defina o status dessa tabela como `ACTIVE`. Depois disso, você poderá começar a inserir itens de dados na tabela.

## Descrever uma tabela com um índice secundário global
<a name="GSIJavaDocumentAPI.DescribeTableWithIndex"></a>

Para obter mais informações sobre índices secundários globais em uma tabela, use `DescribeTable`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

Veja a seguir as etapas necessárias para acessar informações de índice secundário global em uma tabela. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar o índice com o qual você deseja trabalhar.

1. Chame o método `describe` no objeto `Table`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
    }
}
```

## Consultar um índice secundário global
<a name="GSIJavaDocumentAPI.QueryAnIndex"></a>

Você pode usar `Query` em um índice secundário global de forma semelhante ao uso de `Query` em uma tabela. Você precisa especificar o nome do índice, os critérios de consulta da chave de partição e da chave de classificação (se houver) do índice, e os atributos que você deseja retornar. Neste exemplo, o índice é `PrecipIndex`, que tem uma chave de partição `Date` e uma chave de classificação `Precipitation`. A consulta de índice retorna todos os dados climáticos de uma data específica, na qual a precipitação é maior que zero.

Veja a seguir as etapas necessárias para consultar um índice secundário global usando a API de documentos do AWS SDK para Java. 

1. Crie uma instância da classe `DynamoDB`.

1. Crie uma instância da classe `Table` para representar o índice com o qual você deseja trabalhar.

1. Crie uma instância da classe `Index` para o índice que deseja consultar.

1. Chame o método `query` no objeto `Index`.

O nome do atributo `Date` é uma palavra reservada do DynamoDB. Portanto, use um nome de atributo de expressão como um espaço reservado na `KeyConditionExpression`.

O exemplo de código Java a seguir demonstra as etapas anteriores.

**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());
}
```

# Exemplo: índices secundários globais que usam a API de documento do AWS SDK para Java
<a name="GSIJavaDocumentAPI.Example"></a>

O código Java de exemplo a seguir mostra como trabalhar com índices secundários globais. O exemplo cria uma tabela chamada `Issues`, que pode ser usada em um sistema de controle de bugs simples para desenvolvimento de software. A chave de partição é `IssueId` e a chave de classificação é `Title`. Há três índices secundários globais nessa tabela:
+ `CreateDateIndex`: a chave de partição é `CreateDate` e a chave de classificação é `IssueId`. Além das chaves da tabela, os atributos `Description` e `Status` são projetados no índice.
+ `TitleIndex`: a chave de partição é `Title` e a chave de classificação é `IssueId`. Nenhum outro atributo além das chaves da tabela são projetos no índice.
+ `DueDateIndex`: a chave de partição é `DueDate` e não há chave de classificação. Todos os atributos da tabela estão projetados no índice.

Depois que a tabela `Issues` é criada, o programa carrega a tabela com os dados que representam relatórios de bugs do software. Ele consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `Issues`.

Para obter instruções passo a passo sobre como testar o exemplo a seguir, consulte [Exemplos de código Java](CodeSamples.Java.md).

**Example**  

```
package com.amazonaws.codesamples.document;

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

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
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 DocumentAPIGlobalSecondaryIndexExample {

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

    public static String tableName = "Issues";

    public static void main(String[] args) throws Exception {

        createTable();
        loadData();

        queryIndex("CreateDateIndex");
        queryIndex("TitleIndex");
        queryIndex("DueDateIndex");

        deleteTable(tableName);

    }

    public static void createTable() {

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

        attributeDefinitions.add(new AttributeDefinition().withAttributeName("IssueId").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("Title").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("CreateDate").withAttributeType("S"));
        attributeDefinitions.add(new AttributeDefinition().withAttributeName("DueDate").withAttributeType("S"));

        // Key schema for table
        ArrayList<KeySchemaElement> tableKeySchema = new ArrayList<KeySchemaElement>();
        tableKeySchema.add(new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.HASH)); // Partition
                                                                                                           // key
        tableKeySchema.add(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.RANGE)); // Sort
                                                                                                          // key

        // Initial provisioned throughput settings for the indexes
        ProvisionedThroughput ptIndex = new ProvisionedThroughput().withReadCapacityUnits(1L)
                .withWriteCapacityUnits(1L);

        // CreateDateIndex
        GlobalSecondaryIndex createDateIndex = new GlobalSecondaryIndex().withIndexName("CreateDateIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("CreateDate").withKeyType(KeyType.HASH), // Partition
                                                                                                                 // key
                        new KeySchemaElement().withAttributeName("IssueId").withKeyType(KeyType.RANGE)) // Sort
                                                                                                        // key
                .withProjection(
                        new Projection().withProjectionType("INCLUDE").withNonKeyAttributes("Description", "Status"));

        // TitleIndex
        GlobalSecondaryIndex titleIndex = new GlobalSecondaryIndex().withIndexName("TitleIndex")
                .withProvisionedThroughput(ptIndex)
                .withKeySchema(new KeySchemaElement().withAttributeName("Title").withKeyType(KeyType.HASH), // Partition
                                                                                                            // key
                        new KeySchemaElement().withAttributeName("IssueId").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(createDateIndex, titleIndex, dueDateIndex);

        System.out.println("Creating table " + tableName + "...");
        dynamoDB.createTable(createTableRequest);

        // Wait for table to become active
        System.out.println("Waiting for " + tableName + " to become ACTIVE...");
        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 == "CreateDateIndex") {
            System.out.println("Issues filed on 2013-11-01");
            querySpec.withKeyConditionExpression("CreateDate = :v_date and begins_with(IssueId, :v_issue)")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-01").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "TitleIndex") {
            System.out.println("Compilation errors");
            querySpec.withKeyConditionExpression("Title = :v_title and begins_with(IssueId, :v_issue)")
                    .withValueMap(
                            new ValueMap().withString(":v_title", "Compilation error").withString(":v_issue", "A-"));
            items = index.query(querySpec);
        } else if (indexName == "DueDateIndex") {
            System.out.println("Items that are due on 2013-11-30");
            querySpec.withKeyConditionExpression("DueDate = :v_date")
                    .withValueMap(new ValueMap().withString(":v_date", "2013-11-30"));
            items = index.query(querySpec);
        } else {
            System.out.println("\nNo valid index name provided");
            return;
        }

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

        System.out.println("Query: printing results...");

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

    }

    public static void deleteTable(String tableName) {

        System.out.println("Deleting table " + tableName + "...");

        Table table = dynamoDB.getTable(tableName);
        table.delete();

        // Wait for table to be deleted
        System.out.println("Waiting for " + tableName + " to be deleted...");
        try {
            table.waitForDelete();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void loadData() {

        System.out.println("Loading data into table " + tableName + "...");

        // IssueId, Title,
        // Description,
        // CreateDate, LastUpdateDate, DueDate,
        // Priority, Status

        putItem("A-101", "Compilation error", "Can't compile Project X - bad version number. What does this mean?",
                "2013-11-01", "2013-11-02", "2013-11-10", 1, "Assigned");

        putItem("A-102", "Can't read data file", "The main data file is missing, or the permissions are incorrect",
                "2013-11-01", "2013-11-04", "2013-11-30", 2, "In progress");

        putItem("A-103", "Test failure", "Functional test of Project X produces errors", "2013-11-01", "2013-11-02",
                "2013-11-10", 1, "In progress");

        putItem("A-104", "Compilation error", "Variable 'messageCount' was not initialized.", "2013-11-15",
                "2013-11-16", "2013-11-30", 3, "Assigned");

        putItem("A-105", "Network issue", "Can't ping IP address 127.0.0.1. Please fix this.", "2013-11-15",
                "2013-11-16", "2013-11-19", 5, "Assigned");

    }

    public static void putItem(

            String issueId, String title, String description, String createDate, String lastUpdateDate, String dueDate,
            Integer priority, String status) {

        Table table = dynamoDB.getTable(tableName);

        Item item = new Item().withPrimaryKey("IssueId", issueId).withString("Title", title)
                .withString("Description", description).withString("CreateDate", createDate)
                .withString("LastUpdateDate", lastUpdateDate).withString("DueDate", dueDate)
                .withNumber("Priority", priority).withString("Status", status);

        table.putItem(item);
    }

}
```