View a markdown version of this page

Usar índices secundarios - AWS SDK for Java 2.x

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Usar índices secundarios

La clave principal de una tabla define el índice principal, que determina la forma en que DynamoDB almacena y recupera los elementos de forma predeterminada.

Los índices secundarios proporcionan claves alternativas que se utilizan en las operaciones de consulta y escaneo. Los índices secundarios globales (GSI) tienen una clave de partición y una clave de clasificación opcional que pueden diferir de las de la tabla base. Por el contrario, los índices secundarios locales (LSI) comparten la clave de partición del índice principal, pero definen una clave de clasificación diferente.

Defina las claves para los índices secundarios globales y locales

Los atributos que participan en índices secundarios requieren la anotación @DynamoDbSecondaryPartitionKey o @DynamoDbSecondarySortKey.

La siguiente clase muestra las anotaciones de dos índices. El GSI denominado SubjectLastPostedDateIndexutiliza el Subject atributo de la clave de partición y el LastPostedDateTime de la clave de clasificación. El LSI denominado ForumLastPostedDateIndexutiliza el ForumName como clave de partición y LastPostedDateTime como clave de clasificación.

Tenga en cuenta que el atributo Subject cumple una doble función. Es la clave de clasificación de la clave principal y la clave de partición del GSI denominado. SubjectLastPostedDateIndex

Clase MessageThread

