🔍

Vertex AI Vector Search 2.0 でハイブリッド検索を試す

に公開

はじめに

こんにちは、クラウドエースの木村です。

Google Cloud の Vertex AI に、完全マネージドで自己チューニング型のベクトルデータベース Vector Search 2.0 が登場し、従来の 1.0(旧称: Matching Engine)とは異なるアーキテクチャで運用が大きく簡略化されました。

この記事では、Vector Search 2.0 の概要と 1.0 との違いに触れたうえで、ハイブリッド検索(セマンティック検索 + テキスト検索を RRF(Reciprocal Rank Fusion)で統合) を Python SDK で実装する手順を解説します。自身でのエンベディング計算や GCS(Google Cloud Storage)へのアップロードが不要になる点を、実際のコードで確認できます。

対象読者

  • Google Cloud でベクトル検索を触ってみたいエンジニアの方
  • Vector Search 1.0 から 2.0 への移行を検討している方
  • セマンティック検索とキーワード検索を組み合わせたハイブリッド検索の実装方法を知りたい方

第1章:Vector Search 2.0 とは

Vector Search 2.0 は、Google Cloud の完全マネージド型で自己チューニングのベクトルデータベースです。Google 検索・YouTube・Google Play を支える ScaNN (Scalable Nearest Neighbors) アルゴリズムに基づいています。

1.1 主な特徴

  • ゼロインデックスから数十億規模へ: インデックス作成なしで kNN (k-nearest neighbors)によりすぐに開発を開始でき、本番では ANN (Approximate Nearest Neighbor)でミリ秒単位のレイテンシで数十億ベクトル検索が可能(同一 API・同一データセット)
  • 統合データストレージ: ベクトルエンベディングとユーザーデータを統合して保存(別データベースや特徴量ストア不要)
  • 自動エンベディング: Vertex AI エンベディングモデルによりセマンティックエンベディングを自動生成
  • 組み込みフルテキスト検索: スパースエンベディングを自前で用意せずに利用可能。BM25/SPLADE 等の独自スパースエンベディングも利用可能
  • ハイブリッド検索: セマンティックとキーワード/トークン検索を RRF で 1 クエリに統合
  • 自己チューニング: 手動設定なしでパフォーマンスを自動最適化
  • エンタープライズ対応: スケーラビリティ・セキュリティ・コンプライアンスを内蔵

1.2 コアアーキテクチャ

  1. Collections: スキーマで制約されたデータのコンテナ
  2. Data Objects: データとベクトルエンベディングを持つ個々のアイテム
  3. Indexes: kNN で即時近傍検索。低レイテンシには ANN インデックスを使用
  • すぐ始める: kNN でインデックス不要・即検索可能(開発・小規模データ向け)
  • 本番スケール: ScaNN による ANN で数十億件でもサブ秒レイテンシ

1.3 GA とプレビューについて

第2章:1.0 と 2.0 の違い

従来の Vector Search 1.0 では、密ベクトルと疎ベクトル(BM25、TF-IDF など)を自前で計算し、JSONL ファイルを作成して GCS にアップロードし、さらにインデックスとエンドポイントの作成に長時間を費やす必要がありました。Vector Search 2.0 では統合データストレージが採用され、これらのプロセスが大きく簡略化されています。

2.1 大きな違い(3点)

  • エンベディング不要: テキストデータをそのまま API で投入するだけで、システムが自動的にエンベディング(Semantic Search)やテキストインデックス(Text Search)を構築します。
  • インフラ待機時間なし: GCS へのアップロードや、数十分〜数時間かかるインデックス・エンドポイントのデプロイ作業が不要になります。
  • メタデータ統合: 検索対象のテキストや付随するメタデータ(ID、カテゴリなど)をそのまま JSON ドキュメントとして一元管理できます。

2.0 ではインデックスを作成しなくても、データ投入後すぐに kNN による厳密最近傍検索が実行可能です。データ量が増えた段階で、必要に応じてコレクションインデックスを構築し、ANN による近似近傍探索が実行可能です。

