Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Bekerja dengan hasil paginasi: pemindaian dan kueri
Metodescan
, query
dan batch
metode DynamoDB Enhanced API Client mengembalikan respons dengan satu halaman atau lebih. Sebuah halaman berisi satu atau lebih item. Kode Anda dapat memproses respons per halaman atau dapat memproses item individual.
Respons paginasi yang dikembalikan oleh DynamoDbEnhancedClient
klien sinkron mengembalikan PageIterableDynamoDbEnhancedAsyncClient
asinkron mengembalikan objek. PagePublisher
Bagian ini melihat pemrosesan hasil paginasi dan memberikan contoh yang menggunakan pemindaian dan kueriAPIs.
Memindai tabel
scan
Pertama, kita menjelajahi PageIterable
antarmuka dengan melihat scan
metode kelas pemetaan sinkron,. DynamoDbTable
Gunakan sinkron API
Contoh berikut menunjukkan scan
metode yang menggunakan ekspresi
Ekspresi pemfilteran yang ditampilkan setelah baris komentar 2 membatasi ProductCatalog
item yang dikembalikan ke item dengan nilai harga antara 8,00 dan 80,00 secara inklusif.
Contoh ini juga mengecualikan isbn
nilai dengan menggunakan attributesToProject
metode yang ditampilkan setelah baris komentar 1.
Setelah komentar baris 3, PageIterable
objekpagedResults
,, dikembalikan oleh scan
metode. stream
Metode PageIterable
mengembalikan java.util.Stream
Dimulai dengan baris komentar 4, contoh menunjukkan dua variasi mengakses ProductCatalog
item. Versi setelah baris komentar 4a mengalir melalui setiap halaman dan mengurutkan dan mencatat item di setiap halaman. Versi setelah baris komentar 4b melewatkan iterasi halaman dan mengakses item secara langsung.
PageIterable
Antarmuka menawarkan beberapa cara untuk memproses hasil karena dua antarmuka induknya— java.lang.Iterable
SdkIterable
Iterable
membawaforEach
, iterator
dan spliterator
metode, dan SdkIterable
membawa stream
metode.
public static void scanSync(DynamoDbTable<ProductCatalog> productCatalog) { Map<String, AttributeValue> expressionValues = Map.of( ":min_value", numberValue(8.00), ":max_value", numberValue(80.00)); ScanEnhancedRequest request = ScanEnhancedRequest.builder() .consistentRead(true) // 1. the 'attributesToProject()' method allows you to specify which values you want returned. .attributesToProject("id", "title", "authors", "price") // 2. Filter expression limits the items returned that match the provided criteria. .filterExpression(Expression.builder() .expression("price >= :min_value AND price <= :max_value") .expressionValues(expressionValues) .build()) .build(); // 3. A PageIterable object is returned by the scan method. PageIterable<ProductCatalog> pagedResults = productCatalog.scan(request); logger.info("page count: {}", pagedResults.stream().count()); // 4. Log the returned ProductCatalog items using two variations. // 4a. This version sorts and logs the items of each page. pagedResults.stream().forEach(p -> p.items().stream() .sorted(Comparator.comparing(ProductCatalog::price)) .forEach( item -> logger.info(item.toString()) )); // 4b. This version sorts and logs all items for all pages. pagedResults.items().stream() .sorted(Comparator.comparing(ProductCatalog::price)) .forEach( item -> logger.info(item.toString()) ); }
Gunakan asinkron API
scan
Metode asinkron mengembalikan hasil sebagai objek. PagePublisher
PagePublisher
Antarmuka memiliki dua subscribe
metode yang dapat Anda gunakan untuk memproses halaman respons. Salah satu subscribe
metode berasal dari antarmuka org.reactivestreams.Publisher
induk. Untuk memproses halaman menggunakan opsi pertama ini, berikan Subscriber
instance ke subscribe
metode. Contoh pertama yang berikut menunjukkan penggunaan subscribe
metode.
subscribe
Metode kedua berasal dari SdkPublishersubscribe
menerima Consumer
Subscriber
. Variasi subscribe
metode ini ditunjukkan pada contoh kedua berikut.
Contoh berikut menunjukkan versi asinkron dari scan
metode yang menggunakan ekspresi filter yang sama yang ditunjukkan pada contoh sebelumnya.
Setelah baris komentar 3, DynamoDbAsyncTable.scan
mengembalikan PagePublisher
objek. Pada baris berikutnya, kode membuat instance org.reactivestreams.Subscriber
antarmuka,ProductCatalogSubscriber
, yang berlangganan baris PagePublisher
setelah komentar 4.
Subscriber
Objek mengumpulkan ProductCatalog
item dari setiap halaman dalam onNext
metode setelah baris komentar 8 dalam contoh ProductCatalogSubscriber
kelas. Item disimpan dalam List
variabel pribadi dan diakses dalam kode panggilan dengan ProductCatalogSubscriber.getSubscribedItems()
metode. Ini disebut setelah baris komentar 5.
Setelah daftar diambil, kode mengurutkan semua ProductCatalog
item berdasarkan harga dan mencatat setiap item.
CountDownLatchProductCatalogSubscriber
kelas memblokir thread panggilan sampai semua item telah ditambahkan ke daftar sebelum melanjutkan setelah baris komentar 5.
public static void scanAsync(DynamoDbAsyncTable productCatalog) { ScanEnhancedRequest request = ScanEnhancedRequest.builder() .consistentRead(true) .attributesToProject("id", "title", "authors", "price") .filterExpression(Expression.builder() // 1. :min_value and :max_value are placeholders for the values provided by the map .expression("price >= :min_value AND price <= :max_value") // 2. Two values are needed for the expression and each is supplied as a map entry. .expressionValues( Map.of( ":min_value", numberValue(8.00), ":max_value", numberValue(400_000.00))) .build()) .build(); // 3. A PagePublisher object is returned by the scan method. PagePublisher<ProductCatalog> pagePublisher = productCatalog.scan(request); ProductCatalogSubscriber subscriber = new ProductCatalogSubscriber(); // 4. Subscribe the ProductCatalogSubscriber to the PagePublisher. pagePublisher.subscribe(subscriber); // 5. Retrieve all collected ProductCatalog items accumulated by the subscriber. subscriber.getSubscribedItems().stream() .sorted(Comparator.comparing(ProductCatalog::price)) .forEach(item -> logger.info(item.toString())); // 6. Use a Consumer to work through each page. pagePublisher.subscribe(page -> page .items().stream() .sorted(Comparator.comparing(ProductCatalog::price)) .forEach(item -> logger.info(item.toString()))) .join(); // If needed, blocks the subscribe() method thread until it is finished processing. // 7. Use a Consumer to work through each ProductCatalog item. pagePublisher.items() .subscribe(product -> logger.info(product.toString())) .exceptionally(failure -> { logger.error("ERROR - ", failure); return null; }) .join(); // If needed, blocks the subscribe() method thread until it is finished processing. }
private static class ProductCatalogSubscriber implements Subscriber<Page<ProductCatalog>> { private CountDownLatch latch = new CountDownLatch(1); private Subscription subscription; private List<ProductCatalog> itemsFromAllPages = new ArrayList<>(); @Override public void onSubscribe(Subscription sub) { subscription = sub; subscription.request(1L); try { latch.await(); // Called by main thread blocking it until latch is released. } catch (InterruptedException e) { throw new RuntimeException(e); } } @Override public void onNext(Page<ProductCatalog> productCatalogPage) { // 8. Collect all the ProductCatalog instances in the page, then ask the publisher for one more page. itemsFromAllPages.addAll(productCatalogPage.items()); subscription.request(1L); } @Override public void onError(Throwable throwable) { } @Override public void onComplete() { latch.countDown(); // Call by subscription thread; latch releases. } List<ProductCatalog> getSubscribedItems() { return this.itemsFromAllPages; } }
Contoh cuplikan berikut menggunakan versi PagePublisher.subscribe
metode yang menerima baris Consumer
setelah komentar 6. Parameter lambda Java mengkonsumsi halaman, yang selanjutnya memproses setiap item. Dalam contoh ini, setiap halaman diproses dan item pada setiap halaman diurutkan dan kemudian dicatat.
// 6. Use a Consumer to work through each page. pagePublisher.subscribe(page -> page .items().stream() .sorted(Comparator.comparing(ProductCatalog::price)) .forEach(item -> logger.info(item.toString()))) .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
items
Metode PagePublisher
membuka bungkus contoh model sehingga kode Anda dapat memproses item secara langsung. Pendekatan ini ditunjukkan dalam cuplikan berikut.
// 7. Use a Consumer to work through each ProductCatalog item. pagePublisher.items() .subscribe(product -> logger.info(product.toString())) .exceptionally(failure -> { logger.error("ERROR - ", failure); return null; }) .join(); // If needed, blocks the subscribe() method thread until it is finished processing.
Mengkueri Tabel
query()
DynamoDbTable
kelas menemukan item berdasarkan nilai kunci primer. @DynamoDbPartitionKey
Anotasi dan @DynamoDbSortKey
anotasi opsional digunakan untuk menentukan kunci utama pada kelas data Anda.
query()
Metode ini membutuhkan nilai kunci partisi yang menemukan item yang cocok dengan nilai yang diberikan. Jika tabel Anda juga mendefinisikan kunci pengurutan, Anda dapat menambahkan nilai untuk itu ke kueri Anda sebagai kondisi perbandingan tambahan untuk menyempurnakan hasilnya.
Kecuali untuk memproses hasil, versi sinkron dan asinkron bekerja sama. query()
Seperti halnya scan
API, query
API mengembalikan a PageIterable
untuk panggilan sinkron dan panggilan PagePublisher
untuk asinkron. Kami membahas penggunaan PageIterable
dan PagePublisher
sebelumnya di bagian pemindaian.
Query
contoh metode
Contoh kode query()
metode yang mengikuti menggunakan MovieActor
kelas. Kelas data mendefinisikan kunci primer komposit yang terdiri dari movie
atribut untuk kunci partisi dan actor
atribut untuk kunci sortir.
Kelas ini juga memberi sinyal bahwa ia menggunakan indeks sekunder global bernama acting_award_year
. Kunci primer komposit indeks terdiri dari actingaward
atribut untuk kunci partisi dan actingyear
untuk kunci sortir. Kemudian dalam topik ini, ketika kita menunjukkan cara membuat dan menggunakan indeks, kita akan merujuk ke acting_award_year
indeks.
package org.example.tests.model; import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; 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.Objects; @DynamoDbBean public class MovieActor implements Comparable<MovieActor> { private String movieName; private String actorName; private String actingAward; private Integer actingYear; private String actingSchoolName; @DynamoDbPartitionKey @DynamoDbAttribute("movie") public String getMovieName() { return movieName; } public void setMovieName(String movieName) { this.movieName = movieName; } @DynamoDbSortKey @DynamoDbAttribute("actor") public String getActorName() { return actorName; } public void setActorName(String actorName) { this.actorName = actorName; } @DynamoDbSecondaryPartitionKey(indexNames = "acting_award_year") @DynamoDbAttribute("actingaward") public String getActingAward() { return actingAward; } public void setActingAward(String actingAward) { this.actingAward = actingAward; } @DynamoDbSecondarySortKey(indexNames = {"acting_award_year", "movie_year"}) @DynamoDbAttribute("actingyear") public Integer getActingYear() { return actingYear; } public void setActingYear(Integer actingYear) { this.actingYear = actingYear; } @DynamoDbAttribute("actingschoolname") public String getActingSchoolName() { return actingSchoolName; } public void setActingSchoolName(String actingSchoolName) { this.actingSchoolName = actingSchoolName; } @Override public String toString() { final StringBuffer sb = new StringBuffer("MovieActor{"); sb.append("movieName='").append(movieName).append('\''); sb.append(", actorName='").append(actorName).append('\''); sb.append(", actingAward='").append(actingAward).append('\''); sb.append(", actingYear=").append(actingYear); sb.append(", actingSchoolName='").append(actingSchoolName).append('\''); sb.append('}'); return sb.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MovieActor that = (MovieActor) o; return Objects.equals(movieName, that.movieName) && Objects.equals(actorName, that.actorName) && Objects.equals(actingAward, that.actingAward) && Objects.equals(actingYear, that.actingYear) && Objects.equals(actingSchoolName, that.actingSchoolName); } @Override public int hashCode() { return Objects.hash(movieName, actorName, actingAward, actingYear, actingSchoolName); } @Override public int compareTo(MovieActor o) { if (this.movieName.compareTo(o.movieName) != 0){ return this.movieName.compareTo(o.movieName); } else { return this.actorName.compareTo(o.actorName); } } }
Contoh kode yang mengikuti kueri terhadap item berikut.
MovieActor{movieName='movie01', actorName='actor0', actingAward='actingaward0', actingYear=2001, actingSchoolName='null'} MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'} MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'} MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'} MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'} MovieActor{movieName='movie02', actorName='actor0', actingAward='actingaward0', actingYear=2002, actingSchoolName='null'} MovieActor{movieName='movie02', actorName='actor1', actingAward='actingaward1', actingYear=2002, actingSchoolName='actingschool1'} MovieActor{movieName='movie02', actorName='actor2', actingAward='actingaward2', actingYear=2002, actingSchoolName='actingschool2'} MovieActor{movieName='movie02', actorName='actor3', actingAward='actingaward3', actingYear=2002, actingSchoolName='null'} MovieActor{movieName='movie02', actorName='actor4', actingAward='actingaward4', actingYear=2002, actingSchoolName='actingschool4'} MovieActor{movieName='movie03', actorName='actor0', actingAward='actingaward0', actingYear=2003, actingSchoolName='null'} MovieActor{movieName='movie03', actorName='actor1', actingAward='actingaward1', actingYear=2003, actingSchoolName='actingschool1'} MovieActor{movieName='movie03', actorName='actor2', actingAward='actingaward2', actingYear=2003, actingSchoolName='actingschool2'} MovieActor{movieName='movie03', actorName='actor3', actingAward='actingaward3', actingYear=2003, actingSchoolName='null'} MovieActor{movieName='movie03', actorName='actor4', actingAward='actingaward4', actingYear=2003, actingSchoolName='actingschool4'}
Kode berikut mendefinisikan dua QueryConditionalQueryConditionals
bekerja dengan nilai kunci — baik kunci partisi saja atau dalam kombinasi dengan kunci sortir — dan sesuai dengan ekspresi kondisional kunci dari layanan DynamoDB. API Setelah baris komentar 1, contoh mendefinisikan keyEqual
instance yang cocok dengan item dengan nilai partisi. movie01
Contoh ini juga mendefinisikan ekspresi filter yang memfilter item apa pun yang tidak actingschoolname
aktif setelah baris komentar 2.
Setelah baris komentar 3, contoh menunjukkan QueryEnhancedRequestDynamoDbTable.query()
metode. Objek ini menggabungkan kondisi kunci dan filter yang SDK digunakan untuk menghasilkan permintaan ke layanan DynamoDB.
public static void query(DynamoDbTable movieActorTable) { // 1. Define a QueryConditional instance to return items matching a partition value. QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b.partitionValue("movie01")); // 1a. Define a QueryConditional that adds a sort key criteria to the partition value criteria. QueryConditional sortGreaterThanOrEqualTo = QueryConditional.sortGreaterThanOrEqualTo(b -> b.partitionValue("movie01").sortValue("actor2")); // 2. Define a filter expression that filters out items whose attribute value is null. final Expression filterOutNoActingschoolname = Expression.builder().expression("attribute_exists(actingschoolname)").build(); // 3. Build the query request. QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder() .queryConditional(keyEqual) .filterExpression(filterOutNoActingschoolname) .build(); // 4. Perform the query. PageIterable<MovieActor> pagedResults = movieActorTable.query(tableQuery); logger.info("page count: {}", pagedResults.stream().count()); // Log number of pages. pagedResults.items().stream() .sorted() .forEach( item -> logger.info(item.toString()) // Log the sorted list of items. );
Berikut ini adalah output dari menjalankan metode. Output menampilkan item dengan movieName
nilai movie01 dan tidak menampilkan item yang actingSchoolName
sama dengan. null
2023-03-05 13:11:05 [main] INFO org.example.tests.QueryDemo:46 - page count: 1 2023-03-05 13:11:05 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor1', actingAward='actingaward1', actingYear=2001, actingSchoolName='actingschool1'} 2023-03-05 13:11:05 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'} 2023-03-05 13:11:05 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}
Dalam variasi permintaan kueri berikut yang ditampilkan sebelumnya setelah baris komentar 3, kode menggantikan keyEqual
QueryConditional
dengan sortGreaterThanOrEqualTo
QueryConditional
yang didefinisikan setelah baris komentar 1a. Kode berikut juga menghapus ekspresi filter.
QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder() .queryConditional(sortGreaterThanOrEqualTo)
Karena tabel ini memiliki kunci primer komposit, semua QueryConditional
instance memerlukan nilai kunci partisi. QueryConditional
metode yang dimulai dengan sort...
menunjukkan bahwa kunci pengurutan diperlukan. Hasilnya tidak diurutkan.
Output berikut menampilkan hasil dari query. Kueri mengembalikan item yang memiliki movieName
nilai sama dengan movie01 dan hanya item yang memiliki actorName
nilai yang lebih besar dari atau sama dengan actor2. Karena filter telah dihapus, kueri mengembalikan item yang tidak memiliki nilai untuk actingSchoolName
atribut.
2023-03-05 13:15:00 [main] INFO org.example.tests.QueryDemo:46 - page count: 1 2023-03-05 13:15:00 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor2', actingAward='actingaward2', actingYear=2001, actingSchoolName='actingschool2'} 2023-03-05 13:15:00 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor3', actingAward='actingaward3', actingYear=2001, actingSchoolName='null'} 2023-03-05 13:15:00 [main] INFO org.example.tests.QueryDemo:51 - MovieActor{movieName='movie01', actorName='actor4', actingAward='actingaward4', actingYear=2001, actingSchoolName='actingschool4'}