Elasticsearch 5系で距離を算出するscriptをpainlessで書く

  • 1
    いいね
  • 2
    コメント

メモ代わりなので背景などの説明は雑にします。

やりたいこと

Elasticsearchの5.1.1でsearchをしたときに、geo_point型のフィールドとクエリで指定した地点との距離も算出して返して欲しい。2系&Groovyではやり方を知っていたけど、5系&Painlessになったから直す必要がある

なぜ?

Elasticsearchの5.0.0以降ではGroovyが廃止され、Painlessという新しく開発された言語がデフォルトになりました。なので、まずpainlessに変更する必要があります。
また、2.0で使えたいろいろなヘルパーメソッドが廃止されたので代替の処理を書く必要があります。

修正内容

pythonクライアントで使っていたので例がPythonのdict型になっていますが、inlineの中身は共通だと思いますので、REST APIでそのまま使う or 他の言語のクライアントからアクセスする場合は主にinlineとparamsの中身だけ見れば良い気がします。

location_fieldgeo_distance型のフィールド, latitude_valuelongitude_valueはそれぞれ緯度と経度の値が入った変数です。

Before

{
    "distance": {
        "script": {
            "lang": "painless",
            "inline": "doc[\"location_field\"].distanceInKm(lat, lon)",
            "params": {
                "lat": latitude_value
                 "lon": longitude_value
            }
        },
    }
}

After

{
    "distance": {
        "script": {
            "lang": "painless",
            "inline": "doc[\"location_field\"].arcDistance(params.lat, params.lon) * 0.001",
            "params": {
                "lat": latitude_value,
                "lon": longitude_value
            }
        },
    }
}

違い

distanceInKmが廃止されたのでarcDistanceを使います。
ただ、これだと単位が米になるので0.001をかけてkmに変換しています。

もう一点、paramsで定義した変数を以前は定義した名前そのままで使えていたのに、なぜか5系では(painlessでは?)params.を頭に付ける必要がありました。

感想

Groovyもそもそも使ったことないですが、基本文法はだいたい同じだし、複雑なことはあまりやらないと思うので、Documentを読めばなんとかなりそうです。ただ、廃止されたヘルパーメソッドを5系のために書き換えるのは割と大変だなと思いました...(ヘルパーメソッドの処理内容はElasticsearchのドキュメントを読んでもわからないし、painlessでどのヘルパーメソッドが使えるか分からないので)

デバッグできる方法もドキュメントに書かれていましたが、たった1行の処理を書くのに読むのが面倒なのでやりませんでした(結果、割とこの1行のinlineを直すのに1時間近くかかった

文句垂れ流しエントリになってしまいましたが、ちゃんとドキュメントを読み込めば良いだけで僕が悪い可能性が高いので、また深夜テンションを脱したら読み返してみます