2.2 処理フローの違い

Vector Search 1.0(インフラ管理型) — 準備・構築・デプロイに時間がかかり、ペイロードは外部 DB で保持する構成でした。

Vector Search 2.0(統合ストレージ型) — コレクション作成と API 投入のみで、インデックス不要で即座に検索可能です。別途、大規模データ向けに ANN インデックスを構築することも可能です。

第3章:例題シナリオと前提

本章の例題シナリオと前提は、以下の Google Cloud 公式ノートブックをもとに、本記事用にアレンジしています。

3.1 例題シナリオ:アパレル製品検索

本記事では、アパレル製品サンプル(5 件)を用いて、製品検索とハイブリッド検索の手順を実際に試します。

ビジネスユースケース(ハンズオンでの実施順)

  1. 製品発見: 製品名の意味に基づく類似製品の検索(4.3 データ投入)
  2. クエリ・フィルタ: カテゴリ(bottoms / tops など)で絞り込み(4.4)
  3. セマンティック検索: 「ビーチ用のメンズ服」に合う製品を意味の近さで検索(4.5.1)
  4. キーワード検索: 型番などトークン一致で検索(4.5.2)
  5. ハイブリッド検索: セマンティックとキーワードを RRF で統合したレコメンド(4.5.3)

データセット概要(本チュートリアル)

サンプルは次の属性のみを使用します。

  • id: 製品 ID(例: "item-001")
  • name: 製品名(例: "夏用 ビーチメンズショートパンツ ブルー 型番:BP-001")
  • category: カテゴリ(bottoms, tops, dress など)

3.2 前提条件

  • 請求が有効な Google Cloud プロジェクトが必要です。
  • Vector Search API および Vertex AI API を有効にします(手順内で実施)。
  • Colab で実行する場合は、実行前に google.colab.auth.authenticate_user() で認証してください。Colab Enterprise や Cloud Workbench では省略可能な場合があります。

第4章:ハンズオン - 実装手順(Python SDK)

4.1 準備

必要なライブラリをインストールし、プロジェクト ID とロケーションを設定します。

# Vector Search 2.0 用 Python クライアントライブラリをインストール
pip install google-cloud-vectorsearch

API の有効化を行います。Vector Search および(自動エンベディング・セマンティック検索利用時は)Vertex AI API を有効にします。

export PROJECT_ID={your-project-id} # {your-project-id} には利用する環境の Google Cloud プロジェクト ID を指定してください

# Vector Search API と Vertex AI API を有効化
gcloud services enable vectorsearch.googleapis.com aiplatform.googleapis.com --project $PROJECT_ID

実行すると、Operation "operations/..." finished successfully. のように表示されます。

4.2 コレクションの作成

データを格納するための「コレクション」を作成します。スキーマで制約されたデータのコンテナであり、従来のインデックスとエンドポイントに代わるデータストアになります。

from google.cloud import vectorsearch_v1beta

# プロジェクト ID とリージョンを設定
PROJECT_ID = "your-project-id"
LOCATION = "us-central1"

# 作成するコレクションの ID(任意の文字列)
COLLECTION_ID = "apparel-collection"

# クライアントと親リソースパス(プロジェクト・ロケーション)を用意
vector_search_service_client = vectorsearch_v1beta.VectorSearchServiceClient()
parent = f"projects/{PROJECT_ID}/locations/{LOCATION}"

