# 機能設計書 79-クエリサービス

## 概要

本ドキュメントは、GiselleワークフローシステムのRAG（Retrieval-Augmented Generation）パイプラインにおけるクエリサービス機能の設計を記述する。この機能は、ベクトルストアに対する類似検索を実行する。

### 本機能の処理概要

**業務上の目的・背景**：RAGシステムにおいて、ユーザーの質問や検索クエリに対して意味的に関連するドキュメントチャンクを効率的に検索する必要がある。この機能は、検索クエリを埋め込みに変換し、pgvectorを使用したPostgreSQLデータベースに対してコサイン類似度検索を実行する。検索結果には類似度スコアとメタデータが含まれ、後続のAIテキスト生成に活用される。

**機能の利用シーン**：
- ワークフロー内のクエリノードがベクトルストアを検索する場面
- AIテキスト生成時に関連コンテキストを取得する場面
- ナレッジベースから関連情報を抽出する場面

**主要な処理内容**：
1. 検索クエリを埋め込みベクトルに変換
2. コンテキスト情報からフィルター条件を構築
3. pgvectorの距離関数を使用してベクトル類似検索を実行
4. 検索結果をメタデータ付きで返却
5. オプションでadditionalResolverによる追加処理

**関連システム・外部連携**：
- Embedderを介した埋め込み生成API
- pgvector拡張を有効にしたPostgreSQLデータベース
- コネクションプールマネージャー

**権限による制御**：埋め込みAPIキーおよびPostgreSQL接続権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 31 | GitHub Vector Store設定画面 | 主機能 | GitHubリポジトリのベクターストア設定と管理 |
| 32 | ドキュメントVector Store設定画面 | 主機能 | ドキュメントのベクターストア設定と管理 |

## 機能種別

データ検索・ベクトル類似検索

## 入力仕様

### 入力パラメータ（createPostgresQueryService関数）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| database | DatabaseConfig | Yes | データベース接続設定 | connectionString必須 |
| tableName | string | Yes | 検索対象テーブル名 | - |
| contextToEmbeddingProfileId | (context) => EmbeddingProfileId | Yes | コンテキストから埋め込みプロファイル取得関数 | - |
| contextToFilter | (context) => Record<string, unknown> | Yes | コンテキストからフィルター条件生成関数 | - |
| metadataSchema | z.ZodType<TMetadata> | Yes | メタデータのZodスキーマ | - |
| requiredColumnOverrides | Partial<RequiredColumns> | No | 必須カラムのオーバーライド | - |
| metadataColumnOverrides | Partial<Record<keyof TMetadata, string>> | No | メタデータカラムのオーバーライド | - |
| additionalResolver | (results, context) => Promise<QueryResult[]> | No | 追加の結果処理関数 | - |

### 入力パラメータ（search関数）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| query | string | Yes | 検索クエリ文字列 | - |
| context | TContext | Yes | 検索コンテキスト（フィルター用） | - |
| limit | number | No | 結果数上限（デフォルト: 10） | - |
| similarityThreshold | number | No | 類似度閾値（0-1） | - |
| embeddingComplete | EmbeddingCompleteCallback | No | 埋め込み完了コールバック | - |
| headers | Record<string, string> | No | AI Gateway用HTTPヘッダー | - |

### 入力データソース

- ワークフローからの検索クエリ
- PostgreSQLベクトルストア（pgvector）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| QueryResult[].chunk.content | string | チャンクのテキスト内容 |
| QueryResult[].chunk.index | number | チャンクインデックス |
| QueryResult[].similarity | number | 類似度スコア（0-1） |
| QueryResult[].metadata | TMetadata | メタデータ（スキーマ定義による） |
| QueryResult[].additional | Record<string, unknown> | 追加情報（additionalResolver使用時） |

### 出力先

- 呼び出し元（クエリノード、テキスト生成処理）への戻り値

## 処理フロー

### 処理シーケンス

