View a markdown version of this page

Gunakan indeks sekunder - AWS SDK for Java 2.x

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Gunakan indeks sekunder

Kunci utama tabel mendefinisikan indeks utama, yang menentukan bagaimana DynamoDB menyimpan dan mengambil item secara default.

Indeks sekunder menyediakan kunci alternatif yang Anda gunakan dalam operasi kueri dan pemindaian. Indeks sekunder global (GSI) memiliki kunci partisi dan kunci pengurutan opsional yang dapat berbeda dari yang ada di tabel dasar. Sebaliknya, indeks sekunder lokal (LSI) berbagi kunci partisi dari indeks primer tetapi menentukan kunci pengurutan yang berbeda.

Tentukan kunci untuk indeks sekunder global dan lokal

Atribut yang berpartisipasi dalam indeks sekunder memerlukan @DynamoDbSecondarySortKey anotasi @DynamoDbSecondaryPartitionKey atau anotasi.

Kelas berikut menunjukkan anotasi untuk dua indeks. GSI bernama SubjectLastPostedDateIndexmenggunakan Subject atribut untuk kunci partisi dan LastPostedDateTime untuk kunci sortir. LSI bernama ForumLastPostedDateIndexmenggunakan ForumName sebagai kunci partisi dan LastPostedDateTime sebagai kunci sortir.

Perhatikan bahwa Subject atribut tersebut memiliki peran ganda. Ini adalah kunci sortir kunci primer dan kunci partisi dari GSI bernama SubjectLastPostedDateIndex.

MessageThread kelas

MessageThreadKelas ini cocok untuk digunakan sebagai kelas data untuk tabel Thread contoh di Amazon DynamoDB Developer Guide.

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 + '}'; } }

Buat indeks

Dimulai dengan versi 2.20.86 SDK for Java, createTable() metode ini secara otomatis menghasilkan indeks sekunder dari anotasi kelas data. Secara default, semua atribut dari tabel dasar disalin ke indeks dan nilai throughput yang disediakan adalah 20 unit kapasitas baca dan 20 unit kapasitas tulis.

Namun, jika Anda menggunakan versi SDK sebelum 2.20.86, Anda perlu membuat indeks bersama dengan tabel seperti yang ditunjukkan pada contoh berikut. Contoh ini membangun dua indeks untuk tabel. Thread Parameter builder memiliki metode untuk mengkonfigurasi kedua jenis indeks seperti yang ditunjukkan setelah baris komentar 1 dan 2. Anda menggunakan indexName() metode pembuat indeks untuk mengaitkan nama indeks yang ditentukan dalam anotasi kelas data dengan jenis indeks yang dimaksud.

Kode ini mengkonfigurasi semua atribut tabel untuk berakhir di kedua indeks setelah baris komentar 3 dan 4. Informasi selengkapnya tentang proyeksi atribut tersedia di Panduan Pengembang 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)) ) );

Kueri dengan menggunakan indeks

Contoh berikut query indeks ForumLastPostedDateIndexsekunder lokal.

Mengikuti baris komentar 2, Anda membuat QueryConditionalobjek yang diperlukan saat memanggil metode DynamoDbIndex.query().

Anda mendapatkan referensi ke indeks yang ingin Anda kueri setelah baris komentar 3 dengan meneruskan nama indeks. Mengikuti baris komentar 4, Anda memanggil query() metode pada indeks yang lewat di QueryConditional objek.

Anda juga mengonfigurasi kueri untuk mengembalikan tiga nilai atribut seperti yang ditunjukkan setelah baris komentar 5. Jika tidak attributesToProject() dipanggil, query mengembalikan semua nilai atribut. Perhatikan bahwa nama atribut yang ditentukan dimulai dengan huruf kecil. Nama atribut ini cocok dengan yang digunakan dalam tabel, belum tentu nama atribut dari kelas data.

Mengikuti baris komentar 6, ulangi hasil dan log setiap item yang dikembalikan oleh kueri dan juga menyimpannya dalam daftar untuk kembali ke pemanggil.

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; }

Item berikut ada dalam database sebelum query dijalankan.

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}

Pernyataan logging pada baris 1 dan 6 menghasilkan output konsol berikut.

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}

Kueri mengembalikan item dengan forumName nilai Forum02 dan lastPostedDateTime nilai lebih besar dari atau sama dengan 2023.03.31. Hasilnya menunjukkan message nilai dengan string kosong meskipun message atribut memiliki nilai dalam indeks. Ini karena atribut pesan tidak diproyeksikan oleh kode setelah baris komentar 5.

Gunakan kunci komposit untuk indeks sekunder global (GSI)

SDK for Java 2.x DynamoDB Enhanced Client mendukung kunci komposit untuk indeks sekunder global. Anda dapat menentukan hingga empat atribut kunci partisi dan empat atribut kunci pengurutan untuk GSI tunggal. Ini menghilangkan kebutuhan untuk menggabungkan beberapa atribut menjadi satu kunci string di sisi klien.

Gunakan order parameter pada @DynamoDbSecondaryPartitionKey dan @DynamoDbSecondarySortKey anotasi untuk menentukan posisi setiap atribut dalam kunci komposit. orderParameter menerima nilai dari Orderenum (bagian dari Enhanced DynamoDB Client):,,, dan. FIRST SECOND THIRD FOURTH

Anotasi kelas data dengan anotasi kunci komposit

Contoh berikut memodelkan tabel pesanan. Tabel dasar digunakan orderId sebagai kunci partisi. GSI bernama OrdersByStatusDateAmountmenggunakan kunci partisi komposit customerId danstatus, dan kunci sortir komposit dari orderDate danamount. Desain ini memungkinkan Anda menanyakan pesanan pelanggan yang difilter berdasarkan status, tanggal, dan ambang batas jumlah.

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; } }

Kueri dengan menggunakan indeks kunci komposit

Saat Anda menanyakan indeks kunci komposit, gunakan addSortValue() metode addPartitionValue() dan pada pembuat Key. Tambahkan nilai dalam urutan yang sama dengan Order nilai yang ditentukan dalam anotasi. Semua kunci partisi diperlukan. Kunci sortir bersifat opsional dan dapat disediakan dari kiri ke kanan.

Anda membuat QueryConditionalobjek untuk menentukan kondisi kueri. Gunakan keyEqualTo untuk kecocokan persis, atau kondisi kunci pengurutan sepertisortGreaterThan,sortLessThan,sortBetween, atausortBeginsWith. Kondisi ini berlaku untuk kunci pengurutan terakhir yang Anda berikan.

Contoh berikut menanyakan OrdersByStatusDateAmountGSI, secara progresif menambahkan kunci pengurutan untuk mempersempit hasil.

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

Untuk informasi selengkapnya, lihat Multi-key dukungan untuk Indeks Sekunder Global di DynamoDB.