# コレクション作成リクエスト: data_schema(ユーザーデータの型)と vector_schema(エンベディングの定義)を指定
request = vectorsearch_v1beta.CreateCollectionRequest(
    parent=parent,
    collection_id=COLLECTION_ID,
    collection={
        # データスキーマ: 格納する JSON の型定義(id, name, category)
        "data_schema": {
            "type": "object",
            "properties": {
                "id": {"type": "string"},
                "name": {"type": "string"},
                "category": {"type": "string"},
            },
        },
        # ベクトルスキーマ: 密ベクトルエンベディングの定義(Vertex AI で自動生成)
        "vector_schema": {
            "name_dense_embedding": {
                "dense_vector": {
                    "dimensions": 768,  # gemini-embedding-001 の次元数
                    "vertex_embedding_config": {
                        "model_id": "gemini-embedding-001",
                        "text_template": "{name}",  # データの "name" フィールドをエンベディング入力に使用
                        "task_type": "RETRIEVAL_DOCUMENT",  # ドキュメント用ベクトルとして最適化
                    },
                }
            }
        },
    },
)

# コレクション作成を実行(非同期オペレーションの完了を待つ)
response = vector_search_service_client.create_collection(request=request)
response.result()
print(f"Collection {COLLECTION_ID} を作成しました。")

実行結果(例)

Collection apparel-collection を作成しました。

vertex_embedding_config を使用すると、登録時のテキスト(ここでは name)から自動的にエンベディングが生成されます。task_typeRETRIEVAL_DOCUMENT を指定すると、ドキュメント用のベクトルとして最適化されます。

4.3 データの投入(エンベディング計算不要)

1.0 では「自身でのベクトル化」「JSONL形式への変換」「GCS アップロード」が必要でしたが、2.0 では生のテキストを含むデータを直接 API で投入できます。エンベディングはシステム側で自動生成されます。

# データオブジェクト操作用のクライアントとコレクションのリソースパス
data_client = vectorsearch_v1beta.DataObjectServiceClient()
collection_path = f"projects/{PROJECT_ID}/locations/{LOCATION}/collections/{COLLECTION_ID}"

# 投入するサンプルデータ(スキーマの id / name / category に合わせる。name に型番を入れるとキーワード検索の確認に使える)
sample_data = [
    {"id": "item-001", "name": "夏用 ビーチメンズショートパンツ ブルー 型番:BP-001", "category": "bottoms"},
    {"id": "item-002", "name": "速乾性 スポーツハーフパンツ ブラック 型番:SP-202", "category": "bottoms"},
    {"id": "item-003", "name": "カジュアル サマーシャツ 半袖 型番:CS-305", "category": "tops"},
    {"id": "item-004", "name": "メンズ 海用 水泳ショート 型番:BP-002", "category": "bottoms"},
    {"id": "item-005", "name": "ビーチ リゾート レディースドレス ライトブルー 型番:BP-010", "category": "dress"},
]

# 各アイテムをデータオブジェクトとして 1 件ずつ作成(エンベディングは API 側で自動生成)
for item in sample_data:
    data_object = vectorsearch_v1beta.DataObject(data=item)
    request = vectorsearch_v1beta.CreateDataObjectRequest(
        parent=collection_path,
        data_object_id=item["id"],   # 一意の ID(検索結果の参照キーとして使用)
        data_object=data_object,
    )
    data_client.create_data_object(request=request)
print("Data objects upserted.")

実行結果(例)

Data objects upserted.

4.4 クエリとフィルタリング(Query)

データ投入後、Query を用いてデータフィールドによる絞り込みができます。

Query と Search の違い

  • Query: データフィールドによるフィルタ・取得(SQL の WHERE に相当)。QueryDataObjectsRequest を使用。
  • Search: ベクトル類似度やセマンティック・テキスト検索。SearchDataObjectsRequestBatchSearchDataObjectsRequest を使用。

クエリ言語で利用可能な主な演算子は以下のとおりです。

  • 比較: $eq, $ne, $gt, $gte, $lt, $lte
  • 論理: $and, $or
  • 配列: $in, $nin, $all

例1: カテゴリでフィルタ(bottoms のみ取得)

# Query(フィルタ・取得)用のクライアント
data_object_search_service_client = vectorsearch_v1beta.DataObjectSearchServiceClient()

