# 機能設計書 80-チャンクストア

## 概要

本ドキュメントは、GiselleワークフローシステムのRAG（Retrieval-Augmented Generation）パイプラインにおけるチャンクストア機能の設計を記述する。この機能は、チャンクデータをPostgreSQLに保存・管理する。

### 本機能の処理概要

**業務上の目的・背景**：RAGシステムにおいて、埋め込み生成されたチャンクデータを永続化し、検索可能な状態で管理する必要がある。この機能は、pgvector拡張を使用したPostgreSQLにチャンクデータと埋め込みベクトルを保存し、差分インジェストのためのバージョン管理、孤立ドキュメントの削除などの機能を提供する。

**機能の利用シーン**：
- インジェストパイプラインがドキュメントチャンクを保存する場面
- 差分インジェスト時に既存バージョンを照会する場面
- 削除されたドキュメントのチャンクをクリーンアップする場面
- メタデータのみを更新する場面

**主要な処理内容**：
1. チャンクの挿入（既存チャンクの削除→新規挿入のトランザクション）
2. ドキュメントキーによるチャンクの削除
3. 複数ドキュメントの一括削除
4. ドキュメントバージョン情報の取得（差分インジェスト用）
5. メタデータのみの更新（再埋め込み不要時）

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

**権限による制御**：PostgreSQLデータベースへの読み書き権限が必要。

## 関連画面

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

## 機能種別

データ永続化・CRUD操作

## 入力仕様

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

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| database | DatabaseConfig | Yes | データベース接続設定 | connectionString必須 |
| tableName | string | Yes | 保存先テーブル名 | - |
| metadataSchema | z.ZodType<TMetadata> | Yes | メタデータのZodスキーマ | - |
| scope | Record<string, unknown> | Yes | スコープ（フィルター条件の基底） | - |
| embeddingProfileId | number | Yes | 埋め込みプロファイルID | 有効なプロファイルIDであること |
| requiredColumnOverrides | Partial<RequiredColumns> | No | 必須カラムのオーバーライド | - |
| metadataColumnOverrides | Partial<Record<keyof TMetadata, string>> | No | メタデータカラムのオーバーライド | - |

### 入力パラメータ（各メソッド）

#### insert

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| documentKey | string | Yes | ドキュメントの一意キー | - |
| chunks | ChunkWithEmbedding[] | Yes | 埋め込み付きチャンク配列 | - |
| metadata | TMetadata | Yes | ドキュメントメタデータ | スキーマに適合すること |

#### delete

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| documentKey | string | Yes | 削除対象のドキュメントキー | - |

#### deleteBatch

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| documentKeys | string[] | Yes | 削除対象のドキュメントキー配列 | - |

#### updateMetadata

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| documentKey | string | Yes | 更新対象のドキュメントキー | - |
| metadata | TMetadata | Yes | 新しいメタデータ | スキーマに適合すること |

### 入力データソース

- インジェストパイプラインからのチャンクデータ

## 出力仕様

### 出力データ

#### insert/delete/deleteBatch/updateMetadata

戻り値なし（Promise<void>）

#### getDocumentVersions

| 項目名 | 型 | 説明 |
|--------|-----|------|
| documentKey | string | ドキュメントキー |
| version | string | コンテンツバージョン |
| metadataVersion | string \| undefined | メタデータバージョン |

### 出力先

- PostgreSQLチャンクテーブル

## 処理フロー

### 処理シーケンス（insert）

```
1. メタデータスキーマ検証
   └─ metadataSchema.safeParse(metadata)

2. 空チャンク配列チェック
   └─ chunks.length === 0 の場合は早期リターン

3. プール接続取得
   └─ PoolManager.getPool(database)

4. pgvector型初期化
   └─ ensurePgVectorTypes(client, connectionString)

5. トランザクション開始
   └─ BEGIN

6. 既存チャンク削除
   └─ deleteChunksByDocumentKey()

7. チャンクレコード準備
   └─ prepareChunkRecords()

8. チャンク挿入
   └─ insertChunkRecords()

9. トランザクションコミット
   └─ COMMIT

10. クリーンアップ
    └─ client.release()
```

### フローチャート

