Java (AWS SDK v2) での DynamoDB Scan

scanPaginatorLastEvaluatedKey を代わりに面倒みてくれます。そして次に多くの人が手を伸ばすつまみ — .limit(...) — は、同じスキャンを遅く、そしてわずかに高くします。そもそも Scan を完全に避けるべきときについては Query と Scan の比較を参照してください。

コード

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;

public class ScanExample {
    public static void main(String[] args) {
        try (DynamoDbClient ddb = DynamoDbClient.builder()
                .region(Region.US_EAST_1)
                .build()) {

            Map<String, String> names = new HashMap<>();
            names.put("#filter0", "Year");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":filterValue0", AttributeValue.builder().n("2010").build());

            ScanRequest request = ScanRequest.builder()
                    .tableName("Music")
                    .filterExpression("#filter0 >= :filterValue0")
                    .expressionAttributeNames(names)
                    .expressionAttributeValues(values)
                    .build();

            List<Map<String, AttributeValue>> items = new ArrayList<>();
            for (ScanResponse page : ddb.scanPaginator(request)) {
                items.addAll(page.items());
            }
            System.out.println("Matched " + items.size() + " items");
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
        }
    }
}

.limit(25) は 3 リクエストを 25 に変え、しかも高くつく

フィクスチャにはそれぞれ約 3.9 KB の 600 曲が入っており、そのうち 8 曲が条件に合致します。書いたとおりに例を実行し、次に .limit(25) を付けて実行します。

リクエストの形往復回数読み取りユニット返ったアイテム数
書いたとおり3284.58
.limit(25)25288.08

キャパシティはページ単位で、4 KB の境界に切り上げて課金されます。したがって 1 MB の読み取り 1 回を小さな 24 回に切り刻めば、その切り上げを 24 回払うことになります。25 回目のリクエストがもう 1 つの意外な点です。24 ページ目でテーブルは読み終わっていたのに LastEvaluatedKey が返り、ページネーターがもう一度尋ねて scannedCount=0 を得ました。DynamoDB は「もうデータはない」ことを、短いページを返すことではなく、そのキーを省くことで知らせます。そして Limit の境界では、まだ分かっていないのです。

.limit(...) は、ライブのテーブルをスロットリングさせたくないバックグラウンドジョブのための、キャパシティ平準化のつまみです。スキャンを安く、あるいは短くする手段ではありません。

エイリアスは様式ではない

#filter0 を外して Year を直接フィルターに使うと、SDK は awsErrorDetails() を通じてこう表面化させます。

DynamoDbException / ValidationException /
Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: Year
/ http 400

Year は 573 個の予約語のひとつです。この SDK のページネーターのエラーはどれもそうですが、これは scanPaginator(request) を呼んだときではなく for ループの最初の反復で届くので、try はループを包む必要があります。

2026-07-28 に、OpenJDK 26.0.1 上の software.amazon.awssdk:dynamodb 2.49.4 で DynamoDB Local(amazon/dynamodb-local)に対して測定しました。

解説

  • 最初の 2 ページは 0 件を返します。このフィルターではページごとの結果が 0、0、8 件で、読み取りユニットは 128.5、128.5、27.5 です。filterExpression は読み取りの後に走るので、その 2 つの空のレスポンスにも満額かかります。そして if (page.items().isEmpty()) break はどれも、テーブルが空だと報告します。
  • ddb.scanPaginator(request).items() はページを 1 つの Iterable<Map<String, AttributeValue>> に平坦化し、背後でページングするので、アイテムだけが欲しいときに入れ子のループを畳めます。SdkIterable なので .stream() も使え、ここでは .items().stream().count() が 8 を返します。
  • ScanIterable は反復のたびにスキャンを走らせ直します。遅延評価であってキャッシュではありません。同じオブジェクトを 2 周すればリクエストも 2 回送られ、課金も 2 回です。例のように、一度 List に汲み出しましょう。
  • ビルダーでは数値は String ですAttributeValue.builder().n("2010")java.lang.String を取ります。DynamoDB が数値を 10 進のテキストとして運ぶからです。int を渡してもコンパイルできません。
  • .segment(...) / .totalSegments(...) はテーブル全体のスキャンをワーカー間で分割し、それぞれが自分のページネーターを持ちます。これは実時間を割り算しますが、消費するキャパシティは同じです。

ビジュアルに行う

予約語チェッカーは、属性名を AWS の完全なリストに照らして走らせ、ExpressionAttributeNames のマップを返します。YearNameSizeStatus がどれも押さえられていることを ValidationException 1 つずつ学ぶより速いです。

ScanRequest に組み込む前に実際のテーブルでフィルターを試すには、DynoTable をダウンロードして、結果をグリッドでページングしてください。

関連する例

参考資料

このリクエストをビジュアルに組み立てる

この操作を無料の DynamoDB クエリビルダーで組み立て — キー条件、フィルタ、インデックス、Limit、ソート順、ページネーションループ — 実行可能な SDK v3・CLI・boto3 のプログラムとしてコピーして戻れます。

DynamoDB クエリビルダーを開く

Console なしで DynamoDB を扱う

DynamoDB では実行できない本物の SQL(JOINs、GROUP BY、集計)を実行する高速な DynamoDB デスクトップクライアント。ビジュアル編集と、あなた自身の Bedrock キーで動く AI エージェントを備えています。

30日間無料トライアル、クレジットカード不要 — その後は期限のない Free プラン。