知らないと運用できない！Elasticsearchのインデックス管理のキホン！

# インデックス管理とメンテナンス

:::note info
インデックスなどの基本概念の説明は以下の記事を参照。

[今さら聞けないElasticsearchの基本概念・用語のおさらい](https://qiita.com/Saito-3815/items/c53a06105303996fc53e)
:::

## インデックスエイリアス

- インデックスに設定できる別名をインデックスエイリアスと言う。
- ドキュメント格納や検索をエイリアスに対して行うと、参照されている実体のインデックスが操作される。

### インデックスエイリアスのユースケース

- **実体のインデックス変更時に参照先を切り替える目的でエイリアスを使う。**
  通常運用時は常にエイリアスを設定しておき、クライアントからはエイリアスへアクセスする。もしも実体のインデックスに対してマッピングやフィールド定義の変更が発生した場合は、それらを適用した新しいインデックスを作成した後で、エイリアスの参照先を新しいインデックスへ切り替える。
- **複数のインデックスを１つのエイリアスへ束ねて横断検索する。**
  例えば、日毎のログをそれぞれ実体のインデックスとして保持しておき、それらを横断して検索する場合などに複数の実体インデックスを束ねたエイリアスを作成して使用できる。ただし、その場合インデックスへの書き込み操作はエイリアスに対して行うことはできない。

### インデックスエイリアスの操作

エイリアスの操作は、`_aliases` エンドポイントをへ POST メソッドを使用して行う。

#### インデックスエイリアスの作成

```bash
$ curl -XPUT 'http://localhost:9200/_aliases' \
-H 'Content-Type: application/json' -d'
{
  "actions": [
    { "add": { "index": "my_index", "alias": "my_alias" } }
  ]
}
'
```

#### インデックスエイリアスの削除

```bash
$ curl -XPUT 'http://localhost:9200/_aliases' \
-H 'Content-Type: application/json' -d'
{
  "actions": [
    { "remove": { "index": "my_index", "alias": "my_alias" } }
  ]
}
'
```

#### インデックスエイリアスの切り替え

- 上記のエイリアスの作成と削除を一度に行うことも可能。
- 同一のエイリアスに対して、削除と作成を行った場合、いわゆるエイリアスの「切り替え」操作となる。
- 切り替え操作は内部的にはアトミックな処理として実行されるので切り替え途中でインデックスが参照できなくなることはない。

```bash
$ curl -XPUT 'http://localhost:9200/_aliases' \
-H 'Content-Type: application/json' -d'
{
  "actions": [
    { "remove": { "index": "my_index_old", "alias": "my_alias" } },
    { "add": { "index": "my_index_new", "alias": "my_alias" } }
  ]
}
'
```

#### 複数インデックスを対象としたエイリアスの作成

- 複数のインデックスを束ねる場合は、`actions` 配下に `add` アクションを複数記述する。
- 複数のインデックスを束ねたエイリアスに対して、書き込み操作は行えない。

```bash
$ curl -XPUT 'http://localhost:9200/_aliases' \
-H 'Content-Type: application/json' -d'
{
  "actions": [
    { "add": { "index": "my_index_1", "alias": "my_alias" } },
    { "add": { "index": "my_index_2", "alias": "my_alias" } }
  ]
}
'
```

#### filter 指定を伴うエイリアスの作成

元のインデックスを filter で絞り込んだビューをエイリアスとして作成することも可能。

```bash
$ curl -XPUT 'http://localhost:9200/_aliases' \
-H 'Content-Type: application/json' -d'
{
  "actions": [
    {
      "add": {
        "index": "my_index",
        "alias": "my_alias",
        "filter": { "term": { "type": "fruit" } }
      }
    }
  ]
}
'
```

#### エイリアスの一覧取得

```bash
$ curl -XGET 'http://localhost:9200/_alias'
```

## 再インデックス

- 再インデックスは、既存のインデックスにあるドキュメントを別のインデックスにコピーする機能。
- ある条件のデータのみコピーすることやコピー時にコピー先のインデックス定義を変更するといった様々な操作が可能。
- よくあるユースケースとして作成済みのインデックスのシャード数を変更したい時など。(作成後にインデックスのシャード数を変更することはできないのでインデックスの再作成が必要)

### 再インデックスの実行操作

再インデックスは、`_reindex` エンドポイントを使用して行う。

#### 全ドキュメントを対象として再インデックス

```bash
$ curl -XPOST 'http://localhost:9200/_reindex' \
-H 'Content-Type: application/json' -d'
{
  "source": { "index": "my_index" },       # コピー元のインデックス
  "dest": { "index": "my_index_new" }      # コピー先のインデックス
}
'
```

#### 絞り込み条件付きで再インデックス

絞り込み条件を指定して再インデックスを行う場合は、`query` パラメータを使用する。

```bash
$ curl -XPOST 'http://localhost:9200/_reindex' \
-H 'Content-Type: application/json' -d'
{
  "source": {
    "index": "my_index",
    "query": {
      "match": {
        "message": "Elasticsearch"
      }
    }
  },
  "dest": { "index": "my_index_copy" }
}
'
```

#### 再インデックスの実行状態の確認

実行中の再インデックス処理のステータスを確認することもできる。

```bash
$ curl -XGET 'http://localhost:9200/_tasks?detailed=true&actions=*reindex'
```

```bash:レスポンス
{
  "nodes": {
    ...
      "tasks": {
        "DqudkejeIUudsljQkU-1": {
           "node": "Jydgfedjjd_822hsj_sjsd",
           "id": 21321,
           "type": "transport",
           "action": "indices:data/write/reindex",
           "start_time_in_millis": 1611111111111,
           "running_time_in_nanos": 1234567890,
           "status": {
             "total": 1000,
             "updated": 100,           # 実行完了済みの処理件数
             "created": 0,
             "deleted": 0,
             "batches": 1,
             "version_conflicts": 0,
             "noops": 0,
             "retries": 0,
             "throttled_millis": 0,
           }
        }
      }
    }
  }
}
```

また、確認した結果、時間がかかりすぎる場合は以下のコマンドで実行キャンセルすることも可能。
`task_id` は上記のレスポンスの`node`と`id`を`:`で結合したもの。

```bash
$ curl -XPOST 'http://localhost:9200/_tasks/{task_id}/_cancel'
```

## インデックスの open と close

作成したものの実際の運用においてアクティブに運用しない「休眠インデックス」に対して、読み書きを行わないが削除もしたくないというケースの場合、マシンリソースを消費しないために close 処理をして読み書きを停止し、クラスタ上でメタデータの維持をする以外はリソースを消費しない状態にすることができる。

```bash
$ curl -XPOST 'http://localhost:9200/my_index/_close'
```

再度 open する場合は以下のコマンドを実行する。
この時、シャードの再割り当てなどの処理がバックグラウンドで行われるので多少時間がかかる。

```bash
$ curl -XPOST 'http://localhost:9200/my_index/_open'
```

:::note info
インデックス close 処理の活用例

インデックスの close 処理が必要なケースとして Analyzer 定義の変更がある。
open 状態では Anlyzer 定義の変更処理を行おうとするとエラーが発生するため、一度 close してから定義変更した後に再度 open するようにする。
:::

## インデックスの shrink

- shrink は既存のインデックスのシャード数を縮小する機能。
- 再インデックスでもシャード数変更は可能だが、全データの読み書きと再処理が発生する。一方 shrink は、既存のデータセグメントを効率的に再利用するため、ドキュメントの再インデックス処理を大幅にスキップできる。これにより、特に大規模なインデックスにおいて、再インデックスよりもはるかに高速かつ低負荷でシャード数を縮小できる。

### shrink 実行前の準備

shrink 機能の実行を行う前に、以下の条件を満たす必要がある。

- shrink 元のシャード数は shrink 先のシャード数の倍数である必要がある。(shrink 元: 8, shrink 先: 4, 2, 1 のいずれか)
- 実行前に全てのシャードを単一のノードに移動させておく。
- 実行前にインデックスの書き込みをブロックする。

### shrink 実行

```bash: シャード数が6のインデックスを作成
$ curl -XPUT 'http://localhost:9200/my_index_06' \
-H 'Content-Type: application/json' -d'
{
  "settings": {
    "index.number_of_shards": "6",
    "number_of_replicas": "1",
  }
}
'
```

```bash: インデックスの設定変更
$ curl -XPUT 'http://localhost:9200/my_index_06/_settings' \
-H 'Content-Type: application/json' -d'
{
  "index": {
    "routing.allocation.require._name": "node01",           # シャードをnode01に移動
    "blocks.write": true                                    # 書き込みをブロック
  }
}
'
```

```bash: shrink 実行し、シャード数を3に縮小
# my_index_06からシャード数を3に縮小したmy_index_03が作成される
$ curl -XPOST 'http://localhost:9200/my_index_06/_shrink/my_index_03'
-H 'Content-Type: application/json' -d'
{
  "settings": {
    "index.number_of_shards": "3",
    "index.number_of_replicas": "1"
  }
}
'
```