kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Amazon S3 Vectors に入門できるコンテンツ「Tutorial: Getting started with S3 Vectors」

2025年7月15日にプレビューでリリースされた Amazon S3 Vectors を試してみたいな〜❗️と思って,ドキュメントにある公式チュートリアル「Tutorial: Getting started with S3 Vectors」を試してみた.

docs.aws.amazon.com

Amazon S3 Vectors に入門できる最高のコンテンツだった.Amazon S3 Vectors の基礎・Amazon S3 Vectors Embed CLI・Amazon Bedrock ナレッジベース統合・Amazon OpenSearch Service 統合まで幅広く体験できる👏

Amazon S3 Vectors 入門

Step 1 から Step 4 では Amazon S3 Vectors に入門する.今回リージョンは us-east-1 を使うことにした🌍️

まず Step 1Step 2 ではマネジメントコンソールから Amazon S3 の「ベクトルバケット(kakakakakku-media-embeddings)」「ベクトルインデックス(movies)」を作った.ちなみにマネジメントコンソールではベクトルバケットとベクトルインデックスを削除するメニューがなく,ドキュメントを確認したところ You can't delete a vector bucket or vector index using the console. と書いてあった😇現状では AWS CLI・AWS SDK で削除する必要がある.

docs.aws.amazon.com

Step 3 では Boto3 を使ってベクトルインデックスにベクトルを登録する.エンベディングするモデルとしては Amazon Titan Text Embedding v2 を使う.基本的にはチュートリアルにあるコードをそのまま使っていて,region_namevectorBucketName を書き換えた.ベクトルとして登録する映画データとしては Star Wars(スター・ウォーズ)Jurassic Park(ジュラシック・パーク)Finding Nemo(ファインディング・ニモ) になっていた🎥

👾 put-vectors.py

# Populate a vector index with embeddings from Amazon Titan Text Embeddings V2.
import boto3
import json

# Create Bedrock Runtime and S3 Vectors clients in the AWS Region of your choice. 
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
s3vectors = boto3.client("s3vectors", region_name="us-east-1")

# Texts to convert to embeddings.
texts = [
    "Star Wars: A farm boy joins rebels to fight an evil empire in space", 
    "Jurassic Park: Scientists create dinosaurs in a theme park that goes wrong",
    "Finding Nemo: A father fish searches the ocean to find his lost son"
]

# Generate vector embeddings.
embeddings = []
for text in texts:
    response = bedrock.invoke_model(
        modelId="amazon.titan-embed-text-v2:0",
        body=json.dumps({"inputText": text})
    )

    # Extract embedding from response.
    response_body = json.loads(response["body"].read())
    embeddings.append(response_body["embedding"])

# Write embeddings into vector index with metadata.
s3vectors.put_vectors(
    vectorBucketName="kakakakakku-media-embeddings",   
    indexName="movies",   
    vectors=[
        {
            "key": "Star Wars",
            "data": {"float32": embeddings[0]},
            "metadata": {"source_text": texts[0], "genre":"scifi"}
        },
        {
            "key": "Jurassic Park",
            "data": {"float32": embeddings[1]},
            "metadata": {"source_text": texts[1], "genre":"scifi"}
        },
        {
            "key": "Finding Nemo",
            "data": {"float32": embeddings[2]},
            "metadata": {"source_text": texts[2], "genre":"family"}
        }
    ]
)

実行後に登録されたベクトルを確認してみたいな〜と思って,AWS CLI を使って取得してみた.aws s3vectors list-vectors コマンドや aws s3vectors get-vectors コマンドで確認できる.ちなみにデフォルトではベクトルは確認できず,--return-data オプションを指定する必要がある👌

docs.aws.amazon.com

docs.aws.amazon.com

$ aws s3vectors list-vectors \
    --vector-bucket-name kakakakakku-media-embeddings \
    --index-name movies \
    --region us-east-1
{
    "vectors": [
        {
            "key": "Star Wars"
        },
        {
            "key": "Jurassic Park"
        },
        {
            "key": "Finding Nemo"
        }
    ]
}

$ aws s3vectors get-vectors \
    --vector-bucket-name kakakakakku-media-embeddings \
    --index-name movies \
    --keys "Star Wars" \
    --return-data \
    --region us-east-1
{
    "vectors": [
        {
            "key": "Star Wars",
            "data": {
                "float32": [
                    -0.024966709315776825,
                    0.03783351927995682,
                    -0.026106879115104675,
                    0.0013980172807350755,
                    0.04545948654413223,
(中略)
                    -0.015926586464047432,
                    -0.03523598983883858
                ]
            }
        }
    ]
}

