2020-02、2つのMroonga記事を書いている間に気づいた検索スコアの話です。
score がなんか変
> SELECT t_stringvalue,MATCH(t_stringvalue) AGAINST("作業場所") AS score
FROM t_tagproperty
WHERE MATCH(t_stringvalue) AGAINST("作業場所")
ORDER BY score DESC LIMIT 5;
+---------------------------------------+-------+
| t_stringvalue | score |
+---------------------------------------+-------+
| iOS標準ディレクトリ:ファイルの保存場所 | 6513 |
| 本体工(場所打ち) | 6513 |
| 作業場所の整地 | 6513 |
| 作業場所の地耐力を事前に確認すること。 | 6513 |
| 作業場所の整地 | 6513 |
+---------------------------------------+-------+
- 検索query "作業場所" はトークン2つ"作業","場所"になってる様子
- "場所"しかhitのない1行目2行目のscore=6513
- "作業"と"場所"の2つhitした3-5行目も score=6513
Mroongaのスコア仕様
上位N個のトークンを取り出す N = マッチしたトークン数 / 8 + 1
なるほど。query のトークン数8を超えるまで最上位重みのトークン1つしか計算しない仕様です。"作業"と"場所"の両方を含んでもscoreで上位に来ないのはこの仕様のためです。
どうやら「関連文書検索」のようにqueryがとても長いケースを想定しているのが、 IN NATURAL LANGUAGE MODE のようです。long query x long results の score 計算量を抑制する意図が見えます。
MroongaのBOOLEAN MODE推し
デフォルトの IN NATURAL LANGUAGE MODE よりも IN BOOLEAN MODE の方が適切です。なぜなら IN BOOLEAN MODE はWeb検索エンジンのクエリーと似ているからです。多くのユーザーはWeb検索エンジンのクエリーに慣れています。
BOOLEAN MODE での hit , miss, OR, AND, negative くらいで足りるし、結果がわかりやすいって判断ですね。
結論
IN NATURAL LANGUAGE MODE のスコアをHitトークン数が8以下のときのロジックを少し修正して、Hitトークン数を反映することは不可能ではないでしょう。でもやる意味があるかというと疑問です。
queryのトークン数が少ないときの検索者の意図は、どのトークンも重みは同じじゃないでしょうか。
データベースの統計情報から計算して、どれか1つのトークンだけ差別的に重みをつけてもありがた迷惑かなと思います。推されるとおり IN BOOLEAN MODE で使うことにします。
データベースが大きくて、short query だと1位タイのhit多数になるケースが多いでしょうが、そのときの ORDER BY でのメインは、 IN BOOLEAN MODE の score でも、 IN NATURAL LANGUAGE MODE の score でもない、第2キーのなにか別の文書属性になるでしょうから。
Timestamp とか Stars とか Recommends とか
※世紀の変わり目には TF*IDF の検索スコア実装したのを担当してました(Okapi BM25も試してたっけ?)。20世紀は遠くなりにけり