# 7.11. スコアラー

## 7.11.1. 概要

Groongaにはスコアー関数をカスタマイズするスコアーモジュールがあります。スコアー関数はマッチしたレコードのスコアーを計算します。デフォルトのスコアー関数は出現単語数をスコアーにします。これはTF（term frequency。単語の出現数）と呼ばれている計算方法です。

TFは高速なスコアー関数ですが、次のケースには適していません。

> - 検索クエリーが「the」や「a」のように非常によく出現する単語を含んでいる。

> - 文書中に「They are keyword, keyword, keyword ... and keyword」というように同じキーワードが大量に含まれている。検索エンジンのスパマーはこのテクニックを使うかもしれません。

スコアー関数でこれらのケースを解決できます。例えば、 TF-IDF （term frequency-inverse document frequency。その文書中での単語の出現数を、文書全体での単語の出現数で割ったもの）は最初のケースを解決できます。 Okapi BM25 は2番目のケースを解決できます。しかし、これらはTFより遅いです。

Groongaは scorer_tf_idf としてTF-IDFベースのスコアラーを提供しています。しかし、Okapi BM25ベースのスコアラーはまだ提供していません。

> スコアー関数だけでスコアの計算をする必要はありません。スコアー関数は検索クエリーに非常に依存しています。検索クエリーだけでなく、マッチしたレコードのメタデータも使えないか検討しましょう。

> たとえば、Googleはスコアーの計算に ページランク を使っています。あなたも、データの種類（たとえば、「メモ」データよりも「タイトル」データの方が重要など）、タグ、位置情報などを使えないか検討してみましょう。

> スコアーの計算をスコアー関数だけで考えることはやめましょう。

## 7.11.2. 使い方

このセクションではスコアラーの使い方について説明します。

使い方を示すために使うスキーマ定義とサンプルデータは以下の通りです。

サンプルスキーマ:

実行例:

    table_create Memos TABLE_HASH_KEY ShortText
    # [[0, 1337566253.89858, 0.000355720520019531], true]
    column_create Memos title COLUMN_SCALAR ShortText
    # [[0, 1337566253.89858, 0.000355720520019531], true]
    column_create Memos content COLUMN_SCALAR Text
    # [[0, 1337566253.89858, 0.000355720520019531], true]
    table_create Terms TABLE_PAT_KEY ShortText \
      --default_tokenizer TokenBigram \
      --normalizer NormalizerAuto
    # [[0, 1337566253.89858, 0.000355720520019531], true]
    column_create Terms title_index COLUMN_INDEX|WITH_POSITION Memos title
    # [[0, 1337566253.89858, 0.000355720520019531], true]
    column_create Terms content_index COLUMN_INDEX|WITH_POSITION Memos content
    # [[0, 1337566253.89858, 0.000355720520019531], true]

サンプルデータ:

実行例:

    load --table Memos
    [
    {
      "_key": "memo1",
      "title": "Groonga is easy",
      "content": "Groonga is very easy full text search engine!"
    },
    {
      "_key": "memo2",
      "title": "Mroonga is easy",
      "content": "Mroonga is more easier full text search engine!"
    },
    {
      "_key": "memo3",
      "title": "Rroonga is easy",
      "content": "Ruby is very helpful."
    },
    {
      "_key": "memo4",
      "title": "Groonga is fast",
      "content": "Groonga! Groonga! Groonga! Groonga is very fast!"
    },
    {
      "_key": "memo5",
      "title": "PGroonga is fast",
      "content": "PGroonga is very fast!"
    },
    {
      "_key": "memo6",
      "title": "PGroonga is useful",
      "content": "SQL is easy because many client libraries exist."
    },
    {
      "_key": "memo7",
      "title": "Mroonga is also useful",
      "content": "MySQL has replication feature. Mroonga can use it."
    }
    ]
    # [[0, 1337566253.89858, 0.000355720520019531], 7]

match_columns の中でscore関数を使うことができます。次に構文を示します。

scorer_tf_idf のように、いくつかのスコアー関数には引数はありません。:

    SCORE_FUNCTION(COLUMN)

重みを指定することができます。:

    SCORE_FUNCTION(COLUMN) * WEIGHT

scorer_tf_at_most のように引数が必要なスコアー関数もあります。:

    SCORE_FUNCTION(COLUMN, ARGUMENT1, ARGUMENT2, ...)

重みを指定することができます。:

    SCORE_FUNCTION(COLUMN, ARGUMENT1, ARGUMENT2, ...) * WEIGHT

match_columns ではカラムごとに異なるスコア関数を使うことができます。:

    SCORE_FUNCTION1(COLUMN1) ||
      SCORE_FUNCTION2(COLUMN2) * WEIGHT ||
      SCORE_FUNCTION3(COLUMN3, ARGUMENT1) ||
      ...

以下は簡単な使用例です。

