

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 ライブラリ
当初はキーワード検索のみのインデックスでRAGを構築していましたが、以下の問題がありました:
専門用語や表記揺れに弱い — 「エラーハンドリング」で検索しても「例外処理」のドキュメントがヒットしない
意味的に関連するドキュメントが取得できない — キーワードが一致しないと検索結果に含まれない
ハイブリッド検索を行うにはVectorizedQueryを送る必要があるが、インデックス側にVectorizerが設定されていないとベクトルフィールドが正しく機能しない
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}")
新しいインデックスには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}")
ドキュメントをカテゴリ(要件定義、仕様、詳細設計、基礎知識)ごとに別インデックスに振り分けて登録します。これにより、検索時にカテゴリ別のコンテキストを構造的に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
Vectorizerなしのインデックスではハイブリッド検索が正しく機能しないため、Vectorizer付きで再作成が必要
AzureOpenAIVectorizerを使うことで、検索時のクエリベクトル化をAzure側に任せられる
ドキュメントをレイヤー別インデックスに分割することで、RAGのコンテキスト構造が明確になる