La clase MessageThread es adecuada para utilizarla como clase de datos en la tabla Thread de ejemplo de la Guía para desarrolladores de Amazon DynamoDB.

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey; import java.util.List;
@DynamoDbBean public class MessageThread { private String ForumName; private String Subject; private String Message; private String LastPostedBy; private String LastPostedDateTime; private Integer Views; private Integer Replies; private Integer Answered; private List<String> Tags; @DynamoDbPartitionKey public String getForumName() { return ForumName; } public void setForumName(String forumName) { ForumName = forumName; } // Sort key for primary index and partition key for GSI "SubjectLastPostedDateIndex". @DynamoDbSortKey @DynamoDbSecondaryPartitionKey(indexNames = "SubjectLastPostedDateIndex") public String getSubject() { return Subject; } public void setSubject(String subject) { Subject = subject; } // Sort key for GSI "SubjectLastPostedDateIndex" and sort key for LSI "ForumLastPostedDateIndex". @DynamoDbSecondarySortKey(indexNames = {"SubjectLastPostedDateIndex", "ForumLastPostedDateIndex"}) public String getLastPostedDateTime() { return LastPostedDateTime; } public void setLastPostedDateTime(String lastPostedDateTime) { LastPostedDateTime = lastPostedDateTime; } public String getMessage() { return Message; } public void setMessage(String message) { Message = message; } public String getLastPostedBy() { return LastPostedBy; } public void setLastPostedBy(String lastPostedBy) { LastPostedBy = lastPostedBy; } public Integer getViews() { return Views; } public void setViews(Integer views) { Views = views; } @DynamoDbSecondaryPartitionKey(indexNames = "ForumRepliesIndex") public Integer getReplies() { return Replies; } public void setReplies(Integer replies) { Replies = replies; } public Integer getAnswered() { return Answered; } public void setAnswered(Integer answered) { Answered = answered; } public List<String> getTags() { return Tags; } public void setTags(List<String> tags) { Tags = tags; } public MessageThread() { this.Answered = 0; this.LastPostedBy = ""; this.ForumName = ""; this.Message = ""; this.LastPostedDateTime = ""; this.Replies = 0; this.Views = 0; this.Subject = ""; } @Override public String toString() { return "MessageThread{" + "ForumName='" + ForumName + '\'' + ", Subject='" + Subject + '\'' + ", Message='" + Message + '\'' + ", LastPostedBy='" + LastPostedBy + '\'' + ", LastPostedDateTime='" + LastPostedDateTime + '\'' + ", Views=" + Views + ", Replies=" + Replies + ", Answered=" + Answered + ", Tags=" + Tags + '}'; } }

Crear el índice

A partir de la versión 2.20.86 del SDK para Java, el método createTable() genera automáticamente índices secundarios a partir de las anotaciones de las clases de datos. De forma predeterminada, todos los atributos de la tabla base se copian en un índice y los valores de rendimiento aprovisionados son 20 unidades de capacidad de lectura y 20 unidades de capacidad de escritura.

Sin embargo, si utiliza una versión del SDK anterior a la 2.20.86, debe crear el índice junto con la tabla, como se muestra en el siguiente ejemplo. En este ejemplo, se crean los dos índices de la tabla Thread. El parámetro constructor tiene métodos para configurar ambos tipos de índices, como se muestra después de las líneas de comentario 1 y 2. Utilice el método del generador de índices indexName() para asociar los nombres de índice especificados en las anotaciones de las clases de datos con el tipo de índice deseado.

Este código configura todos los atributos de la tabla para que terminen en ambos índices después de las líneas de comentario 3 y 4. Encontrará más información sobre las proyecciones de atributos en la Guía para desarrolladores de Amazon DynamoDB.

public static void createMessageThreadTable(DynamoDbTable<MessageThread> messageThreadDynamoDbTable, DynamoDbClient dynamoDbClient) { messageThreadDynamoDbTable.createTable(b -> b // 1. Generate the GSI. .globalSecondaryIndices(gsi -> gsi.indexName("SubjectLastPostedDateIndex") // 3. Populate the GSI with all attributes. .projection(p -> p .projectionType(ProjectionType.ALL)) ) // 2. Generate the LSI. .localSecondaryIndices(lsi -> lsi.indexName("ForumLastPostedDateIndex") // 4. Populate the LSI with all attributes. .projection(p -> p .projectionType(ProjectionType.ALL)) ) );

Consultar utilizando un índice

El siguiente ejemplo consulta el índice secundario global ForumLastPostedDateIndex.

Tras la línea de comentario 2, se crea un QueryConditionalobjeto que es obligatorio al llamar al método DynamoDbIndex.query().

Para obtener una referencia al índice que desea consultar después de la línea de comentario 3, debe pasar al nombre del índice. Tras la línea de comentario 4, se llama al método query() del índice que pasa al objeto QueryConditional.

También puede configurar la consulta para que devuelva tres valores de atributo, como se muestra tras la línea de comentario 5. Si no se llama attributesToProject(), la consulta devuelve todos los valores de los atributos. Los nombres de los atributos especificados comienzan con letras minúsculas. Estos nombres coinciden con los utilizados en la tabla, no necesariamente con los de la clase de datos.

Siguiendo la línea de comentario 6, se itera a través de los resultados y se registra cada elemento devuelto por la consulta y también se almacena en la lista para devolvérsela a la persona que llama.

public class IndexScanExamples { private static Logger logger = LoggerFactory.getLogger(IndexScanExamples.class); public static List<MessageThread> queryUsingSecondaryIndices(String lastPostedDate, DynamoDbTable<MessageThread> threadTable) { // 1. Log the parameter value. logger.info("lastPostedDate value: {}", lastPostedDate); // 2. Create a QueryConditional whose sort key value must be greater than or equal to the parameter value. QueryConditional queryConditional = QueryConditional.sortGreaterThanOrEqualTo(qc -> qc.partitionValue("Forum02").sortValue(lastPostedDate)); // 3. Specify the index name to query. final DynamoDbIndex<MessageThread> forumLastPostedDateIndex = threadTable.index("ForumLastPostedDateIndex"); // 4. Perform the query using the QueryConditional object. final SdkIterable<Page<MessageThread>> pagedResult = forumLastPostedDateIndex.query(q -> q .queryConditional(queryConditional) // 5. Request three attribute in the results. .attributesToProject("forumName", "subject", "lastPostedDateTime")); List<MessageThread> collectedItems = new ArrayList<>(); // 6. Iterate through pages response and sort the items. pagedResult.stream().forEach(page -> page.items().stream() .sorted(Comparator.comparing(MessageThread::getLastPostedDateTime)) .forEach(mt -> { // 7. Log the returned items and add the collection to return to the caller. logger.info(mt.toString()); collectedItems.add(mt); })); return collectedItems; }

En la base de datos existen los siguientes elementos antes de que se ejecute la consulta.

MessageThread{ForumName='Forum01', Subject='Subject01', Message='Message01', LastPostedBy='', LastPostedDateTime='2023.03.28', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject02', Message='Message02', LastPostedBy='', LastPostedDateTime='2023.03.29', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject04', Message='Message04', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject08', Message='Message08', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject10', Message='Message10', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum03', Subject='Subject03', Message='Message03', LastPostedBy='', LastPostedDateTime='2023.03.30', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum03', Subject='Subject06', Message='Message06', LastPostedBy='', LastPostedDateTime='2023.04.02', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum03', Subject='Subject09', Message='Message09', LastPostedBy='', LastPostedDateTime='2023.04.05', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum05', Subject='Subject05', Message='Message05', LastPostedBy='', LastPostedDateTime='2023.04.01', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum07', Subject='Subject07', Message='Message07', LastPostedBy='', LastPostedDateTime='2023.04.03', Views=0, Replies=0, Answered=0, Tags=null}

Las instrucciones de registro de las líneas 1 y 6 dan como resultado la siguiente salida de consola.

lastPostedDate value: 2023.03.31 MessageThread{ForumName='Forum02', Subject='Subject04', Message='', LastPostedBy='', LastPostedDateTime='2023.03.31', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject08', Message='', LastPostedBy='', LastPostedDateTime='2023.04.04', Views=0, Replies=0, Answered=0, Tags=null} MessageThread{ForumName='Forum02', Subject='Subject10', Message='', LastPostedBy='', LastPostedDateTime='2023.04.06', Views=0, Replies=0, Answered=0, Tags=null}

La consulta devolvió elementos con un valor forumName de Forum02 y un valor de lastPostedDateTime superior o igual a 2023.03.31. Los resultados muestran valores message con una cadena vacía, aunque los atributos message tienen valores en el índice. Esto se debe a que el atributo del mensaje no se proyectó mediante código después de la línea de comentario 5.

Utilice claves compuestas para los índices secundarios globales (GSI)

El SDK para Java 2.x DynamoDB Enhanced Client admite claves compuestas para índices secundarios globales. Puede definir hasta cuatro atributos de clave de partición y cuatro atributos de clave de clasificación para un solo GSI. Esto elimina la necesidad de concatenar varios atributos en una sola clave de cadena en el lado del cliente.

Utilice el order parámetro de las @DynamoDbSecondarySortKey anotaciones @DynamoDbSecondaryPartitionKey y para especificar la posición de cada atributo en la clave compuesta. El order parámetro acepta valores de la Orderenumeración (parte del cliente de DynamoDB mejorado)FIRST:SECOND,, y. THIRD FOURTH

Anote la clase de datos con anotaciones clave compuestas

El siguiente ejemplo modela una tabla de pedidos. La tabla base se utiliza orderId como clave de partición. Un GSI denominado OrdersByStatusDateAmountutiliza una clave de partición compuesta de customerId ystatus, y una clave de clasificación compuesta de orderDate yamount. Este diseño permite consultar los pedidos de un cliente filtrados por estado, fecha y límite de importe.

import software.amazon.awssdk.enhanced.dynamodb.mapper.Order; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondarySortKey;
@DynamoDbBean public class OrderItem { private String orderId; private String customerId; private String status; private String orderDate; private Integer amount; @DynamoDbPartitionKey public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } // First partition key attribute for the GSI. @DynamoDbSecondaryPartitionKey(indexNames = "OrdersByStatusDateAmount", order = Order.FIRST) public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } // Second partition key attribute for the GSI. @DynamoDbSecondaryPartitionKey(indexNames = "OrdersByStatusDateAmount", order = Order.SECOND) public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } // First sort key attribute for the GSI. @DynamoDbSecondarySortKey(indexNames = "OrdersByStatusDateAmount", order = Order.FIRST) public String getOrderDate() { return orderDate; } public void setOrderDate(String orderDate) { this.orderDate = orderDate; } // Second sort key attribute for the GSI. @DynamoDbSecondarySortKey(indexNames = "OrdersByStatusDateAmount", order = Order.SECOND) public Integer getAmount() { return amount; } public void setAmount(Integer amount) { this.amount = amount; } }

Realice consultas mediante un índice de claves compuesto

Al consultar un índice de claves compuesto, utilice los addSortValue() métodos addPartitionValue() y del generador de claves. Añada valores en el mismo orden que los Order valores definidos en las anotaciones. Todas las claves de partición son obligatorias. Las claves de clasificación son opcionales y se pueden proporcionar de izquierda a derecha.

Se crea un QueryConditionalobjeto para especificar la condición de la consulta. keyEqualToÚselo para obtener coincidencias exactas o una condición clave de ordenación como sortGreaterThansortLessThan,sortBetween, osortBeginsWith. La condición se aplica a la última clave de clasificación que haya proporcionado.

En los ejemplos siguientes, OrdersByStatusDateAmountse consulta el GSI y se añaden progresivamente claves de ordenación para limitar los resultados.

DynamoDbIndex<OrderItem> index = orderTable.index("OrdersByStatusDateAmount"); // All PENDING orders for customer-123. SdkIterable<Page<OrderItem>> allPending = index.query(q -> q .queryConditional(QueryConditional.keyEqualTo(k -> k .addPartitionValue("customer-123") .addPartitionValue("PENDING")))); // PENDING orders on a specific date. SdkIterable<Page<OrderItem>> pendingOnDate = index.query(q -> q .queryConditional(QueryConditional.keyEqualTo(k -> k .addPartitionValue("customer-123") .addPartitionValue("PENDING") .addSortValue("2025-11-04")))); // PENDING orders on a specific date with amount greater than 100. SdkIterable<Page<OrderItem>> filtered = index.query(q -> q .queryConditional(QueryConditional.sortGreaterThan(k -> k .addPartitionValue("customer-123") .addPartitionValue("PENDING") .addSortValue("2025-11-04") .addSortValue(100))));

Para obtener más información, consulte la Multi-key compatibilidad con Global Secondary Index en DynamoDB.