自分のブログの索引の作り方...試行錯誤

ブログの目次を自動的に生成するサービス"Mokuji"というのがあって、面白そうだなーと思ってアクセスしてみると、緑と黒ベースのシンプルな美しさのページにさらに惹かれてしまい、登録してみた。暫くすると、自分のブログの目次が出来上がった。
自分の目次を見て、面白いなーと思った。はてなダイアリーの「記事一覧」で目次としての用は足りるのだけど、タイトルの羅列だけではすべての日記が対等な関係でメリハリがないなーと感じていたので。キーワードで括ったり、月別に分類してテーマとなるキーワードを表示したりすることで、同じタイトルでも見た瞬間に感じる直感力がアップするような気がした。
しかし、すべてを自動で生成してくれる便利さの反面、目次のキーワードに、書いた人の気持ちが反映されていない部分もある。文章を要約するようなキーワードを見つけることは、コンピューターにとっては恐らくとても高度な作業になると思う。よって究極的には、書いた人の気持ちは書いた人が一番よく分かるのだから、日記を書く人がその都度タグ付けしておくのが一番正確な方法になるだろう。(ちゃんと出来る人は...。)
ところが、日記を書き続けていると、このタグ付けに迷いが生じる。具体的にはタグの粒度をどのくらいの大きさにしようか悩むのである。例えば、[rails]とダグ付けするのか、もっと細かく[scaffold][validate][render]...とするのか。そして粒度を細かくすればするほど、一つの日記により多くのタグ付けが必要になり、結果、ものぐさな自分はそのレベルでのタグ付けが続かなくなってしまう...。
また、日記で取り扱う内容の範囲が広がると、過去の日記に新たな視点でダグを追加したくもなる。日記が少ないうちは、もう一度タグの付け直しをするのも苦にならないが、ある程度増えてくるともはやそんな気力は無くなる...。
そんな訳で、現在進行形のブログに、分かり易い目次を付けるのは、実は相当面倒臭くて、自動でやろうとすればなかなか難しいことなのでは...と感じたのである。そして、自分のブログの内容を表現するキーワードの集まり、つまり「索引」を作ってみたくなったのである。

単語の出現頻度による索引

最初に思い付いたのが、単語の出現頻度による索引だ。単純に出現頻度が多い単語を索引として抽出するようにしてみる。

日記データのダウンロード

自分が今まで書いたはてな日記は「管理 >> データの管理」で一括してダウンロードできる。余分なHTMLタグは不要なので「はてなの日記データ形式」でダウンロードしてみた。

      • 意外とショックだったのは、ダウンロードしたファイルサイズが2MBしかなかったこと。これまで書き溜めた日記はかなり大きなサイズになると思っていたが、文字データとして書き出してしまえば、実はその程度のサイズしかないのだ...。
単語に分割

そのままではひと続きの文章なので、処理単位の単語に分解する必要がある。この作業も高度なので、以前インストールしたMeCabを利用した。

  • mecabコマンドで対話形式のmecabモードに入って、「日本語を解析する。」と入力すれば、以下のように品詞単位に分解したデータを返してくれる。
$ mecab
日本語を解析する。
日本語	名詞,一般,*,*,*,*,日本語,ニホンゴ,ニホンゴ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
解析	名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
する	動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
。	記号,句点,*,*,*,*,。,。,。
  • そして、ファイルパスを指定すれば、そのファイルの内容を解析した結果を出力してくれる。
$ mecab ~/Downloads/zariganitosh.xml
...(中略)...
「	記号,括弧開,*,*,*,*,「,「,「
hello	名詞,固有名詞,組織,*,*,*,*
」	記号,括弧閉,*,*,*,*,」,」,」
という	助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
名前	名詞,一般,*,*,*,*,名前,ナマエ,ナマエ
の	助詞,連体化,*,*,*,*,の,ノ,ノ
データベース	名詞,一般,*,*,*,*,データベース,データベース,データベース
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
作成	名詞,サ変接続,*,*,*,*,作成,サクセイ,サクセイ
。	記号,句点,*,*,*,*,。,。,。
EOS
&	名詞,サ変接続,*,*,*,*,*
gt	名詞,一般,*,*,*,*,*
;|	名詞,サ変接続,*,*,*,*,*
EOS
mysql	名詞,固有名詞,組織,*,*,*,*
&	名詞,サ変接続,*,*,*,*,*
gt	名詞,一般,*,*,*,*,*
;	名詞,サ変接続,*,*,*,*,*
&	名詞,サ変接続,*,*,*,*,*
lt	名詞,一般,*,*,*,*,*
;	名詞,サ変接続,*,*,*,*,*
span	名詞,一般,*,*,*,*,*
style	名詞,一般,*,*,*,*,*
=&	名詞,サ変接続,*,*,*,*,*
quot	名詞,一般,*,*,*,*,*
;	名詞,サ変接続,*,*,*,*,*
...(中略)...
単語を集計