# フィルタ条件: category が "bottoms" のものだけ取得。data_fields=["*"] で全フィールドを返す
request = vectorsearch_v1beta.QueryDataObjectsRequest(
    parent=collection_path,
    filter={"category": {"$eq": "bottoms"}},
    output_fields=vectorsearch_v1beta.OutputFields(data_fields=["*"]),
)
results = data_object_search_service_client.query_data_objects(request)
print("カテゴリが 'bottoms' のデータオブジェクト:")
for p in results:
    print(f"  - {p.data.get('name', 'N/A')} (category: {p.data.get('category', 'N/A')})")

実行結果(例)

カテゴリが 'bottoms' のデータオブジェクト:
  - メンズ 海用 水泳ショート 型番:BP-002 (category: bottoms)
  - 速乾性 スポーツハーフパンツ ブラック 型番:SP-202 (category: bottoms)
  - 夏用 ビーチメンズショートパンツ ブルー 型番:BP-001 (category: bottoms)

例2: $and で複合条件

# $and で複数条件をすべて満たすデータのみ取得(category=bottoms かつ id=item-001)
request = vectorsearch_v1beta.QueryDataObjectsRequest(
    parent=collection_path,
    filter={"$and": [{"category": {"$eq": "bottoms"}}, {"id": {"$eq": "item-001"}}]},
    output_fields=vectorsearch_v1beta.OutputFields(data_fields=["*"]),
)
results = data_object_search_service_client.query_data_objects(request)
print("category=bottoms かつ id=item-001 のデータ:")
for p in results:
    print(f"  - id: {p.data.get('id')} | {p.data.get('name')} | {p.data.get('category')}")

実行結果(例)

category=bottoms かつ id=item-001 のデータ:
  - id: item-001 | 夏用 ビーチメンズショートパンツ ブルー 型番:BP-001 | bottoms

例3: $or で複数条件(bottoms または tops)

# $or でいずれか一つの条件を満たすデータを取得(category が bottoms または tops)
request = vectorsearch_v1beta.QueryDataObjectsRequest(
    parent=collection_path,
    filter={
        "$or": [
            {"category": {"$eq": "bottoms"}},
            {"category": {"$eq": "tops"}},
        ]
    },
    output_fields=vectorsearch_v1beta.OutputFields(data_fields=["*"]),
)
results = data_object_search_service_client.query_data_objects(request)
print("カテゴリが 'bottoms' または 'tops' のデータ:")
for p in results:
    print(f"  - {p.data.get('name')} | {p.data.get('category')}")

実行結果(例)

カテゴリが 'bottoms' または 'tops' のデータ:
  - メンズ 海用 水泳ショート 型番:BP-002 | bottoms
  - カジュアル サマーシャツ 半袖 型番:CS-305 | tops
  - 速乾性 スポーツハーフパンツ ブラック 型番:SP-202 | bottoms
  - 夏用 ビーチメンズショートパンツ ブルー 型番:BP-001 | bottoms

集約(COUNT)

コレクション内のデータオブジェクト総件数を取得するには、AggregateDataObjectsRequestCOUNT を指定します。

# コレクション内のデータオブジェクト件数を集約(COUNT)で取得
aggregate_request = vectorsearch_v1beta.AggregateDataObjectsRequest(
    parent=collection_path,
    aggregate="COUNT",
)
response = data_object_search_service_client.aggregate_data_objects(aggregate_request)
print("コレクション内のデータオブジェクト総数:", response)

実行結果(例)

コレクション内のデータオブジェクト総数: aggregate_results {
  fields {
    key: "count"
    value {
      number_value: 5
    }
  }
}

件数は number_value: 5 のように返ります。

4.5 セマンティック検索・キーワード検索・ハイブリッド検索

ここでは セマンティック検索キーワード検索ハイブリッド検索 の順に試します。
結果に ID・商品名を出力するには、各検索で output_fields=OutputFields(data_fields=["id", "name", "category"]) を指定してください。

