当ブログの関連記事をtf-idfによって生成するようにしました

雑記ブログは難しい!

このブログ「テストステ論」はおれが新卒間もない頃に始めたもので、 主に、当時開発していたdm-writeboostというソフトウェアの開発日記として始めたものです。

しかし今となっては単なる雑記ブログであり、 中学受験、ルシファーヲチ、自殺、筋トレ、他者への攻撃など、 さまざまなジャンルの記事があります。 その数は実に500記事を超えています。 かなり巨大な雑記ブログと言ってもよいでしょう。

ブログへの流入は主に検索流入です。 おかげさまでテストステ論と検索して来るファンもいますし、 特定のワード(例「首吊り」「中学受験 全落ち」)などで来る人もいます。

ブログの管理人としては、たまたまブログにたどり着いてくれた人に、 他の記事も見てもらい、テストステ論のファンになってほしいものです。

このような目的のために一般的に使われる機能は

  • カテゴリ分け
  • タグ付け
  • 関連記事

ですが、

このうちカテゴリ分けは雑記ブログではかなり難しくなります。 カテゴリ分けは、ある特定の分野について書く特化ブログの場合にはあらかじめ きれいに設計することが出来ると思いますが、雑記ブログには向きません。 破綻しないように大雑把に分類するというのは手ですが、 あまりにも抽象的なカテゴリに100件入ってしまっては、実質的に無意味です。 今まではこの方法で管理していました。

手動でタグをつけていくことも、結局タグが多くなりすぎて 現実的ではなくなります。 手動なタグ付けも、特化ブログの場合にはそこに出てくるタグも 限られるでしょうから意味がありそうですが、 雑記ブログの場合には意味はありません。

Hugoの関連記事機能はゴミ

雑記ブログでは手動がだめなことはわかりました。 では自動ということになります。

Hugoには、自動で関連記事を出す機能があります。 しかしこの機能は、

  • 手動でつけたカテゴリやタグをあらかじめ与えた数値によって重みづけして、関連記事を計算
  • 新しい記事を優先してリスト

という仕様で、 第一に、手動でカテゴリやタグをつけることが前提になってること、 さらに最悪なのは新しい記事を優先することです。 新しい記事を優先してしまうと、古い記事が関連記事に出てこなくなります。

科学的解決をしよう

直感的に、各記事から特徴的な単語を列挙出来て、 記事ごとの距離や内積が定義出来れば「類似記事」を計算することが出来そうです。

tf-idfは「レアな単語ほどその記事を特徴づけるはずだ」というアイデアによって 記事に特徴ベクトルを与えます。

特徴ベクトルが与えられた時、記事間の類似度はコサイン類似度という値を計算することで 求めることが出来ます。

記事から単語を列挙するにはどうすればよいでしょうか? これには形態素解析という手法が使えます。 このアルゴリズムを実装したものとしてMeCabがあります。 (デフォルトのものではなく、NEologdという新しい辞書を使っています)

これらを組み合わせたものを実装しました。 Dockerコンテナに閉じ込めてあるので、記事を与えるだけで動きます。

この方法ならば、全記事の順番を無視した上で もっとも関連した記事を計算して列挙することが出来ます。 精度については、明らかに同カテゴリのものについてはちゃんと関連記事に出ていますから、 十分といえます。少なくとも手動よりははるかにマシです。 さらにこの方法だと、記事が多くなればなるほど精度が上がっていきます。 まさに、雑記ブログ向けの手法です。

計算時間ですが、 コサイン類似度の計算は、 ナイーブに考えると記事数の二乗が入ってきそうなので相当重い(数分かかる)かと思いましたが、 500記事に対して4.5秒でした。ここには形態素解析のコストも入っていますから、 1000記事までは余裕で耐えられそうです。

関連記事