あとは単語の出現回数をカウントすれば良いだけだ。このような場合、以前、頻繁に使うシェルコマンドベスト30を集計とるワンライナーというのが紹介されており、これがそのまま使えると思った。(素晴らしい技の紹介に感謝です!パイプでシェルコマンドを連携させるだけで、ちょっと手間のかかりそうな集計もあっという間に(MacBookで30秒くらい)完了してしまい感動!CUIの素晴らしさが、ここにあるなと感じてしまった。)

$ mecab ~/Users/bebe/Downloads/zariganitosh.xml | awk '{print $1}'| sort | uniq -c | sort -nr
36206 EOS
22181 ;
18114 &
15295 gt
13908 _
11642 lt
11420 quot
10992 .
10888 の
10616 :
10317 、
8840 。
8610 -
7779 /
7568 を
7235 に
...(中略)...
必要な単語をフィルタリングして集計

しかし、結果を見て無駄な集計が多いことに気付く。awkコマンドの使い方をちょっとだけ勉強して、以下のようなワンライナーに変更してみた。

  • 「名詞」と「一般」が含まれる行だけ抽出する設定を追加してみる。
  • 上位500件だけ出力してみる。
$ mecab /Users/bebe/Downloads/zariganitosh.xml | awk '/名詞,一般/{print $1}'| sort | uniq -c | sort -nr | head -500
15293 gt
11641 lt
11420 quot
3625 span
2156 id
1770 style
1110 title
1086 to
1006 color
 981 slip
 934 font
 931 action
 899 ファイル
 868 http
 867 FF
 809 name
 795 p
 767 size
 766 field
 686 app
 671 f
 666 for
 660 slips
 652 x
 650 list
 647 Rails
...(中略)...


品詞の種類をフィルタリングしない時と比べれば相当良くなったが、それでも満足できるレベルではない...。(だって、Railsメインの日記なのにその順位は25位なのだから。無意味な単語は除いたとしても、ファイルやfield、list、slips等が上位なのは許せない。)
問題は、コードを表示するブロック内も、<p>ダグも、<h1>ダグも単語が出現すれば単純に1カウントしてしまっているところが問題なのだ。単語は出現する場所によって、その重要度が違う。<h1>ダグ内の単語は、コードを表示するブロック内や<p>ダグよりも遥かに重要視する必要があったのだ...。
しかし、タグの重要度まで考慮した単語の順位付けは、相当手間がかかるし、タグによってどれくらいの重要度にするかのさじ加減も必要になる。今の自分のレベルでは実現するのは難しい...。(恐らく無理)それならどこかにそんなことを実現してくれるプラグインがないか考えてみた時、遥か昔からほとんど毎日、自分自身が使っていたことに気付いた...。
検索サイト!(googleとか、yahooとか...)検索サイトはものすごく高度な方法で、世界中のページを日々評価してくれている。そして、自分ははてなカウンターを契約していて、検索語の検索回数順のリストを簡単に見ることができる。この検索語こそが、自分のブログを要約して表現する索引になるのではないかと。(最初からこのことに気付くべきだった...。またしても遠回り。)

はてなカウンターによる索引

検索語を抽出
  • はてなカウンターの検索語レポートは、テーブルになっている。必要な部分を選択してコピー&ペーストするだけで、表計算ソフト*1でも同じ形式の表データとして利用できるようになった。
  • 上位500件の検索語の索引が欲しかったので、上記コピー&ペーストを地道に10回繰り返した。(はてなカウンターが50件ごとのページ切り替えなので...。一気に500件表示する方法ってあるだろうか?)


表計算ソフトで加工する

上記元データを数式で加工して、以下のようなタグを生成するようにしてみた。

  • 検索語の検索回数によって、フォントサイズを拡大縮小する。
  • はてな記事検索にリンクする<a>タグで囲って、クリックしたら関連する記事一覧を表示する。
A B C D E F G
1 No. 内容 回数 比率 0.00154 フォントサイズ タグ生成
2 1 rails 4285 10.71% 69.47 81.47 <span style='font-size:81.4732745199798;'>
  <a href='http://d.hatena.ne.jp/zariganitosh/archive?word=rails'rails</a>
</span>
3 2 ruby 1546 3.86% 25.04 37.04 <span style='font-size:37.0389206019722;'>
  <a href='http://d.hatena.ne.jp/zariganitosh/archive?word=ruby'ruby</a>
</span>
4 3 form_for 931 2.33% 15.11 27.11 <span style='font-size:27.1141670991179;'>
  <a href='http://d.hatena.ne.jp/zariganitosh/archive?word=form_for'>form_for</a>
</span>
5 ... ... ... ... ...(中略)... ...(中略)... ...(中略)...
  • 0.00154は比率合計を全体の件数500で割って、1件当たりの平均比率を求めた結果(=SUM(D2:D501)/500)
# E列: 平均比率に比べて何倍の出現率か?
=D2/$E$1

# F列: フォントサイズの数式
=IF(E2>1;12+E2;8*E2+4)

