フィールドの配列から特定の要素を削除する方法


#1

こんにちは。
タイトルにある方法をここしばらく探していまして、どうしても見つからず皆様のお知恵をお貸し頂けないでしょうか。

以下のように、フィールドが配列になっているドキュメントがあります。

{
"Description": "Jay Desc 1",
"Entities": [
{
"ID": "1234",
"NAME": "TAROU",
},
{
"ID": "1234_KANJI",
"NAME": "太郎",
},
{
"ID": "1234_RUBY",
"NAME": "たろう",
},
]
}

ここから、IDが1234_RUBYの要素を削除する場合、以下の方法があります。

POST /test/type/1/_update
{
  "script": {
    "lang": "painless",
    "inline": "ctx._source.Entities.removeAll(Collections.singleton(params.Entities))",
    "params" : {
        "Entities":{
            "ID": "1234_RUBY",
            "NAME": "たろう",
        }
    }
  }
}

ただしこの方法だと、削除したい要素のすべての情報(上記例だとIDとNAME両方)を指定する必要があります。
ですが、IDに"_RUBY"が含まれていることだけが分かっていて数字部分が判らない、且つ、NAMEには何が入っているか不明な場合、どのようにして削除することができるでしょうか。ID=".*_RUBY",NAME=".*"とかやってみたのですがうまくいきませんでした。

何卒宜しくお願い致します。


(Makoto Nozawa) #2

これでいかがでしょうか。
手元の環境ではうまくいきました。
正規表現でマッチングするのであればまた変わってきそうですね。

POST /test/type/1/_update
{
  "script": {
    "lang": "painless",
    "source": "ctx._source.Entities.removeIf(item -> item.ID.contains(params.pattern));",
    "params" : {
        "pattern": "RUBY"
    }
  }
}

#3

mnozawa様

ありがとうございます!完璧に動作しました。
マッチする要素が複数あっても、forで回す必要なくすべてきれいに削除できますね!
さっそく全ドキュメントで実行したところ、こちらも大成功です。

POST /test/type/_update_by_query
{
  "query": {
    "match_all": { }
  },
  "script": {
    "lang": "painless",
    "source": "ctx._source.Entities.removeIf(item -> item.ID.contains(params.pattern));",
    "params" : {
        "pattern": "RUBY"
    }
  }
}

#ElasticsearchのリファレンスよりJAVAの勉強が必要なのだろうか…とちょっと思っちゃいました


#4

度々申し訳ありません。
上記の続きですが、どうしてもうまくいかなくなってしまいまして、また教えていただけませんでしょうか。

前述のインデックスに以下のデータを入れたのですが、text型でマッピングしている
フォールドに「数値」として保存されてしまい、containsメソッドが失敗してしまいました。

{
"Description": "Jay Desc 1",
"Entities": [
    {
    "ID": 5678,    ← ダブルクォーテーションをつけないと数値として保存される
    "NAME": "TAROU"
    },
    {
    "ID": "5678_KANJI",
    "NAME": "太郎"
    },
    {
    "ID": "5678_RUBY",
    "NAME": "たろう"
    }
]
}

いろいろ試していて、値をインクリメントできたことから数値である
こと気がついたのですが、なぜマッピング定義に反した型で保存できて
しまうのでしょうか。

また、このような場合、保存されている型を判定してエラーを回避するには
どのようにすれば良いでしょうか。

よろしくお願いいたします。


#5

すみません。自己解決しましたので一応ご報告として書いておきます。
以下のようにすることで、IDフィールドに整数が入っていてもエラーなく
実行できるようになりました。

POST /test/type/_update_by_query
{
  "query": {
    "match_all": { }
  },
  "script": {
    "lang": "painless",
    "source": "ctx._source.Entities.removeIf(item -> item.ID.toString().contains(params.pattern));",
    "params" : {
        "pattern": "RUBY"
    }
  }
}

text型に整数値が保存されている理由ですが、色々試した結果、「保存はtext型で入っているけど、
スクリプトで演算しようとすると、整数型とみなされる」ということなんじゃないかと思っています。

そこで演算時にStringにキャストすれば行けるのかと思い、上記の方法を思いつきました。
これが最適な方法かは全くわかりませんが…


(system) #6

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.