Part 2で学ぶこと
Part 1では、Azure AI Searchへのデータの入れ方(プッシュモデルとプルモデル)を学びました。
Part 2では、そのデータを「どう保存するか」について詳しく見ていきます:
- 検索インデックスの構造
- フィールドの設計方法
- ベクターインデックスとは?
- RAGアプリケーションへの活用
検索インデックス: データの「住所録」を作ろう
インデックスって結局何なの?
一言で表すと: 検索用に最適化されたデータの保管場所です。
普通のデータベースとの違い:
| 項目 | 普通のDB (SQL Database) | 検索インデックス |
|---|---|---|
| 得意なこと | データの保存・更新 | 高速な検索 |
| データの持ち方 | 行と列 | ドキュメント |
| 検索方法 | SQL文 | 全文検索・ベクトル検索 |
| 更新頻度 | リアルタイム | 少し遅れることがある |
例え話:
- データベース = 会社の人事システム(正確な情報管理が重要)
- 検索インデックス = 社内の人物検索システム(素早く見つけることが重要)
インデックスの基本構造
インデックスは「スキーマ」という設計図で定義されます。
スキーマの主要な要素:
{
"name": "hotels-index",
"fields": [
{
"name": "hotelId",
"type": "Edm.String",
"key": true
},
{
"name": "hotelName",
"type": "Edm.String",
"searchable": true
},
{
"name": "rating",
"type": "Edm.Int32",
"filterable": true,
"sortable": true
}
]
}
これを日本語で言うと:
- ホテルID: 各ホテルを識別する鍵(キー)
- ホテル名: 検索可能なテキスト
- 評価: フィルターや並び替えができる数値
フィールドの種類を理解しよう
データ型: どんな種類のデータが保存できる?
Azure AI Searchで使える主なデータ型:
1. 文字列 (Edm.String)
使い道: 名前、説明文、IDなど
例:
{
"name": "title",
"type": "Edm.String"
}
- 商品名: "Apple iPhone 15 Pro"
- 説明文: "最新のスマートフォンです"
2. 数値
種類:
-
Edm.Int32: 整数 (-2,147,483,648 ~ 2,147,483,647) -
Edm.Int64: 大きな整数 -
Edm.Double: 小数
例:
{
"name": "price",
"type": "Edm.Double"
}
- 価格: 129800.00
- 在庫数: 50
3. ブール値 (Edm.Boolean)
使い道: はい/いいえ、有効/無効など
例:
{
"name": "inStock",
"type": "Edm.Boolean"
}
- 在庫あり: true
- 販売中止: false
4. 日時 (Edm.DateTimeOffset)
使い道: 作成日時、更新日時など
例:
{
"name": "publishedDate",
"type": "Edm.DateTimeOffset"
}
- 公開日: "2024-01-15T09:30:00Z"
5. コレクション (Collection)
使い道: 複数の値を持つフィールド
例:
{
"name": "tags",
"type": "Collection(Edm.String)"
}
- タグ: ["セール", "人気", "新商品"]
6. ベクトル (Collection(Edm.Single))
使い道: AI検索用の数値ベクトル
例:
{
"name": "contentVector",
"type": "Collection(Edm.Single)",
"dimensions": 1536
}
- これについては後で詳しく説明します!
フィールド属性: フィールドに「特技」を持たせよう
フィールドには、それぞれ「できること」を設定できます。
主な属性一覧
| 属性 | 意味 | 使い道 |
|---|---|---|
key |
主キー | ドキュメントを一意に識別 |
searchable |
全文検索可能 | キーワード検索の対象 |
filterable |
フィルター可能 | 条件絞り込み |
sortable |
並び替え可能 | 価格順、日付順など |
facetable |
ファセット可能 | カテゴリ別集計 |
retrievable |
取得可能 | 検索結果に含める |
1. key (キー)
必須の属性! 各ドキュメントを識別する唯一の値
ルール:
- インデックスに1つだけ
- Edm.String型のみ
- 値は重複不可
例:
{
"name": "productId",
"type": "Edm.String",
"key": true
}
2. searchable (検索可能)
全文検索の対象にする
こんな時に使う:
- ユーザーがキーワードで検索するフィールド
- 商品名、説明文、レビューなど
注意点:
- 文字列型(Edm.String)のみ
- 内部で「単語分割」される
- 例: "青いリンゴ" → "青い" + "リンゴ"
例:
{
"name": "description",
"type": "Edm.String",
"searchable": true
}
3. filterable (フィルター可能)
条件で絞り込める
こんな時に使う:
- 「価格が1万円以下」
- 「在庫ありのみ」
- 「カテゴリがスマホ」
例:
{
"name": "category",
"type": "Edm.String",
"filterable": true
}
4. sortable (並び替え可能)
結果を並び替える
こんな時に使う:
- 価格の安い順
- 新着順
- 人気順
注意:
- コレクション型(Collection)は不可
例:
{
"name": "price",
"type": "Edm.Double",
"sortable": true
}
5. facetable (ファセット可能)
カテゴリごとの件数を集計
ECサイトでよく見るやつ:
カテゴリ
├─ スマートフォン (120件)
├─ パソコン (85件)
└─ タブレット (45件)
価格帯
├─ ~1万円 (30件)
├─ 1万~5万円 (150件)
└─ 5万円~ (70件)
例:
{
"name": "brand",
"type": "Edm.String",
"facetable": true
}
6. retrievable (取得可能)
検索結果に含める
ほとんどのフィールドはtrue
falseにする例:
- 内部IDなど、ユーザーに見せたくない情報
- 検索には使うけど表示不要な情報
例:
{
"name": "internalId",
"type": "Edm.String",
"retrievable": false
}
フィールド設計の実践例
シナリオ: ECサイトの商品検索を作る
{
"name": "products-index",
"fields": [
{
"name": "productId",
"type": "Edm.String",
"key": true,
"searchable": false,
"retrievable": true
},
{
"name": "productName",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"sortable": false,
"facetable": false,
"retrievable": true
},
{
"name": "description",
"type": "Edm.String",
"searchable": true,
"filterable": false,
"retrievable": true
},
{
"name": "price",
"type": "Edm.Double",
"searchable": false,
"filterable": true,
"sortable": true,
"facetable": true,
"retrievable": true
},
{
"name": "category",
"type": "Edm.String",
"searchable": false,
"filterable": true,
"sortable": false,
"facetable": true,
"retrievable": true
},
{
"name": "inStock",
"type": "Edm.Boolean",
"filterable": true,
"retrievable": true
},
{
"name": "tags",
"type": "Collection(Edm.String)",
"searchable": true,
"filterable": true,
"facetable": true,
"retrievable": true
}
]
}
この設計のポイント:
-
productName,description: キーワード検索の対象 -
price: 価格順ソート、価格帯フィルター、価格帯ファセット -
category: カテゴリ絞り込み、カテゴリファセット -
inStock: 在庫ありフィルター -
tags: タグ検索、タグ絞り込み、タグファセット
インデックスのサイズを理解しよう
サイズに影響する要因
インデックスのサイズ(ストレージ容量)は、以下の要素で決まります:
1. ドキュメント数
当たり前ですが: 件数が多いほど大きくなります
2. フィールドの属性
意外と重要! 属性によってストレージ消費量が変わります
実験結果の例:
-
retrievableのみ: ベースライン -
filterable+sortable+facetable: 約2~3倍 -
searchable: 約1.5~2倍 - 全属性ON: 約3~4倍
理由: 各属性に対応する内部データ構造が作られるため
3. suggester (サジェスト機能)
これが曲者!
suggesterとは?
- Googleの検索ボックスのような「入力補完」機能
- "appl" → "apple", "application" と候補を出す
ストレージへの影響:
- インデックスサイズが大幅に増加することがある
- 必要なフィールドにのみ設定すべき
サイズ最適化のTips
✅ 必要最小限の属性を設定
- 使わない属性はOFFに
- 例: 内部IDは
searchableにしない
✅ suggesterは慎重に
- ユーザーが実際に入力するフィールドのみ
✅ 定期的なサイズ監視
- Azure Portalでストレージ使用量を確認
ベクターインデックス: 次世代の検索を理解しよう
ベクター検索って何?
従来のキーワード検索:
- 「リンゴ」で検索 → "リンゴ"という単語が含まれる文書を探す
- 完全一致または部分一致
ベクター検索:
- 「リンゴ」で検索 → "果物", "赤い", "甘い" など意味が似ている文書を探す
- 意味の類似度で検索
例えばこんな検索ができる:
クエリ: "スマホの充電が遅い"
キーワード検索の結果:
- "充電"や"遅い"という言葉が入った記事
ベクター検索の結果:
- "バッテリーのチャージ時間を改善する方法"
- "高速充電に対応した充電器"
- ← 単語は違うけど意味が似ている!
ベクトルって何?
簡単に言うと: テキストや画像を数値の列に変換したもの
イメージ:
"犬" → [0.2, 0.8, 0.1, 0.5, ..., 0.3] (1536個の数値)
"猫" → [0.3, 0.7, 0.2, 0.4, ..., 0.4] (1536個の数値)
"車" → [0.8, 0.1, 0.9, 0.2, ..., 0.1] (1536個の数値)
ポイント:
- 意味が似ているものは、数値も似てくる
- "犬"と"猫"のベクトルは近い
- "犬"と"車"のベクトルは遠い
ベクターフィールドの定義方法
{
"name": "contentVector",
"type": "Collection(Edm.Single)",
"searchable": true,
"retrievable": true,
"dimensions": 1536,
"vectorSearchProfile": "my-vector-profile"
}
重要なプロパティ:
-
dimensions (次元数)
- 使用する埋め込みモデルに合わせる
- 例: OpenAIの
text-embedding-ada-002は1536次元
-
vectorSearchProfile
- どのアルゴリズムで検索するか
- HNSW (高速)またはExhaustive KNN (高精度)
実践: テキスト検索とベクトル検索を組み合わせる
ベクターインデックスの基本構造:
{
"name": "documents-index",
"fields": [
{
"name": "id",
"type": "Edm.String",
"key": true
},
{
"name": "content",
"type": "Edm.String",
"searchable": true,
"retrievable": true
},
{
"name": "contentVector",
"type": "Collection(Edm.Single)",
"searchable": true,
"retrievable": true,
"dimensions": 1536,
"vectorSearchProfile": "my-vector-profile"
},
{
"name": "category",
"type": "Edm.String",
"filterable": true,
"facetable": true
}
]
}
このインデックスでできること:
-
キーワード検索:
contentフィールドで全文検索 -
ベクター検索:
contentVectorフィールドで意味検索 - ハイブリッド検索: 両方を組み合わせて最高の結果を!
- フィルター: カテゴリで絞り込み
RAG (検索拡張生成) への活用
RAGって何?
RAG = Retrieval Augmented Generation
(検索拡張生成)
簡単に言うと: ChatGPTのようなAIに、自社のデータを参照させて回答させる技術
従来のChatGPT:
- 学習済みの知識のみで回答
- 最新情報や社内情報は知らない
RAG を使ったChatGPT:
- 質問に関連するドキュメントを検索
- 検索結果を踏まえて回答
- → 自社データに基づいた正確な回答!
RAGでのインデックス設計
2つのインデックスを使う構成が一般的:
1. コンテンツインデックス
役割: 実際のドキュメントを保存
{
"name": "knowledge-base",
"fields": [
{
"name": "id",
"type": "Edm.String",
"key": true
},
{
"name": "chunk",
"type": "Edm.String",
"searchable": true
},
{
"name": "vector",
"type": "Collection(Edm.Single)",
"dimensions": 1536,
"vectorSearchProfile": "my-profile"
},
{
"name": "source",
"type": "Edm.String",
"filterable": true
}
]
}
ポイント:
-
chunk: ドキュメントを小さく分割したテキスト -
vector: チャンクのベクトル表現 -
source: 元ドキュメントの情報
2. 会話履歴インデックス (オプション)
役割: チャットの履歴を保存
{
"name": "conversations",
"fields": [
{
"name": "id",
"type": "Edm.String",
"key": true
},
{
"name": "conversationId",
"type": "Edm.String",
"filterable": true
},
{
"name": "content",
"type": "Edm.String",
"searchable": true
},
{
"name": "type",
"type": "Edm.String",
"filterable": true
},
{
"name": "createdAt",
"type": "Edm.DateTimeOffset",
"filterable": true,
"sortable": true
}
]
}
ポイント:
-
conversationId: チャットセッションの識別 -
type: "user" または "assistant" -
createdAt: 時系列での管理
チャンキングの重要性
チャンキングとは?
- 大きなドキュメントを小さな塊(チャンク)に分割すること
なぜ必要?
-
AIモデルの入力制限
- GPT-4などには入力トークン数の制限がある
- 長すぎる文書は丸ごと渡せない
-
検索精度の向上
- 小さな単位で検索した方が関連部分を正確に取得できる
-
コストの削減
- 必要な部分だけをAIに渡せる
チャンクサイズの目安:
- 一般的: 500~1000トークン
- 重なり(オーバーラップ): 50~100トークン
Part 2のまとめ
押さえておきたいポイント:
📌 インデックスはスキーマで設計
- フィールドの型と属性を適切に設定
- 属性によってストレージ消費量が変わる
📌 フィールド属性の使い分け
- searchable: キーワード検索
- filterable: 絞り込み
- sortable: 並び替え
- facetable: カテゴリ集計
📌 ベクター検索は意味で検索
- 単語の一致ではなく意味の類似度
- ハイブリッド検索で最高の結果
📌 RAGではチャンキングが重要
- 適切なサイズに分割
- 検索精度とコストのバランス
次のPart 3では:
-
インデクサーの詳細
- スキルセットとAIエンリッチメント
- スケジュール設定と監視
-
ナレッジストア
- 分析用のデータ保存
- Power BIとの連携
Azure AI Searchのデータ管理完全ガイド - Part 3: インデクサーとナレッジストアを使いこなそう
Azure AI Searchのデータ管理完全ガイド - Part 1: データの流れを理解しよう
この記事が役に立ったら、ぜひ「いいね」をお願いします!質問やフィードバックもお待ちしています。