# G列: タグ生成の数式
="<span style='font-size:"&F2&";'>"&"<a href='http://d.hatena.ne.jp/zariganitosh/archive?word="&B2&"'>"&B2&"</a></span>"
  • その後、検索語をABC順*2に並べ替えて...
  • 改行コードを取り除いて*3自分のブログに貼付けると...


そして、以下のような索引が出来上がった!果たして、この日記の内容を的確に表現できているだろうか?自分では結構気に入っているのだけど...。

      • このような作業をwebサービスとして提供できれば良いのだけど...。

検索単語による索引

=> 1.1 2 2.1 10.4 10.5 36897 :partial .bash_profile .profile 2.0.2 a action actionview::templateerror active activerecord acts_as_tree adsl air airmac airmacユーティリティ ajax applescript aptana aptanastudio assert assert_select authenticity_token authz auto_complete auto_complete_field auto_complete_for autopagerize autotest bash_profile bayes blank blank? book builder bus capsule check_box check_box_tag checkbox class classifier close cocoa collection collection_select conditions content_tag control control.modal controller cookie create css csv db db:fixtures:load delete destroy development dhcp disable_with div do dock download eclipse edit empty empty? engine error error_messages_for errors expect extreme f.submit f.text_field fields_for file file_column file_field filter firewall fixture fixtures flash flash[:notice] footer for form form_for form_remote_tag form_tag gem get gettext gif growl growlnotify gui has_many have hd hdd helper hidden hidden_field hidden_field_tag html http icon id if iframe image_tag import in_place_editor index init_gettext input install intel intelmac interface iphone iphoto isight java javascript javascript_include_tag label lan layout leopard li link_to link_to_function link_to_if link_to_remote list loading locals locomotive login loginengine mac macbook macos macos8.6 macosx map map.connect map.resources mecab member method modal model mysql name nat new nil nil判定 noobproof object observe_field on option options options_for_select os os9 osx page paginate pagination_links params partial passwd patch patchコマンド path periodically_call_remote piclens pleiades plugin plus post pro production protect_from_forgery prototype prototype.js publisher put python radio_button radrails rail railroad rails rails2 rails2.0 rails2.1 rake rdoc realm redirect_to render replace_html require resource resources rest rhtml rjs rom ror routes routes.rb routing rror_message_on ruby rubygem rubyonrails sanitize_sql save scaffold script seagate select select_tag selected send_data session sheepshaver show size sortable_element span sql sqlite sqlite3 start_form_tag store studio submit submit_tag submit_to_remote subversion svn svnserve synergy synergys table terminal test text_area text_field text_field_with_auto_complete textmate the time timecapsule to trac tree ul undefined update updatepo uri url user user_engine validate validates validates_format_of validates_presence_of validation value verify visual_effect vnc wds wep when will_paginate window windows wpa x xcode xcode3 xml yaml you アイコン アクション アクセス権 アップデート アプリケーション インストール インポート ウインドウ ウィンドウ エラー エラー表示 オプション カスタマイズ カメラ カンマ カンマ区切り クッキー このネットワークの拡張を許可 コピー コマンド コメント コントローラ サイズ ザリガニ ザリガニが見ていた サンプル サーバ サーバー シェル シェルスクリプト シンボル スクリプト スタイルシート スタック スティッキーズ スリープ スリープ復帰 セッション タイマー ダウンロード タグ ターミナル チェック チェックボックス つながらない ップロード ツリー ツリー構造 できない テスト テストデータ データ データベース テーブル ネットワーク バインディング パス パスワード パスを通す パッチ パラメータ バージョン バージョン管理 ハードディスク ファイアウォール ファイル ファイル共有 ファイル名 フィルタ フィールド名 フォルダ フォーム フッタ フッター プラグイン ブリッジ プルダウン プルダウンリスト ベイジアン ベイジアンフィルタ ヘルパー ページ ベースステーション ポート ポート解放 ポート開放 マウス メソッド メニュー メニューバー モデル モーダル モーダルウインドウ モーダルウィンドウ ユーティリティ ライブカメラ リスト リポジトリ リンク ルータ ルーター レイアウト レコード ロック ワイヤレスネットワークを拡張 位置 移行アシスタント 違い 一括 一覧 右寄せ 温度 画像 画像ファイル 画像表示 解除 改行 開放 階層 拡張 確認 楽観的ロック

  • 索引ページへ>>...どうやら文字数制限*4に引っかかって、索引が途中で切れてしまっていた...。別のページに設定し直してみた。

*1:最近バージョンならExcelでも、OpenOffice(またはNeoOffice)でもHTMLのテーブルをコピー&ペーストで理想的な形式で取り込めると思う。

*2:文字コード順なので漢字の検索語は人間的には無意味

*3:テキストエディタ「mi」を利用した。置き換え処理に改行も指定可能。

*4:1日の日記に登録できる最大文字数は、半角で約6万5千文字、全角で約3万2千文字までTIPS・ご注意