Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
513 changes: 513 additions & 0 deletions dev-reports/design/issue-63-semantic-search-design-policy.md

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions dev-reports/issue/63/issue-review/hypothesis-verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 仮説検証レポート(Issue #63: Semantic Search)

## 検証結果サマリー

| 仮説 | 判定 | 説明 |
|------|------|------|
| 1. CLIオプション排他性 | Partially Confirmed | `--semantic`未実装。排他性パターンは既存(`--related`)で実績あり |
| 2a. EmbeddingProvider | Confirmed | Ollama/OpenAIプロバイダー実装済み |
| 2b. コサイン類似度検索 | Confirmed | `search_similar()`でSQLite embeddingsテーブルからtop-k検索可能 |
| 2c. Tantivyメタデータ | Confirmed | IndexReaderWrapperでメタデータ取得可能 |
| 3. フィルタ機能 | Confirmed | `--tag`, `--path`, `--type`実装済み |
| 4. 出力フォーマット | Confirmed | human/json/path形式対応済み |
| 5. 依存Issue | Confirmed | #61・#62マージ済み、基盤整備完了 |

## 詳細

### 1. CLIオプション排他性
- `src/main.rs` (line 27-59): `--semantic`オプションは未実装
- `--related`の排他性パターン(`conflicts_with_all`)が参考になる
- 新規追加時は`query`, `symbol`, `related`と排他にする

### 2. 検索フロー

#### 2a. EmbeddingProvider
- `src/embedding/mod.rs`: EmbeddingProviderトレイト定義済み
- `embed(&self, texts: &[String]) -> Result<Vec<Vec<f32>>, EmbeddingError>`
- Ollama/OpenAIプロバイダー実装済み

#### 2b. コサイン類似度検索
- `src/indexer/symbol_store.rs` (line 211): `cosine_similarity()`関数
- `search_similar()` (line 602): top-k類似度検索
- `EmbeddingSimilarityResult`: file_path, section_heading, similarity

#### 2c. Tantivyメタデータ取得
- `src/indexer/reader.rs`: SearchResult構造体(path, heading, body, tags等)
- `search_by_exact_path()`でファイルパスからメタデータ取得可能

### 3. フィルタ機能
- `SearchFilters`: path_prefix, file_type
- `SearchOptions`: query, tag, heading, limit
- Post-filterパターンで適用

### 4. 出力フォーマット
- `src/output/mod.rs`: OutputFormat enum (Human, Json, Path)
- 各形式実装済み(human.rs, json.rs, path.rs)

### 5. 依存Issue
- #61 (commit 80397b8): Embedding生成基盤追加
- #62 (commit 935dc28): Embeddingストレージ追加
- 両方マージ済み(commit d85a1b3)

## 未実装項目

1. `--semantic` CLIオプション追加
2. セマンティック検索関数実装
3. フィルタ対応(search_similar後のpost-filter)
4. セマンティック検索結果の出力フォーマット対応
1 change: 1 addition & 0 deletions dev-reports/issue/63/issue-review/original-issue.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"body":"## 概要\n\n`commandindex search --semantic <query>` オプションを実装し、クエリとドキュメントのembedding類似度に基づく意味検索を実現する。\n\n## 背景・動機\n\n全文検索(BM25)ではキーワードの完全一致が必要だが、意味検索により「概念的に近い」ドキュメントを発見できる。例えば「認証の流れ」で検索して「ログインフロー」や「セッション管理」に関するドキュメントが見つかるようになる。\n\n## 提案する解決策\n\n### CLIオプション\n\n```bash\n# 意味検索\ncommandindex search --semantic \"認証の流れ\"\n\n# 出力形式指定\ncommandindex search --semantic \"ログイン処理\" --format json\n\n# 件数制限\ncommandindex search --semantic \"API設計\" --limit 5\n```\n\n### 排他制御\n\n- `--semantic` は `--related` / `--symbol` / 通常query と排他\n- `--tag`, `--path`, `--type` によるフィルタリングは適用可能\n\n### 検索フロー\n\n1. クエリテキストをEmbeddingProviderでベクトル化\n2. SQLiteのembeddingsテーブルからコサイン類似度でtop-k件を取得\n3. tantivy から該当セクションのメタデータ(パス、見出し、スニペット等)を取得\n4. フィルタ(--tag, --path, --type)を適用\n5. 結果を出力\n\n### 出力フォーマット\n\nhuman / json / path の各形式に対応。類似度スコア付き。\n\n```json\n{\"path\":\"docs/auth/design.md\",\"heading\":\"認証フロー\",\"score\":0.89,\"snippet\":\"...\"}\n```\n\n### Embeddingが未生成の場合\n\n- embeddingsテーブルが空の場合:エラーメッセージ + `commandindex embed` の実行を案内\n- Ollamaが起動していない場合(クエリのベクトル化時):適切なエラーメッセージ\n\n## 受け入れ基準\n\n- [ ] `--semantic` でクエリの意味に近いドキュメントが検索できる\n- [ ] 類似度スコアでソートされる\n- [ ] human / json / path 出力形式に対応\n- [ ] `--semantic` と `--related` / `--symbol` / query の排他制御\n- [ ] `--tag`, `--path`, `--type` フィルタが適用できる\n- [ ] embeddingが未生成の場合に適切なエラーメッセージ\n- [ ] Ollamaが起動していない場合に適切なエラーメッセージ\n- [ ] cargo test / clippy / fmt 全パス\n\n## 依存 Issue\n\n- #61 Embedding生成基盤\n- #62 Embeddingストレージ","title":"[Feature] Semantic Search(意味検索)"}
63 changes: 63 additions & 0 deletions dev-reports/issue/63/issue-review/stage1-review-context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"must_fix": [
{
"id": "M1",
"category": "整合性(Embeddingストレージ)",
"description": "Issueの検索フローに「SQLiteのembeddingsテーブルからコサイン類似度でtop-k件を取得」とあるが、実際にはコサイン類似度検索(search_similar)はsymbol_store.rs内のSymbolStoreに実装されており、symbols.db内のembeddingsテーブルを使用する。一方、embedding::store::EmbeddingStoreはembeddings.dbを操作する別のストアであり、search_similar()メソッドを持たない。Issueではどちらのストアを使うか明確にされていない。",
"suggestion": "検索フローの記述を「SymbolStore(symbols.db)のsearch_similar()を使用してコサイン類似度でtop-k件を取得」と明記する。"
},
{
"id": "M2",
"category": "整合性(フィルタ仕様)",
"description": "search_similar()の戻り値EmbeddingSimilarityResultにはfile_pathとsection_headingしか含まれず、tagやfile_type情報がない。タグフィルタの適用にはtantivyのメタデータと結合する必要があるが、結合方法がIssueに記載されていない。また、--relatedオプションは--tag等と排他だが、--semanticでフィルタを許可する場合は異なるconflicts設定が必要。",
"suggestion": "検索フローでsearch_similar()結果のfile_path+section_headingをキーにtantivyのsearch_by_exact_path()でメタデータ取得→フィルタリングの具体的な方法を記述する。"
}
],
"should_fix": [
{
"id": "S1",
"category": "正確性(仮説検証セクション)",
"description": "SearchFilters/SearchOptionsはtantivy全文検索用であり、semantic検索ではsearch_similar()結果へのポストフィルタとして再利用する設計が必要。この点が誤解を招く。",
"suggestion": "semantic検索でのフィルタ方式を明確に補足する。"
},
{
"id": "S2",
"category": "受け入れ基準(出力形式の詳細)",
"description": "JSONサンプルの「score」はEmbeddingSimilarityResultの「similarity」に対応。snippetの取得元も未記載。",
"suggestion": "フィールド対応と、snippetはtantivyのSearchResultのbodyから取得する旨を記載。出力用の新構造体定義方針を追記。"
},
{
"id": "S3",
"category": "実装方針(スケーラビリティ)",
"description": "search_similar()は全embeddingをメモリに読み込んでブルートフォース計算する実装。パフォーマンス劣化リスクが未記載。",
"suggestion": "現時点ではブルートフォースで十分である旨と、将来改善の可能性を注記。"
},
{
"id": "S4",
"category": "受け入れ基準(エラーハンドリング)",
"description": "embeddingsテーブルが空の場合のエラー条件が曖昧。SymbolStoreとEmbeddingStoreのどちらを指すか不明。",
"suggestion": "具体的な判定条件を明記する。"
}
],
"nice_to_have": [
{
"id": "N1",
"category": "実装方針(ハイブリッド検索)",
"description": "将来的なBM25+semantic検索のハイブリッド検索への拡張パスが示されていない。",
"suggestion": "将来拡張の可能性を備考欄に記載。"
},
{
"id": "N2",
"category": "受け入れ基準(類似度の閾値)",
"description": "類似度スコアの最低閾値に関する記述がない。",
"suggestion": "--min-score等のオプション追加を検討。"
},
{
"id": "N3",
"category": "実装方針(プロバイダー設定のバリデーション)",
"description": "格納済みembeddingと異なるモデルでクエリを実行した場合の挙動が未定義。",
"suggestion": "モデル不一致時の警告/エラーメッセージを追加。"
}
],
"summary": "Issue #63は全体として既存コードベースとの整合性が高く実装可能。主な問題は(1)embeddingストレージが2系統存在しどちらを使用するか曖昧、(2)フィルタ適用方法がsemantic検索特有の結合処理を要するが未記載。must_fix解消で実装者が迷わず作業できるIssueになる。"
}
32 changes: 32 additions & 0 deletions dev-reports/issue/63/issue-review/stage2-apply-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"stage": 2,
"applied_fixes": [
{
"id": "M1",
"action": "検索フローの記述を「SymbolStore(symbols.db)のsearch_similar()を使用」と明記。EmbeddingSimilarityResultのフィールド名も追記。"
},
{
"id": "M2",
"action": "フィルタ適用方法を具体化:search_similar()結果のfile_pathをキーにtantivyのsearch_by_exact_path()でメタデータ取得→ポストフィルタとして適用。--semanticと--tag等の排他設定が--relatedとは異なることを明記。"
},
{
"id": "S2",
"action": "出力フォーマットのフィールド対応を明記(score→similarity)。snippetの取得元(SearchResult.body)を追記。SemanticSearchResult構造体定義方針を追記。"
},
{
"id": "S3",
"action": "パフォーマンスに関する注記セクションを追加。ブルートフォースの現状と将来改善の可能性を記載。"
},
{
"id": "S4",
"action": "エラーハンドリングの判定条件をSymbolStoreのembeddingsテーブルレコード0件と具体化。"
}
],
"skipped_fixes": [
{
"id": "S1",
"reason": "M2の修正で検索フロー全体が具体化されたため、別途対応不要"
}
],
"status": "completed"
}
67 changes: 67 additions & 0 deletions dev-reports/issue/63/issue-review/stage3-review-context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"must_fix": [
{
"id": "M1",
"category": "CLI定義(排他制御)",
"description": "main.rsのSearch enumに--semanticオプション追加時、conflicts_with_allの設定が必要。既存--relatedのconflicts_with_allにもsemanticを追加が必要。",
"suggestion": "--semantic: conflicts_with_all=[query, symbol, related, heading]。既存--relatedにもsemantic追加。matchパターン4変数化。"
},
{
"id": "M2",
"category": "SearchError型",
"description": "SearchError enumにsemantic検索固有のエラーバリアント(EmbeddingError、NoEmbeddings等)が不足。",
"suggestion": "Embedding/EmbeddingStore/NoEmbeddingsバリアント追加+From実装。"
},
{
"id": "M3",
"category": "出力フォーマット",
"description": "SemanticSearchResult構造体とformat_semantic_results関数が必要。human.rs/json.rs/path.rsそれぞれに対応関数追加。",
"suggestion": "既存パターンに沿って4種類目として追加。"
},
{
"id": "M4",
"category": "SymbolStore依存",
"description": "SymbolStore.search_similar()(symbols.db)を使用し、embeddings.db(embedding/store.rs)は使用しない設計判断の明記が必要。",
"suggestion": "Issueの仕様通りSymbolStoreを使う。コード内コメントで明記。"
}
],
"should_fix": [
{
"id": "S1",
"category": "パフォーマンス",
"description": "search_similar()の線形スキャン方式。大規模時のメモリ消費・応答時間。",
"suggestion": "現段階では十分。ANN導入可能性をコメント記載。"
},
{
"id": "S2",
"category": "テストへの影響",
"description": "tests/cli_args.rsの既存テスト(search_requires_query_or_symbol等)がエラーメッセージ変更で壊れる可能性。",
"suggestion": "テスト更新+新規conflictテスト追加。"
},
{
"id": "S3",
"category": "ポストフィルタ設計",
"description": "file_pathに複数セクションがある場合のsection_heading照合が必要。インデックスにないセクションの挙動も定義要。",
"suggestion": "section_headingマッチング+見つからない場合のフォールバック定義。"
},
{
"id": "S4",
"category": "Ollama未起動時のエラー",
"description": "NetworkError時の専用案内メッセージが必要。",
"suggestion": "SearchError側でNetworkErrorキャッチ時にOllama起動案内を表示。"
},
{
"id": "S5",
"category": "既存検索への非影響確認",
"description": "matchパターン3変数→4変数の網羅性変更。",
"suggestion": "4変数タプルの慎重な設計+既存パターンの動作確認テスト。"
}
],
"nice_to_have": [
{"id": "N1", "category": "出力フォーマットリファクタリング", "description": "4種類目追加。次の追加時にtrait-basedリファクタ検討。"},
{"id": "N2", "category": "EmbeddingStore二重管理", "description": "embeddings.dbとsymbols.dbの責務明確化。"},
{"id": "N3", "category": "新規クレート依存", "description": "追加不要。確認済み。"},
{"id": "N4", "category": "E2Eテスト", "description": "Ollama依存のE2Eテストはモック化or#[ignore]で対応。"}
],
"summary": "影響範囲は主に4ファイル: main.rs, cli/search.rs, output/mod.rs+各形式, tests/cli_args.rs。既存検索ロジックへの直接影響なし。新規クレート不要。注意点はmatchパターン網羅性とSearchError型拡張。"
}
38 changes: 38 additions & 0 deletions dev-reports/issue/63/issue-review/stage4-apply-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"stage": 4,
"applied_fixes": [
{
"id": "M1",
"action": "排他制御セクションに具体的なconflicts_with_all設定を明記。既存--related/--symbolへのsemantic追加も記載。"
},
{
"id": "M2",
"action": "エラーハンドリングセクションを新設。SearchErrorの具体的なバリアント(Embedding, SymbolStore, NoEmbeddings)とメッセージを明記。"
},
{
"id": "M3",
"action": "出力フォーマットセクションにSemanticSearchResult構造体とformat_semantic_results関数の具体的な定義方針を記載。"
},
{
"id": "M4",
"action": "検索フローのステップ2にEmbeddingStore(embeddings.db)は使用しない旨の注記を追加。"
},
{
"id": "S2",
"action": "テストへの影響セクションを新設。既存テスト更新と新規テスト追加の具体内容を記載。"
},
{
"id": "S3",
"action": "検索フローのステップ3にsection_heading照合とセクション未発見時のスキップ処理を追記。"
},
{
"id": "S4",
"action": "エラーハンドリングにOllama未起動時の具体的なメッセージを追記。"
},
{
"id": "S5",
"action": "main.rsの変更セクションを新設。matchパターン4変数化と網羅性維持を明記。"
}
],
"status": "completed"
}
55 changes: 55 additions & 0 deletions dev-reports/issue/63/issue-review/stage5-review-context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"reviewer": "Claude Opus (Codexタイムアウトのため代替)",
"must_fix": [
{
"id": "M1",
"category": "整合性/用語",
"description": "section_heading照合の具体ルールが未定義。section_headingが空文字列の場合(ファイル全体のembedding)の照合ルールが未定義。",
"suggestion": "section_headingが空文字の場合はfile_path一致のみでマッチ。非空の場合はtantivyのheadingとの完全一致で照合。"
},
{
"id": "M2",
"category": "排他制御/正確性",
"description": "--headingはtantivy全文検索のフィルタであり、semantic検索はtantivyクエリを使用しないため併用不可。理由が排他制御セクションから読み取れない。",
"suggestion": "排他制御セクションに理由を明記する。"
},
{
"id": "M3",
"category": "エラーハンドリング/不整合",
"description": "NoEmbeddingsエラーの検知方法がSymbolStoreのAPIと不整合。SymbolStoreにはembedding件数取得メソッドがない。search_similar()は空Vecを返すだけ。",
"suggestion": "SymbolStoreにembedding_count()メソッドを追加するか、検索フロー前に件数チェックステップを追加。"
}
],
"should_fix": [
{
"id": "S1",
"category": "受け入れ基準/網羅性",
"description": "--limitが semantic 検索でも有効であることが受け入れ基準にない。",
"suggestion": "受け入れ基準に追加。"
},
{
"id": "S2",
"category": "検索フロー/精度",
"description": "ポストフィルタ適用時のオーバーサンプリング考慮が未記載。",
"suggestion": "search_similar()のtop_kにオーバーサンプリング係数適用。"
},
{
"id": "S3",
"category": "出力フォーマット/具体性",
"description": "SemanticSearchResult構造体のフィールド定義が未記載。",
"suggestion": "想定フィールドを明記。"
},
{
"id": "S4",
"category": "エラーハンドリング/一貫性",
"description": "EmbeddingError→SearchErrorの変換方針が未記載。NetworkErrorの条件具体化が必要。",
"suggestion": "変換方針明記。"
}
],
"nice_to_have": [
{"id": "N1", "category": "パフォーマンス", "description": "ブルートフォースの注記"},
{"id": "N2", "category": "テスト戦略", "description": "具体的テストケースのリストアップ"},
{"id": "N3", "category": "CLI/UX", "description": "config.toml読み込みフローの明記"}
],
"summary": "1回目の反映は概ね正しい。新たにMust Fix 3件検出:section_heading照合ルール、--heading排他の理由、NoEmbeddings検知方法。"
}
Loading
Loading