使用されなくなった古いフィールドを削除したい。
フィールドを消すにはid
を指定して次の_update
クエリを実行するか、
POST test/1/_update
{
"script": "ctx._source.remove('field_to_delete')",
}
フィールドをもつドキュメントすべてに対して削除したい場合はexitsクエリ
で絞って_update_by_query
を実行する。
POST test/_update_by_query
{
"script": "ctx._source.remove('field_to_delete')",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "field_to_delete"
}
}
]
}
}
}
しかし、exitsクエリ
はフィールドがnullかつnull_value
の設定をしていない場合、フィールドを持っていないと判断してしまう。つまり、不要なフィールドがnullの場合は検索結果に入ってこない。
existsクエリ
null_valueの設定をすればnullは検索できる
厄介なこととして、例えば、上の更新コマンドを実行中に処理を誤って中断してしまった場合や、全て削除したにも関わらず、そのあと追加されたドキュメントが不要なフィールドを持っていた場合、同じインデックス内に不要フィールドを持っているやつと持っていないやつが混在することになる。
その場合、例えば厳密にentityの型を定義しているデータマイニングツールなどでは、処理の途中でカラム数が合わず処理が失敗する可能性がある。
そうでなくても、同じインデックス内にフィールドのあるなしのドキュメントが混在するのはよくない。
しかし、データ量が多く、全データに対してなにかやるのは嫌だけど、不要なフィールドを持っているドキュメントだけを検索してやっつけるということができないので割と困った。
対応方法①:全データに対して_update_by_query
やはり、全件検索をするのは免れなそう。
ただし、消したいフィールドを含むドキュメントだけ削除するようにすることができるので処理速度をある程度削減できた。
(全ドキュメントに不要なフィールドがある場合は効果なしだと思われる)
POST test/_update_by_query
{
"script": {
"source": """
if (ctx._source.containsKey('field_to_delete')) {
ctx._source.remove('field_to_delete');
} else {
ctx.op='noop';
}
"""
}
}
ステータスの確認は以下を実行する。
GET _tasks?detailed=true&actions=*update*
次のような結果がかえってくる
{
"nodes" : {
"qsJdt39QT0uDGRMhIb468w" : {
...
"tasks" : {
"qsJdt39QT0uDGRMhIb468w:59320333" : {
...
"status" : {
"total" : 10000
"updated" : 10,
...
"noops" : 174885,
...
},
...
}
}
}
}
}
total
10000件に対して、updated
が10件、noops
が174885件とどれくらい不要なフィールドがあったのか確認することができる。
対応方法②:reindex
不要なフィールドが全てnullの場合(existsを使った検索が0件ならば、逆に全てがnullであるといえる)新しいマッピング定義を行ったインデックスに対してreindexをすることで不要なフィールドを取り除くことができる。
ただし、大量のデータの場合、一時的でもデータ量が2倍になるので、ディスク容量などに余裕が必要となるので注意が必要。
参考
https://stackoverflow.com/questions/29002215/remove-a-field-from-a-elasticsearch-document
https://stackoverflow.com/questions/56649273/elasticsearch-delete-field-from-all-documents-where-it-exists-with-painless