```
1. データベース設定の検証
   └─ connectionStringの存在確認、poolConfigのバリデーション

2. カラムマッピングの作成
   └─ createColumnMappingでスキーマからカラム名をマッピング

3. search関数実行
   ├─ プール接続の取得
   ├─ pgvector型の初期化
   └─ クライアントリリース

4. 埋め込み生成
   ├─ コンテキストからプロファイルID取得
   ├─ APIキー取得（Gateway or Provider）
   ├─ Embedder作成
   └─ クエリを埋め込みに変換

5. フィルター条件の構築
   └─ contextToFilter(context)でフィルター取得

6. SQLクエリの構築
   ├─ SELECT句（content、index、metadata、similarity）
   ├─ WHERE句（フィルター、埋め込みプロファイル、類似度閾値）
   └─ ORDER BY句（距離順）、LIMIT句

7. クエリ実行
   └─ pool.query(sql, values)

8. 結果のマッピング
   └─ mapRowToResultでDBの行をQueryResultに変換

9. 追加処理（additionalResolver設定時）
   └─ additionalResolver(mappedResults, context)

10. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{データベース検証}
    B -->|NG| C[ValidationError]
    B -->|OK| D[カラムマッピング作成]
    D --> E[search呼び出し]

    subgraph search_process [search処理]
        F[プール接続取得] --> G[pgvector型初期化]
        G --> H[プロファイルID取得]
        H --> I{APIキー取得}
        I -->|なし| J[ConfigurationError]
        I -->|あり| K[Embedder作成]
        K --> L[クエリ埋め込み生成]
        L --> M[フィルター条件取得]
        M --> N[SQLクエリ構築]
        N --> O[クエリ実行]
        O --> P[結果マッピング]
        P --> Q{additionalResolver?}
        Q -->|Yes| R[追加処理]
        Q -->|No| S[結果返却]
        R --> S
    end

    E --> F
    C --> T[終了]
    J --> T
    S --> T
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | デフォルト検索件数 | limitのデフォルト値は10件 | limit未指定時 |
| BR-02 | 類似度閾値 | similarityThreshold指定時、閾値未満の結果を除外 | 閾値 > 0 |
| BR-03 | 埋め込み次元キャスト | 3072次元はhalfvec(3072)、それ以外はvector(1536)にキャスト | 常時 |
| BR-04 | 距離順ソート | コサイン距離の昇順（類似度の降順）でソート | 常時 |
| BR-05 | メタデータ検証 | 取得したメタデータはZodスキーマで検証 | 常時 |

### 計算ロジック

類似度計算：
```sql
-- コサイン類似度 = 1 - コサイン距離
1 - (vector_column <=> $1) as similarity
```

埋め込み次元に応じたキャスト：
```typescript
const embeddingCast = embeddingDimensions === 3072
    ? `${column}::halfvec(3072)`
    : `${column}::vector(1536)`;
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ベクトル検索 | チャンクテーブル | SELECT | コサイン類似度による検索 |

### テーブル別操作詳細

#### チャンクテーブル

| 操作 | 項目（カラム名） | 取得条件 | 備考 |
|-----|-----------------|---------|------|
| SELECT | chunk_content | - | チャンク内容 |
| SELECT | chunk_index | - | チャンクインデックス |
| SELECT | embedding_vector | ORDER BY用 | 埋め込みベクトル |
| SELECT | metadata columns | - | メタデータ各カラム |
| WHERE | embedding_profile_id | = $2 | プロファイルID |
| WHERE | embedding_dimensions | = $3 | 次元数 |
| WHERE | filter columns | = $N | ユーザー指定フィルター |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | connectionString未設定 | 接続文字列を設定 |
| - | ValidationError | poolConfigの値が範囲外 | 有効な値を設定 |
| - | ConfigurationError | 無効な埋め込みプロファイルID | 有効なプロファイルIDを使用 |
| - | ConfigurationError | 埋め込みAPIキー未設定 | 環境変数にAPIキーを設定 |
| - | DatabaseError | SQLクエリ実行エラー | SQL文、接続設定を確認 |
| - | ValidationError | メタデータスキーマ不適合 | スキーマ定義を確認 |

### リトライ仕様

本関数自体にはリトライロジックは含まれない。Embedderのリトライ設定に依存。

## トランザクション仕様

読み取り専用のためトランザクション管理は不要。

## パフォーマンス要件

