[groonga-dev,02792] IN NATURAL LANGUAGE MODEにおける検索スコア

Back to archive index

Kazuhiko kazuh****@fdiar*****
2014年 9月 24日 (水) 04:16:38 JST


こんにちは、かずひこです。

MroongaのNATURAL LANGUAGE MODEを試しています。ドキュメントによると、

http://mroonga.org/ja/docs/reference/full_text_search/scoring.html
> 1.クエリをトークンに分割する
> 2.マッチしないトークンを除去する
> 3.トークン毎の重みを計算する
> 4.重みが大きい上位N個のトークンを取り出す
> 5.上位N個のトークンについて、トークンが出現する文書に重みを足し、すべての重みを足したものがクエリと文書の類似度となる
(snip)
> 6.2.1.4. 重みが大きい上位N個のトークンを取り出す
> Nは以下の式で求めています。N = マッチしたトークン数 / 8 + 1
> 今回は「マッチしたトークン数」が2なので「2 / 8 + 1 = 1」で N = 1です。

とありますが、この「マッチしたトークン数 / 8 + 1」は少なすぎるのではない
かと感じました。

このドキュメントのページにあるサンプルを元に、MyISAMと比較してみました
(MyISAMの「50%以上のレコードにマッチする検索語は無視」という制約のため
に、マッチしないダミーのデータを足しています。)

* Mroonga

MariaDB> SELECT *, MATCH (content) AGAINST ("today rain") AS score FROM
diaries;
+----+--------------------------------------------------+--------+
| id | content                                          | score  |
+----+--------------------------------------------------+--------+
|  1 | It'll be fine tomorrow as well.                  |      0 |
|  2 | It'll rain tomorrow.                             |      0 |
|  3 | It's fine today. It'll be fine tomorrow as well. | 131073 |
|  4 | It's fine today. But it'll rain tomorrow.        | 131073 |
|  5 | dummy                                            |      0 |
|  6 | dummy                                            |      0 |
|  7 | dummy                                            |      0 |
|  8 | dummy                                            |      0 |
|  9 | dummy                                            |      0 |
+----+--------------------------------------------------+--------+
9 rows in set (0.00 sec)

ここでは、today も rain もマッチするレコードのあるトークンなので、N =
2/8 + 1 => 1 になって、より重みの大きいトークンである today のみが用いら
れています。なので、"today"だけで検索しても、結果は全く同じです。

* MyISAM

MariaDB> SELECT *, MATCH (content) AGAINST ("today rain") AS score FROM
diaries;
+----+--------------------------------------------------+--------------------+
| id | content                                          | score
     |
+----+--------------------------------------------------+--------------------+
|  1 | It'll be fine tomorrow as well.                  |
   0 |
|  2 | It'll rain tomorrow.                             |
1.2245972156524658 |
|  3 | It's fine today. It'll be fine tomorrow as well. |
0.9837008714675903 |
|  4 | It's fine today. But it'll rain tomorrow.        |
2.3953402042388916 |
|  5 | dummy                                            |
   0 |
|  6 | dummy                                            |
   0 |
|  7 | dummy                                            |
   0 |
|  8 | dummy                                            |
   0 |
|  9 | dummy                                            |
   0 |
+----+--------------------------------------------------+--------------------+
9 rows in set (0.00 sec)

この例だと、today の分のスコアも rain の分のスコアも反映されているのが分
かります(「id=2のスコア + id=4のスコア」と「id=3のスコア」が異なるのが
気にならなくはないけれど)。

CJKを対象にbigramで検索するのなら、トークン数は多くなるので、これくらい
の小さいNでも困らないのかもしれませんが、英単語などで検索する場合、検索
語が1語でも2語でも(たぶん7語でも)検索結果が全く同じというのは不自然に
感じます。

現状の n / 8 + 1 というのは、おそらくヒューリスティックなものだとは思い
ますが、それを尊重すると、例えば

N = n              (if n < 8)
N = 8 + (n-8 / 8)  (if n >= 8)

とかだとより自然な結果が得られそうな気がしますがいかがでしょうか?
他のNATURAL LANGUAGE MODEをご利用の方のご意見もぜひお聞かせください。

かずひこ




groonga-dev メーリングリストの案内
Back to archive index