こんにちは!Web3課のコウです。 現在携わっている案件では、仕様変更や新機能の開発に伴い、既存のElasticsearchのIndexマッピングを更新することが時々あります。
Indexのマッピング更新は、RDBのテーブル構造の変更に似ています。例えば、MySQLでカラム定義を変更したりカラムを追加・削除する際にはALTER TABLE文
を使用しますが、既存テーブルのデータ移行は不要です。しかし、ElasticsearchではALTER TABLE
のような機能がないため、更新後のマッピングを用いて新しいIndexを作成し、古いIndexからdocumentを新しいIndexに移行する必要があります。
今回の記事では、Index移行の手順を紹介したいと考えています。
curl -XPUT 'http://localhost:9200/students_20240621?pretty' -H 'Content-Type: application/json' -d '{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"sex": {
"type": "keyword"
},
"age": {
"type": "keyword"
}
}
}
}'
curl -XPOST 'http://localhost:9200/_aliases?pretty' -H 'Content-Type: application/json' -d '{
"actions": [
{
"add": {
"index": "students_20240621",
"alias": "students"
}
}
]
}'
エイリアスを追加する理由: 検索を行う際にIndexを直接参照することは可能ですが、今回のようにマッピングを更新して新しいIndexを作成する場合、アプリ側でも参照先を全て変更しなければならず、効率的ではありません。エイリアスを使用すると、新しいIndexを作成した際にエイリアスを追加するだけで、アプリ側の参照先の変更は不要になります。
curl -XPOST 'http://localhost:9200/_bluk?pretty' -H 'Content-Type: application/json' -d '
{"index": {"_index": "students", "_id": "1"}}
{"name": "学生一", "sex": "男", "age": "20"}
{"index": {"_index": "students", "_id": "2"}}
{"name": "学生二", "sex": "女", "age": "21"}
{"index": {"_index": "students", "_id": "3"}}
{"name": "学生三", "sex": "男", "age": "21"}
{"index": {"_index": "students", "_id": "4"}}
{"name": "学生四", "sex": "女", "age": "22"}
{"index": {"_index": "students", "_id": "5"}}
{"name": "学生五", "sex": "男", "age": "21"}
'
full_name
に変更short
に変更department
フィールドを追加curl -XPUT 'http://localhost:9200/students_20240622?pretty' -H 'Content-Type: application/json' -d '{
"mappings": {
"properties": {
"full_name": {
"type": "keyword"
},
"sex": {
"type": "keyword"
},
"age": {
"type": "short"
},
"department": {
"type": "keyword"
}
}
}
}'
作成したstudents_20240622
Indexのマッピングを確認してみましょう。
curl 'http://localhost:9200/students_20240622/_mapping?pretty'
結果
{
"students_20240622": {
"mappings": {
"properties": {
"full_name": {
"type": "keyword"
},
"sex": {
"type": "keyword"
},
"age": {
"type": "short"
},
"department": {
"type": "keyword"
}
}
}
}
}
更新したマッピングが反映されました。
curl -XPOST 'http://localhost:9200/_reindex?pretty' -H 'Content-Type: application/json' -d '
{
"source": {
"index": "students_20240621"
},
"dest": {
"index": "students_20240622"
},
"script": {
"source": "ctx._source.full_name = ctx._source.remove(\"name\")"
}
}'
今回field名の変更を行いましたので、scriptを使用して、フィールド名を変更しながら値を移行します。フィールド名を複数で変更する場合、下記のように、
;
区切りでscript文を作成します。
"script": {
"source": "ctx._source.new_name_1 = ctx._source.remove(\"old_name_1\");ctx._source.new_name_2 = ctx._source.remove(\"old_name_2\")"
}
実行した後のレスポンスは下記となります。created
は5
になっていますので、移行元のdocumentは5件全部移行できたということです。
{
"took": 2020,
"timed_out": false,
"total": 5,
"updated": 0,
"created": 5,
"deleted": 0,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"failures": []
}
curl -XPOST 'http://localhost:9200/_aliases?pretty' -H 'Content-Type: application/json' -d '{
"actions": [
{
"remove": {
"index": "students_20240621",
"alias": "students"
}
},
{
"add": {
"index": "students_20240622",
"alias": "students"
}
}
]
}’
上記の_aliases API
を利用して、アプリ側サービス無停止でIndexを更新する効果が実現できます。
注意: _aliases APIの
actions
にはremove
とremove_index
という2つの似たようなキーワードがあります。remove
は指定したIndexのエイリアスを削除しますが、remove_index
はエイリアス名の指定は不要で、Index名の指定だけでIndexを削除します。古いIndexがまだ必要な場合は十分に注意して実行してください。
Indexのエイリアスを確認してみましょう。
curl 'http://localhost:9200/_aliases?pretty'
結果
{
"students_20240621": {
"aliases": {}
},
"students_20240622": {
"aliases": {
"students": {}
}
}
}
エイリアス名students
は新Indexの方に移動しました。
一度検索クエリを実行してみましょう。
curl 'http://localhost:9200/students/_search?pretty' -H 'Content-Type: application/json' -d '
{
"query": {
"range": {
"age": {
"gt": 21
}
}
}
}'
結果
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "students_20240622",
"_id": "4",
"_score": 1.0,
"_source": {
"full_name": "学生四",
"sex": "女",
"age": "22"
}
}
]
}
}
検索の参照先はstudents_20240622
になり、name
フィールドもfull_name
に変更されています。 追加したdepartment
フィールドはこれからdocumentの更新処理により、検索結果に反映されます。 今回はdocument更新処理を省略します。
以上、多少参考になったら嬉しいです。 最後までお読みいただき、ありがとうございました!
Elasticsearch Guide _reindex API
Elasticsearch Guide _aliases API