アペフチ

Groonga悩み相談「類似文書検索で検索結果が少ないからより多くヒットするようにパラメーター調整したい」

Groongaで学ぶ全文検索 2016-05-20に行って来た。

今日の話題は「類似文書検索」。

参加者の一人が、今作っているサービスでMroonga(Groongaの機能をMySQL経由で使うストレージエンジン)を使っていて、その類似文書検索のパラメーター調整の相談があるということで、類似文書検索が話題に選ばれた。

まだ世に出ていないサービスなので、以降はその物ではなくて僕が適当に変換した話を書く。

サービス概要(フェイク)

話をブログに例えると、はてなダイアリー(はてなブログではない)のような物。

まず、普通にブログ記事を書ける。

そして、(最近の人は知らないかも知れないけど)「おとなり日記」という機能があって、自分の記事と似ている記事一覧が、コメントの所に表示される(今はないかも?)。

勿論、はてなダイアリーには他にも色々な機能があるが、今日の話に必要なのはこの二つ。

やりたいことと直面している課題

やりたいのは、日記を書いた時に、おとなり日記のように、似た記事を探してきて、見せること。

そこの所を、Mroongaの類似文書検索の機能を使って実装したのだが、ヒットする類似文書が少なすぎるので、もっと増やしたい。そのために、今はMroongaが「似ているといえば似ているが、この特徴を似ていると言ってしまうと、およそ全ての日記がお互いに似ていることになってしまう、つまり何も言っていないに等しい」と判断して切り捨てている特徴を、復活させたい、そのためのパラメーターがあるのであれば知りたい、ということだった。もう少し具体的に言うと、ほぼ全日記に含まれるような言葉は、検索時に省かれているが、それを復活させたいということ。

なお、そうするとノイズが増えることは理解していて、ただ、全体の件数が少ない今のフェイズに限っては復活させたいということだった。増えてきたら、そういう「どの日記にも含まれているキーワード」は検索語に含まないように調整するとのこと。

Groongaの類似文書検索

類似文書検索を知らない参加者もいたので、まずはその説明から行われた。

いつものように入力と出力を考えると、入力は(今書いたばかりの)日記で、出力はその日記と似ている日記。こうした入出力を実現するためにシステムはこうなっているとよい。というか、Groongaの類似文書検索はこうなっている。

1. 入力の文書から特徴となる語(=特徴語)を抜き出す

例えば「私はRubyができます。」という日記を書いたとする。この時、「は」とか「私」とかは、非常に多くの日記にも含まれる。「ぼくはPythonができます。」という日記を誰かが書いていたとしたら、そこにも「は」が含まれる。

一方で「Ruby」は(Rubyistのための開発日誌サービスでもない限り)あまり出てこない。同様に、別の人の日記の「Python」もあまりなさそう。こうした「他の文書には入っていないけど、この文書(を含む小数の文書)には入っている」という語が、この文書の特徴語になる。

2. 特徴語でOR検索する

さっきは違うと書いたけど、仮に、「私」と「Ruby」が、先の日記の特徴語だとしよう。似た日記を探す際には、まずその二つの語でOR検索する。すると、今日の日記の特徴語が含まれる記事がヒットする。これは、「特徴」が同じなので、似ていると言えるだろう。

これで類似文書が選べたことになる。

但し、特徴語が上手に選ばれていれば、だ。

特徴語の妥当な抽出方法

日記から特徴語を抜き出す時は、日本語として自然な単語やそれに類する物(≒形態素)を抜き出すのがよい。

何らかの語を抜き出す方法として、文字数を決めて、その文字数単位で切り出すことも出来る。例えば二文字と決めると、「ぼく」「くは」「はP」「Py」「yt」「th」「ho」「on」「nが」「がで」「でき」「きま」「ます」「す。」と14の語(?)を抽出できる。しかし、さっき言ったようにOR検索した時、「『がで』という文字列が含まれている日記はにている」という判断をされても、困ってしまう。

全文検索ではこうした区切り方(n-gram)もありなのだが、類似文書検索の場合は、形態素による分割一択になる。

課題の見直し

さて、ここで課題に戻ろう。

  1. おとなり日記の数が少なすぎる(のでサービス内回遊ができない)。
  2. それは、特徴語を選ぶ時の基準が厳しくて、検索に使われる特徴語が少ないからのように思われる
  3. なので、「私」や「は」といった通常使わないような語も特徴語として類似文書検索に使うようなパラメーター(など何らかの方法)を知りたい

ということだった。結論は「そのようなパラメーターはない」だった(Mroongaには。Groongaにはある)。

だが、そもそも、課題は、そういうことではないのでは? という疑問が呈される。以下「再現率」と「適合率」という言葉を使う。勉強会ではこれらの言葉も説明もあったのだが、実はこの勉強会の2015年11月6日の回でそのことをやっていたので、ここでは端折る。以下の勉強会ページの下に過去の勉強会レポートがまとまっているので、該当日の所を探して読まれたい。

https://groonga.doorkeeper.jp/events/43780

課題を言い換えると「再現率を増やしたい」ということになる。しかし再現率と適合率はトレードオフの関係にあるので、再現率を増やすと適合率が下がる、つまりノイズが増えて、ユーザーが使わなくなりそうである。

ただ、そもそも、たくさんヒットした時に、全部見る人はいない(ような文脈が多い)。大体、最初の数件しか見ないので、ヒットする件数が多いか少ないかというよりも、どの日記が上に来ているのか、という方が重要になる。つまり、検索結果のスコアリングが大事だということだ。スコアリングはMroongaで色々と調整できるので、そこで頑張るのがよいということになる。

また、検索結果の中にユーザーが望む物がなかった時のフォローを入れておくというのも最近よくやられている(らしい)。例えば、今Googleで「ズートピア」を検索すると、ページ下部で次のように関連キーワードが案内される。 「ズートピア」検索結果画面の下部にある関連キーワード
ページ下部まで見たということは望みの検索結果が得られなかったと判断して、「もしかしてこういう検索をしたかったのでは?」と提案しているわけだ。

ウェブページの全文検索ではなく、ツイートやチャットだと、新しい方が探したいことが多いだろうから、投稿日時を使ってスコアリングするというのもある。日記にお気に入り機能があれば、お気に入りが多い物のスコアを上げてもいい。

このように、文書その物以外のメタデータを使って、よりユーザーの望みそうな物に高い検索スコアを与え、上位に表示させるというのが最近のはやりらしい。