DynamoDBのS3エクスポートにフィルタ指定が追加。FullとIncrementalで試してみた
はじめに
2026-10-01 に、DynamoDB の Export to S3 が Filtered export に対応しました。Full export と Incremental export の両方で使え、GovCloud を除く全リージョンで利用できます。
指定できる3つの式
Filtered export では、--filter-specification に次の3つの式を指定できます。
| 式 | 書き方の規則 | 読む量 |
|---|---|---|
| KeyCondition | Query と同じ。PK は単一の値との等価条件、SK は任意の条件 | 減る |
| Filter | Scan と同じ。読んだ後に適用される | 減らない |
| Projection | 出力する属性を指定する | — |
export は非同期に実行され、読み取りキャパシティ(RCU)を消費せず、テーブルの性能にも影響しません。料金は従来の export と同じ単価で、フィルタの追加料金はありません。KeyCondition で PK を1つの値に絞った export は、読んだ分だけが課金対象で、最小課金は1回の export あたり 10MB です。Incremental export の最小課金も 10MB です。
検証環境
- リージョン:ap-northeast-1
- AWS CLI:aws-cli/2.37.8
- テーブル:PK は TenantId、SK は WorkOrderId、オンデマンド、PITR 有効
- 属性:Status / Priority / CustomerEmail / CustomerPhone / AmountDue / UpdatedAt
- 件数:tenant-A 400件、tenant-B 400件、tenant-C 200件の合計1,000件(すべて架空のデータ)
PK でテナントを管理するテーブルを想定した例です。1,000件程度ならフィルタなしの export でも困らない規模ですが、各式がどのように出力を絞るかを確認する目的なので、少量のデータで試しています。
Full export で絞り込む
KeyCondition で PK の値と SK の前方一致を指定する
tenant-A のうち、WorkOrderId が WO-01 で始まる項目だけを出力しました。指定を f1-filter.json に保存し、--filter-specification で渡しました。
{
"KeyConditionExpression": "#tid = :tid AND begins_with(#wo, :prefix)",
"ExpressionAttributeNames": {"#tid": "TenantId", "#wo": "WorkOrderId"},
"ExpressionAttributeValues": {":tid": {"S": "tenant-A"}, ":prefix": {"S": "WO-01"}}
}
aws dynamodb export-table-to-point-in-time --table-arn <テーブルARN> --export-time 2026-10-03T09:54:00Z --s3-bucket <バケット名> --s3-prefix f1/ --export-format DYNAMODB_JSON --filter-specification file://f1-filter.json
出力は100件で、すべて tenant-A の WO-0100〜WO-0199 でした。同じ条件の Query(--select COUNT)も100件でした。1行目は次のとおりです。
{"Item":{"WorkOrderId":{"S":"WO-0100"},"TenantId":{"S":"tenant-A"},"CustomerPhone":{"S":"+81-90-0000-0100"},"UpdatedAt":{"S":"2026-10-03T09:00:00Z"},"Priority":{"S":"NORMAL"},"AmountDue":{"N":"1100"},"Status":{"S":"IN_PROGRESS"},"CustomerEmail":{"S":"user0100@example.com"}}}
Full export の各行は、Item をキーに持つ DynamoDB JSON 形式でした。適用したフィルタ指定は、export を要求した直後のレスポンスには含まれません。DescribeExport の FilterSpecification で確認できます。
Filter と Projection で項目と属性を絞る
Status が COMPLETED の項目に絞り、出力する属性を4つにしました。Status は予約語のため、式の中では別名(#st)を使っています。指定を f2-filter.json に保存して実行しました。
{
"FilterExpression": "#st = :done",
"ProjectionExpression": "#tid, #wo, #st, #amt",
"ExpressionAttributeNames": {"#tid": "TenantId", "#wo": "WorkOrderId", "#st": "Status", "#amt": "AmountDue"},
"ExpressionAttributeValues": {":done": {"S": "COMPLETED"}}
}
aws dynamodb export-table-to-point-in-time --table-arn <テーブルARN> --export-time 2026-10-03T09:54:00Z --s3-bucket <バケット名> --s3-prefix f2/ --export-format DYNAMODB_JSON --filter-specification file://f2-filter.json
出力は333件で、内訳は tenant-A が133件、tenant-B が133件、tenant-C が67件でした。1行目は次のとおりです。
{"Item":{"AmountDue":{"N":"1002"},"Status":{"S":"COMPLETED"},"TenantId":{"S":"tenant-A"},"WorkOrderId":{"S":"WO-0002"}}}
全行が Status=COMPLETED で、CustomerEmail と CustomerPhone を含む指定外の属性は出力されませんでした。連絡先を除いた出力は、Projection に残す属性を並べるだけで作れます。
Incremental export で絞り込む
対象期間内の変更と KeyCondition
ExportFromTime から ExportToTime までの15分間を対象期間にしました。1,000件の投入は対象期間の開始前に終えており、開始後に次の変更を加えました。
| 変更 | TenantId | WorkOrderId | 変更前 → 後 |
|---|---|---|---|
| 更新 | tenant-A | WO-0003 | OPEN → COMPLETED、AmountDue 1003 → 999001 |
| 更新 | tenant-A | WO-0002 | COMPLETED → OPEN、AmountDue 1002 → 999002 |
| 更新 | tenant-A | WO-0008 | COMPLETED のまま、AmountDue 1008 → 999003 |
| 更新 | tenant-B | WO-0003 | OPEN → COMPLETED、AmountDue 1003 → 999004 |
| 削除 | tenant-A | WO-0005 | 削除前は COMPLETED |
| 削除 | tenant-A | WO-0004 | 削除前は IN_PROGRESS |
| 追加 | tenant-A | WO-0401 | COMPLETED、AmountDue 500 |
| 追加して削除 | tenant-A | WO-0402 | 追加後に対象期間内で削除 |
対象期間は incremental-spec.json に指定しました。
{"ExportFromTime": "2026-10-03T09:54:30Z", "ExportToTime": "2026-10-03T10:09:30Z", "ExportViewType": "NEW_AND_OLD_IMAGES"}
tenant-A だけに絞る KeyCondition は、i1-filter.json として保存しました。この export を以下 I1 と呼びます。
{
"KeyConditionExpression": "#tid = :tid",
"ExpressionAttributeNames": {"#tid": "TenantId"},
"ExpressionAttributeValues": {":tid": {"S": "tenant-A"}}
}
aws dynamodb export-table-to-point-in-time --table-arn <テーブルARN> --export-type INCREMENTAL_EXPORT --incremental-export-specification file://incremental-spec.json --s3-bucket <バケット名> --s3-prefix i1/ --export-format DYNAMODB_JSON --filter-specification file://i1-filter.json
出力は6件で、すべて tenant-A の項目でした。各行は Keys / Metadata / NewImage / OldImage を持つ構造で、Full export の Item とは形が異なります。Projection を指定していないため、各イメージは8属性でした。
更新した3件(WO-0002、WO-0003、WO-0008)は、OldImage と NewImage の両方が出力されました。削除した2件(WO-0004、WO-0005)は OldImage のみ、追加した1件(WO-0401)は NewImage のみでした。tenant-B の WO-0003 は、PK の値が KeyCondition と異なるため含まれませんでした。追加して対象期間内で削除した WO-0402 も、出力に含まれませんでした。
Filter は最新イメージで評価される
KeyCondition は付けず、同じ対象期間に対して Filter と Projection を指定しました。指定は f2-filter.json と同じ(Status が COMPLETED の Filter と、4属性の Projection)で、i2-filter.json として保存しています。この export を以下 I2 と呼びます。実行したコマンドは、前の小節のコマンドの --s3-prefix と --filter-specification の値を、i2/ と file://i2-filter.json に置き換えたものです。
出力は5件でした。対象期間内の変更のうち、追加して削除した WO-0402 を除く7件について、I1(KeyCondition のみ)と I2(Filter と Projection)の出力を対応づけます。
| TenantId / WorkOrderId | 変更 | 最新のイメージ | I1(KeyCondition のみ) | I2(Filter: Status=COMPLETED) |
|---|---|---|---|---|
| tenant-A / WO-0003 | OPEN → COMPLETED | COMPLETED | 含まれる | 含まれる |
| tenant-A / WO-0008 | COMPLETED のまま金額変更 | COMPLETED | 含まれる | 含まれる |
| tenant-A / WO-0401 | 追加(COMPLETED) | COMPLETED | 含まれる | 含まれる |
| tenant-A / WO-0005 | 削除(削除前は COMPLETED) | なし(旧イメージで判定) | 含まれる | 含まれる |
| tenant-B / WO-0003 | OPEN → COMPLETED | COMPLETED | 含まれない | 含まれる |
| tenant-A / WO-0002 | COMPLETED → OPEN | OPEN | 含まれる | 含まれない |
| tenant-A / WO-0004 | 削除(削除前は IN_PROGRESS) | なし(旧イメージで判定) | 含まれる | 含まれない |
Incremental export の Filter は、各項目の最新イメージに対して評価されます。削除された項目は、旧イメージで評価されます。
I2 の1行目(tenant-A の WO-0003)を見ると、Projection は OldImage と NewImage の両方に適用されていました。
{"Metadata":{"WriteTimestampMicros":{"N":"1791021301924409"}},"Keys":{"TenantId":{"S":"tenant-A"},"WorkOrderId":{"S":"WO-0003"}},"OldImage":{"AmountDue":{"N":"1003"},"Status":{"S":"OPEN"},"TenantId":{"S":"tenant-A"},"WorkOrderId":{"S":"WO-0003"}},"NewImage":{"AmountDue":{"N":"999001"},"Status":{"S":"COMPLETED"},"TenantId":{"S":"tenant-A"},"WorkOrderId":{"S":"WO-0003"}}}
指定が不正なときのエラー
次の4通りの指定を試したところ、いずれも export が始まる前に ValidationException が返りました。
| 指定 | メッセージ |
|---|---|
指定が空({}) |
Invalid FilterSpecification: The specification can not be empty |
| KeyCondition と Filter の両方に TenantId | Invalid FilterExpression: key attributes are not allowed in the filter expression when a KeyConditionExpression is present: TenantId |
KeyCondition の PK で等価以外(#tid > :tid)を使用 |
Invalid KeyConditionExpression: only the equality operator is supported for the partition key: TenantId |
Filter で予約語 Status を別名化せず記述(Status = :done) |
Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: Status |
まとめ
DynamoDB の Export to S3 に今回追加されたフィルタ指定(--filter-specification)は、Full export と Incremental export のどちらでも機能することが確認できました。
更新の多いテーブルから1日1回、その時点のデータをスナップショットとして保存する用途なら、Full export に条件を付けて、必要な項目と属性だけを S3 に書き出せます。
DynamoDB 上の特定条件の項目のみ S3 に保存したい場合や、S3 のプレフィックスでデータをあらかじめ分類しておきたい場合などに、ご活用ください。







