# 機能設計書 38-GeoIPプロセッサ

## 概要

本ドキュメントは、OpenSearchのGeoIPプロセッサ機能の設計を記述する。GeoIPプロセッサはIPアドレスからMaxMindデータベースを使用して地理情報（国、都市、緯度経度等）をドキュメントに付与するインジェストプロセッサである。

### 本機能の処理概要

GeoIPプロセッサは、ドキュメント内のIPアドレスフィールドを読み取り、MaxMind社のGeoIP2データベース（GeoLite2-City、GeoLite2-Country、GeoLite2-ASN）を参照して地理情報を取得し、ドキュメントのターゲットフィールドに付与するプロセッサである。

**業務上の目的・背景**：アクセスログやセキュリティログに含まれるIPアドレスから地理的位置情報を自動的に付与し、地理空間分析やダッシュボード可視化を可能にする。ネットワークトラフィックの地理的分布の把握、不正アクセスの地域分析等に利用。

**機能の利用シーン**：インジェストパイプラインのprocessors配列内でgeoipプロセッサを定義し、IPアドレスフィールドとターゲットフィールドを指定して利用する。

**主要な処理内容**：
1. ドキュメントからIPアドレスフィールド値を取得
2. IPアドレスをInetAddressに変換
3. データベースタイプ（City/Country/ASN）に基づく検索メソッドの選択
4. MaxMind GeoIP2 APIでデータベースを検索
5. GeoIpCacheで結果をキャッシュ
6. 地理情報をターゲットフィールドに設定

**関連システム・外部連携**：MaxMind GeoIP2データベース（GeoLite2-City.mmdb等）。DatabaseReaderLazyLoaderによる遅延ロード。

**権限による制御**：インジェストパイプラインの管理権限に従う。データベースファイルへのファイルアクセス権限が必要。

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| field | String | Yes | IPアドレスを含むフィールド名 | 存在するフィールド |
| target_field | String | No | 地理情報の出力先フィールド（デフォルト"geoip"） | - |
| database_file | String | No | 使用するデータベースファイル名（デフォルト"GeoLite2-City.mmdb"） | 有効なmmdbファイル |
| properties | String[] | No | 出力するプロパティ一覧 | サポートされるプロパティ |
| ignore_missing | Boolean | No | フィールド欠損時に無視するか（デフォルトfalse） | - |
| first_only | Boolean | No | 配列の場合最初の結果のみ返すか（デフォルトtrue） | - |

### 入力データソース

IngestDocumentのIPアドレスフィールド。MaxMind GeoIP2データベースファイル。

## 出力仕様

### 出力データ

Cityデータベース使用時：

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ip | String | 入力IPアドレス |
| country_iso_code | String | 国コード（ISO 3166-1） |
| country_name | String | 国名 |
| continent_name | String | 大陸名 |
| region_iso_code | String | 地域コード |
| region_name | String | 地域名 |
| city_name | String | 都市名 |
| timezone | String | タイムゾーン |
| location | GeoPoint | 緯度経度（lat, lon） |

ASNデータベース使用時：

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ip | String | 入力IPアドレス |
| asn | Long | 自律システム番号 |
| organization_name | String | 組織名 |
| network | String | ネットワークCIDR |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. IngestDocumentからIPアドレスフィールド値を取得
   └─ String型またはList<String>型を期待
2. IPアドレスのバリデーション
   └─ InetAddresses.forString()でInetAddressに変換
3. データベースタイプの判定
   └─ DatabaseReaderLazyLoader.getDatabaseType()でCity/Country/ASN判定
4. GeoIP情報の取得
   └─ データベースタイプに基づく検索メソッド呼び出し
5. キャッシュ確認・登録
   └─ GeoIpCacheでputIfAbsent
6. 結果の設定
   └─ IngestDocument.setFieldValue(targetField, geoData)
```

### フローチャート

```mermaid
flowchart TD
    A[IPアドレスフィールド取得] --> B{値がnull?}
    B -->|Yes, ignoreMissing| C[スキップ]
    B -->|Yes, not ignoreMissing| D[例外スロー]
    B -->|No| E{String or List?}
    E -->|String| F[getGeoData単一]
    E -->|List| G[getGeoData配列]
    F --> H{DBタイプ?}
    G --> H
    H -->|City| I[retrieveCityGeoData]
    H -->|Country| J[retrieveCountryGeoData]
    H -->|ASN| K[retrieveAsnGeoData]
    I --> L[GeoIpCache参照]
    J --> L
    K --> L
    L --> M{キャッシュヒット?}
    M -->|Yes| N[キャッシュ結果使用]
    M -->|No| O[DB検索 → キャッシュ登録]
    N --> P[targetFieldに設定]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | DB種別自動判定 | データベースファイル名のサフィックスでCity/Country/ASNを判定 | DB参照時 |
| BR-38-02 | IPアドレス未検出 | AddressNotFoundExceptionの場合は空のgeoDataを返却 | DB検索時 |
| BR-38-03 | 遅延ロード | DatabaseReaderLazyLoaderで初回使用時にDBを読込 | プロセッサ初期化 |
| BR-38-04 | first_only | 配列IPの場合、first_only=trueで最初のマッチのみ返却 | 配列入力時 |
| BR-38-05 | プロパティフィルタ | propertiesパラメータで出力するフィールドを制限可能 | geoipプロセッサ |

