Elasticsearchで見る検索エンジンの仕組み(5): スコアリング編

##### [前回] [Elasticsearchで見る検索エンジンの仕組み(4): サンプルデータでクエリ編](https://qiita.com/mingchun_zhao/items/29d4e497ecfc1d2f016a)

## はじめに

前回は、Elasticsearch付属のサンプルデータでクエリを実行しました。
今回は、検索結果におけるランキングを理解します。

## スコアリング(ランク付け)とは

- ユーザーにとって重要と思われる文書を上位に表示するようにソート
- 独自のランク付けルールを適用し`重要度`と呼んでいる
- 使用される手法
    - 文書中の検索単語出現頻度
        - 検索単語が、各文書内でどのくらいの頻度で出現しているかを表す割合
    - TF-IDF
        - TF(term frequency)は、ある文書における単語の出現頻度
        - IDF(inverse document frequency)は、単語の文書間でのレア度(希少価値)を表す
            - どの文書にもある単語はレア度(重要度)が低い
    - BM25(Okapi BM25)
        - tf-idfを改良した手法で、クエリとの関連性に応じて、文書を順位付け
            - Elasticsearchで使用 
    - ページランク
        - `重要度の高いページからリンクされているページは重要である`という原理に基づいたランク付け
    - HTMLタグの解析
        - `<title>`タグや`<H1>`タグを重視するランキング
        - ※ 引用元: https://ja.wikipedia.org/wiki/%E5%85%A8%E6%96%87%E6%A4%9C%E7%B4%A2

## スコアリングを検証

### KibanaのDev Toolsで、score-testインデックスへドキュメント登録

```
POST /score-test/_bulk
{"index": {"_id": 1}}
{"message": "Apache Lucene Solr Blog"}
{"index": {"_id": 2}}
{"message": "Elasticsearch Tech"}
{"index": {"_id": 3}}
{"message": "Apache Lucene Tech Elasticsearch Tech Blog"}
{"index": {"_id": 4}}
{"message": "Lucene Tech Elasticsearch Tech Solr Tech"}
{"index": {"_id": 5}}
{"message": "Lucene Elasticsearch Blog"}
```

### 登録されたドキュメントを確認

- クエリ
```
GET /score-test/_search
```

- 結果
    - 5件ヒット

### スコアを確認

- `Elasticsearch Tech`で、インデックスscore-testを検索

```
GET /score-test/_search
{
  "query": {
    "match": {
      "message": "Elasticsearch Tech"
    }
  }
}
```

- 検索結果
    - 検索条件と類似した4件がヒット
    - ドキュメント`_id: 2`の`Elasticsearch Tech`が、最もスコアが高く、検索条件に類似(完全一致)
    - その他ドキュメントのランク付けの根拠は?

```
  ... ...
  "hits": {
    "total": {
      "value": 4,
      "relation": "eq"
    },
    "max_score": 1.0521364,
    "hits": [
      {
        "_index": "score-test",
        "_id": "2",
        "_score": 1.0521364,
        "_source": {
          "message": "Elasticsearch Tech"
        }
      },
      {
        "_index": "score-test",
        "_id": "4",
        "_score": 1.0205201,
        "_source": {
          "message": "Lucene Tech Elasticsearch Tech Solr Tech"
        }
      },
      {
        "_index": "score-test",
        "_id": "3",
        "_score": 0.9061662,
        "_source": {
          "message": "Apache Lucene Tech Elasticsearch Tech Blog"
        }
      },
      {
        "_index": "score-test",
        "_id": "5",
        "_score": 0.32575765,
        "_source": {
          "message": "Lucene Elasticsearch Blog"
        }
      }
    ]
  ... ...
```

### スコア計算ロジックを確認

- `explain=true`パラメータを付けて検索
```
GET /score-test/_search?explain=true
{
  "query": {
    "match": {
      "message": "Elasticsearch Tech"
    }
  }
}
```

- スコア計算の過程が詳細に表示される
    - boost、idf、tfなどの値でスコアが計算されている
```
    ... ...
        "_explanation": {
          "value": 1.0521364,
          "description": "sum of:",
          "details": [
            {
              "value": 0.36614084,
              "description": "weight(message:elasticsearch in 1) [PerFieldSimilarity], result of:",
              "details": [
                {
                  "value": 0.36614084,
                  "description": "score(freq=1.0), computed as boost * idf * tf from:",
                  "details": [
                    {
                      "value": 2.2,
                      "description": "boost",
                      "details": []
                    },
                    {
                      "value": 0.2876821,
                      "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                      "details": [
                        {
                          "value": 4,
                          "description": "n, number of documents containing term",
                          "details": []
                        },
                        {
                          "value": 5,
                          "description": "N, total number of documents with field",
                          "details": []
                        }
                      ]
                    },
                    {
                      "value": 0.57851243,
                      "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                      "details": [
                        {
                          "value": 1,
                          "description": "freq, occurrences of term within document",
                          "details": []
                        },
                        {
                          "value": 1.2,
                          "description": "k1, term saturation parameter",
                          "details": []
                        },
                        {
                          "value": 0.75,
                          "description": "b, length normalization parameter",
                          "details": []
                        },
                        {
                          "value": 2,
                          "description": "dl, length of field",
                          "details": []
                        },
                        {
                          "value": 4.2,
                          "description": "avgdl, average length of field",
                          "details": []
                        }
                      ]
                    }
                  ]
                }
              ]
            },
    ... ...
```

## おわりに

全文検索のスコアリングを理解しました。
次回も続きます。お楽しみに。

##### [次回] [Elasticsearchで見る検索エンジンの仕組み(6): Lukeでインデックス操作編](https://qiita.com/mingchun_zhao/items/dcd7d3862d260aa28f5a)