新機能のS3 AnnotationsをCRUDし、Annotation Table + Athenaで横断検索してみた

新機能のS3 AnnotationsをCRUDし、Annotation Table + Athenaで横断検索してみた

2026年6月16日に発表されたAmazon S3 Annotationsを、boto3とAWS CLIから操作してみました。AnnotationのPut/Get/List/Deleteを確認し、Annotation Tableを有効化してAthenaからSQLで横断検索できるところまで検証しています。
2026.06.17

はじめに

2026年6月16日、Amazon S3の新機能「S3 Annotations」が発表されました。S3オブジェクトに対して最大1000個、各最大1MBのカスタムメタデータ(annotation)を付与できる機能です。

従来のS3メタデータとの比較を以下に示します。

項目 user-defined metadata object tags S3 Annotations
上限数 10個 1000個
サイズ上限 リクエストヘッダー内 2KB Key 最大128文字、Value 最大256文字 各1MB
形式 Key-Value(ASCII) Key-Value 任意(JSON、テキスト等)
更新 オブジェクト再PUT必須 個別更新可 個別更新可
ライフサイクル連携
アクセス制御連携 ✅(条件キー)
横断検索(Athena) S3 Inventory経由 Annotation Table

タグはライフサイクルルールやIAM条件キーとの連携に使われる仕組みであり、Annotationsはこれらの上位互換ではありません。

本記事では、boto3およびAWS CLIでAnnotationのCRUD操作を確認し、Annotation Tableを有効化してAthenaによる横断検索まで実施します。

https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-s3-annotations/

検証環境

項目
リージョン ap-northeast-1
バケット種別 汎用 S3 バケット(バージョニング無効)
Python 3.14(rc1)
boto3 1.43.31(2026-06-16 リリース)
botocore 1.43.31
AWS CLI v2.35.6(2026-06-17 リリース)
Athena エンジンバージョン3

本記事の操作はboto3およびAWS CLIで実施しています。

Annotation CRUD 操作(boto3)

boto3 1.43.31で利用可能なannotation関連メソッド:

import boto3

s3 = boto3.client('s3', region_name='ap-northeast-1')
[m for m in dir(s3) if 'annot' in m.lower()]
# ['delete_object_annotation', 'get_object_annotation', 'list_object_annotations',
#  'put_object_annotation', 'update_bucket_metadata_annotation_table_configuration']

以下、バケットにテスト用オブジェクト test-object.txt を配置した状態で操作します。

import json

BUCKET = "my-annotation-demo-bucket"
KEY = "test-object.txt"

PutObjectAnnotation(JSON)

annotation_json = json.dumps({
    "project": "annotation-test",
    "owner": "demo-user",
    "created": "2026-06-17"
})

resp = s3.put_object_annotation(
    Bucket=BUCKET,
    Key=KEY,
    AnnotationName='test-metadata',
    AnnotationPayload=annotation_json.encode()
)
{
    'ETag': '"1fa459dad748f9fcc3be1e3dcc50ea82"',
    'Key': 'test-object.txt',
    'AnnotationName': 'test-metadata',
    'ResponseMetadata': {
        'RequestId': 'XXXXXXXXXXXX',
        'HostId': 'XXXXXXXXXXXX',
        'HTTPStatusCode': 200
    }
}

ResponseMetadataは以降省略します。

PutObjectAnnotation(Plain Text)

resp = s3.put_object_annotation(
    Bucket=BUCKET,
    Key=KEY,
    AnnotationName='ai-summary',
    AnnotationPayload=b'AI-generated summary: A test file for demonstrating S3 Annotations.'
)
{
    'ETag': '"403c26f2a55cdc54cf931b03be006b75"',
    'AnnotationName': 'ai-summary'
}

ListObjectAnnotations

resp = s3.list_object_annotations(Bucket=BUCKET, Key=KEY)
{
    'AnnotationCount': 2,
    'Annotations': [
        {
            'AnnotationName': 'ai-summary',
            'Size': 67,
            'ETag': '"403c26f2a55cdc54cf931b03be006b75"',
            'LastModified': datetime(2026, 6, 17, 1, 37, 36, tzinfo=tzutc()),
            'ChecksumAlgorithm': ['CRC32']
        },
        {
            'AnnotationName': 'test-metadata',
            'Size': 78,
            'ETag': '"1fa459dad748f9fcc3be1e3dcc50ea82"',
            'LastModified': datetime(2026, 6, 17, 1, 37, 36, tzinfo=tzutc()),
            'ChecksumAlgorithm': ['CRC32']
        }
    ]
}

