# 機能設計書 39-User-Agentプロセッサ

## 概要

本ドキュメントは、OpenSearchのUser-Agentプロセッサ機能の設計を記述する。User-AgentプロセッサはHTTPリクエストのUser-Agent文字列を解析し、ブラウザ名、バージョン、OS情報等を構造化データとしてドキュメントに付与するインジェストプロセッサである。

### 本機能の処理概要

User-Agentプロセッサは、ドキュメント内のUser-Agent文字列フィールドを読み取り、uap-javaライブラリ（ua-parser）を使用してブラウザ名・バージョン、OS名・バージョン、デバイス情報等に解析し、ターゲットフィールドに構造化データとして設定するプロセッサである。

**業務上の目的・背景**：Webアクセスログに含まれるUser-Agent文字列から、ブラウザ種別、OS種別、デバイスタイプ等のクライアント情報を自動的に抽出する。これによりアクセス分析、ブラウザ互換性の監視、デバイス分布の可視化等が可能となる。

**機能の利用シーン**：インジェストパイプラインのprocessors配列内でuser_agentプロセッサを定義し、User-Agentフィールドを指定して利用する。

**主要な処理内容**：
1. ドキュメントからUser-Agentフィールド値を取得
2. UserAgentParserでUser-Agent文字列を解析
3. UserAgentCacheで解析結果をキャッシュ
4. propertiesパラメータに基づいて出力フィールドを選択
5. ターゲットフィールドに構造化データを設定

**関連システム・外部連携**：uap-java（ua-parser）ライブラリ。regexes.yamlパターンファイル。

**権限による制御**：インジェストパイプラインの管理権限に従う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | インジェストパイプライン内で利用されるプロセッサ |

## 機能種別

データ連携（データエンリッチメント）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| field | String | Yes | User-Agent文字列を含むフィールド名 | 存在するフィールド |
| target_field | String | No | 出力先フィールド（デフォルト"user_agent"） | - |
| regex_file | String | No | カスタムregexファイル名 | 有効なYAMLファイル |
| properties | String[] | No | 出力するプロパティ一覧 | サポートされるプロパティ |
| ignore_missing | Boolean | No | フィールド欠損時に無視するか（デフォルトfalse） | - |
| ecs | Boolean | No | ECS形式で出力するか | - |

### 入力データソース

IngestDocumentのUser-Agentフィールド。ua-parserのregexes.yamlパターンファイル。

## 出力仕様

### 出力データ

ECS形式の場合：

| 項目名 | 型 | 説明 |
|--------|-----|------|
| user_agent.name | String | ブラウザ名 |
| user_agent.version | String | ブラウザバージョン |
| user_agent.os.name | String | OS名 |
| user_agent.os.version | String | OSバージョン |
| user_agent.os.full | String | OS完全名 |
| user_agent.device.name | String | デバイス名 |
| user_agent.original | String | 元のUser-Agent文字列 |

### 出力先

IngestDocumentのtarget_fieldにマップ形式で設定。

## 処理フロー

### 処理シーケンス

```
1. IngestDocumentからUser-Agentフィールド値を取得
   └─ String型を期待
2. UserAgentCacheでキャッシュ確認
   └─ キャッシュヒット時はキャッシュ結果を使用
3. UserAgentParser.parse()で解析
   └─ uap-javaライブラリでブラウザ・OS・デバイス情報を抽出
4. propertiesに基づくフィールド選択
   └─ NAME, OS, DEVICE, ORIGINAL等のPropertyで出力を制御
5. ターゲットフィールドに結果を設定
   └─ ECS形式またはレガシー形式で構造化データを設定
```

### フローチャート