```mermaid
flowchart TD
    subgraph insert [insert処理]
        A[開始] --> B{メタデータ検証}
        B -->|NG| C[ValidationError]
        B -->|OK| D{chunks空?}
        D -->|Yes| E[早期リターン]
        D -->|No| F[プール接続取得]
        F --> G[pgvector初期化]
        G --> H[BEGIN]
        H --> I[既存チャンク削除]
        I --> J[チャンクレコード準備]
        J --> K[チャンク挿入]
        K --> L{成功?}
        L -->|Yes| M[COMMIT]
        L -->|No| N[ROLLBACK]
        M --> O[client.release]
        N --> P[DatabaseError]
        O --> Q[終了]
    end

    subgraph delete [delete処理]
        R[開始] --> S[プール接続取得]
        S --> T[pgvector初期化]
        T --> U[deleteChunksByDocumentKey]
        U --> V[client.release]
        V --> W[終了]
    end

    subgraph getVersions [getDocumentVersions処理]
        X[開始] --> Y{version列設定?}
        Y -->|No| Z[ConfigurationError]
        Y -->|Yes| AA[プール接続取得]
        AA --> AB[pgvector初期化]
        AB --> AC[queryDocumentVersions]
        AC --> AD[client.release]
        AD --> AE[結果返却]
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 空配列早期リターン | chunks配列が空の場合は処理をスキップ | insert時 |
| BR-02 | トランザクション保証 | 削除と挿入は同一トランザクション内で実行 | insert時 |
| BR-03 | バージョン列必須 | getDocumentVersionsはversion列の設定が必須 | getDocumentVersions呼び出し時 |
| BR-04 | メタデータ検証 | insert/updateMetadataはスキーマ検証を実行 | 常時 |
| BR-05 | スコープフィルター | 全操作はscopeで指定された条件内で実行 | 常時 |
| BR-06 | プロファイル固定 | 全操作は指定された埋め込みプロファイルIDと次元数でフィルター | 常時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| insert | チャンクテーブル | DELETE + INSERT | 既存削除後に新規挿入 |
| delete | チャンクテーブル | DELETE | 指定キーのチャンク削除 |
| deleteBatch | チャンクテーブル | DELETE | 複数キーのチャンク一括削除 |
| getDocumentVersions | チャンクテーブル | SELECT DISTINCT | ドキュメントバージョン取得 |
| updateMetadata | チャンクテーブル | UPDATE | メタデータフィールド更新 |

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

#### insert

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | document_key | = $1 AND scope conditions | 既存チャンク削除 |
| INSERT | document_key | ドキュメントキー | - |
| INSERT | chunk_content | チャンク内容 | - |
| INSERT | chunk_index | チャンクインデックス | - |
| INSERT | embedding_vector | 埋め込みベクトル | pgvector形式 |
| INSERT | embedding_profile_id | プロファイルID | - |
| INSERT | embedding_dimensions | 次元数 | - |
| INSERT | metadata columns | メタデータ各値 | - |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | メタデータスキーマ不適合 | メタデータを確認・修正 |
| - | ConfigurationError | version列未設定でgetDocumentVersions呼び出し | version列を設定 |
| - | ConfigurationError | 無効な埋め込みプロファイルID | 有効なプロファイルIDを使用 |
| - | DatabaseError.transactionFailed | トランザクション失敗 | DB接続・権限を確認 |
| - | DatabaseError.queryFailed | クエリ実行エラー | SQL文・テーブル構造を確認 |

### リトライ仕様

本モジュール自体にはリトライロジックは含まれない。インジェストパイプラインのretryOperationで処理される。

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

- insert: DELETE + INSERTを同一トランザクション内で実行
- delete/deleteBatch/updateMetadata: 単一操作のため暗黙的トランザクション
- getDocumentVersions: 読み取り専用

## パフォーマンス要件

- 単一ドキュメントの挿入: 通常500ms以内
- バッチ削除: ドキュメント数に応じてスケール
- バージョン取得: インデックス使用により通常100ms以内

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

- SQLインジェクション対策: パラメタライズドクエリとescapeIdentifierを使用
- 接続文字列はセキュアに管理
- scopeによりテナント分離を実現

## 備考

- pgvector拡張が有効なPostgreSQLが必要
- 埋め込みプロファイルIDと次元数でデータを分離管理
- deleteBatchは空配列の場合は早期リターン

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/rag/src/chunk-store/types.ts` | ChunkStore、ChunkWithEmbedding型定義 |

