
【実装】Azure AI Searchでベクトル検索対応インデックスを作成・移行する方法
はじめに
RAGシステムの検索精度を向上させるため、Azure AI Searchのインデックスをキーワード検索のみ → ハイブリッド検索(キーワード + ベクトル)に移行しました。本記事ではその手順と注意点をまとめます。
この記事でわかること
-
Azure AI SearchでVectorizer付きインデックスを作成する方法
-
既存インデックスからVectorizer対応インデックスへの移行手順
-
レイヤー別(要件定義/仕様/設計/説明)にインデックスを分割管理する設計
-
Pythonでのインデックス作成・ドキュメント登録の実装例
対象読者
-
Azure AI Searchを使ったRAGシステムを構築・運用している方
-
キーワード検索からハイブリッド検索への移行を検討している方
前提条件
-
Azure AI Searchリソースが作成済み
-
Azure OpenAI Serviceでembeddingsモデル(text-embedding-3-small等)がデプロイ済み
-
Python 3.10+、azure-search-documents ライブラリ
背景: なぜVectorizer対応が必要だったか
当初はキーワード検索のみのインデックスでRAGを構築していましたが、以下の問題がありました:
-
専門用語や表記揺れに弱い — 「エラーハンドリング」で検索しても「例外処理」のドキュメントがヒットしない
-
意味的に関連するドキュメントが取得できない — キーワードが一致しないと検索結果に含まれない
-
ハイブリッド検索を行うにはVectorizedQueryを送る必要があるが、インデックス側にVectorizerが設定されていないとベクトルフィールドが正しく機能しない
移行手順
Step 1: 旧インデックスの削除
Vectorizerなしで作成した旧インデックスを削除します。他のインデックスを誤って消さないよう、削除対象を明示的に指定します。
from azure.search.documents.indexes import SearchIndexClient
from azure.core.credentials import AzureKeyCredential
client = SearchIndexClient(
endpoint="[ENDPOINT]",
credential=AzureKeyCredential("[API_KEY]")
)
# 削除対象のインデックス名を明示的にリストアップ
target_indexes = [
"myapp_basic_knowledge_20260131",
"myapp_requirements_definition_20260131",
"myapp_specification_20260131",
"myapp_detailed_design_20260131",
]
for name in target_indexes:
client.delete_index(name)
print(f"Deleted: {name}")
Step 2: Vectorizer付きインデックスの作成
新しいインデックスにはAzureOpenAIVectorizerを設定します。これにより、検索時にクエリを自動的にベクトル化できます。
from azure.search.documents.indexes.models import (
SearchIndex,
SearchField,
SearchFieldDataType,
VectorSearch,
HnswAlgorithmConfiguration,
VectorSearchProfile,
AzureOpenAIVectorizer,
AzureOpenAIVectorizerParameters,
)
def create_index_with_vectorizer(client, index_name: str):
fields = [
SearchField(name="id", type=SearchFieldDataType.String, key=True),
SearchField(name="content", type=SearchFieldDataType.String, searchable=True),
SearchField(name="file_name", type=SearchFieldDataType.String, filterable=True),
SearchField(name="page", type=SearchFieldDataType.String),
SearchField(name="url", type=SearchFieldDataType.String),
SearchField(
name="content_vector",
type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
searchable=True,
vector_search_dimensions=1536,
vector_search_profile_name="my-vector-profile",
),
]
vector_search = VectorSearch(
algorithms=[HnswAlgorithmConfiguration(name="my-hnsw")],
profiles=[
VectorSearchProfile(
name="my-vector-profile",
algorithm_configuration_name="my-hnsw",
vectorizer_name="my-vectorizer",
)
],
vectorizers=[
AzureOpenAIVectorizer(
vectorizer_name="my-vectorizer",
parameters=AzureOpenAIVectorizerParameters(
resource_url="[AOAI_ENDPOINT]",
deployment_name="text-embedding-3-small",
model_name="text-embedding-3-small",
api_key="[AOAI_API_KEY]",
),
)
],
)
index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search)
client.create_or_update_index(index)
print(f"Created: {index_name}")
Step 3: レイヤー別にドキュメントを登録
ドキュメントをカテゴリ(要件定義、仕様、詳細設計、基礎知識)ごとに別インデックスに振り分けて登録します。これにより、検索時にカテゴリ別のコンテキストを構造的にLLMに渡せます。
LAYER_TO_FOLDER = {
"requirements": "_requirements_definition_",
"specifications": "_specification_",
"detailed_design": "_detailed_design_",
"explanation": "_basic_knowledge_",
}
for layer, folder in LAYER_TO_FOLDER.items():
index_name = f"{prefix}{folder}{date_suffix}"
create_index_with_vectorizer(client, index_name)
# レイヤーに属するチャンクを抽出して登録
chunks = [c for c in all_chunks if c["layer"] == layer]
search_client = client.get_search_client(index_name)
search_client.upload_documents(chunks)
検索側の実装: ハイブリッド検索
インデックスにVectorizerを設定したら、検索側でVectorizedQueryを使ったハイブリッド検索が可能になります。
from azure.search.documents.models import VectorizedQuery
def search_with_hybrid(index_name: str, query: str, top: int = 5):
vector_query = VectorizedQuery(
vector=generate_embeddings(query),
k_nearest_neighbors=top,
fields="content_vector",
)
search_client = client.get_search_client(index_name)
results = search_client.search(
search_text=query, # キーワード検索
vector_queries=[vector_query], # ベクトル検索
select=["content", "file_name", "page", "url"],
top=top,
)
return results
Tips
参考リンク
まとめ
-
Vectorizerなしのインデックスではハイブリッド検索が正しく機能しないため、Vectorizer付きで再作成が必要
-
AzureOpenAIVectorizerを使うことで、検索時のクエリベクトル化をAzure側に任せられる
-
ドキュメントをレイヤー別インデックスに分割することで、RAGのコンテキスト構造が明確になる
最新記事
- 【設定・環境構築】OpenNext でNext.js SSGサイトをCloudflare Workersにデプロイする完全ガイド
2026/3/19
- 【実装】Notion calloutブロックをNext.jsでカラフルなUIコンポーネントとして表示する
2026/3/19
- 【トラブルシューティング】Cloudflare Pages → Workers 移行で遭遇したEdge Runtime問題集
2026/3/19
- 【実践】Next.js 13→16メジャーアップグレードの全記録 — 破壊的変更と対応策
2026/3/19
- 【自動化】Gemini Imagen APIでブログのeyecatch画像を自動生成してR2にアップロードする
2026/3/19
- 【実装】Notion APIでブログシステムを構築する(Next.js 13 App Router × SDK v5)
2026/3/19
- 【移行ガイド】microCMSからNotion APIへブログCMSを完全移行する
2026/3/19
- 【トラブルシューティング】本番デプロイで遭遇した問題と解決策まとめ
2026/3/15
- 【環境構築】Next.js × Cloudflare Workers の本番環境を一から構築する
2026/3/15
- 【設定・環境構築】Neon → Prisma Postgres 移行とローカル開発環境の構築
2026/2/26