4.5.1 セマンティック検索

クエリの意味の近さでランク付けされ、キーワードの完全一致は問いません。同じクエリ「ビーチ用のメンズ服」で試します。

# 検索(Search)用のクライアント
search_client = vectorsearch_v1beta.DataObjectSearchServiceClient()

# セマンティック検索リクエスト: クエリテキストの意味に近いデータをベクトル類似度で取得
semantic_request = vectorsearch_v1beta.SearchDataObjectsRequest(
    parent=collection_path,
    semantic_search=vectorsearch_v1beta.SemanticSearch(
        search_text="ビーチ用のメンズ服",           # 検索クエリ(質問文)
        search_field="name_dense_embedding",        # コレクションで定義した密ベクトルフィールド名
        task_type="QUESTION_ANSWERING",             # クエリ側は質問用エンベディングとして最適化
        top_k=10,                                  # 上位 10 件を返す
        output_fields=vectorsearch_v1beta.OutputFields(data_fields=["id", "name", "category"]),
    ),
)
semantic_results = search_client.search_data_objects(semantic_request)
# 結果を 1 件ずつ表示(distance は小さいほど類似度が高い)
for i, result in enumerate(semantic_results, 1):
    do = getattr(result, "data_object", None)
    data = getattr(do, "data", None) if do else {}
    data = data or {}
    print(f"{i}. ID: {data.get('id', 'N/A')} | {data.get('name', 'N/A')} | distance: {getattr(result, 'distance', None)}")

実行結果(例)

【セマンティック検索のみ】'ビーチ用のメンズ服'
--- 検索結果 ---
1. ID: item-001 | 夏用 ビーチメンズショートパンツ ブルー 型番:BP-001 | distance: 0.2576836943626404
2. ID: item-004 | メンズ 海用 水泳ショート 型番:BP-002 | distance: 0.2533119320869446
3. ID: item-005 | ビーチ リゾート レディースドレス ライトブルー 型番:BP-010 | distance: 0.2327461540699005
4. ID: item-003 | カジュアル サマーシャツ 半袖 型番:CS-305 | distance: 0.22579875588417053
5. ID: item-002 | 速乾性 スポーツハーフパンツ ブラック 型番:SP-202 | distance: 0.21566367149353027

意味が近い順(distance が小さいほど類似度が高い)にランク付けされています。

4.5.2 キーワード検索

型番(例: "BP-001")で検索するとヒットします。「ビーチ用のメンズ服」ではキーワード一致しないため 0 件、型番ではトークン一致でヒットすることを確認できます。

# テキスト(キーワード)検索リクエスト: 指定フィールド内のトークン一致で検索
text_request = vectorsearch_v1beta.SearchDataObjectsRequest(
    parent=collection_path,
    text_search=vectorsearch_v1beta.TextSearch(
        search_text="BP-001",                      # 検索キーワード(型番など)
        data_field_names=["name"],                 # 検索対象のデータフィールド
        top_k=10,
        output_fields=vectorsearch_v1beta.OutputFields(data_fields=["id", "name", "category"]),
    ),
)
text_results = search_client.search_data_objects(text_request)
for i, result in enumerate(text_results, 1):
    do = getattr(result, "data_object", None)
    data = getattr(do, "data", None) if do else {}
    data = data or {}
    print(f"{i}. ID: {data.get('id', 'N/A')} | {data.get('name', 'N/A')}")

実行結果(例)

【キーワード検索】型番 'BP-001' で検索
--- 検索結果 ---
1. ID: item-001 | 夏用 ビーチメンズショートパンツ ブルー 型番:BP-001 | distance: 0.2820570170879364

4.5.3 ハイブリッド検索

1 回の API 呼び出しで「セマンティック検索」と「テキスト検索」を並列実行し、RRF(Reciprocal Rank Fusion) で統合し、よりバランスの取れた結果を得られます。