Listで返るETagはオブジェクト本体のETagではなく、各annotationに対して返される値です。

GetObjectAnnotation

resp = s3.get_object_annotation(
    Bucket=BUCKET,
    Key=KEY,
    AnnotationName='test-metadata'
)
body = resp['AnnotationPayload'].read().decode()
# body
'{"project": "annotation-test", "owner": "demo-user", "created": "2026-06-17"}'

# resp(AnnotationPayload 以外)
{
    'ETag': '"1fa459dad748f9fcc3be1e3dcc50ea82"',
    'ContentLength': 78
}

AnnotationPayloadStreamingBody 型で、.read() で本文を取得します。

DeleteObjectAnnotation

resp = s3.delete_object_annotation(
    Bucket=BUCKET,
    Key=KEY,
    AnnotationName='ai-summary'
)
{}  # HTTPStatusCode: 204

削除後にListを再取得して確認します。

resp = s3.list_object_annotations(Bucket=BUCKET, Key=KEY)
{
    'AnnotationCount': 1,
    'Annotations': [
        {
            'AnnotationName': 'test-metadata',
            'Size': 78,
            'ETag': '"1fa459dad748f9fcc3be1e3dcc50ea82"',
            'LastModified': datetime(2026, 6, 17, 1, 37, 36, tzinfo=tzutc()),
            'ChecksumAlgorithm': ['CRC32']
        }
    ]
}

ai-summary が消え、test-metadata のみが残っていることを確認できました。

AWS CLI での操作(v2.35.6)

AWS CLI v2.35.6(2026-06-17リリース)でannotation操作コマンドが追加されました。boto3との主な違いを含めて紹介します。

PutObjectAnnotation

--annotation-payload はstreaming blobで、ファイルパスを直接指定します。file://fileb:// プレフィックスは使用できません。

echo -n '{"source":"cli","version":"2.35.6"}' > /tmp/payload.txt

aws s3api put-object-annotation \
  --bucket my-annotation-demo-bucket \
  --key videos/sample.mp4 \
  --annotation-name "cli-test" \
  --annotation-payload /tmp/payload.txt \
  --region ap-northeast-1
{
    "ETag": "\"39ce0435575e8e057d4a919c727ffe0a\"",
    "ChecksumCRC64NVME": "SvqIamuCqI0=",
    "ChecksumType": "FULL_OBJECT",
    "ServerSideEncryption": "AES256",
    "Key": "videos/sample.mp4",
    "AnnotationName": "cli-test"
}

GetObjectAnnotation

ペイロードの出力先は位置引数で指定します(s3api get-object と同じパターン)。

aws s3api get-object-annotation \
  --bucket my-annotation-demo-bucket \
  --key videos/sample.mp4 \
  --annotation-name "cli-test" \
  --region ap-northeast-1 \
  /tmp/output.txt

cat /tmp/output.txt
# {"source":"cli","version":"2.35.6"}

ListObjectAnnotations / DeleteObjectAnnotation

# List
aws s3api list-object-annotations \
  --bucket my-annotation-demo-bucket \
  --key videos/sample.mp4 \
  --region ap-northeast-1

# Delete
aws s3api delete-object-annotation \
  --bucket my-annotation-demo-bucket \
  --key videos/sample.mp4 \
  --annotation-name "cli-test" \
  --region ap-northeast-1

boto3 との違い

項目 boto3 AWS CLI(v2.35.6)
ペイロード指定 AnnotationPayload=bytes --annotation-payload <filepath>file:// 不可)
ペイロード取得 StreamingBody.read() 位置引数で出力先ファイル指定
チェックサム 本検証ではCRC32 本検証ではCRC64NVME
コピー時のannotation --copy-props alls3 cp/mv/sync 時にコピー

--copy-props all でのコピー

v2.35.6で追加された --copy-props all オプションにより、S3間コピー時にannotation・メタデータ・タグをまとめてコピーできます。

aws s3 cp s3://my-annotation-demo-bucket/videos/sample.mp4 \
  s3://my-annotation-demo-bucket/videos/sample-copy.mp4 \
  --copy-props all \
  --region ap-northeast-1

Annotation Table で横断検索(Athena)

