はじめに
こんばんは。
今回はElasticSearchです。
保存されたドキュメントの配列に、追加・削除を行いたいという場面がありまして、なかなかうまく行かず、試行錯誤した備忘録です。
参考サイト
本題
サンプルデータ
{
"shop_id": 10000,
"items": [
{
"item_id": 100,
"name": アイテム100,
"price": 500,
},
{
"item_id": 200,
"name": アイテム200,
"price": 1000,
},
{
"item_id": 300,
"name": アイテム300,
"price": 1500,
},
{
"item_id": 400,
"name": アイテム400,
"price": 2000,
},
{
"item_id": 500,
"name": アイテム500,
"price": 2500,
},
{
"item_id": 600,
"name": アイテム600,
"price": 3000,
},
]
},
{
"shop_id": 20000,
"items": [
{
"item_id": 100,
"name": アイテム100,
"price": 500,
},
{
"item_id": 200,
"name": アイテム200,
"price": 1000,
},
{
"item_id": 700,
"name": アイテム700,
"price": 3500,
},
]
},
削除
shop_id: 10000
のitemsのなかの、item_id: 300
と item_id: 600
のものだけを消したいということあると思います。
その場合、以下のような形で、削除できました!
POST _update_by_query
"query": {
"bool": {
"must": [
{
"term": {
"shop_id": 10000
}
}
]
}
},
"script": {
"lang": "painless",
"inline": "for (item_id in params.item_ids) { ctx._source.items.removeIf(item -> item.item_id.toString().contains(item_id)) }",
"params"': {
"item_ids" => [
"300",
"600"
],
}
}
removeIfでループしながら処理して、itemsに入っているitem_idと合致するかを調べて、合致すれば削除されます。
追加
shop_id: 20000
のitemsに新たに item_id: 600
を追加します。
POST _update_by_query
query": {
"bool": {
"must": [
{
"term": {
"shop_id": 10000
}
}
]
}
},
"script": {
"lang": "painless",
"inline": "ctx._source.items.addAll(params.items)",
"params"': {
"items" => [
{
"item_id": 600,
"name": アイテム600,
"price": 3000,
}
],
}
}
本来は、データがあれば更新、データがなければ追加みたいな感じのことをやりたかったので、scriptでループ処理をして対応しようと思っていたのですが、 Painless script loop maximum number of statements limit
とエラーがでてしまいまして、それならばということで、存在していれば一旦削除して、その後対象を追加していくという方式にしました。
僕の場合、上記の理由で、1リクエストで削除・追加を行うので、 conflicts=proceed
をつけないと、 version_conflict_engine_exception
でバージョン違いになります。
また、順番的に削除が先に行われるので、削除の方では、 refresh=wait_for
もつけることで今回のやりたいことを実現してます。
終わりに
かなり手こずりましたが、なんとかなりました。
現場からは以上です。