Step 4 では同じく Boto3 を使ってベクトルを検索する.検索キーワードは adventures in space になっていた.実装としては s3vectors.query_vectors() を2回実行していて,2回目は filter={"genre": "scifi"}, でメタデータフィルタを追加した検索になっている🔍️

👾 query-vectors.py

# Query a vector index with an embedding from Amazon Titan Text Embeddings V2.
import boto3 
import json 

# Create Bedrock Runtime and S3 Vectors clients in the AWS Region of your choice. 
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
s3vectors = boto3.client("s3vectors", region_name="us-east-1") 

# Query text to convert to an embedding. 
input_text = "adventures in space"

# Generate the vector embedding.
response = bedrock.invoke_model(
    modelId="amazon.titan-embed-text-v2:0",
    body=json.dumps({"inputText": input_text})
) 

# Extract embedding from response.
model_response = json.loads(response["body"].read())
embedding = model_response["embedding"]

# Query vector index.
response = s3vectors.query_vectors(
    vectorBucketName="kakakakakku-media-embeddings",
    indexName="movies",
    queryVector={"float32": embedding}, 
    topK=3, 
    returnDistance=True,
    returnMetadata=True
)
print(json.dumps(response["vectors"], indent=2))

# Query vector index with a metadata filter.
response = s3vectors.query_vectors(
    vectorBucketName="kakakakakku-media-embeddings",
    indexName="movies",
    queryVector={"float32": embedding}, 
    topK=3, 
    filter={"genre": "scifi"},
    returnDistance=True,
    returnMetadata=True
)
print(json.dumps(response["vectors"], indent=2))

👾 query-vectors.py(実行結果)

1回目と2回目の検索結果が出力された👌

$ uv run query-vectors.py
[
  {
    "key": "Star Wars",
    "metadata": {
      "source_text": "Star Wars: A farm boy joins rebels to fight an evil empire in space",
      "genre": "scifi"
    },
    "distance": 0.7918925285339355
  },
  {
    "key": "Jurassic Park",
    "metadata": {
      "genre": "scifi",
      "source_text": "Jurassic Park: Scientists create dinosaurs in a theme park that goes wrong"
    },
    "distance": 0.859985888004303
  },
  {
    "key": "Finding Nemo",
    "metadata": {
      "genre": "family",
      "source_text": "Finding Nemo: A father fish searches the ocean to find his lost son"
    },
    "distance": 0.9480686187744141
  }
]
[
  {
    "key": "Star Wars",
    "metadata": {
      "source_text": "Star Wars: A farm boy joins rebels to fight an evil empire in space",
      "genre": "scifi"
    },
    "distance": 0.7918925285339355
  },
  {
    "key": "Jurassic Park",
    "metadata": {
      "genre": "scifi",
      "source_text": "Jurassic Park: Scientists create dinosaurs in a theme park that goes wrong"
    },
    "distance": 0.859985888004303
  }
]

Amazon S3 Vectors Embed CLI

次はオプションタスクとして,ベクトル操作(Put と Query)を簡単に行える Amazon S3 Vectors Embed CLI を試す❗️

docs.aws.amazon.com

とは言え特に手順はなく,GitHub リポジトリの README を参照して試してね〜という流れになっていた.

github.com

まずは sandbox というベクトルインデックスを作った.今度はマネジメントコンソールではなく AWS CLI の aws s3vectors create-index コマンドを使ってみることにした.

$ aws s3vectors create-index \
    --vector-bucket-name kakakakakku-media-embeddings \
    --index-name sandbox \
    --data-type float32 \
    --dimension 1024 \
    --distance-metric cosine

そして README を参考に s3vectors-embed put コマンドと s3vectors-embed query コマンドを実行した👌

$ uvx --from s3vectors-embed-cli s3vectors-embed put \
  --vector-bucket-name kakakakakku-media-embeddings \
  --index-name sandbox \
  --model-id amazon.titan-embed-text-v2:0 \
  --text-value 'Hello, world!' \
  --region us-east-1
{
  "key": "54e0a292-d760-4ff6-a315-61663d7a785b",
  "bucket": "kakakakakku-media-embeddings",
  "index": "sandbox",
  "model": "amazon.titan-embed-text-v2:0",
  "contentType": "text",
  "embeddingDimensions": 1024,
  "metadata": {
    "S3VECTORS-EMBED-SRC-CONTENT": "Hello, world!"
  }
}