### 計算ロジック

特になし。MaxMind GeoIP2データベースのルックアップ処理。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| GeoIPルックアップ | MaxMind mmdbファイル | READ | IPアドレスから地理情報を検索 |

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

#### MaxMind GeoIP2データベース

| 操作 | 項目 | 更新値・取得条件 | 備考 |
|-----|------|-----------------|------|
| READ | 地理情報 | InetAddressで検索 | GeoIpCacheでキャッシュ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 500 | illegal_argument_exception | フィールド値がnullでignore_missing=false | ignore_missing=trueに設定 |
| 500 | illegal_argument_exception | 配列内に非文字列要素 | 文字列のみの配列を使用 |
| 500 | opensearch_parse_exception | サポートされないデータベースタイプ | City/Country/ASNのDBを使用 |
| - | - | IPアドレス未検出（AddressNotFoundException） | 空結果として処理（エラーにならない） |

### リトライ仕様

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

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

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

## パフォーマンス要件

- GeoIpCacheにより頻出IPアドレスの検索結果をキャッシュ
- DatabaseReaderLazyLoaderによる遅延ロードでメモリ使用量を最適化
- MaxMindデータベースのインメモリ検索は高速（ツリー構造）

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

- MaxMindデータベースファイルへのファイルシステムアクセス権限が必要
- SpecialPermission.check()によるセキュリティマネージャチェック
- AccessController.doPrivileged()で特権アクセス

## 備考

- GeoLite2データベースはMaxMind社から無料で提供される（ライセンス確認が必要）
- IngestGeoIpModulePluginでモジュール登録
- DatabaseReaderLazyLoaderでデータベースファイルの遅延読込と共有を実現

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | GeoIpProcessor.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/GeoIpProcessor.java` | プロセッサ本体。Property列挙型でCity/Country/ASNのプロパティを定義 |

**読解のコツ**: GeoIpProcessor内のPropertyは出力フィールドの種類を定義する列挙型。データベースタイプごとに有効なPropertyが異なる点に注意。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | IngestGeoIpModulePlugin.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/IngestGeoIpModulePlugin.java` | モジュールプラグイン。GeoIpCacheの管理 |
| 2-2 | GeoIpProcessor.java (Factory) | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/GeoIpProcessor.java` | Factory内部クラスでプロセッサ生成 |

**主要処理フロー**:
- **73行目**: GeoIpProcessorクラス定義。TYPE = "geoip"
- **76-78行目**: CITY_DB_SUFFIX, COUNTRY_DB_SUFFIX, ASN_DB_SUFFIX定数
- **80-86行目**: field, targetField, lazyLoader, properties, ignoreMissing, cache, firstOnlyフィールド
- **126-166行目**: execute()メソッド。String/Listの分岐、getGeoData()呼び出し
- **168-197行目**: getGeoData()。データベースタイプによるCity/Country/ASN分岐

#### Step 3: データベースロードメカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DatabaseReaderLazyLoader.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/DatabaseReaderLazyLoader.java` | 遅延ロードによるDBリーダー管理 |

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

```
IngestGeoIpModulePlugin
    |
    +-- getProcessors() -> {"geoip": GeoIpProcessor.Factory}
          |
          +-- Factory.create() -> GeoIpProcessor
                |
                +-- execute(IngestDocument)
                      |
                      +-- getGeoData(ipString)
                      |     |
                      |     +-- getDatabaseType() [City/Country/ASN判定]
                      |     |
                      |     +-- retrieveCityGeoData(ipAddress)
                      |     |     +-- GeoIpCache.putIfAbsent()
                      |     |     +-- DatabaseReaderLazyLoader.get().city()
                      |     |
                      |     +-- retrieveCountryGeoData(ipAddress)
                      |     +-- retrieveAsnGeoData(ipAddress)
                      |
                      +-- IngestDocument.setFieldValue(targetField, geoData)
```

### データフロー図

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

IngestDocument       +--> IPアドレスフィールド取得
(field: "ip")        |
                     +--> InetAddresses.forString()
                     |
MaxMind DB           +--> DatabaseReaderLazyLoader
(GeoLite2-City.mmdb) |     +-- get().city(ipAddress)
                     |
GeoIpCache           +--> キャッシュ確認/登録
                     |
                     +--> geoDataマップ構築           +--> IngestDocument
                           (country, city, location等)      (target_field: geoip)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| GeoIpProcessor.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/GeoIpProcessor.java` | ソース | GeoIPプロセッサ本体 |
| IngestGeoIpModulePlugin.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/IngestGeoIpModulePlugin.java` | ソース | モジュールプラグイン |
| DatabaseReaderLazyLoader.java | `modules/ingest-geoip/src/main/java/org/opensearch/ingest/geoip/DatabaseReaderLazyLoader.java` | ソース | DBリーダー遅延ロード |