- 埋め込み生成: 通常1秒以内
- ベクトル検索: インデックス最適化により通常100ms以内
- pgvectorのIVFFlatまたはHNSWインデックス使用を推奨

## セキュリティ考慮事項

- 検索クエリは外部埋め込みAPIに送信される
- SQLインジェクション対策: escapeIdentifierでカラム名をエスケープ
- パラメタライズドクエリでフィルター値を安全に渡す

## 備考

- pgvector拡張が有効なPostgreSQLが必要
- halfvec(3072)はOpenAI text-embedding-3-large用
- vector(1536)はOpenAI text-embedding-3-small、Google等用

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/rag/src/query-service/types.ts` | QueryResult、QueryService型定義 |

**読解のコツ**: QueryResultがchunk、similarity、metadataを含む構造であることを理解する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/rag/src/query-service/postgres/index.ts` | createPostgresQueryService関数 |

**主要処理フロー**:
1. **45-79行目**: バリデーション関数（validatePoolConfig、validateDatabase）
2. **81-98行目**: createPostgresQueryService関数のシグネチャと初期設定
3. **99-104行目**: カラムマッピング作成
4. **106-193行目**: search関数の実装
5. **195-268行目**: buildSearchQuery - SQL構築
6. **294-310行目**: mapRowToResult - 結果マッピング

#### Step 3: SQL構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/rag/src/query-service/postgres/index.ts` | buildSearchQuery関数 |

**主要処理フロー**:
- **219-223行目**: 埋め込み次元に応じたキャスト決定
- **225-238行目**: WHERE条件の構築（フィルター、プロファイル、閾値）
- **254-264行目**: SELECT文の構築

### プログラム呼び出し階層図

```
createPostgresQueryService(config)
    │
    ├─ validateDatabase()
    ├─ createColumnMapping()
    │
    └─ { search }  [返却されるオブジェクト]
           │
           └─ search(query, context, limit, ...)
                  │
                  ├─ PoolManager.getPool()
                  ├─ pool.connect()
                  ├─ ensurePgVectorTypes()
                  │
                  ├─ contextToEmbeddingProfileId(context)
                  ├─ EMBEDDING_PROFILES[profileId]
                  ├─ createEmbedderFromProfile()
                  ├─ embedder.embed(query)
                  │
                  ├─ contextToFilter(context)
                  │
                  ├─ buildSearchQuery()
                  │      └─ SQL文とvalues構築
                  │
                  ├─ pool.query(sql, values)
                  │
                  ├─ mapRowToResult()
                  │      └─ parseMetadata()
                  │
                  └─ additionalResolver?()
```

### データフロー図

```
[入力]                        [処理]                        [出力]

query ──────────────────▶ embedder.embed() ──────▶ queryEmbedding
                                                        │
context ────────────────▶ contextToFilter() ────▶ filters
                                                        │
                                                        ▼
                                            buildSearchQuery()
                                                        │
                                              ┌─────────┴─────────┐
                                              │                   │
                                           SQL文              values配列
                                              │                   │
                                              └─────────┬─────────┘
                                                        │
                                                        ▼
                                              pool.query(sql, values)
                                                        │
                                                        ▼
                                              rows配列
                                                        │
                                                        ▼
                                              mapRowToResult()
                                                        │
                                                        ▼
                                              QueryResult[]
                                                        │
                         ┌──────────────────────────────┴──────────────────────────────┐
                         │                                                              │
                    [additionalResolver未設定]                               [additionalResolver設定]
                         │                                                              │
                         ▼                                                              ▼
                    QueryResult[]                                     additionalResolver(results, context)
                                                                                        │
                                                                                        ▼
                                                                                QueryResult[]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/rag/src/query-service/postgres/index.ts` | ソース | メイン実装 |
| types.ts | `packages/rag/src/query-service/types.ts` | ソース | 型定義 |
| column-mapping.ts | `packages/rag/src/query-service/column-mapping.ts` | ソース | カラムマッピング |
| pool-manager.ts | `packages/rag/src/database/postgres/pool-manager.ts` | ソース | プール管理 |
| errors.ts | `packages/rag/src/errors.ts` | ソース | エラークラス |
