Elasticsearchによる距離検索のアレコレ

距離検索の選択肢

Soudai Sasada

Soudai Sasada

Geo-distance Query

geo_distance クエリは指定された地点からの距離によりフィルタリングをするためのクエリです。 geo_distance クエリはフィルターのため対象を絞り込むだけで後述するクエリと違い関連性スコアに影響を与えることはありません。一定以上の距離で検索対象を絞り込みたい場合には適切なアプローチといえます。

GET my_geoshapes/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_distance": {
          "distance": "200km",
          "pin.location": {
            "lat": 40,
            "lon": -70
          }
        }
      }
    }
  }
}

一方で「距離」を軸とする場合に特定地点から直線距離での計算となる都合上、必ずしも適切とは言えないケースも存在します(たとえば賃貸物件を会社からの通勤時間を考慮して探したい場合に直線距離で対象を絞り込むよりも会社の最寄り駅からの通勤時間で絞り込めた方が適切でしょう)。

ドキュメントはこちらになります。 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html

Distance feature query

distance_feature クエリは指定された点からの距離により関連性スコアを調整する クエリです。対象は「地点」の他に「日付」も可能となります。distance_feature クエリで使用可能なプロパティは datedate_nanos 、 または geo_point 型です。

distance_feature クエリの特徴は bool クエリの should コンテキストで使用することでこれによりドキュメントの関連性スコアに影響を与えることができます。計算式は次のとおりです。

relevance score = boost * pivot / (pivot + distance)

関連性スコアを直接boostさせるため距離が検索結果にとって重要なファクターとなる場合に有効です。またフィルタリングと違い絶対値で対象を不必要に絞り込むことがなく、また、ドキュメントの順序をsort クエリを使わずに並べ替えることができます。

GET /items/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "name": "chocolate"
        }
      },
      "should": {
        "distance_feature": {
          "field": "location",
          "pivot": "1000m",
          "origin": [-71.3, 41.15]
        }
      }
    }
  }
}

sort クエリの問題点は並べ替え指定が複数ある場合にその順序で並べ替えが適用される点にあります。
たとえば画像の有無で優先的に並び替えを行おうとすると検索ワードとの関連性より画像があることが優先されるため画像がないけど関連性の高いドキュメントは画像があるけど関連性が低いドキュメントより後に並ぶことになります。一方で関連性スコアを優先すると画像の有無は考慮されず検索ワードとの関連性が高いドキュメントが優先され、また、関連性スコアが同じ値を返す確率は低いため画像の有無はほぼ考慮されない結果となります。
これらの特性から筆者は sort クエリはあえて使わず関連性スコアで結果を調整することが多いです。

ドキュメントはこちらになります。 https://www.elastic.co/guide/en/elasticsearch/reference/7.x/query-dsl-distance-feature-query.html

Decay Function (Function score query)

function_score クエリはElasticsearchが提供する関数を使うことで関連性スコアを調整できるクエリですが、Decay Functionという関数では指定した地点からの距離によりスコアを減衰できます。

以下、サンプルです。

GET /_search
{
  "query": {
    "function_score": {
      "gauss": {
        "@timestamp": {
          "origin": "2013-09-17", 
          "scale": "10d",
          "offset": "5d",         
          "decay": 0.5            
        }
      }
    }
  }
}

gauss はスコアを減衰させる関数となります。 gauss 以外に explinear が指定でき特性が異なるので用途に合わせて使い分けることができます。ドキュメントにはそれぞれの計算式、及びスコアが減衰されるイメージが載っていてとても分かりやすいです。

ドキュメントはこちらになります。 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#function-decay

TODO: function_scoreでboolクエリやsortクエリが使えるか調べる

まとめ

Elasticsearchによる距離を使った検索をかんたんに調べてみました。
距離による検索を検討にあたりこのドキュメントが参考になれば幸いです。

この記事がお役に立てたら一杯のコーヒーを恵んで頂けると励みになります 😊

Buy Me A Coffee
© 2020, Soudai Sasada