個別オブジェクトのannotationをAPIで取得するだけでなく、バケット全体のannotationをSQLで横断検索できます。S3 MetadataのAnnotation Tableを有効化し、Athenaから参照する手順を確認しました。

S3 Metadata との関係

Annotation Tableは、2024年のre:Inventで発表された「S3 Metadata」基盤の拡張です。S3 Metadataでは、オブジェクトの作成・削除イベントを記録するJournal Tableと、オブジェクト一覧のスナップショットであるInventory Tableが提供されていました。今回のS3 Annotationsリリースに合わせて、annotationペイロードを横断検索するためのAnnotation Tableが追加されています。

いずれも同じ MetadataConfiguration で設定し、S3 Tables(Apache Iceberg)上に格納される点は共通です。

従来構成との比較

これまでS3オブジェクトにメタデータを持たせて横断検索したい場合、外部データベース(DynamoDB等)に保存する構成が一般的でした。DevelopersIOでも以下のような構成が紹介されています。

https://dev.classmethod.jp/articles/s3-lambda-dynamodb/

https://dev.classmethod.jp/articles/stepfunctions-s3-to-dyanmoDB-ks/

これらの構成とAnnotationsを比較すると、以下のようになります。

観点 従来構成(S3 + Lambda + DynamoDB) S3 Annotations
メタデータ保存先 DynamoDB テーブル S3 オブジェクト自体に付随
同期の仕組み EventBridge → Lambda / Step Functions 外部DBへの同期処理は不要(Annotation Table への反映は非同期)
追加コンポーネント Lambda, DynamoDB, EventBridge 等 自前の同期処理・外部DBは不要
横断検索 DynamoDB Query / Scan / GSI Annotation Table + Athena
レイテンシ DynamoDB: ミリ秒単位 Athena: 秒単位(バッチ向き)
コスト構造 Lambda 実行 + DynamoDB RCU/WCU S3 API リクエスト + Athena スキャン

Annotationsにより、メタデータ管理のための構成を大幅に簡素化できます。一方、ミリ秒単位の低レイテンシな参照が必要な場合は従来構成が適切です。

ここからの検証では、横断検索の有用性を示すため複数オブジェクトへannotationを追加しています。対象はvideos/sample.mp4videos/another.mp4docs/report.pdfの3つです。

IAM ロール作成

S3 Metadataがannotation情報をAnnotation Tableへ反映する際に使用するサービスロールを作成します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "metadata.s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

権限ポリシー:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObjectAnnotation",
        "s3:GetObjectVersionAnnotation",
        "s3:ListBucket",
        "s3:ListBucketVersions"
      ],
      "Resource": [
        "arn:aws:s3:::my-annotation-demo-bucket",
        "arn:aws:s3:::my-annotation-demo-bucket/*"
      ]
    }
  ]
}

Metadata Configuration 有効化

s3.create_bucket_metadata_configuration(
    Bucket=BUCKET,
    MetadataConfiguration={
        'JournalTableConfiguration': {
            'RecordExpiration': {'Expiration': 'DISABLED'}
        },
        'InventoryTableConfiguration': {
            'ConfigurationState': 'DISABLED'
        },
        'AnnotationTableConfiguration': {
            'ConfigurationState': 'ENABLED',
            'Role': 'arn:aws:iam::123456789012:role/S3MetadataAnnotationRole'
        }
    }
)

本記事の検証時点ではboto3で実行しましたが、AWS CLI v2.35.6でも実行可能であることを確認しました。

バックフィルと ACTIVE 確認

今回の検証では、作成直後の TableStatusBACKFILLING でした。既存のannotationをテーブルに反映する処理が走ります。

resp = s3.get_bucket_metadata_configuration(Bucket=BUCKET)
config = resp['GetBucketMetadataConfigurationResult']['MetadataConfigurationResult']
print(config['AnnotationTableConfigurationResult']['TableStatus'])
BACKFILLING

今回の検証では、3オブジェクト・3 annotationの小規模環境でMetadata Configuration作成から約25分で ACTIVE になりました。

Glue Data Catalog に federated catalog を作成

AthenaからAnnotation Tableを参照するには、Glue Data CatalogにS3 Tables用のfederated catalogを作成します。

import boto3

