# 機能設計書 102-グローバル検索

## 概要

本ドキュメントは、GitLabのグローバル検索機能についての機能設計書である。

### 本機能の処理概要

グローバル検索は、GitLabインスタンス全体にわたってプロジェクト、イシュー、マージリクエスト、コード、ユーザーなどを横断的に検索する機能である。ナビゲーションバーの検索ボックスから即座にアクセスでき、複数のスコープ（検索対象）を切り替えて利用できる。

**業務上の目的・背景**：大規模なGitLabインスタンスにおいて、ユーザーが必要な情報を迅速に見つけるための中心的な機能を提供する。プロジェクト横断での情報検索は、複数プロジェクトに関わる開発者やマネージャーにとって不可欠な機能である。

**機能の利用シーン**：
- ナビゲーションバーから特定のプロジェクトやイシューを素早く検索
- 過去に作業したマージリクエストを検索
- 特定のコード片やファイル名でコードベース全体を検索
- ユーザー名やグループ名で人物・組織を検索
- トピックやラベルでプロジェクトをフィルタリング

**主要な処理内容**：
1. 検索クエリの受付とバリデーション
2. 検索スコープ（projects, issues, merge_requests等）の決定
3. プロジェクト横断のアクセス権限チェック
4. 検索エンジンへのクエリ実行
5. 検索結果のソート・ページネーション
6. 結果カウントの取得（タブ表示用）
7. オートコンプリート候補の提供

**関連システム・外部連携**：
- Elasticsearch/OpenSearch（高度な検索機能有効時）
- Zoekt（コード検索用）
- PostgreSQL全文検索（基本検索）

**権限による制御**：
- 未認証ユーザー：公開プロジェクトのみ検索可能
- 認証ユーザー：アクセス権限のあるプロジェクト全てを検索可能
- グローバル検索の無効化設定が可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 284 | 検索結果 | 主画面 | 検索結果表示 |
| 19 | プロジェクト探索 | 補助機能 | プロジェクトの検索処理 |
| 22 | トピック一覧 | 主画面 | プロジェクトトピックの一覧表示 |

## 機能種別

データ検索 / 全文検索 / オートコンプリート

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| search | String | Yes | 検索キーワード | 最大256文字、最大64語 |
| scope | String | No | 検索スコープ | projects/issues/merge_requests/milestones/users/blobs等 |
| group_id | Integer | No | グループID | グループ内検索時に指定 |
| project_id | Integer | No | プロジェクトID | プロジェクト内検索時に指定 |
| sort | String | No | ソート順 | created_desc/created_asc等 |
| state | String | No | 状態フィルタ | opened/closed/merged等 |
| confidential | Boolean | No | 機密フラグ | true/false |
| language | Array | No | プログラミング言語フィルタ | コード検索時 |
| page | Integer | No | ページ番号 | 1以上 |

### 入力データソース

- ナビゲーションバー検索ボックス
- 検索結果ページのフィルタUI
- オートコンプリートリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| search_results | Array | 検索結果オブジェクト配列 |
| search_objects | Array | ページネーション済み結果 |
| formatted_count | Hash | スコープ別結果件数 |
| search_highlight | Hash | ハイライト情報 |

### 出力先

- 検索結果画面（HTML）
- JSON API（カウント、オートコンプリート）

## 処理フロー

### 処理シーケンス

