はじめに
こんばんは。
今回は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
もつけることで今回のやりたいことを実現してます。
終わりに
かなり手こずりましたが、なんとかなりました。
現場からは以上です。