**読解のコツ**: ChunkStoreインターフェースが5つのメソッド（insert、delete、deleteBatch、getDocumentVersions、updateMetadata）を持つことを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | postgres-chunk-store.ts | `packages/rag/src/chunk-store/postgres/postgres-chunk-store.ts` | createPostgresChunkStore関数 |

**主要処理フロー**:
1. **26-45行目**: createPostgresChunkStore関数のシグネチャと設定抽出
2. **47-51行目**: カラムマッピング作成
3. **53-65行目**: 埋め込みプロファイル検証
4. **70-133行目**: insert関数の実装
5. **138-166行目**: delete（deleteDocument）関数の実装
6. **171-204行目**: deleteBatch関数の実装
7. **209-251行目**: getDocumentVersions関数の実装
8. **256-298行目**: updateMetadata関数の実装

#### Step 3: ユーティリティ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | utils.ts | `packages/rag/src/chunk-store/postgres/utils.ts` | データベース操作ユーティリティ |

**主要処理フロー**:
- deleteChunksByDocumentKey: ドキュメントキーによる削除
- deleteChunksByDocumentKeys: 複数キーによる一括削除
- prepareChunkRecords: 挿入用レコード準備
- insertChunkRecords: バルクインサート
- queryDocumentVersions: バージョン照会
- updateMetadataFields: メタデータ更新

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

```
createPostgresChunkStore(config)
    │
    ├─ createColumnMapping()
    ├─ EMBEDDING_PROFILES検証
    │
    └─ ChunkStore  [返却されるオブジェクト]
           │
           ├─ insert(documentKey, chunks, metadata)
           │      ├─ metadataSchema.safeParse()
           │      ├─ PoolManager.getPool()
           │      ├─ ensurePgVectorTypes()
           │      ├─ BEGIN
           │      ├─ deleteChunksByDocumentKey()
           │      ├─ prepareChunkRecords()
           │      ├─ insertChunkRecords()
           │      └─ COMMIT / ROLLBACK
           │
           ├─ delete(documentKey)
           │      ├─ PoolManager.getPool()
           │      ├─ ensurePgVectorTypes()
           │      └─ deleteChunksByDocumentKey()
           │
           ├─ deleteBatch(documentKeys)
           │      ├─ PoolManager.getPool()
           │      ├─ ensurePgVectorTypes()
           │      └─ deleteChunksByDocumentKeys()
           │
           ├─ getDocumentVersions()
           │      ├─ version列設定確認
           │      ├─ PoolManager.getPool()
           │      ├─ ensurePgVectorTypes()
           │      └─ queryDocumentVersions()
           │
           └─ updateMetadata(documentKey, metadata)
                  ├─ metadataSchema.safeParse()
                  ├─ PoolManager.getPool()
                  ├─ ensurePgVectorTypes()
                  └─ updateMetadataFields()
```

### データフロー図

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

documentKey ─────────────┐
                         │
chunks ──────────────────┼──▶ insert()
                         │        │
metadata ────────────────┘        ├─ メタデータ検証
                                  ├─ BEGIN
                                  ├─ 既存DELETE
                                  ├─ INSERT
                                  └─ COMMIT
                                          │
                                          ▼
                                    PostgreSQL
                                    チャンクテーブル
                                          │
                                          │
getDocumentVersions() ◀───────────────────┤
        │                                  │
        ▼                                  │
  Array<{documentKey,                      │
         version,                          │
         metadataVersion}>                 │
                                          │
deleteBatch(keys) ────────────────────────▶│ DELETE
                                          │
updateMetadata() ─────────────────────────▶│ UPDATE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| postgres-chunk-store.ts | `packages/rag/src/chunk-store/postgres/postgres-chunk-store.ts` | ソース | メイン実装 |
| types.ts | `packages/rag/src/chunk-store/types.ts` | ソース | 型定義 |
| utils.ts | `packages/rag/src/chunk-store/postgres/utils.ts` | ソース | DB操作ユーティリティ |
| column-mapping.ts | `packages/rag/src/chunk-store/column-mapping.ts` | ソース | カラムマッピング |
| pool-manager.ts | `packages/rag/src/database/postgres/pool-manager.ts` | ソース | プール管理 |
| errors.ts | `packages/rag/src/errors.ts` | ソース | エラークラス |