```
1. 検索リクエスト受付
   └─ SearchController#show がリクエストを受け付け
2. クエリバリデーション
   └─ 文字数・語数制限チェック
3. レート制限チェック
   └─ check_search_rate_limit! で制限確認
4. スコープ決定
   └─ 指定スコープまたはデフォルトスコープ選択
5. 権限チェック
   └─ クロスプロジェクトアクセス権限確認
6. 検索実行
   └─ SearchService経由で検索エンジンにクエリ
7. 結果整形
   └─ ページネーション・ハイライト適用
8. レスポンス返却
   └─ HTML/JSON形式で結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[検索リクエスト] --> B{クエリ有効?}
    B -->|No| C[エラー表示]
    B -->|Yes| D{レート制限OK?}
    D -->|No| E[429 Too Many Requests]
    D -->|Yes| F{認証必要?}
    F -->|Yes| G{認証済み?}
    F -->|No| H[検索実行]
    G -->|No| I[ログイン要求]
    G -->|Yes| H
    H --> J{単一コミット結果?}
    J -->|Yes| K[コミット詳細へリダイレクト]
    J -->|No| L[検索結果表示]
    L --> M[Apdexメトリクス記録]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-102-01 | 検索文字数制限 | 最大256文字 | 全検索 |
| BR-102-02 | 検索語数制限 | 最大64語 | 全検索 |
| BR-102-03 | デフォルトスコープ | 'projects' | スコープ未指定時 |
| BR-102-04 | 単一コミットリダイレクト | コミットSHA検索で1件のみの場合、詳細へリダイレクト | プロジェクト内検索 |
| BR-102-05 | 匿名検索制限 | 設定により匿名検索を無効化可能 | インスタンス設定 |

### 計算ロジック

検索結果カウントのキャッシュ:
- ブラウザキャッシュ: 1分間
- タブ切り替え時のカウント取得を効率化

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロジェクト検索 | projects | SELECT | 全文検索クエリ |
| イシュー検索 | issues | SELECT | 全文検索クエリ |
| マージリクエスト検索 | merge_requests | SELECT | 全文検索クエリ |
| ユーザー検索 | users | SELECT | 部分一致検索 |
| コード検索 | - | - | Gitalyまたは外部検索エンジン |

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

#### projects テーブル

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | name, description, path | 検索キーワードで全文検索 | topics, route をプリロード |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Flash Alert | 検索文字数超過 | 短い検索キーワードに変更 |
| - | Flash Alert | 検索語数超過 | 語数を減らす |
| 408 | Request Timeout | クエリタイムアウト | 検索条件を絞る |
| 429 | Too Many Requests | レート制限超過 | 待機後リトライ |

### リトライ仕様

- タイムアウト時: タイムアウトエラー画面を表示
- レート制限時: 待機後にリトライ

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

- 検索は読み取り専用操作のため、トランザクション制御不要
- `with_fast_read_statement_timeout` で高速タイムアウト適用（基本検索時）

## パフォーマンス要件

- 検索レスポンスタイム: Apdexメトリクスで監視
- 結果カウントは1分間ブラウザキャッシュ
- Gitaly参照キャッシュ有効

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

- クロスプロジェクトアクセス権限チェック
- 機密イシューのフィルタリング
- 匿名検索の制御設定
- 検索クエリのサニタイズ

## 備考

- global_search フィーチャーカテゴリ
- urgency: low（低優先度エンドポイント）
- EEでは追加の検索スコープ（Elasticsearch/Zoekt）が利用可能

---

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

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

### 推奨読解順序

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

検索結果の構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | search_results.rb | `lib/gitlab/search_results.rb` | 検索結果クラスの基本構造 |
| 1-2 | project_search_results.rb | `lib/gitlab/project_search_results.rb` | プロジェクト内検索結果 |

**読解のコツ**: `Gitlab::SearchResults`クラスが検索結果のラッパーとして機能し、各スコープ（projects, issues等）のメソッドで実際のクエリを実行する。

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

HTTPリクエストの受付処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | search_controller.rb | `app/controllers/search_controller.rb` | HTTPリクエスト処理、認証、クエリ実行 |

**主要処理フロー**:
1. **29行目**: `allow_gitaly_ref_name_caching` でGitaly参照キャッシュ有効化
2. **31行目**: `skip_before_action :authenticate_user!` 条件付き認証スキップ
3. **39行目**: `check_search_rate_limit!` でレート制限チェック
4. **48-69行目**: `show`メソッドで検索実行と結果表示
5. **71-97行目**: `count`メソッドでスコープ別カウント取得
6. **113-129行目**: `autocomplete`メソッドでオートコンプリート

#### Step 3: 検索サービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | global_service.rb | `app/services/search/global_service.rb` | グローバル検索サービス |

**主要処理フロー**:
- **8行目**: `DEFAULT_SCOPE = 'projects'` デフォルトスコープ定義
- **17-25行目**: `execute`メソッドで`Gitlab::SearchResults`生成
- **28-30行目**: `projects`メソッドで検索対象プロジェクト取得
- **40-43行目**: `scope`メソッドで有効なスコープを決定

#### Step 4: バリデーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | search_controller.rb | `app/controllers/search_controller.rb` | クエリバリデーション |

**主要処理フロー**:
- **187-200行目**: `search_term_valid?`で文字数・語数チェック
- **203-213行目**: `search_type_valid?`で検索タイプ検証

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

```
SearchController#show
    │
    ├─ check_search_rate_limit!
    │      └─ SearchRateLimitable
    │
    ├─ search_service
    │      └─ SearchService (ファクトリ)
    │             │
    │             ├─ Search::GlobalService (グローバル検索)
    │             │      └─ Gitlab::SearchResults
    │             │
    │             ├─ Search::GroupService (グループ内検索)
    │             │      └─ Gitlab::GroupSearchResults
    │             │
    │             └─ Search::ProjectService (プロジェクト内検索)
    │                    └─ Gitlab::ProjectSearchResults
    │
    ├─ search_term_valid?
    │      └─ Gitlab::Search::Params
    │
    └─ haml_search_results
           │
           ├─ search_results.formatted_count
           └─ Gitlab::Metrics::GlobalSearchSlis.record_apdex
```

### データフロー図

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

検索クエリ (search) ────▶ SearchController#show ────────▶ HTML検索結果
スコープ (scope)                 │
フィルタ (state等)               ├─ SearchService
                                │      │
                                │      └─ Search::GlobalService
                                │             │
                                │             └─ Gitlab::SearchResults
                                │                    │
                                │                    └─ DB/Elasticsearch/Zoekt
                                │
                                └─ Presenter
                                       │
                                       └─ 検索結果表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| search_controller.rb | `app/controllers/search_controller.rb` | ソース | HTTPエンドポイント処理 |
| global_service.rb | `app/services/search/global_service.rb` | ソース | グローバル検索サービス |
| group_service.rb | `app/services/search/group_service.rb` | ソース | グループ内検索サービス |
| project_service.rb | `app/services/search/project_service.rb` | ソース | プロジェクト内検索サービス |
| search_results.rb | `lib/gitlab/search_results.rb` | ソース | 検索結果クラス |
| project_search_results.rb | `lib/gitlab/project_search_results.rb` | ソース | プロジェクト検索結果 |
| search_helper.rb | `app/helpers/search_helper.rb` | ソース | 検索ヘルパー |
| search_rate_limitable.rb | `app/controllers/concerns/search_rate_limitable.rb` | ソース | レート制限 |
