アペフチ

Fluentd設定ファイルのシンタックスハイライト

RougeというRuby製のシンタックスハイライト用ライブラリーがあって、それのFluentd設定ファイル用の追加レクサー(トークナイザー)を作ってみた。

https://github.com/KitaitiMakoto/rouge-lexers-fluentd

始めはApache用のレクサーを使ってみたんだけどうまくいかなかった。<Directory>とかのキーワードがホワイトリスト形式だったり(これはサブクラス作ることで簡単に解決できたけど)、やっぱりFluentd独自の構文に対応したくなったりしてきたので、自分で書いたのだった。

使ってみると、こんな感じ。

# Receive events from 24224/tcp
# This is used by log forwarding and the fluent-cat command
<source>
  @type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

# Match events tagged with "myapp.access" and
# store them to /var/log/fluent/access.%Y-%m-%d
# Of course, you can control how you partition your data
# with the time_slice_format option.
<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

Rougeはターミナル向けにもフォーマットできる。 シンタックスハイライトのターミナルアウトプット

READMEに書いた通りまだやることは残っているけど、取り敢えず最低限の用はなすと思う。具体的には、『サーバ/インフラエンジニア養成読本 ログ収集〜可視化編』のシンタックスハイライトをできる程度には使える。

サーバ/インフラエンジニア養成読本 ログ収集〜可視化編でのシンタックスハイライト

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で「ズートピア」を検索すると、ページ下部で次のように関連キーワードが案内される。 「ズートピア」検索結果画面の下部にある関連キーワード
ページ下部まで見たということは望みの検索結果が得られなかったと判断して、「もしかしてこういう検索をしたかったのでは?」と提案しているわけだ。

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

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

パンチの空いた本

本なんて、パンチ穴を開けた紙の束で売ればいいのではないだろうか。

みんな「マイバインダー」を持って、そこに本を挟むようにすれば、一冊という単位に縛られず、バインダーの厚さが許す限りは、何冊持ち歩いてもよい。仕切りのカードを挟んで、そこから後ろに、お気に入りの本のお気に入りのページを集めた物を常設しておいてもよい。小説のお気に入りの場面、まんがのコマ、詩、ビジネス格言集、参考書のテスト範囲……。

本屋では、本ごとの専用のバインダーを置いてそこで売る。買う時はレジに運んで、店員が中から紙の束だけ外し、客に渡す。当然、ファンは、タイトルや表紙絵、写真が入ったそのバインダーを欲しがるだろうから、マーチャンダイズとして売ればいい。まんがの原画やアニメのセル画のように、プレミアを付けて、プレゼントにしてもよい(そして転売される)。

バインダーの方も、専用デザイナーが生まれて気に入った物を買うようになったり、好きな写真家の写真入りにしたり、イラストレーターの一点物を大事にしていたり、iPhoneケースのように方々で作って売られるようになるだろう。

どうして、こういう形の売り方がされてこなかったのだろうか。