

# Índices secundários locais
<a name="LSI"></a>

Alguns aplicativos só precisam consultar dados usando a chave primária da tabela base. No entanto, podem haver situações em que uma chave de classificação alternativa seria útil. Para oferecer à sua aplicação opções de chaves de classificação, você pode criar um ou mais índices secundários locais em uma tabela do Amazon DynamoDB e emitir solicitações de `Query` ou `Scan` nesses índices.

**Topics**
+ [Cenário: Uso de um índice secundário local](#LSI.Scenario)
+ [Projeções de atributo](#LSI.Projections)
+ [Criação de um índice secundário local](#LSI.Creating)
+ [Ler dados de um índice secundário local](#LSI.Reading)
+ [Gravações de itens e índices secundários locais](#LSI.Writes)
+ [Considerações sobre throughput provisionado para índices secundários locais](#LSI.ThroughputConsiderations)
+ [Considerações sobre armazenamento para índices secundários locais](#LSI.StorageConsiderations)
+ [Conjuntos de itens em índices secundários locais](#LSI.ItemCollections)
+ [Como trabalhar com índices secundários locais: Java](LSIJavaDocumentAPI.md)
+ [Como trabalhar com índices secundários locais: .NET](LSILowLevelDotNet.md)
+ [Trabalhar com índices secundários locais no DynamoDB usando a AWS CLI](LCICli.md)

## Cenário: Uso de um índice secundário local
<a name="LSI.Scenario"></a>

Como exemplo, considere a tabela `Thread`. Esta tabela é útil para aplicações como os [Fóruns de discussão da AWS](https://forums.aws.amazon.com/). O diagrama a seguir mostra como os itens da tabela seriam organizados. (Nem todos os atributos são mostrados.)

![\[A tabela Thread que contém uma lista de nomes, assuntos, hora da última publicação e o número de repostas do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_01.png)


O DynamoDB armazena continuamente todos os itens com o mesmo valor de chave de partição. Neste exemplo, dado um determinado `ForumName`, uma operação `Query` poderia localizar imediatamente todos os threads desse fórum. Em um grupo de itens com o mesmo valor de chave de partição, os itens são classificados pelo valor de chave de classificação. Se a chave de classificação (`Subject`) também for fornecida na consulta, o DynamoDB poderá reduzir os resultados que são retornados. Por exemplo, retornar todos os threads do fórum "S3" em que `Subject` começa com a letra "a".

Algumas solicitações podem exigir padrões mais complexos de acesso aos dados. Por exemplo:
+ Quais threads do fórum recebem visualizações e respostas?
+ Qual thread em um determinado fórum tem o maior número de mensagens?
+ Quantos threads foram publicados em um fórum específico em um determinado período?

A ação `Query` não seria suficiente para responder a essas perguntas. Em vez disso, você teria de `Scan` toda a tabela. Para uma tabela com milhões de itens, isso poderia consumir uma grande quantidade de throughput provisionado de leitura e levar muito tempo para ser concluído.

No entanto, é possível especificar um ou mais índices secundários em atributos que não são chaves, como `Replies` ou `LastPostDateTime`.

Um *índice secundário local* mantém uma chave de classificação alternativa para um determinado valor de chave de partição. Um índice secundário local também contém uma cópia de alguns ou de todos os atributos de sua tabela-base. Você especifica quais atributos são projetados no índice secundário local ao criar a tabela. Os dados em um índice secundário local são organizados com a mesma chave de partição que a tabela-base, mas com outra chave de classificação. Isso permite que você acesse os itens de dados de forma eficiente nessa dimensão diferente. Para uma maior flexibilidade de consulta ou verificação, você pode criar até cinco índices secundários locais por tabela. 

Suponha que um aplicativo precise encontrar todos os threads que foram publicados nos últimos três meses em um fórum específico. Sem um índice secundário local, a aplicação precisaria realizar `Scan` de toda a tabela `Thread` e descartar todas as publicações que não estivessem dentro do período especificado. Com um índice secundário local, uma operação de `Query` poderia usar `LastPostDateTime` como uma chave de classificação e encontrar os dados rapidamente.

O diagrama a seguir mostra um índice secundário local chamado `LastPostIndex`. Observe que a chave de partição é a mesma que a da tabela `Thread`, mas a chave de classificação é `LastPostDateTime`.

![\[A tabela LastPostIndex que contém uma lista de nomes, assuntos e a hora da última publicação do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_02.png)


Cada índice secundário local deve atender às seguintes condições:
+ A chave de partição é a mesma que a de sua tabela-base.
+ A chave de classificação consiste em exatamente um atributo escalar.
+ A chave de classificação da tabela-base é projetada no índice, onde ela atua como um atributo que não é chave.

Neste exemplo, a chave de partição é `ForumName` e a chave de classificação do índice secundário local é `LastPostDateTime`. Além disso, o valor da chave de classificação da tabela base (neste exemplo, `Subject`) é projetado no índice, mas não faz parte da chave do índice. Se um aplicativo precisar de uma lista baseada em `ForumName` e `LastPostDateTime`, ele poderá emitir uma solicitação de `Query` com relação a `LastPostIndex`. Os resultados da consulta são classificados por `LastPostDateTime` e podem ser retornados em ordem crescente ou decrescente. A consulta também pode aplicar condições de chave, como retornar apenas os itens que têm uma `LastPostDateTime` dentro de um período específico.

Cada índice secundário local contém automaticamente as chave de partição e de classificação de sua tabela-base, mas você pode opcionalmente projetar atributos não chave no índice. Quando você consultar o índice, o DynamoDB poderá recuperar esses atributos projetados com eficiência. Quando você consulta um índice secundário local, a consulta também pode recuperar atributos que *não* são projetados no índice. O DynamoDB buscará automaticamente esses atributos na tabela-base, mas com uma latência maior e com custos de throughput provisionado mais altos.

Para qualquer índice secundário local, você pode armazenar até 10 GB de dados por valor de chave de partição distinta. Esta imagem inclui todos os itens na tabela-base, além de todos os itens nos índices, que têm o mesmo valor de chave de partição. Para obter mais informações, consulte [Conjuntos de itens em índices secundários locais](#LSI.ItemCollections).

## Projeções de atributo
<a name="LSI.Projections"></a>

Com `LastPostIndex`, um aplicativo poderia usar `ForumName` e `LastPostDateTime` como critérios de consulta. No entanto, para recuperar qualquer atributo adicional, o DynamoDB deve executar operações de leitura adicionais na tabela `Thread`. Essas leituras extras são conhecidas como *buscas* e podem aumentar a quantidade total de throughput provisionado necessário para uma consulta.

Suponha que você quisesse preencher uma página da Web com uma lista de todos os threads de "S3" e o número de respostas para cada thread, classificados pela última data/hora de resposta, começando pela resposta mais recente. Para preencher essa lista, você precisaria dos seguintes atributos:
+ `Subject`
+ `Replies`
+ `LastPostDateTime`

A maneira mais eficiente de consultar esses dados e evitar operações de busca seria projetar o atributo `Replies` da tabela no índice secundário local conforme mostrado neste diagrama.

![\[A tabela LastPostIndex que contém uma lista de nomes, datas das últimas publicações, assuntos e respostas do fórum.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_03.png)




Uma *projeção* é o conjunto de atributos que é copiado de uma tabela para um índice secundário. A chave de partição e a chave de classificação da tabela são sempre projetadas no índice; você pode projetar outros atributos para suportar os requisitos de consulta da sua aplicação. Quando você consulta um índice, o Amazon DynamoDB pode acessar quaisquer atributos na projeção como se estivessem em uma tabela própria.

Quando você cria um índice secundário, é necessário especificar os atributos que serão projetados no índice. O DynamoDB proporciona três opções diferentes para fazer isso:
+ *KEYS\$1ONLY*: cada item do índice consiste apenas nos valores de chaves de partição e nas chaves de classificação da tabela, além dos valores de chaves do índice. A opção `KEYS_ONLY` resulta no menor índice secundário possível.
+ *INCLUDE*: além dos atributos descritos em `KEYS_ONLY`, o índice secundário incluirá outros atributos não chave que você especificar.
+ *ALL*: o índice secundário inclui todos os atributos da tabela de origem. Como todos os dados da tabela são duplicados no índice, uma projeção `ALL` resulta no maior índice secundário possível.

No diagrama anterior, o atributo `Replies` que não é chave é projetado em `LastPostIndex`. Um aplicativo pode consultar `LastPostIndex` em vez da tabela `Thread` completa para preencher uma página da Web com `Subject`, `Replies` e `LastPostDateTime`. Se quaisquer outros atributos que não são chaves forem solicitados, o DynamoDB precisará buscar esses atributos na tabela `Thread`. 

Do ponto de vista de um aplicativo, buscar atributos adicionais da tabela-base é automático e transparente, portanto, não há necessidade de reescrever qualquer lógica de aplicativo. No entanto, essa busca pode reduzir significativamente a vantagem de performance proporcionada pelo uso de um índice secundário local.

Ao escolher os atributos para projetar em um índice secundário local, você deve considerar a desvantagem entre os custos de throughput provisionado e os custos de armazenamento:
+ Se você precisar acessar apenas alguns atributos com a latência mais baixa possível, considere projetar apenas os atributos em um índice secundário local. Quanto menor o índice, menores serão os custos de armazenamento e de gravação. Se houver atributos que você precisa buscar ocasionalmente, o custo de throughput provisionado pode ultrapassar o custo por um prazo mais longo do armazenamento desses atributos.
+ Se sua aplicação acessar frequentemente alguns atributos não chave, considere projetar esses atributos em um índice secundário local. Os custos adicionais de armazenamento do índice secundário local compensarão o custo de executar verificações de tabelas frequentes.
+ Se precisar acessar a maioria dos atributos não chave com frequência, você poderá projetar esses atributos, inclusive a tabela-base inteira, em um índice secundário local. Isso fornece flexibilidade máxima e menor consumo de throughput provisionado, porque nenhuma busca será necessária. No entanto, o custo do armazenamento deve aumentar ou até dobrar se você estiver projetando todos os atributos.
+ Se o seu aplicativo precisa consultar uma tabela com pouca frequência, mas deve realizar muitas gravações ou atualizações nos dados na tabela, pense em projetar *KEYS\$1ONLY*. O índice secundário local seria de tamanho mínimo, mas ainda estaria disponível quando necessário para a atividade de consulta. 

## Criação de um índice secundário local
<a name="LSI.Creating"></a>

Para criar um ou mais índices secundários locais, use o parâmetro `LocalSecondaryIndexes` da operação `CreateTable`. Os índices secundários locais em uma tabela são criados quando a tabela é criada. Quando você exclui uma tabela, todos os índices secundários locais da tabela também são excluídos.

Você deve especificar um atributo não chave para atuar como a chave de classificação do índice secundário local. O atributo escolhido deve ser de um tipo escalar como `String`, `Number` ou `Binary` Outros tipos escalares, tipos de documento e tipos de conjunto não são permitidos. Para obter uma lista completa de tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

**Importante**  
Para tabelas com índices secundários locais, há um limite de tamanho de 10 GB para cada valor de chave de partição. Uma tabela com índices secundários locais pode armazenar qualquer número de itens, desde que o tamanho total de qualquer valor de chave de partição não exceda 10 GB. Para obter mais informações, consulte [Limite de tamanho de conjunto de itens](#LSI.ItemCollections.SizeLimit).

Você pode projetar atributos de qualquer tipo de dados em um índice secundário local. Isso inclui escalares, documentos e conjuntos. Para obter uma lista completa de tipos de dados, consulte [Tipos de dados](HowItWorks.NamingRulesDataTypes.md#HowItWorks.DataTypes).

## Ler dados de um índice secundário local
<a name="LSI.Reading"></a>

Você pode recuperar itens de um índice secundário local usando as operações `Query` e `Scan`. As operações `GetItem` e `BatchGetItem` não podem ser usadas em um índice secundário local.

### Como consultar um índice secundário local
<a name="LSI.Querying"></a>

Em uma tabela do DynamoDB, o valor da chave de partição combinada e o valor da chave de classificação de cada item devem ser exclusivos. No entanto, em um índice secundário local, o valor da chave de classificação não precisa ser exclusivo para um determinado valor de chave de partição. Se houver vários itens no índice secundário local com o mesmo valor de chave de classificação, uma operação `Query` retornará todos os itens que têm o mesmo valor de chave de partição. Na resposta, os itens correspondentes não são retornados em uma ordem específica.

Você pode consultar um índice secundário local usando leituras fortemente consistentes ou finais consistentes. Para especificar qual tipo de consistência você deseja, use o parâmetro `ConsistentRead` da operação `Query`. Uma leitura fortemente consistente de um índice secundário local sempre retorna os valores atualizados mais recentes. Se a consulta precisar buscar atributos adicionais na tabela base, esses atributos serão consistentes com relação ao índice.

**Example**  
Considere os seguintes dados retornados de uma `Query` que solicita dados dos threads de discussão em um determinado fórum.  

```
{
    "TableName": "Thread",
    "IndexName": "LastPostIndex",
    "ConsistentRead": false,
    "ProjectionExpression": "Subject, LastPostDateTime, Replies, Tags",
    "KeyConditionExpression": 
        "ForumName = :v_forum and LastPostDateTime between :v_start and :v_end",
    "ExpressionAttributeValues": {
        ":v_start": {"S": "2015-08-31T00:00:00.000Z"},
        ":v_end": {"S": "2015-11-31T00:00:00.000Z"},
        ":v_forum": {"S": "EC2"}
    }
}
```
Nesta consulta:  
+ O DynamoDB acessa `LastPostIndex` usando a chave de partição `ForumName` para localizar os itens do índice para o "EC2". Todos os itens do índice com essa chave são armazenados lado a lado para rápida recuperação.
+ Neste fórum, o DynamoDB usa o índice para pesquisar as chaves que correspondem à condição `LastPostDateTime` especificada.
+ Como o atributo `Replies` é projetado no índice, o DynamoDB pode recuperar esse atributo sem consumir nenhum throughput provisionado adicional.
+ O atributo `Tags` não é projetado no índice, portanto, o DynamoDB deve acessar a tabela `Thread` e buscar esse atributo.
+ Os resultados são retornados, classificados por `LastPostDateTime`. As entradas de índice são classificadas por valor de chave de partição e, em seguida, pelo valor de chave de classificação, e `Query` retorna-as na ordem em que são armazenadas. (Você pode usar o parâmetro `ScanIndexForward` para retornar os resultados em ordem decrescente.)
Como o atributo `Tags` não é projetado no índice secundário local, o DynamoDB deve consumir unidades de capacidade de leitura adicionais para buscar esse atributo na tabela-base. Se for necessário executar essa consulta com frequência, projete `Tags` no `LastPostIndex` para evitar a busca na tabela base. No entanto, se for necessário acessar `Tags` apenas ocasionalmente, o custo do armazenamento adicional para a projeção de `Tags` no índice pode não valer a pena.

### Verificação de um índice secundário local
<a name="LSI.Scanning"></a>

Você pode usar `Scan` para recuperar todos os dados de um índice secundário local. Você deve fornecer o nome da tabela-base e o nome de índice na solicitação. Com uma operação `Scan`, o DynamoDB lê todos os dados do índice e os retorna para a aplicação. Você também pode solicitar que apenas alguns dos dados sejam retornados, e que os dados restantes sejam descartados. Para fazer isso, use o parâmetro `FilterExpression` da API `Scan`. Para obter mais informações, consulte [Expressões de filtro para verificação](Scan.md#Scan.FilterExpression).

## Gravações de itens e índices secundários locais
<a name="LSI.Writes"></a>

O DynamoDB mantém automaticamente todos os índices secundários locais sincronizados com suas respectivas tabelas base. Os aplicativos nunca gravam diretamente em um índice. No entanto, é importante compreender as implicações de como o DynamoDB mantém esses índices.

Ao criar um índice secundário local, você especifica um atributo para servir como a chave de classificação do índice. Você também especifica um tipo de dados desse atributo. Isso significa que sempre que você grava um item na tabela-base, se o item define um atributo de chave do índice, seu tipo deve corresponder ao tipo de dados do esquema de chaves do índice. No caso de `LastPostIndex`, a chave de classificação de `LastPostDateTime` no índice é definida como um tipo de dados `String`. Se você tentar adicionar um item à tabela `Thread` e especificar um tipo de dados diferente para `LastPostDateTime` (como `Number`), o DynamoDB retornará uma `ValidationException` devido à inconsistência do tipo de dados.

Não há necessidade de um relacionamento de um para um entre os itens em uma tabela-base e os itens em um índice secundário local. Na verdade, esse comportamento pode ser vantajoso para muitas aplicações. 

Os custos das atividades de gravação em uma tabela com muitos índices secundários serão mais altos do que em uma tabela com um número menor de índices. Para obter mais informações, consulte [Considerações sobre throughput provisionado para índices secundários locais](#LSI.ThroughputConsiderations).

**Importante**  
Para tabelas com índices secundários locais, há um limite de tamanho de 10 GB para cada valor de chave de partição. Uma tabela com índices secundários locais pode armazenar qualquer número de itens, desde que o tamanho total de qualquer valor de chave de partição não exceda 10 GB. Para obter mais informações, consulte [Limite de tamanho de conjunto de itens](#LSI.ItemCollections.SizeLimit).

## Considerações sobre throughput provisionado para índices secundários locais
<a name="LSI.ThroughputConsiderations"></a>

Ao criar uma tabela no DynamoDB, você provisiona unidades de capacidade de leitura e gravação para a workload esperada na tabela. Essa workload inclui a atividade de leitura e gravação nos índices secundários locais da tabela.

Para visualizar as taxas atuais da capacidade de throughput provisionado, acesse [Preços do Amazon DynamoDB](https://aws.amazon.com/dynamodb/pricing).

### Unidades de capacidade de leitura
<a name="LSI.ThroughputConsiderations.Reads"></a>

Quando você consulta um índice secundário local, o número de unidades de capacidade de leitura consumidas depende de como os dados são acessados.

Assim como ocorre com as consultas de tabela, uma consulta de índice pode usar leituras fortemente consistentes ou eventualmente consistentes, dependendo do valor de `ConsistentRead`. Uma leitura fortemente consistente consome uma unidade de capacidade de leitura, uma leitura eventualmente consistente consome apenas metade disso. Assim, escolhendo leituras eventualmente consistentes, você pode reduzir seus encargos de unidade de capacidade de leitura.

Para consultas do índice que solicitam apenas chaves de índice e atributos projetados, o DynamoDB calcula a atividade de leitura provisionada da mesma forma que para consultas em tabelas. A única diferença é que o cálculo é baseado no tamanho das entradas de índice, em vez do tamanho do item na tabela-base. O número de unidades de capacidade de leitura é a soma de todos os tamanhos de atributos projetados em todos os itens retornados; o resultado é, então, arredondado para o próximo limite de 4 KB. Para obter mais informações sobre como o DynamoDB calcula a utilização de throughput provisionado, consulte [Modo de capacidade provisionada do DynamoDB](provisioned-capacity-mode.md).

Para consultas de índice que leem atributos que não estão projetados no índice secundário local, o DynamoDB precisa buscar esses atributos na tabela-base, além de ler os atributos projetados no índice. Essas buscas ocorrem quando você inclui quaisquer atributos não projetados nos parâmetros `Select` ou `ProjectionExpression` da operação `Query`. A busca causa latência adicional nas respostas da consulta, e também incorre em um custo mais alto de throughput provisionado: além das leituras do índice secundário local descritas acima, você é cobrado pelas unidades de capacidade de leitura de cada item buscado na tabela-base. Essa cobrança é para ler cada item inteiro da tabela, não apenas os atributos solicitados.

O tamanho máximo dos resultados retornados por uma operação `Query` é 1 MB. Isso inclui os tamanhos de todos os nomes e valores de atributos de todos os itens retornados. No entanto, se uma consulta em um índice secundário local fizer o DynamoDB buscar atributos de item na tabela-base, o tamanho máximo dos dados no resultado poderá ser menor. Neste caso, o tamanho do resultado é a soma de:
+ O tamanho dos itens correspondentes no índice, arredondado para os próximos 4 KB.
+ O tamanho de cada item correspondente na tabela-base, com cada item individualmente arredondado para os próximos 4 KB.

Usando esta fórmula, o tamanho máximo dos resultados retornados por uma operação Query ainda é 1 MB.

Por exemplo, considere uma tabela na qual o tamanho de cada item é 300 bytes. Há um índice secundário local nessa tabela, mas apenas 200 bytes de cada item são projetados no índice. Agora, suponha que você use a operação `Query` nesse índice, que a consulta requer buscas de tabela para cada item e que a consulta retorne 4 itens. O DynamoDB soma o seguinte:
+ O tamanho dos itens correspondentes no índice: 200 bytes × 4 itens = 800 bytes; isso é, então, arredondado para 4 KB.
+ O tamanho de cada item correspondente na tabela-base: (300 bytes, arredondados para 4 KB) × 4 itens = 16 KB.

O tamanho total dos dados no resultado é, portanto, 20 KB.

### Unidades de capacidade de gravação
<a name="LSI.ThroughputConsiderations.Writes"></a>

Quando um item é adicionado, atualizado ou excluído de uma tabela, a atualização dos índices secundários locais consome unidades de capacidade de gravação provisionadas para a tabela. O custo total do throughput provisionado para uma gravação é a soma das unidades de capacidade de gravação consumidas pela gravação na tabela e aquelas consumidas pela atualização dos índices secundários locais.

O custo de gravar um item em um índice secundário local depende de vários fatores:
+ Se você gravar um novo item na tabela que define um atributo indexado, ou atualizar um item existente para definir um atributo indexado indefinido anteriormente, uma operação de gravação é necessária para inserir o item no índice.
+ Se uma atualização na tabela alterar o valor de um atributo de chave indexado (de A para B), duas gravações serão necessárias, uma para excluir o item anterior do índice e outra gravação para inserir o novo item no índice.  
+ Se um item estava presente no índice, mas uma gravação na tabela fez com que o atributo indexado fosse excluído, uma gravação é necessária para excluir a projeção do item antigo do índice.
+ Se um item não estiver presente no índice antes ou depois que o item é atualizado, não haverá custo de gravação adicionais para o índice.

Todos esses fatores supõem que o tamanho de cada item no índice seja menor ou igual ao tamanho de item de 1 KB para calcular unidades de capacidade de gravação. Entradas de índice maiores exigirão unidades adicionais de capacidade de gravação. Você pode minimizar os custos de gravação considerando de quais atributos suas consultas precisam para retornar e projetar apenas esses atributos no índice.

## Considerações sobre armazenamento para índices secundários locais
<a name="LSI.StorageConsiderations"></a>

Quando uma aplicação grava um item em uma tabela, o DynamoDB copia automaticamente o subconjunto correto de atributos em todos os índices secundários locais nos quais esses atributos devem aparecer. Sua conta da AWS é cobrada pelo armazenamento do item na tabela-base e também pelo armazenamento dos atributos em todos os índices secundários locais nessa tabela.

A quantidade de espaço usada por um item do índice é a soma do seguinte:
+ O tamanho em bytes da chave primária da tabela-base (chave de partição e chave de classificação)
+ O tamanho em bytes do atributo de chave do índice
+ O tamanho em bytes dos atributos projetados (se houver)
+ 100 bytes de sobrecarga por item de índice

Para estimar os requisitos de armazenamento de um índice secundário local, você pode estimar o tamanho médio de um item no índice e multiplicar pelo número de itens no índice.

Se uma tabela contiver um item em que um determinado atributo não está definido, mas esse atributo estiver definido como uma chave de classificação do índice, o DynamoDB não gravará nenhum dado desse item no índice. 

## Conjuntos de itens em índices secundários locais
<a name="LSI.ItemCollections"></a>

**nota**  
A seção refere-se apenas a tabelas que têm índices secundários locais.

No DynamoDB, uma *coleção de itens* é qualquer grupo de itens que têm o mesmo valor de chave de partição em uma tabela e todos os seus índices secundários locais. Nos exemplos usados nesta seção, a chave de partição da tabela `Thread` é `ForumName`, e a chave de partição de `LastPostIndex` também é `ForumName`. Todos os itens da tabela e do índice com o mesmo `ForumName` fazem parte da mesma coleção de itens. Por exemplo, na tabela `Thread` e no índice secundário local `LastPostIndex`, existe uma coleção de itens para o fórum do `EC2` e uma coleção de itens diferente para o fórum do `RDS`.

O seguinte diagrama mostra a coleção de itens do fórum do `S3`.

![\[Uma coleção de itens do DynamoDB com itens de tabela e de índice secundário local que têm o mesmo valor de chave de partição de S3.\]](http://docs.aws.amazon.com/pt_br/amazondynamodb/latest/developerguide/images/LSI_04.png)


Neste diagrama, a coleção de itens consiste em todos os itens em `Thread` e `LastPostIndex` em que o valor da chave da partição `ForumName` é "S3". Se houver outros índices secundários locais na tabela, todos os itens nesses índices com `ForumName` igual a "S3" também farão parte da coleção de itens.

Você pode usar qualquer uma das operações a seguir no DynamoDB para retornar informações sobre coleções de itens:
+ `BatchWriteItem`
+ `DeleteItem`
+ `PutItem`
+ `UpdateItem`
+ `TransactWriteItems`

Cada uma dessas operações é compatível com o parâmetro `ReturnItemCollectionMetrics`. Ao definir esse parâmetro como `SIZE`, você pode exibir informações sobre o tamanho de cada coleção de itens no índice.

**Example**  
Este é um exemplo da saída de uma operação `UpdateItem` na tabela `Thread`, com `ReturnItemCollectionMetrics` definido como `SIZE`. O item que foi atualizado tinha um valor `ForumName` de "EC2", portanto, a saída inclui informações sobre essa coleção de itens.  

```
{
    ItemCollectionMetrics: {
        ItemCollectionKey: {
            ForumName: "EC2"
        },
        SizeEstimateRangeGB: [0.0, 1.0]
    }
}
```
O objeto `SizeEstimateRangeGB` mostra que o tamanho dessa coleção de itens está entre 0 e 1 GB. O DynamoDB atualiza periodicamente essa estimativa de tamanho, portanto, os números podem ser diferentes na próxima vez em que o item é modificado.

### Limite de tamanho de conjunto de itens
<a name="LSI.ItemCollections.SizeLimit"></a>

O tamanho máximo de qualquer coleção de itens para uma tabela com um ou mais índices secundários locais é 10 GB. Isso não se aplica a coleções de itens em tabelas sem índices secundários locais e também não se aplica a coleções de itens em índices secundários globais. Apenas as tabelas que têm um ou mais índices secundários locais são afetadas.

Se uma coleção de itens exceder o limite de 10 GB, o DynamoDB pode retornar um `ItemCollectionSizeLimitExceededException`, e você não poderá adicionar mais itens à coleção de itens ou aumentar os tamanhos dos itens que estão na coleção de itens. (As operações de leitura e gravação que diminuem o tamanho da coleção de itens ainda são permitidas.) Você ainda pode adicionar itens a outras coleções de itens.

Para reduzir o tamanho de uma coleção de itens, você pode executar uma das seguintes ações:
+ Excluir todos os itens desnecessários com o valor da chave de partição em questão. Quando você exclui esses itens da tabela-base, o DynamoDB também remove todas as entradas do índice que têm o mesmo valor de chave de partição.
+ Atualize os itens, removendo atributos ou reduzindo o tamanho dos atributos. Se esses atributos forem projetados em qualquer índice secundário local, o DynamoDB também reduzirá o tamanho das entradas do índice correspondentes.
+ Crie uma nova tabela com a mesma chave de partição e chave de classificação e, em seguida, mova os itens da tabela antiga para a nova tabela. Essa pode ser uma boa abordagem, se uma tabela tiver dados históricos que são acessados com pouca frequência. Você também pode considerar arquivar esses dados históricos no Amazon Simple Storage Service (Amazon S3).

Quando o tamanho total da coleção de itens tornar-se inferior a 10 GB, você poderá adicionar itens novamente com o mesmo valor de chave de partição.

Recomendamos como uma melhor prática que você instrumente seu aplicativo para monitorar os tamanhos de suas coleções de itens. Uma maneira de fazer isso é definir o parâmetro `ReturnItemCollectionMetrics` como `SIZE` sempre que você usar `BatchWriteItem`, `DeleteItem`, `PutItem` ou `UpdateItem`. Seu aplicativo deve examinar o objeto `ReturnItemCollectionMetrics` na saída e gerar uma mensagem de erro sempre que uma coleção de itens exceder um limite definido pelo usuário (por exemplo, 8 GB). Configurar um limite menor que 10 GB oferece um sistema de aviso antecipado para que você saiba que uma coleção de itens está se aproximando do limite a tempo de resolver o problema.

### Conjuntos de itens e partições
<a name="LSI.ItemCollections.OnePartition"></a>

Em uma tabela com um ou mais índices secundários locais, uma coleção de itens é armazenada em uma partição. O tamanho total dessa coleção de itens é limitado à capacidade dessa partição: 10 GB. Para uma aplicação em que o modelo de dados inclui coleções de itens de tamanho ilimitado ou na qual a expectativa é de que algumas coleções de itens aumentem além de 10 GB no futuro, pense em usar um índice secundário global.

Você deve criar seus aplicativos para que os dados da tabela sejam distribuídos uniformemente entre diferentes valores de chave de partição. Para tabelas com índices secundários locais, seus aplicativos não devem criar pontos de atividade de leitura e gravação em uma única coleção de itens em uma única partição. 

# Como trabalhar com índices secundários locais: Java
<a name="LSIJavaDocumentAPI"></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 locais na tabela e executar consultas usando os índices.

Veja a seguir as etapas comuns para operações de tabela usando a API de documento do AWS SDK para Java.

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 local](#LSIJavaDocumentAPI.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LSIJavaDocumentAPI.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LSIJavaDocumentAPI.QueryAnIndex)
+ [Exemplo: índices secundários locais que usam a API de documentos do Java](LSIJavaDocumentAPI.Example.md)

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

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use o método `createTable` e forneça suas especificações para um ou mais índices secundários locais. O exemplo de código Java a seguir cria uma tabela para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, facilita consultas por título de álbum. 

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário local 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 local, você deve fornecer o nome do índice, o nome e o tipo de dados da chave de classificação do índice, o esquema de chave para o índice e a projeção de atributos.

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 (`Music`) com um índice secundário no atributo `AlbumTitle`. A chave de partição de tabela e a chave de classificação, bem como a chave de classificação de índice, são os únicos atributos projetados para o índice.

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

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 local
<a name="LSIJavaDocumentAPI.DescribeTableWithIndex"></a>

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

Veja a seguir as etapas para acessar informações do índice secundário local de uma tabela usando a API de documento do AWS SDK para Java.

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

1. Crie uma instância da classe `Table`. Você deve fornecer o nome da tabela.

1. Chame o método `describeTable` 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);

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

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

Você pode usar a operação `Query` em um índice secundário local de forma semelhante ao uso de `Query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](LSI.md#LSI.Projections).

Veja a seguir as etapas para consultar um índice secundário local usando a API de documento do AWS SDK para Java. 

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

1. Crie uma instância da classe `Table`. Você deve fornecer o nome da tabela.

1. Crie uma instância da classe `Index`. Você deve fornecer o nome do índice.

1. Chame o método `query` da classe `Index`.

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

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

### Leituras consistentes em um índice secundário local
<a name="LSIJavaDocumentAPI.ConsistentReads"></a>

Ao contrário dos índices secundários globais, que permitem leituras finais consistentes, o índice secundário local permite leituras altamente consistentes. Uma leitura fortemente consistente de um índice secundário local sempre retorna os valores atualizados mais recentes. Se a consulta precisar buscar atributos adicionais na tabela base, esses atributos também serão consistentes com relação ao índice.

Por padrão, `Query` usa leituras finais consistentes. Para solicitar uma leitura altamente consistente, defina `ConsistentRead` como `true` em `QuerySpec`. O exemplo a seguir consulta `AlbumTitleIndex` usando uma leitura altamente consistente:

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

**nota**  
Uma leitura altamente consistente consome 1 unidade de capacidade de leitura por 4 KB de dados exibidos (arredondados para cima), enquanto uma leitura final consistente consome metade disso. Por exemplo, uma leitura altamente consistente que exibe 9 KB de dados consome 3 unidades de capacidade de leitura (9 KB/4 KB = 2,25, arredondado para 3), enquanto a mesma consulta usando uma leitura final consistente consome 1,5 unidade de capacidade de leitura. Se sua aplicação admitir a leitura de dados que possam estar um pouco obsoletos, use leituras finais consistentes para reduzir o uso da capacidade de leitura. Para obter mais informações, consulte [Unidades de capacidade de leitura](LSI.md#LSI.ThroughputConsiderations.Reads).

# Exemplo: índices secundários locais que usam a API de documentos do Java
<a name="LSIJavaDocumentAPI.Example"></a>

O exemplo de código Java a seguir mostra como trabalhar com índices secundários locais no Amazon DynamoDB. O exemplo cria uma tabela chamada `CustomerOrders` com uma chave de partição `CustomerId` e uma chave de classificação `OrderId`. Há dois índices secundários locais nessa tabela:
+ `OrderCreationDateIndex`: a chave de classificação é `OrderCreationDate`, e os seguintes atributos são projetados no índice:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: a chave de classificação é `IsOpen`, e todos os atributos da tabela estão projetados no índice.

Depois que a tabela `CustomerOrders` é criada, o programa carrega a tabela com os dados que representam pedidos de clientes. Ele então consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `CustomerOrders`.

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

**Example**  

```
package com.example.dynamodb;

import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;
import software.amazon.awssdk.services.dynamodb.waiters.DynamoDbWaiter;

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

public class DocumentAPILocalSecondaryIndexExample {

    static DynamoDbClient client = DynamoDbClient.create();
    public static String tableName = "CustomerOrders";

    public static void main(String[] args) {
        createTable();
        loadData();
        query(null);
        query("IsOpenIndex");
        query("OrderCreationDateIndex");
        deleteTable(tableName);
    }

    public static void createTable() {
        CreateTableRequest request = CreateTableRequest.builder()
            .tableName(tableName)
            .provisionedThroughput(ProvisionedThroughput.builder()
                .readCapacityUnits(1L)
                .writeCapacityUnits(1L)
                .build())
            .attributeDefinitions(
                AttributeDefinition.builder().attributeName("CustomerId").attributeType(ScalarAttributeType.S).build(),
                AttributeDefinition.builder().attributeName("OrderId").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("OrderCreationDate").attributeType(ScalarAttributeType.N).build(),
                AttributeDefinition.builder().attributeName("IsOpen").attributeType(ScalarAttributeType.N).build())
            .keySchema(
                KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                KeySchemaElement.builder().attributeName("OrderId").keyType(KeyType.RANGE).build())
            .localSecondaryIndexes(
                LocalSecondaryIndex.builder()
                    .indexName("OrderCreationDateIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("OrderCreationDate").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.INCLUDE)
                        .nonKeyAttributes("ProductCategory", "ProductName")
                        .build())
                    .build(),
                LocalSecondaryIndex.builder()
                    .indexName("IsOpenIndex")
                    .keySchema(
                        KeySchemaElement.builder().attributeName("CustomerId").keyType(KeyType.HASH).build(),
                        KeySchemaElement.builder().attributeName("IsOpen").keyType(KeyType.RANGE).build())
                    .projection(Projection.builder()
                        .projectionType(ProjectionType.ALL)
                        .build())
                    .build())
            .build();

        System.out.println("Creating table " + tableName + "...");
        client.createTable(request);

        try (DynamoDbWaiter waiter = client.waiter()) {
            WaiterResponse<DescribeTableResponse> response = waiter.waitUntilTableExists(r -> r.tableName(tableName));
            response.matched().response().ifPresent(System.out::println);
        }
    }

    public static void query(String indexName) {
        System.out.println("\n***********************************************************\n");
        System.out.println("Querying table " + tableName + "...");

        if ("IsOpenIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that are open.");
            System.out.println("Only a user-specified list of attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_isopen", AttributeValue.builder().n("1").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and IsOpen = :v_isopen")
                .expressionAttributeValues(values)
                .projectionExpression("OrderCreationDate, ProductCategory, ProductName, OrderStatus")
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else if ("OrderCreationDateIndex".equals(indexName)) {
            System.out.println("\nUsing index: '" + indexName + "': Bob's orders that were placed after 01/31/2015.");
            System.out.println("Only the projected attributes are returned\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());
            values.put(":v_orddate", AttributeValue.builder().n("20150131").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .indexName(indexName)
                .keyConditionExpression("CustomerId = :v_custid and OrderCreationDate >= :v_orddate")
                .expressionAttributeValues(values)
                .select(Select.ALL_PROJECTED_ATTRIBUTES)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);

        } else {
            System.out.println("\nNo index: All of Bob's orders, by OrderId:\n");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":v_custid", AttributeValue.builder().s("bob@example.com").build());

            QueryRequest request = QueryRequest.builder()
                .tableName(tableName)
                .keyConditionExpression("CustomerId = :v_custid")
                .expressionAttributeValues(values)
                .build();

            System.out.println("Query: printing results...");
            client.query(request).items().forEach(System.out::println);
        }
    }

    public static void deleteTable(String tableName) {
        System.out.println("Deleting table " + tableName + "...");
        client.deleteTable(DeleteTableRequest.builder().tableName(tableName).build());

        try (DynamoDbWaiter waiter = client.waiter()) {
            waiter.waitUntilTableNotExists(r -> r.tableName(tableName));
        }
    }

    public static void loadData() {
        System.out.println("Loading data into table " + tableName + "...");

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150101").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("The Great Outdoors").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Bike").build(),
            "ProductName", AttributeValue.builder().s("Super Mountain").build(),
            "OrderStatus", AttributeValue.builder().s("ORDER RECEIVED").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("alice@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150304").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("A Quiet Interlude").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("176493").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150111").build(),
            "ProductCategory", AttributeValue.builder().s("Movie").build(),
            "ProductName", AttributeValue.builder().s("Calm Before The Storm").build(),
            "OrderStatus", AttributeValue.builder().s("SHIPPING DELAY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("859323").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("2").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150124").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("E-Z Listening").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("756943").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("3").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150221").build(),
            "ProductCategory", AttributeValue.builder().s("Music").build(),
            "ProductName", AttributeValue.builder().s("Symphony 9").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("645193").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("4").build(),
            "IsOpen", AttributeValue.builder().n("1").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150222").build(),
            "ProductCategory", AttributeValue.builder().s("Hardware").build(),
            "ProductName", AttributeValue.builder().s("Extra Heavy Hammer").build(),
            "OrderStatus", AttributeValue.builder().s("PACKING ITEMS").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("5").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150309").build(),
            "ProductCategory", AttributeValue.builder().s("Book").build(),
            "ProductName", AttributeValue.builder().s("How To Cook").build(),
            "OrderStatus", AttributeValue.builder().s("IN TRANSIT").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("440185").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("6").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150318").build(),
            "ProductCategory", AttributeValue.builder().s("Luggage").build(),
            "ProductName", AttributeValue.builder().s("Really Big Suitcase").build(),
            "OrderStatus", AttributeValue.builder().s("DELIVERED").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("893927").build()));

        putItem(Map.of(
            "CustomerId", AttributeValue.builder().s("bob@example.com").build(),
            "OrderId", AttributeValue.builder().n("7").build(),
            "OrderCreationDate", AttributeValue.builder().n("20150324").build(),
            "ProductCategory", AttributeValue.builder().s("Golf").build(),
            "ProductName", AttributeValue.builder().s("PGA Pro II").build(),
            "OrderStatus", AttributeValue.builder().s("OUT FOR DELIVERY").build(),
            "ShipmentTrackingId", AttributeValue.builder().s("383283").build()));
    }

    private static void putItem(Map<String, AttributeValue> item) {
        client.putItem(PutItemRequest.builder().tableName(tableName).item(item).build());
    }
}
```

# Como trabalhar com índices secundários locais: .NET
<a name="LSILowLevelDotNet"></a>

**Topics**
+ [Criar uma tabela com um índice secundário local](#LSILowLevelDotNet.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LSILowLevelDotNet.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LSILowLevelDotNet.QueryAnIndex)
+ [Exemplo: índices secundários locais que usam a API de baixo nível do AWS SDK para .NET](LSILowLevelDotNet.Example.md)

Você pode usar a API de baixo nível do AWS SDK para .NET para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários locais na tabela e executar consultas usando os índices. Essas operações são mapeadas nas ações correspondentes da API de baixo nível do DynamoDB. Para obter mais informações, consulte [Exemplos de código .NET](CodeSamples.DotNet.md). 

Veja a seguir as etapas comuns para operações de tabela usando a API de baixo nível do .NET. 

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

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

   Por exemplo, crie um objeto `CreateTableRequest` para criar uma tabela e crie um objeto `QueryRequest` para consultar uma tabela ou um índice. 

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

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

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use `CreateTable` e forneça suas especificações para um ou mais índices secundários locais. O exemplo de código C\$1 a seguir cria uma tabela para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, facilita consultas por título de álbum. 

Veja a seguir as etapas necessárias para criar uma tabela com um índice secundário local usando a API de baixo nível do .NET. 

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

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 local, você deve fornecer o nome do índice, o nome e o tipo de dados da chave de classificação do índice, o esquema de chave para o índice e a projeção de atributos.

1. Execute o método `CreateTable` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores. O código cria uma tabela (`Music`) com um índice secundário no atributo `AlbumTitle`. A chave de partição de tabela e a chave de classificação, bem como a chave de classificação de índice, são os únicos atributos projetados para o índice.

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

CreateTableRequest createTableRequest = new CreateTableRequest()
{
    TableName = tableName
};

//ProvisionedThroughput
createTableRequest.ProvisionedThroughput = new ProvisionedThroughput()
{
    ReadCapacityUnits = (long)5,
    WriteCapacityUnits = (long)5
};

//AttributeDefinitions
List<AttributeDefinition> attributeDefinitions = new List<AttributeDefinition>();

attributeDefinitions.Add(new AttributeDefinition()
{
    AttributeName = "Artist",
    AttributeType = "S"
});

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "SongTitle",
     AttributeType = "S"
 });

attributeDefinitions.Add(new AttributeDefinition()
 {
     AttributeName = "AlbumTitle",
     AttributeType = "S"
 });

createTableRequest.AttributeDefinitions = attributeDefinitions;

//KeySchema
List<KeySchemaElement> tableKeySchema = new List<KeySchemaElement>();

tableKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
tableKeySchema.Add(new KeySchemaElement() { AttributeName = "SongTitle", KeyType = "RANGE" });  //Sort key

createTableRequest.KeySchema = tableKeySchema;

List<KeySchemaElement> indexKeySchema = new List<KeySchemaElement>();
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "Artist", KeyType = "HASH" });  //Partition key
indexKeySchema.Add(new KeySchemaElement() { AttributeName = "AlbumTitle", KeyType = "RANGE" });  //Sort key

Projection projection = new Projection() { ProjectionType = "INCLUDE" };

List<string> nonKeyAttributes = new List<string>();
nonKeyAttributes.Add("Genre");
nonKeyAttributes.Add("Year");
projection.NonKeyAttributes = nonKeyAttributes;

LocalSecondaryIndex localSecondaryIndex = new LocalSecondaryIndex()
{
    IndexName = "AlbumTitleIndex",
    KeySchema = indexKeySchema,
    Projection = projection
};

List<LocalSecondaryIndex> localSecondaryIndexes = new List<LocalSecondaryIndex>();
localSecondaryIndexes.Add(localSecondaryIndex);
createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

CreateTableResponse result = client.CreateTable(createTableRequest);
Console.WriteLine(result.CreateTableResult.TableDescription.TableName);
Console.WriteLine(result.CreateTableResult.TableDescription.TableStatus);
```

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 local
<a name="LSILowLevelDotNet.DescribeTableWithIndex"></a>

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

Veja a seguir as etapas para acessar informações do índice secundário local para uma tabela usando a API de baixo nível do .NET. 

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

1. Crie uma instância da classe `DescribeTableRequest` para fornecer as informações solicitadas. Você deve fornecer o nome da tabela.

1. Execute o método `describeTable` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**Example**  

```
AmazonDynamoDBClient client = new AmazonDynamoDBClient();
string tableName = "Music";

DescribeTableResponse response = client.DescribeTable(new DescribeTableRequest() { TableName = tableName });
List<LocalSecondaryIndexDescription> localSecondaryIndexes =
    response.DescribeTableResult.Table.LocalSecondaryIndexes;

// This code snippet will work for multiple indexes, even though
// there is only one index in this example.
foreach (LocalSecondaryIndexDescription lsiDescription in localSecondaryIndexes)
{
    Console.WriteLine("Info for index " + lsiDescription.IndexName + ":");

    foreach (KeySchemaElement kse in lsiDescription.KeySchema)
    {
        Console.WriteLine("\t" + kse.AttributeName + ": key type is " + kse.KeyType);
    }

    Projection projection = lsiDescription.Projection;

    Console.WriteLine("\tThe projection type is: " + projection.ProjectionType);

    if (projection.ProjectionType.ToString().Equals("INCLUDE"))
    {
        Console.WriteLine("\t\tThe non-key projected attributes are:");

        foreach (String s in projection.NonKeyAttributes)
        {
            Console.WriteLine("\t\t" + s);
        }

    }
}
```

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

Você pode usar `Query` em um índice secundário local de forma semelhante ao uso de `Query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](LSI.md#LSI.Projections)

Veja a seguir as etapas para consultar um índice secundário local usando a API de baixo nível do .NET. 

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

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

1. Execute o método `query` fornecendo o objeto de solicitação como um parâmetro.

O exemplo de código C\$1 a seguir demonstra as etapas anteriores.

**Example**  

```
QueryRequest queryRequest = new QueryRequest
{
    TableName = "Music",
    IndexName = "AlbumTitleIndex",
    Select = "ALL_ATTRIBUTES",
    ScanIndexForward = true,
    KeyConditionExpression = "Artist = :v_artist and AlbumTitle = :v_title",
    ExpressionAttributeValues = new Dictionary<string, AttributeValue>()
    {
        {":v_artist",new AttributeValue {S = "Acme Band"}},
        {":v_title",new AttributeValue {S = "Songs About Life"}}
    },
};

QueryResponse response = client.Query(queryRequest);

foreach (var attribs in response.Items)
{
    foreach (var attrib in attribs)
    {
        Console.WriteLine(attrib.Key + " ---> " + attrib.Value.S);
    }
    Console.WriteLine();
}
```

# Exemplo: índices secundários locais que usam a API de baixo nível do AWS SDK para .NET
<a name="LSILowLevelDotNet.Example"></a>

O exemplo de código C\$1 a seguir mostra como trabalhar com índices secundários locais no Amazon DynamoDB. O exemplo cria uma tabela chamada `CustomerOrders` com uma chave de partição `CustomerId` e uma chave de classificação `OrderId`. Há dois índices secundários locais nessa tabela:
+ `OrderCreationDateIndex`: a chave de classificação é `OrderCreationDate`, e os seguintes atributos são projetados no índice:
  + `ProductCategory`
  + `ProductName`
  + `OrderStatus`
  + `ShipmentTrackingId`
+ `IsOpenIndex`: a chave de classificação é `IsOpen`, e todos os atributos da tabela estão projetados no índice.

Depois que a tabela `CustomerOrders` é criada, o programa carrega a tabela com os dados que representam pedidos de clientes. Ele então consulta os dados usando os índices secundários globais. Por fim, o programa exclui a tabela `CustomerOrders`.

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

**Example**  

```
using System;
using System.Collections.Generic;
using System.Linq;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime;
using Amazon.SecurityToken;

namespace com.amazonaws.codesamples
{
    class LowLevelLocalSecondaryIndexExample
    {
        private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        private static string tableName = "CustomerOrders";

        static void Main(string[] args)
        {
            try
            {
                CreateTable();
                LoadData();

                Query(null);
                Query("IsOpenIndex");
                Query("OrderCreationDateIndex");

                DeleteTable(tableName);

                Console.WriteLine("To continue, press Enter");
                Console.ReadLine();
            }
            catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); }
            catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        private static void CreateTable()
        {
            var createTableRequest =
                new CreateTableRequest()
                {
                    TableName = tableName,
                    ProvisionedThroughput =
                    new ProvisionedThroughput()
                    {
                        ReadCapacityUnits = (long)1,
                        WriteCapacityUnits = (long)1
                    }
                };

            var attributeDefinitions = new List<AttributeDefinition>()
        {
            // Attribute definitions for table primary key
            { new AttributeDefinition() {
                  AttributeName = "CustomerId", AttributeType = "S"
              } },
            { new AttributeDefinition() {
                  AttributeName = "OrderId", AttributeType = "N"
              } },
            // Attribute definitions for index primary key
            { new AttributeDefinition() {
                  AttributeName = "OrderCreationDate", AttributeType = "N"
              } },
            { new AttributeDefinition() {
                  AttributeName = "IsOpen", AttributeType = "N"
              }}
        };

            createTableRequest.AttributeDefinitions = attributeDefinitions;

            // Key schema for table
            var tableKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                  //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderId", KeyType = "RANGE"
              } }                                                //Sort key
        };

            createTableRequest.KeySchema = tableKeySchema;

            var localSecondaryIndexes = new List<LocalSecondaryIndex>();

            // OrderCreationDateIndex
            LocalSecondaryIndex orderCreationDateIndex = new LocalSecondaryIndex()
            {
                IndexName = "OrderCreationDateIndex"
            };

            // Key schema for OrderCreationDateIndex
            var indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              } },                                                    //Partition key
            { new KeySchemaElement() {
                  AttributeName = "OrderCreationDate", KeyType = "RANGE"
              } }                                                            //Sort key
        };

            orderCreationDateIndex.KeySchema = indexKeySchema;

            // Projection (with list of projected attributes) for
            // OrderCreationDateIndex
            var projection = new Projection()
            {
                ProjectionType = "INCLUDE"
            };

            var nonKeyAttributes = new List<string>()
        {
            "ProductCategory",
            "ProductName"
        };
            projection.NonKeyAttributes = nonKeyAttributes;

            orderCreationDateIndex.Projection = projection;

            localSecondaryIndexes.Add(orderCreationDateIndex);

            // IsOpenIndex
            LocalSecondaryIndex isOpenIndex
                = new LocalSecondaryIndex()
                {
                    IndexName = "IsOpenIndex"
                };

            // Key schema for IsOpenIndex
            indexKeySchema = new List<KeySchemaElement>()
        {
            { new KeySchemaElement() {
                  AttributeName = "CustomerId", KeyType = "HASH"
              }},                                                     //Partition key
            { new KeySchemaElement() {
                  AttributeName = "IsOpen", KeyType = "RANGE"
              }}                                                  //Sort key
        };

            // Projection (all attributes) for IsOpenIndex
            projection = new Projection()
            {
                ProjectionType = "ALL"
            };

            isOpenIndex.KeySchema = indexKeySchema;
            isOpenIndex.Projection = projection;

            localSecondaryIndexes.Add(isOpenIndex);

            // Add index definitions to CreateTable request
            createTableRequest.LocalSecondaryIndexes = localSecondaryIndexes;

            Console.WriteLine("Creating table " + tableName + "...");
            client.CreateTable(createTableRequest);
            WaitUntilTableReady(tableName);
        }

        public static void Query(string indexName)
        {
            Console.WriteLine("\n***********************************************************\n");
            Console.WriteLine("Querying table " + tableName + "...");

            QueryRequest queryRequest = new QueryRequest()
            {
                TableName = tableName,
                ConsistentRead = true,
                ScanIndexForward = true,
                ReturnConsumedCapacity = "TOTAL"
            };


            String keyConditionExpression = "CustomerId = :v_customerId";
            Dictionary<string, AttributeValue> expressionAttributeValues = new Dictionary<string, AttributeValue> {
            {":v_customerId", new AttributeValue {
                 S = "bob@example.com"
             }}
        };


            if (indexName == "IsOpenIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that are open.");
                Console.WriteLine("Only a user-specified list of attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and IsOpen = :v_isOpen";
                expressionAttributeValues.Add(":v_isOpen", new AttributeValue
                {
                    N = "1"
                });

                // ProjectionExpression
                queryRequest.ProjectionExpression = "OrderCreationDate, ProductCategory, ProductName, OrderStatus";
            }
            else if (indexName == "OrderCreationDateIndex")
            {
                Console.WriteLine("\nUsing index: '" + indexName
                          + "': Bob's orders that were placed after 01/31/2013.");
                Console.WriteLine("Only the projected attributes are returned\n");
                queryRequest.IndexName = indexName;

                keyConditionExpression += " and OrderCreationDate > :v_Date";
                expressionAttributeValues.Add(":v_Date", new AttributeValue
                {
                    N = "20130131"
                });

                // Select
                queryRequest.Select = "ALL_PROJECTED_ATTRIBUTES";
            }
            else
            {
                Console.WriteLine("\nNo index: All of Bob's orders, by OrderId:\n");
            }
            queryRequest.KeyConditionExpression = keyConditionExpression;
            queryRequest.ExpressionAttributeValues = expressionAttributeValues;

            var result = client.Query(queryRequest);
            var items = result.Items;
            foreach (var currentItem in items)
            {
                foreach (string attr in currentItem.Keys)
                {
                    if (attr == "OrderId" || attr == "IsOpen"
                        || attr == "OrderCreationDate")
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].N);
                    }
                    else
                    {
                        Console.WriteLine(attr + "---> " + currentItem[attr].S);
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nConsumed capacity: " + result.ConsumedCapacity.CapacityUnits + "\n");
        }

        private static void DeleteTable(string tableName)
        {
            Console.WriteLine("Deleting table " + tableName + "...");
            client.DeleteTable(new DeleteTableRequest()
            {
                TableName = tableName
            });
            WaitForTableToBeDeleted(tableName);
        }

        public static void LoadData()
        {
            Console.WriteLine("Loading data into table " + tableName + "...");

            Dictionary<string, AttributeValue> item = new Dictionary<string, AttributeValue>();

            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130101"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "The Great Outdoors"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            PutItemRequest putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Bike"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Super Mountain"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "ORDER RECEIVED"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "alice@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130304"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "A Quiet Interlude"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "176493"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "1"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130111"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Movie"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Calm Before The Storm"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "SHIPPING DELAY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "859323"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "2"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130124"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "E-Z Listening"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "756943"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "3"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130221"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Music"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Symphony 9"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "645193"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "4"
            };
            item["IsOpen"] = new AttributeValue
            {
                N = "1"
            };
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130222"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Hardware"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Extra Heavy Hammer"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "PACKING ITEMS"
            };
            /* no ShipmentTrackingId attribute */
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "5"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130309"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Book"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "How To Cook"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "IN TRANSIT"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "440185"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "6"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130318"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Luggage"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "Really Big Suitcase"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "DELIVERED"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "893927"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);

            item = new Dictionary<string, AttributeValue>();
            item["CustomerId"] = new AttributeValue
            {
                S = "bob@example.com"
            };
            item["OrderId"] = new AttributeValue
            {
                N = "7"
            };
            /* no IsOpen attribute */
            item["OrderCreationDate"] = new AttributeValue
            {
                N = "20130324"
            };
            item["ProductCategory"] = new AttributeValue
            {
                S = "Golf"
            };
            item["ProductName"] = new AttributeValue
            {
                S = "PGA Pro II"
            };
            item["OrderStatus"] = new AttributeValue
            {
                S = "OUT FOR DELIVERY"
            };
            item["ShipmentTrackingId"] = new AttributeValue
            {
                S = "383283"
            };
            putItemRequest = new PutItemRequest
            {
                TableName = tableName,
                Item = item,
                ReturnItemCollectionMetrics = "SIZE"
            };
            client.PutItem(putItemRequest);
        }

        private static void WaitUntilTableReady(string tableName)
        {
            string status = null;
            // Let us wait until table is created. Call DescribeTable.
            do
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                    status = res.Table.TableStatus;
                }
                catch (ResourceNotFoundException)
                {
                    // DescribeTable is eventually consistent. So you might
                    // get resource not found. So we handle the potential exception.
                }
            } while (status != "ACTIVE");
        }

        private static void WaitForTableToBeDeleted(string tableName)
        {
            bool tablePresent = true;

            while (tablePresent)
            {
                System.Threading.Thread.Sleep(5000); // Wait 5 seconds.
                try
                {
                    var res = client.DescribeTable(new DescribeTableRequest
                    {
                        TableName = tableName
                    });

                    Console.WriteLine("Table name: {0}, status: {1}",
                              res.Table.TableName,
                              res.Table.TableStatus);
                }
                catch (ResourceNotFoundException)
                {
                    tablePresent = false;
                }
            }
        }
    }
}
```

# Trabalhar com índices secundários locais no DynamoDB usando a AWS CLI
<a name="LCICli"></a>

Você pode usar a AWS CLI para criar uma tabela do Amazon DynamoDB com um ou mais índices secundários locais, descrever os índices na tabela e realizar consultas usando os índices.

**Topics**
+ [Criar uma tabela com um índice secundário local](#LCICli.CreateTableWithIndex)
+ [Descrever uma tabela com um índice secundário local](#LCICli.DescribeTableWithIndex)
+ [Consultar um índice secundário local](#LCICli.QueryAnIndex)

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

Os índices secundários locais devem ser criados ao mesmo tempo que uma tabela é criada. Para fazer isso, use o parâmetro `create-table` e forneça as especificações para um ou mais índices secundários locais. O exemplo a seguir cria uma tabela (`Music`) para armazenar informações sobre músicas em uma coleção de músicas. A chave de partição é `Artist` e a chave de classificação é `SongTitle`. Um índice secundário, `AlbumTitleIndex`, no atributo `AlbumTitle` facilita consultas por título de álbum. 

```
aws dynamodb create-table \
    --table-name Music \
    --attribute-definitions AttributeName=Artist,AttributeType=S AttributeName=SongTitle,AttributeType=S \
        AttributeName=AlbumTitle,AttributeType=S  \
    --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=10,WriteCapacityUnits=5 \
    --local-secondary-indexes \
        "[{\"IndexName\": \"AlbumTitleIndex\",
        \"KeySchema\":[{\"AttributeName\":\"Artist\",\"KeyType\":\"HASH\"},
                      {\"AttributeName\":\"AlbumTitle\",\"KeyType\":\"RANGE\"}],
        \"Projection\":{\"ProjectionType\":\"INCLUDE\",  \"NonKeyAttributes\":[\"Genre\", \"Year\"]}}]"
```

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. Você pode usar [describe-table](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/describe-table.html) para determinar o status da criação da tabela. 

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

Para obter mais informações sobre índices secundários locais em uma tabela, use o parâmetro `describe-table`. Para cada índice, você pode acessar seu nome, esquema de chaves e atributos projetados.

```
aws dynamodb describe-table --table-name Music
```

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

Você pode usar a operação `query` em um índice secundário local de modo semelhante a como você `query` em uma tabela. Você deve especificar o nome do índice, os critérios de consulta da chave de classificação do índice e os atributos que deseja retornar. Neste exemplo, o índice é `AlbumTitleIndex` e a chave de classificação do índice é `AlbumTitle`. 

Os únicos atributos retornados são aqueles que foram projetados no índice. É possível modificar essa consulta para selecionar atributos não chave também, mas isso exigiria atividades de busca de tabela que são relativamente caras. Para obter mais informações sobre buscas de tabela, consulte [Projeções de atributo](LSI.md#LSI.Projections).

```
aws dynamodb query \
    --table-name Music \
    --index-name AlbumTitleIndex \
    --key-condition-expression "Artist = :v_artist and AlbumTitle = :v_title" \
    --expression-attribute-values  '{":v_artist":{"S":"Acme Band"},":v_title":{"S":"Songs About Life"} }'
```