glue = boto3.client('glue', region_name='ap-northeast-1')
glue.create_catalog(
    Name='s3tablescatalog',
    CatalogInput={
        'FederatedCatalog': {
            'Identifier': 'arn:aws:s3tables:ap-northeast-1:123456789012:bucket/*',
            'ConnectionName': 'aws:s3tables'
        },
        'CreateDatabaseDefaultPermissions': [
            {
                'Principal': {'DataLakePrincipalIdentifier': 'IAM_ALLOWED_PRINCIPALS'},
                'Permissions': ['ALL']
            }
        ],
        'CreateTableDefaultPermissions': [
            {
                'Principal': {'DataLakePrincipalIdentifier': 'IAM_ALLOWED_PRINCIPALS'},
                'Permissions': ['ALL']
            }
        ]
    }
)

Annotation Table のスキーマ

ACTIVEになったAnnotation TableをAthenaで確認すると、以下のカラム構成でした。

カラム 説明
bucket バケット名
object_key オブジェクトキー
object_version_id バージョンID(非バージョニング環境ではNULL)
name Annotation 名
last_modified_date Annotation 最終更新日時
size Annotation サイズ(バイト)
e_tag Annotation ETag
checksum_algorithm チェックサムアルゴリズム
text_value Annotation ペイロード(テキスト)

本検証で作成したJSON / テキスト形式のannotationは、text_value カラムに文字列として格納されていました。JSON文字列として保存したannotationであれば、Athenaの json_extract_scalar で内部フィールドを抽出できます。

Athena クエリ

テーブルパスは "s3tablescatalog/aws-s3"."b_<バケット名>"."annotation" です。

全件取得

SELECT object_key, name, text_value
FROM "s3tablescatalog/aws-s3"."b_my-annotation-demo-bucket"."annotation"
LIMIT 10;
object_key name text_value
videos/sample.mp4 mediainfo {"codec":"H.265","resolution":"3840x2160","audio_tracks":12}
videos/another.mp4 mediainfo {"codec":"H.264","resolution":"1920x1080","audio_tracks":2}
docs/report.pdf classification {"category":"finance","sensitivity":"internal"}

3件のannotationがすべて格納されていることを確認しました。

JSON フィールドでフィルタ

JSON形式のannotationに対して json_extract_scalar で条件指定できます。annotation名で絞ってからJSON抽出を行います。

SELECT object_key, name, text_value
FROM "s3tablescatalog/aws-s3"."b_my-annotation-demo-bucket"."annotation"
WHERE name = 'mediainfo'
  AND CAST(json_extract_scalar(text_value, '$.audio_tracks') AS INTEGER) > 8;
object_key name text_value
videos/sample.mp4 mediainfo {"codec":"H.265","resolution":"3840x2160","audio_tracks":12}

audio_tracks > 8 の条件で正しく1件のみヒットしました。S3オブジェクトに付与したannotationの中身を、SQLで横断検索できることを確認できました。

まとめ

S3 Annotationsをboto3 / AWS CLIで操作し、AnnotationのPut / Get / List / Deleteと、Annotation Table + Athenaによる横断検索を確認しました。今回利用したboto3 1.43.31 / botocore 1.43.31およびAWS CLI v2.35.6では、本記事で扱ったAnnotationのCRUD操作を実行できました。

S3 Annotationsは、S3オブジェクトに対して従来のuser-defined metadataやobject tagsより大きな情報を付与できる仕組みです。今回の検証では、JSON文字列やテキストをannotationとして保存し、個別APIやCLIで取得できることを確認しました。

また、Annotation Tableを有効化することで、保存したannotationをAthenaからSQLで参照できました。JSON文字列として保存したannotationについては、json_extract_scalar を使って内部フィールドを条件にした検索も可能でした。

従来、S3オブジェクトに付随するメタデータを横断検索したい場合は、LambdaやDynamoDBなどを組み合わせて別途管理する構成が必要になることがありました。S3 AnnotationsとAnnotation Tableを利用することで、ユースケースによっては自前の同期基盤や外部DBを用意せずに、メタデータの付与からAthenaによる横断検索までを構成できます。

一方で、Annotation Tableへの反映は非同期です。今回の小規模な検証環境でも、Metadata Configuration作成から ACTIVE になるまで約25分かかりました。ミリ秒単位の低レイテンシな参照や、GSIなどを使った検索が必要な場合は、DynamoDBなどの従来構成が適している場面もあります。

AWS CLI v2.35.6ではannotation操作コマンドが追加され、Put / Get / List / DeleteをCLIからも実行できました。SDKだけでなくCLIからも扱えるようになったことで、検証やスクリプト化もしやすくなっています。

参考リンク

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事