```mermaid
flowchart TD
    A[User-Agentフィールド取得] --> B{値がnull?}
    B -->|Yes, ignoreMissing| C[スキップ]
    B -->|Yes, not ignoreMissing| D[例外スロー]
    B -->|No| E[UserAgentCache確認]
    E --> F{キャッシュヒット?}
    F -->|Yes| G[キャッシュ結果使用]
    F -->|No| H[UserAgentParser.parse]
    H --> I[キャッシュ登録]
    G --> J[propertiesフィルタ適用]
    I --> J
    J --> K{ECS形式?}
    K -->|Yes| L[ECS形式で構造化]
    K -->|No| M[レガシー形式で構造化]
    L --> N[targetFieldに設定]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | ECS形式 | ecs=true（デフォルト）でElastic Common Schema形式出力 | user_agentプロセッサ |
| BR-39-02 | キャッシュ | UserAgentCacheで解析結果をキャッシュし重複解析を回避 | 全解析処理 |
| BR-39-03 | プロパティフィルタ | propertiesで出力するフィールドを制限可能 | propertiesパラメータ指定時 |
| BR-39-04 | カスタムregex | regex_fileでカスタムパターンファイルを使用可能 | regex_file指定時 |

### 計算ロジック

- ua-parserライブラリによるUser-Agent文字列の正規表現マッチング
- VersionedName（名前+major.minor.patch）でバージョン情報を構造化

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| User-Agent解析 | なし（インメモリ） | 変換 | User-Agent文字列の正規表現マッチング |

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

直接的なデータベース操作はない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 500 | illegal_argument_exception | フィールド値がnullでignore_missing=false | ignore_missing=trueに設定 |
| 400 | opensearch_parse_exception | 不正なregex_fileの指定 | 有効なYAMLファイルを指定 |

### リトライ仕様

プロセッサエラーはインジェストパイプラインのon_failureハンドラで処理。

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

IngestDocument単位での処理。トランザクション制御は不要。

## パフォーマンス要件

- UserAgentCacheによりUser-Agent文字列の重複解析を回避
- 正規表現マッチングのコストはパターン数に依存

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

- インジェストパイプラインの管理権限に従う
- カスタムregex_fileへのファイルアクセス権限が必要

## 備考

- IngestUserAgentModulePluginでモジュール登録
- UserAgentParser.Detailsで解析結果（name, major, minor, patch, build, os, device）を保持
- DeprecationLoggerでレガシー形式使用時の非推奨警告を出力

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | UserAgentParser.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentParser.java` | UA解析ロジック。Details, VersionedName内部クラス |
| 1-2 | UserAgentCache.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentCache.java` | 解析結果キャッシュ |

**読解のコツ**: UserAgentParser.Detailsがブラウザ名、OS情報、デバイス情報を保持する中間データ構造。VersionedNameは名前とバージョン（major.minor.patch）を持つ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | UserAgentProcessor.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentProcessor.java` | プロセッサ本体。execute()メソッドとProperty列挙型 |
| 2-2 | IngestUserAgentModulePlugin.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/IngestUserAgentModulePlugin.java` | モジュールプラグイン |

**主要処理フロー**:
- **57行目**: UserAgentProcessorクラス定義。AbstractProcessorを継承
- **61行目**: TYPE = "user_agent"
- **63-68行目**: field, targetField, properties, parser, ignoreMissing, useECSフィールド
- **70-79行目**: コンストラクタ

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

```
IngestUserAgentModulePlugin
    |
    +-- getProcessors() -> {"user_agent": UserAgentProcessor.Factory}
          |
          +-- Factory.create() -> UserAgentProcessor
                |
                +-- execute(IngestDocument)
                      |
                      +-- UserAgentCache.get(userAgent)
                      |     |
                      |     +-- [miss] UserAgentParser.parse(userAgent)
                      |     +-- [hit] キャッシュ結果
                      |
                      +-- Property列挙に基づくフィールド構築
                      +-- IngestDocument.setFieldValue(targetField, details)
```

### データフロー図

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

IngestDocument       +--> User-Agentフィールド取得
(field: "agent")     |
                     +--> UserAgentCache確認
regexes.yaml         |
(パターン定義)       +--> UserAgentParser.parse()
                     |     +-- ブラウザ名/バージョン抽出
                     |     +-- OS名/バージョン抽出
                     |     +-- デバイス名抽出
                     |
                     +--> propertiesフィルタ          +--> IngestDocument
                     +--> ECS/レガシー形式変換              (target_field: user_agent)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| UserAgentProcessor.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentProcessor.java` | ソース | プロセッサ本体 |
| IngestUserAgentModulePlugin.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/IngestUserAgentModulePlugin.java` | ソース | モジュールプラグイン |
| UserAgentParser.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentParser.java` | ソース | UA解析ロジック |
| UserAgentCache.java | `modules/ingest-user-agent/src/main/java/org/opensearch/ingest/useragent/UserAgentCache.java` | ソース | 解析結果キャッシュ |