query_text = "ビーチ用のメンズ服"
# バッチ検索: 複数の Search を 1 回の API で実行し、combine で RRF 統合
batch_search_request = vectorsearch_v1beta.BatchSearchDataObjectsRequest(
    parent=collection_path,
    searches=[
        # 1 つ目: セマンティック検索
        vectorsearch_v1beta.Search(
            semantic_search=vectorsearch_v1beta.SemanticSearch(
                search_text=query_text,
                search_field="name_dense_embedding",
                task_type="QUESTION_ANSWERING",
                top_k=20,
                output_fields=vectorsearch_v1beta.OutputFields(data_fields=["id", "name", "category"]),
            )
        ),
        # 2 つ目: テキスト(キーワード)検索
        vectorsearch_v1beta.Search(
            text_search=vectorsearch_v1beta.TextSearch(
                search_text=query_text,
                data_field_names=["name"],
                top_k=20,
                output_fields=vectorsearch_v1beta.OutputFields(data_fields=["id", "name", "category"]),
            )
        ),
    ],
    # RRF で両検索結果を統合(weights で各検索の重みを指定可能。ここでは 1:1)
    combine=vectorsearch_v1beta.BatchSearchDataObjectsRequest.CombineResultsOptions(
        ranker=vectorsearch_v1beta.Ranker(rrf=vectorsearch_v1beta.ReciprocalRankFusion(weights=[1.0, 1.0]))
    ),
)
batch_results = search_client.batch_search_data_objects(batch_search_request)
print(f"ハイブリッド検索 '{query_text}' (RRF):")
if batch_results.results:
    # 統合結果の先頭 10 件を表示(results[0] が 1 回目のバッチの結果)
    for i, result in enumerate(batch_results.results[0].results[:10], 1):
        d = result.data_object.data
        name = d.get("name", "N/A") if hasattr(d, "get") else getattr(d, "name", "N/A")
        category = d.get("category", "") if hasattr(d, "get") else getattr(d, "category", "")
        print(f"  {i:2}. {name} | {category}")
else:
    print("  該当なし(データ件数が少ない場合など)")

実行結果(例)

本サンプル(5 件)ではハイブリッド統合結果が 0 件となるため、次のように表示されます。

ハイブリッド検索 'ビーチ用のメンズ服' (RRF):
  該当なし(データ件数が少ない場合など)

第5章:ハイブリッド検索の考え方(補足)

5.1 同じクエリで異なるアプローチ

上記では同じクエリ「ビーチ用のメンズ服」を、セマンティック検索テキスト検索の両方に渡して実行しています。

  • セマンティック検索: クエリの意図を理解(「ビーチ」→ 水着・カジュアル系など)。
  • テキスト検索: 製品名フィールドで「ショート」「パンツ」などのキーワード一致を評価。
  • 組み込み RRF: BatchSearchDataObjectsRequest が両検索を並列実行し、ReciprocalRankFusion(weights=[1.0, 1.0]) で結果を融合します。weights で各検索の重みを指定できます。

5.2 ハイブリッド検索が「両方の良いとこ取り」になる理由

クエリの例 セマンティック検索 テキスト検索 ハイブリッド検索
「ビーチ用のメンズ服」 ✅ 意図を理解 ❌ キーワード一致なし ✅ 有効
型番 "BP-001" ❌ ドメイン外 ✅ キーワード一致 ✅ 有効
新しいブランド名 ❌ 学習データにない ✅ キーワード一致 ✅ 有効
typo "ショト"(ショートの誤り) ✅ 理解する場合あり ❌ 一致しない ✅ 部分的に有効

5.3 RRF の利点

  • 両方の検索で上位に出るドキュメントが、統合スコアでも上位になりやすい。
  • 意味の近さ(セマンティック)とトークン一致(キーワード)のバランスが取りやすい。
  • 一方の検索の弱点を、もう一方の強みで補える。

5.4 タスクタイプで精度を上げる