実行例:

    select Memos \
      --match_columns "scorer_tf_idf(content)" \
      --query "Groonga" \
      --output_columns "content, _score" \
      --sort_keys "-_score"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     [
    #       [
    #         2
    #       ],
    #       [
    #         [
    #           "content",
    #           "Text"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "Groonga! Groonga! Groonga! Groonga is very fast!",
    #         2
    #       ],
    #       [
    #         "Groonga is very easy full text search engine!",
    #         1
    #       ]
    #     ]
    #   ]
    # ]

`Groonga! Groonga! Groonga! Groonga is very fast!` には `Groonga` が4つ含まれています。デフォルトのTFベースのスコアラーを使うと、 `_score` は `4` です。しかし、実際は `_score` は `2` になります。なぜなら、この `select` コマンドはTF-IDFベースの `scorer_tf_idf()` スコアラーを使っているからです。

以下は重みを使った例です。

実行例:

    select Memos \
      --match_columns "scorer_tf_idf(content) * 10" \
      --query "Groonga" \
      --output_columns "content, _score" \
      --sort_keys "-_score"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     [
    #       [
    #         2
    #       ],
    #       [
    #         [
    #           "content",
    #           "Text"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "Groonga! Groonga! Groonga! Groonga is very fast!",
    #         22
    #       ],
    #       [
    #         "Groonga is very easy full text search engine!",
    #         10
    #       ]
    #     ]
    #   ]
    # ]

`Groonga! Groonga! Groonga! Groonga is very fast!` の `_score` は `22` です。重みを指定していない前の例では `_score` は `2` でした。

以下は必ず引数を1つ指定しなければいけないスコアラーを使う例です。 scorer_tf_at_most スコアラーには引数を1つ指定しなければいけません。このスコアラーを使うと、TFのスコアーの最大値を制限することができます。

実行例:

    select Memos \
      --match_columns "scorer_tf_at_most(content, 2.0)" \
      --query "Groonga" \
      --output_columns "content, _score" \
      --sort_keys "-_score"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     [
    #       [
    #         2
    #       ],
    #       [
    #         [
    #           "content",
    #           "Text"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "Groonga! Groonga! Groonga! Groonga is very fast!",
    #         2
    #       ],
    #       [
    #         "Groonga is very easy full text search engine!",
    #         1
    #       ]
    #     ]
    #   ]
    # ]

`Groonga! Groonga! Groonga! Groonga is very fast!` は `Groonga` を4つ含んでいます。もし、デフォルトのスコアラーである標準のTFベースのスコアラーを使っていた場合、 `_score` は `4` になります。しかし、実際の `_score` は `2` です。なぜなら、この `select` コマンドが使っているスコアラーは最大スコアーを `2` に制限しているからです。

以下は複数のスコアラーを使う例です。

実行例:

    select Memos \
      --match_columns "scorer_tf_idf(title) || scorer_tf_at_most(content, 2.0)" \
      --query "Groonga" \
      --output_columns "title, content, _score" \
      --sort_keys "-_score"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     [
    #       [
    #         2
    #       ],
    #       [
    #         [
    #           "title",
    #           "ShortText"
    #         ],
    #         [
    #           "content",
    #           "Text"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "Groonga is fast",
    #         "Groonga! Groonga! Groonga! Groonga is very fast!",
    #         3
    #       ],
    #       [
    #         "Groonga is easy",
    #         "Groonga is very easy full text search engine!",
    #         2
    #       ]
    #     ]
    #   ]
    # ]

この `--match_columns` は `scorer_tf_idf(title)` と `scorer_tf_at_most(content, 2.0)` を使っています。 `_score` の値はこれら2つの値の合計になります。

同じ `--match_columns` の中でデフォルトのスコアラーとカスタムスコアラーを使うことができます。単にマッチ対象のカラムを指定するとデフォルトのスコアラーを使います。

実行例:

    select Memos \
      --match_columns "title || scorer_tf_at_most(content, 2.0)" \
      --query "Groonga" \
      --output_columns "title, content, _score" \
      --sort_keys "-_score"
    # [
    #   [
    #     0,
    #     1337566253.89858,
    #     0.000355720520019531
    #   ],
    #   [
    #     [
    #       [
    #         2
    #       ],
    #       [
    #         [
    #           "title",
    #           "ShortText"
    #         ],
    #         [
    #           "content",
    #           "Text"
    #         ],
    #         [
    #           "_score",
    #           "Int32"
    #         ]
    #       ],
    #       [
    #         "Groonga is fast",
    #         "Groonga! Groonga! Groonga! Groonga is very fast!",
    #         3
    #       ],
    #       [
    #         "Groonga is easy",
    #         "Groonga is very easy full text search engine!",
    #         2
    #       ]
    #     ]
    #   ]
    # ]

この `--match_columns` は `title` にはデフォルトのスコアラー（TF）を使い、 `content` には scorer_tf_at_most を使います。 `_score` の値はこれらのスコアラーの結果の合計になります。

## 7.11.3. 組み込みスコアラー

以下は組み込みのスコアラーです。

- 7.11.3.1. `scorer_tf_at_most`
- 7.11.3.2. `scorer_tf_idf`