elasticsearchのスコアリングについてのメモ書き

検索した結果、ある条件の結果を優先して表示したいという場合があります。
分かりやすい例でいうと、地図検索。ある地点から近い順に検索条件に該当したものを並べたい場合

このときつかうものとしてscore計算です。
scoreが高い順に検索検索結果が並びます。

headプラグインを使うと、scoreの値がいくつかわかります。

![scoreに関する図.png](https://qiita-image-store.s3.amazonaws.com/0/1686/141081a2-890f-d29b-1ea1-5ab99230b042.png)


ここの_score列がそれにあたります。

# scoringの計算方法

検索文字に対する類似度を計算している。その計算方式は以下ようにやっているらしい。(デフォルトの設定だと)

```
score(q,d)  =  
            queryNorm(q)  
          · coord(q,d)    
          · ∑ (           
                tf(t in d)   
              · idf(t)²      
              · t.getBoost() 
              · norm(t,d)    
            ) (t in q)    

```

## 自分でscore値の計算方法を定義して検索させる場合のquery例

```
{ 
        query: {
         function_score: {
           score_mode: 'sum', # functionsないのスコアの計算方法
           boost_mode: 'multiply', # クエリの合計スコアとfunctionのスコアの計算方法 
           query: {
             simple_query_string: {
               query: photo_search.search_word,
               fields: ['description'],
               default_operator: :and,
             }
           },
           functions: [
              {
                field_value_factor: {
                  field: "good_point",
                  factor: 2.0,
                  modifier: "square",
                  missing: 1
                },
                weight: 20
              },
              {
                field_value_factor: {
                  field: "id",
                  factor: 1.5,
                  modifier: "sqrt",
                  missing: 1
                },
                weight: 10
              }
            ]
         }
        }
      }
```

# score検索
score検索をする場合はfunction_scoreクエリを使う。
書式はマニュアルの[ここ](https://www.elastic.co/guide/en/elasticsearch/reference/1.7/query-dsl-function-score-query.html#function-random)に書いてある通り。
で、ここの中の<code>FUNCTION</code>って書いてある箇所に幾つか種類がある。
上の例では<code>field_value_factor</code>というのを使っているが、以下の５つの種類がある。

1.script_score
2.weight
3.random_score
4.field_value_factor
5.decay functions: gauss, linear, exp

## script_score
他のnumber型のfieldの値を使ってscore計算をカスタマイズできる

## weight
数値を設定。score計算の結果、設定した数値分値が掛け合わせられる

## random_score
ランダムな数値を返す

## field_value_factor
script_scoreに似ている。他のfieldの値を使って計算式を定義してscoreの値を返す

## decay functions: gauss, linear, exp
距離計算など。よくあるのがある地点から半径〜〜キロメートルの範囲にあるものを近い順に出すなど。

こういった関数を使い出したscoreを<code>score_mode</code>の種類によって最終的な検索結果のスコア値として算出し、その値の順で検索結果を返す。
以下score_modeの例

1.multiply
デフォルトの設定

2.sum
合計値

3.avg
平均値

4.first
最初に定義した関数(functionsの中で最初に定義したもの)の中でひかかったものものの値を使う。

5.max
最大値を使う

6.min
最小値を使う

# scoreの値を確認したい場合
検索結果のjsonの「_score」の値を見るとscoreの値がわかる。今回ruby/railsを使って色々と検証していたので、scoreの確認する場合の例を以下に示す。使うのは[elasticsearch-model](https://github.com/elastic/elasticsearch-rails/blob/d023d43cbb2f616e7ac5b3a33437ca610333295e/elasticsearch-model/README.md)です。

```
class Photo < 
  include Elasticsearch::Model
end


@client = Photo.__elasticsearch__
@client.search(query).records.each_with_hit do |photo, hit|
  puts "#{photo.description}: #{hit._score}"
end

これはテスト。11犬の画像です。: 7842.8647
これはテスト。100犬の画像です。: 7841.9272
これはテスト。21犬の画像です。: 7840.7812
これはテスト。1犬の画像です。: 7837.034
これはテスト。18犬の画像です。: 7836.9346
これはテスト。37犬の画像です。: 7836.548
これはテスト。58犬の画像です。: 7832.993
これはテスト。98犬の画像です。: 7832.7773
これはテスト。76犬の画像です。: 7831.8076
これはテスト。63犬の画像です。: 7830.5396

```

ざっとですが、上記のようなやり方だとscoreの値を確認することができます。

# 参照
[Lucene’s Practical Scoring Function](https://www.elastic.co/guide/en/elasticsearch/guide/current/practical-scoring-function.html?ref=driverlayer.com/web?ref=driverlayer.com/web)

[Function Score Query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html)