Vector Search 2.0(Semantic Search 利用時)では、エンベディング生成時の タスクタイプ(task_type) の指定が重要です。通常、ユーザーの「短い質問(クエリ)」と「詳細な回答(ドキュメント)」は、単純なベクトル空間では類似度が高くなりづらいという課題があります。データ登録時には RETRIEVAL_DOCUMENT(検索対象ドキュメント)、検索実行時には QUESTION_ANSWERING(質問応答)を指定することで、モデルが意図に合わせてベクトル空間を最適化し、関連する結果が適切にランク付けされます。

第6章:クリーンアップ

Vector Search 2.0 のリソースは、アクティブな間に継続してコストが発生します。予期せぬ請求を避けるために、作成したコレクションを必ず削除してください。

削除の順序: コレクション内にデータオブジェクトが残っているとコレクションは削除できません。先にデータオブジェクトを削除してから、コレクションを削除してください。

本記事では ANN インデックスを作成していないため、データオブジェクト削除 → コレクション削除の順で行います。

# ステップ1: コレクション内のデータオブジェクト一覧を取得し、バッチ削除
collection_name = f"projects/{PROJECT_ID}/locations/{LOCATION}/collections/{COLLECTION_ID}"
data_client = vectorsearch_v1beta.DataObjectServiceClient()

# コレクション内のデータオブジェクトの name(リソースパス)を取得(id のみ返すクエリで十分)
list_request = vectorsearch_v1beta.QueryDataObjectsRequest(
    parent=collection_name,
    page_size=1000,
    output_fields=vectorsearch_v1beta.OutputFields(data_fields=["id"]),
)
data_object_names = [obj.name for obj in data_object_search_service_client.query_data_objects(list_request)]
print(f"  取得件数: {len(data_object_names)} 件")

# 最大 1000 件ずつバッチ削除(API の上限)
BATCH_SIZE = 1000
for i in range(0, len(data_object_names), BATCH_SIZE):
    chunk = data_object_names[i : i + BATCH_SIZE]
    requests = [vectorsearch_v1beta.DeleteDataObjectRequest(name=name) for name in chunk]
    try:
        data_client.batch_delete_data_objects(parent=collection_name, requests=requests)
        print(f"  バッチ削除: {len(chunk)} 件 (合計 {min(i + BATCH_SIZE, len(data_object_names))}/{len(data_object_names)})")
    except Exception as e:
        print(f"  バッチ削除でエラー: {e}")
print("ステップ1 完了.")

# --- ステップ2: コレクションの削除(データオブジェクトが 0 件になった状態で実行)---
try:
    request = vectorsearch_v1beta.DeleteCollectionRequest(name=collection_name)
    operation = vector_search_service_client.delete_collection(request=request)
    operation.result()  # 削除オペレーションの完了を待つ
    print(f"🗑️ コレクション削除: {COLLECTION_ID}")
    print("\n✅ クリーンアップ完了。Vector Search 2.0 リソースはすべて削除されました。")
except Exception as e:
    print(f"コレクション削除に失敗しました: {e}")

実行結果(例)

  取得件数: 5 件
  バッチ削除: 5 件 (合計 5/5)
ステップ1 完了.
🗑️ コレクション削除: apparel-collection

✅ クリーンアップ完了。Vector Search 2.0 リソースはすべて削除されました。

おわりに

Vector Search 2.0 を利用することで、「テキストのベクトル化処理」と「インフラ(インデックス/エンドポイント)のデプロイ待ち時間」 という、1.0 の課題が解消されます。アプリケーション側は、クエリテキストをそのまま API に投げるだけで、高度なハイブリッド検索(Semantic + Text + RRF 統合)を実装できるようになりました。まずは小規模なコレクションで kNN による即時検索を試し、必要に応じてコレクションインデックス(ANN)の構築やタスクタイプの調整で精度・性能を高めていく流れで活用してみてください。

参考リンク

Discussion