$ uvx --from s3vectors-embed-cli s3vectors-embed query \
  --vector-bucket-name kakakakakku-media-embeddings \
  --index-name sandbox \
  --model-id amazon.titan-embed-text-v2:0 \
  --query-input 'Hello!' \
  --k 5 \
  --region us-east-1
{
  "results": [
    {
      "key": "54e0a292-d760-4ff6-a315-61663d7a785b",
      "metadata": {
        "S3VECTORS-EMBED-SRC-CONTENT": "Hello, world!"
      }
    }
  ],
  "summary": {
    "queryType": "text",
    "model": "amazon.titan-embed-text-v2:0",
    "index": "sandbox",
    "resultsFound": 1,
    "queryDimensions": 1024
  }
}

他にも試していたら README に誤りがあることに気付いて,修正のプルリクエストを出しておいた👌

github.com

Amazon Bedrock ナレッジベース統合

オプションタスクの2つ目として Amazon S3 Vectors と「Amazon Bedrock ナレッジベース」の統合を試す❗️こっちは基本的な手順があって,参考にしながら進めることができた.

docs.aws.amazon.com

ちなみに Amazon Bedrock ナレッジベースは過去にも使ったことがあって,手順を参考にポチポチと設定した.ポイントは「ベクトルデータベース」を設定するときに Amazon S3 Vectors を選択するところ👌

ちなみに「ベクトルデータベース」を設定するときに既に作ってある「ベクトルインデックス」を指定したらハマってしまった😇Amazon Bedrock ナレッジベースで Amazon S3 にアップロードした PDF ファイルを同期するときに Filterable metadata must have at most 2048 bytes というエラーが出てしまった.

Encountered error: Invalid record for key '3bf6136e-8097-499e-ba64-591230bc7b78': Filterable metadata must have at most 2048 bytes (Service: S3Vectors, Status Code: 400, Request ID: 4a6c87ca-c46f-413b-a1ab-e4e8660e7e91) (SDK Attempt Count: 1). Call to Amazon S3 Vectors did not succeed.

解決策はドキュメントにちゃんと書いてあって,「ベクトルインデックス」を作るときに nonFilterableMetadataKeys(フィルタリングできないメタデータ)AMAZON_BEDROCK_TEXT を指定する必要があった.ちなみに確認も兼ねてマネジメントコンソールで「新しいベクトルストアをクイック作成 - 推奨」を選択して「ベクトルインデックス」を作ってみたところ,デフォルトで AMAZON_BEDROCK_TEXT 以外に AMAZON_BEDROCK_METADATA も設定される仕様になっていることを確認できた💡

docs.aws.amazon.com

というハマりポイントもありつつ,最終的に以下のように「ベクトルインデックス」を作り直して,Amazon Bedrock ナレッジベースの同期ができるようになった👏

$ aws s3vectors create-index \
    --vector-bucket-name kakakakakku-media-embeddings \
    --index-name integrated-knowledge-base \
    --data-type float32 \
    --dimension 1024 \
    --distance-metric cosine \
    --metadata-configuration nonFilterableMetadataKeys=AMAZON_BEDROCK_TEXT,AMAZON_BEDROCK_METADATA

そして aws s3vectors list-vectors コマンドでベクトル一覧を確認できた👌

$ aws s3vectors list-vectors \
    --vector-bucket-name kakakakakku-media-embeddings \
    --index-name integrated-knowledge-base \
    --region us-east-1
{
    "vectors": [
        {
            "key": "8c9a8cec-b957-4caf-9c39-969efbdb1ab3"
        },
        {
            "key": "716e3806-4c79-43be-9f2b-826a94324e6b"
        },
        {
            "key": "f4ccd138-aeef-44e5-9d83-c604c37525c8"
        },
(中略)
        {
            "key": "c26f25c6-3d90-4e6d-8df6-abf07c35abcb"
        },
        {
            "key": "3b4024a9-7522-48ba-b901-b800bc996907"
        }
    ]
}

今回は AWS Well-Architected DevOps Guidance の PDF(236ページ)を Amazon Bedrock ナレッジベースに同期して AWS Well-Architected DevOps Guidance で提唱されている Everything as code とは? というプロンプトを実行したらイイ感じに回答が返ってきた \( 'ω')/

docs.aws.amazon.com

Amazon OpenSearch Service 統合

今回は試さなかった🙅

まとめ

「Tutorial: Getting started with S3 Vectors」は Amazon S3 Vectors に入門するのに最適なコンテンツだった❗️そろそろ Amazon S3 Vectors を試してみようかな〜と思っている人がいたらおすすめできる \( 'ω')/

関連記事

aws.amazon.com

aws.amazon.com