Milkodeをgrepと組み合わせたら検索速度が40倍速くなった

ファイル数が多いとgmilkが遅くなるという指摘があったので高速化しました。

f:id:tuto0621:20130611002855j:plain

その1. テスト、ソースコード数の多いパッケージを登録

テスト用にlinuxをパッケージに登録。

$ tar xzvf linux-3.10-rc4.tag.xz
$ cd linux-3.10-rc4
$ milk add .
package    : linux-3.10-rc4
result     : 1 packages, 42810 records, 42810 add. (22m 39.2s)
*milkode*  : 188 packages, 201999 records in /Users/ongaeshi/.milkode/db/milkode.db.

4万ファイル、1600万行です。データとしては申し分無いです。

$ cd linux-3.10-rc4
$ milk info
Name:      linux-3.10-rc4
Records:   42810
Breakdown: C:34005(79%), Makefile:1713(4%), Text:1707(3%), .S:1375(3%), other:1688(3%), unknown:2322(5%)
Linecount: 16916142

その2. 古いバージョンで検索

Milkode1.0.0、キーワードはint mainで検索してみます。

$ time gmilk int main | wc 
    8375   59821  717038

real    1m22.843s
user    1m0.299s
sys 0m1.965s

1分22秒かかりましたこれはいかんですね。

※ 最後のwcは出力にかかる時間を省力して純粋に検索にかかった時間を調べるため

その3. マッチしたレコード数を調べる

gmilk -mでキーワードにマッチしたレコード数を調べることが出来ます。(1.0.2から)

$ gmilk int main -m | wc
    9027    9027  711003

int mainを含む行を持つ可能性のファイルが9027個。これを一つずつ探索するのはスクリプトなのでオーバーヘッドはそこかなあと予想。ファイルリストさえ作ったらそれを検索するのはgrepとかagに任せた方が速いのでは?というアイデアを思いついたのでやってみることに。

その4. シェルで頑張る

-mでファイルリストを生成、結果をxargs grepに渡して、さらにその結果をgrepに渡します。(後半はよくあるgrepでAND検索のテクニックです)

time gmilk int main -m | xargs grep -n int | grep main | wc
real    0m2.962s
user    0m1.564s
sys 0m0.217s

1m22s -> 2.96s と大分速くなりました(約40倍!)。同じキーワードを何回も入力しないといけないのが面倒ですね。

その5. -eオプションの追加

gmilkに-e grepを付けると、その4でやったことを自動でやってくれるようにしました。

$ time gmilk int main -e grep | wc 
   19427  124715 2623891

real    0m3.062s
user    0m2.685s
sys 0m0.429s

-e agも出来ます。意外にもgrepの方が速かったです。

$ time gmilk int main -e ag | wc 
   19427  124715 2623891

real    0m6.356s
user    0m5.584s
sys 0m0.784s

その6. 自動で"-e grep"する

マッチするレコードの数が500を超えると自動で-e grepの検索に切り替えます。(xargsとgrepがある環境のみ。)

$ time gmilk int main | wc 
Number of records is large. Use auto external tool (gmilk -e grep)
   19427  124715 2623891

real    0m3.038s
user    0m2.662s
sys 0m0.448s

レコード数が遅くてもスクリプトで検索したい時(ちゃんと行内の単語だけでマッチさせたい時など)は--no-externalオプションを使って下さい。

$ time gmilk int main --no-external | wc 
    8375   59821  717038

気にしなくても勝手に速くなるよ!ってことです。

ダウンロード

速くなったMilkode を是非一度お試し下さい。

$ gem install milkode

ダウンロード, Gems

milk webは検索結果を1ページに表示出来る数だけ少しずつ検索していくのでこの問題はそもそもありません

おまけ. gmilkのいい所

  1. AND検索のたびにコマンドをパイプでつなげなくてよい(私的にはgrenの頃から大切)

  2. 検索ディレクトリを指定せずに検索出来る

$ cd /a/proj/lib/command/
# プロジェクト全体から検索したい・・
$ grep -r -i a_keyword ../../

# ディレクトリ変わったのでパスも書き換えないと・・
$ cd foo/bar
$ grep -r -i a_keyword ../../../..

これが個人的には結構面倒です。gmilkだとパッケージを認識するので常にパッケージ全体を検索します。

$ cd /a/proj/lib/command/
$ gmilk a_keyword

$ cd foo/bar
$ gmilk a_keyword

常にgmilk キーワード1 キーワード2 …で検索出来ることを大切にしています。

行指向のソースコード検索エンジンMilkode1.0.0リリース!

1.0.0 になりました。初のメジャーリリースバージョンとなります。

  • ホームページリニューアル
  • 統計情報に拡張子絞り込みのリンクを追加
  • 1.0.0rc1で既に組み込まれている機能についてはこちらをどうぞ

インストール

$ gem install milkode

ダウンロード, Gems

ホームページリニューアル

f:id:tuto0621:20130519235217p:plain

MilkodeのホームページをJekyllでリニューアルしました。
[詳しくみる]

統計情報に拡張子絞り込みのリンクを追加

f:id:tuto0621:20130523013645p:plain

統計情報から拡張子絞り込みのためのリンクを追加しました。
.srcなどの未登録な拡張子も表示するようにしました。

リリースノート

  • milk web

    • 統計情報
      • 拡張子絞り込みのリンクを追加
      • unknownの表示形式を変更
        • 旧: 'hoge.list' -> 'unknown'
        • 新: 'hoge.list' -> '.list'
  • gmilk

    • Windows環境でgmilkが動かない問題を修正
  • etc

    • test/unit 2.5.4 で警告が出る箇所を修正

関連記事

終わりに

2011年7月に0.1.0をリリースしてから二年近く経とうとしています。こんなに長く1つのソフトを開発し続けるのは始めてかもしれません。

こんなに長く続けられたのは、使ってくれたり、要望やバグ報告やパッチをくれたり、ブログやTwitterなどでMilkodeに言及してくれる皆様のおかげです。あらためてありがとうございます。

幸いまだやりたいことが残っているのでMilkode1.1に向けて開発を続ける予定です。要望の多いサブURLの対応とせっかくここまで作ったので英語化は最低限したいなあとか思っています。

gihyo.jpに記事を書いた時の感想

忘れないうちにメモ。宣伝も兼ねてます(ぼそっ)

f:id:tuto0621:20130522023918p:plain

第4回 rroongaを使ったソースコード検索エンジンMilkode:隔週連載groonga|gihyo.jp … 技術評論社

隔週groongaの連載第4回です。今回はMilkodeが内部で使っているrroongaについて紹介しています。

勉強会で発表したりアドベントカレンダーに参加はしたことはあったのですが、出版者さんのサイトに記事を書くのははじめてだったので色々と新鮮でした。Milkodeとrroongaの関係についてはリンク先を読んでもらうとして、以下は記事を書いた時の感想など。

校正

いつもは一人で書いているので忘れがちですが、他の人に校正してもらうと文章はぐっとよくなります

誤字脱字やゆらぎの修正はもちろんのこと、伝えたいことをより伝えやすくするための段落の入れ替えなど、編集の方の手にかかるとどんどん分かりやすくなっていくのは勉強になりました。

※ 普段ブログを書いている時も誰かに校正してもらいたいです・・。安く自分の書いた記事を校正してくれるサービスとか需要ありそうだけどどうなんでしょ?

締め切り効果

人によるとは思いますが、

  • 大勢の人に見てもらえる
  • 締め切りを過ぎると大変

みたいな適度なプレッシャーがよい方に働きました。

先に文章の構成をぼんやりと考えたり、大体の構成が決まった後もすぐに書き始めずに構成の順番を入れ替えたり・・といった普段面倒くさがってやらないようなことを自然とやるのは締め切り効果のなせる技です。

この文章みたいに思いついたことを書き出しながらまとめていくのも好きですけどね。書きたい文章の種類によって決めればいいんだと思います。

リンクの貼り方で覚えたこと

  • 強くて大きいです。

二行使うしリンクを踏む気がない人はリズムが途切れてしまいます。

強くて大きいAAAは・・・。

文章のなかにリンクを埋め込むと読むの人のリズムが途切れません。

原稿料

原稿料をもらわないという選択肢を取ることが出来ました。やる前はそういうことが出来るか分からなかったのでちょっと不安でした。 ふと思ってググってみたら頂かないで寄付したという人達が結構いるようで、なるほどその手があったか、と今更感。

文章のフォーマット

書き慣れたMarkdownで書くことが出来ました。 他の形式でも対応してくれるみたいでした。

おわりに

執筆を通して自分のつたない文章力も少しは上がった気がするので、チャンスがあればやってみる価値はあるのではと思います。

隔週groongaでは引き続き記事を書いてくれる人を募集しているみたいですよ。

自作ソフトのホームページをMediaWikiからJekyllに移行した

MilkodeのホームページをJekyllでリニューアルしました。

Milkode - 行指向のソースコード検索エンジン

※ 旧Wikiページにリダイレクトされてしまう方はお手数ですがブラウザのキャッシュを削除してみて下さい。

f:id:tuto0621:20130519235217p:plain

移行の経緯

MilkodeのホームページはずっとMediaWikiを使っていたのですが、以前別の自作ソフトのドキュメント作成にJekyllを使い結構感触が良かったので思い切って移行することにしました。

文章量が多かったため移行に2週間位かかりました。

MediaWikiからJekyllに移行して良かったこと

  • ファイルで原稿を書ける
    • Rubyを使ってフィルター処理をしたり、まとめてコピーといった一括処理が簡単です
  • Markdownで書ける
    • emacsのmarkdown-modeやKobito等、対応しているエディタが多いのがいい所です
  • git管理出来る
    • 編集履歴が見やすい形で残ります、差分の再利用などもやりすくなります
  • ページの表示が高速
    • 事前にhtmlを生成しておくので高速です(MediaWikiレンダリングもそんなに遅いという訳ではないですが)
  • スパム攻撃を受けない
    • 以前スパム攻撃で苦労して最終的に自分以外は書き込み不可にすることになり、それじゃWikiの意味ないじゃん・・とは思ってました
  • _layouts/layout.html と Liquidテンプレートの組み合わせで結構色々なことが出来る
    • 変数展開やちょっとした繰り返し処理が書けます
    • ヘッダやフッターはlayout.htmlに一回だけ書いてメイン記事となるxxx.mdには記事本体しか書かないように出来ます
    • 「面倒なHTMLを書かずにすぐに記事本文を書き始めたい」は自分にとってWikiを使う大きなモチベーションの一つだったのでこれで切り替える気になりました
    • とはいえ最初の一回は自分でテンプレート書く必要がありますが、もう一回書いたので次からはもっと楽に出来そうです

大勢で編集する時はやはりWikiがいいですが、主に一人で作っているサイトをJekyllで作るのはなかなかいいと思いました。

実際にJekyllドキュメントシステムを動かしてみる

ongaeshi/milkode at gh-pages · GitHub

お手元の環境で再現するには

$ git clone git://github.com/ongaeshi/milkode.git
$ cd milkode
$ git checkout -b gh-pages origin/gh-pages

ソースコードをチェックアウトした後

$ jekyll serve --watch
Configuration file: xxx
            Source: xxx
       Destination: xxx/_site
      Generating... done.
 Auto-regeneration: enabled
[2013-05-19 23:16:07] INFO  WEBrick 1.3.1
[2013-05-19 23:16:07] INFO  ruby 2.0.0 (2013-02-24) [x86_64-darwin11]
[2013-05-19 23:16:07] INFO  WEBrick::HTTPServer#start: pid=31564 port=4000

で、webサーバーを起動した後に http://0.0.0.0:4000 にアクセスして下さい。

jekyllをインストールしていない人は事前に

$ gem install jekyll

が必要です。

Jekyllの簡易テンプレートやサンプルコードとしてお使い下さい。

ページをカスタマイズする

  • ページの内容を書き換えたい → *.mdを編集
  • ページテンプレートを書き換えたい → `layout.html
  • Jekyllの設定やsite.xxxといった変数の値を書き換えたい → _config.yml

注意: _config.ymlを書き換えた時は jekyll serve --watch を一回停止して再起動しないと変更が反映されません。(たまに忘れます・・)

関連記事

お知らせ(宣伝ともいう)

おそらく明日辺りにgihyo.jpにMilkodeの記事が載ります。Milkodeにおけるgroonga(主にrroonga)の使い方について書きました。

隔週連載groonga第四回として掲載される予定です。

  • Rubyで検索エンジンを作ってみたい
  • 作るかは分からないけどその辺の技術に興味はある

ような方にとっては面白いかもしれません、お楽しみに~。

Milkode 0.9.9.9 リリース!(実質1.0.0.rc1) - Ruby2.0対応とか

0.9.9.9 になりました。まだまだやりたいことや直せていないバグもあったりするのですが、「コードを読む事をもっと簡単にするためのツール」として最低限必要な機能はそろったのではないかと思います。1.0.0.rc1 としてバグ修正や微調整をしながら五月中には 1.0.0 をリリースする予定です。

1.0直前ということで色々いれました!順番に説明していきます。

  • お気に入りリスト
  • 統計情報
  • 「新規タブ」ボタン
  • help画面のリニューアル
  • gmilkの高速化
  • Ruby2.0対応

インストール

$ gem install milkode

詳しくはこちらをどうぞ - ダウンロード, Gems

お気に入りリスト

f:id:tuto0621:20130508011320j:plain

複数のパッケージ間を行き来しながら検索する時などに便利です。 個人的に好きな機能です。

統計情報

f:id:tuto0621:20130508011400j:plain

milk infoで出来ることをwebアプリからも出来るようにしました。ファイル数行数使われている言語種類などをすぐに調べることが出来ます。やっぱりブラウザからみたいですよね。

「新規タブ」ボタン

f:id:tuto0621:20130508011410j:plain

タブを開きながら検索出来ます。

help画面のリニューアル

f:id:tuto0621:20130508011418j:plain

読みにくかったので読みやすくしました。

gmilkの高速化

# 起動時間の短縮
$ gmilk --help   # 0.632s -> 0.182s

# ダイレクトパス検索に関してはさらに高速化
$ gmilk /path/to/file:1 # 0.832s -> 0.191s

requireの依存関係を整理して起動時間を短縮しました。ダイレクトパス検索('gmilk /path/to/file:5')に関してはデータベースへのアクセスを最小限にしてさらに高速にしています。

ダイレクトパス検索がはやくなったのでmilkode:jump-from-browserも高速 になります。

Ruby2.0に対応

そろそろ手元の環境でもRuby2.0を使いたくなったので動くようにしました。

リリースノート

  • milk web

    • お気に入りリスト

      • お気に入りを付けたパッケージにすぐアクセス出来る
      • ☆マークをクリックでwebアプリからも設定が可能に
    • 統計情報ボタンの設置

      • ファイル数、行数、言語別割合の表示をWebインターフェースで
    • 「新規タブ」ボタンを設置

      • タブを開きながら検索
    • help.haml

      • 全体的にリニューアル
      • 'w:' オプションについて追記
  • gmilk

    • 依存関係を整理して、起動時間の高速化
    • ダイレクトパス検索('gmilk /path/to/file:5')に関してはさらに高速化
    • gmilk -d が正しく動いていない問題を修正
  • milk

    • milk fav --sync-yaml を追加
      • webアプリ経由のお気に入り設定をyamlに取り込む
  • etc

    • Ruby2.0.0 に対応

      • test/test_milkode_yaml.rb が動かない問題を修正: Yaml#dumpの取得形式が変わった
      • Gemfile更新: test-unit >= 2.5.4
      • .travis.yml に Ruby2.0 を追加
    • Gemfile

      • 'thor 0.18.1' に対応
      • 'rack 1.5.2' に対応
    • ファイル構造の整理 : findgrep/findgrep.rb -> grep/findgrep.rb

  • バグ修正

    • Issues#47 add meta tag for favicon (thanks y-ken)

関連記事

終わりに(お知らせ)

gihyo.jpにMilkodeの記事が載ります!

隔週連載groongaという連載シリーズの第四回として掲載される予定です。

Milkodeにおけるgroonga(主にrroonga)の使い方について書いています。Rubyで検索エンジンを作ってみたい、その辺りの技術に興味がある方にとっては面白いかもしれません。お楽しみに!

複数行の検索に対応、Emacsからファイルを直接開けるように - ソースコード検索エンジンMilkode

0.9.9 になりました。個人的にずっと欲しかった複数行検索を入れるのに一ヶ月かかりました。

f:id:tuto0621:20130327231203j:plain

  • 複数行の検索(ワイド範囲検索)
  • 検索オプションに'w:'を追加
  • ブラウザで見ているファイルを直接開けるように

インストール

$ gem install milkode

詳しくはこちらをどうぞ - ダウンロード, Gems

複数行の検索(ワイド範囲検索)

begin rescue end で検索した時に一行だけではなく複数行範囲にマッチさせることが出来るようになりました。検索範囲は後述する w:オプションで調整可能です。

def test
  begin                 # <-- ここと
    func()
  rescue RuntimeError   # <-- ここと
    p 'error'
  end                   # <-- ここにマッチする!!
end

検索オプションに'w:'を追加

検索範囲行を明示的に指定するためのオプションです。Milkodeの検索ボックスに以下のように入力します。

begin end       # 基本
begin end w:1   # 1行にbeginとendを含むものにマッチ(今までの挙動)
begin end w:7   # 7行範囲にbeginとendを含むものにマッチ
begin end w:0   # ファイル全体でbeginとendを含むものにマッチ

未指定の場合は

  1. w:1 で検索
  2. 見つからなければ w:7 で検索
  3. それでも見つからなければ w:0 で検索

・・というルールで検索するので通常時の挙動は今までと変わりません。見つからなかった時に少し範囲を広げて自動で検索してくれます。

ブラウザで見ているファイルを直接開けるように

Emacs, Firefox の組み合わせ限定ですが便利です。

ブラウザで見ているソースコードのファイルをエディタから一瞬で開く

リリースノート

  • ワイド範囲検索のサポート

    • 指定行内に複数のキーワードが含まれている場所を探す
    • 複数のキーワードが一行でマッチしなかった場合、自動的に範囲を広げて再検索
  • 検索オプション w: を追加

    • w:7 で7行以内に全てのキーワードが含まれている場所を返す
    • w:1 で今までの検索
    • w:0 の時は検索範囲をファイル全域に
  • Support sinatra-reloader

    • export MILKODE_SINATRA_RELOADER=1
  • Delete 'milkode/cdweb/app_error.rb'

    • Recommend 'RACK_ENV=production'

リンク

終わりに

ファイル数や行数をブラウザから調べる機能を作りたいです。

ブラウザで見ているソースコードのファイルをエディタから一瞬で開く

f:id:tuto0621:20130324172538g:plain

個人的にお気に入りな開発環境を構築出来たので紹介します。どういうものかというと、

  • Milkodeを使ってブラウザからソースコードを検索
  • 目的の関数を見つけたら、ジャンプしたい行をクリックしてマークお
  • エディタ(Emacs)に移動して M-x milkode:jump-from-browser を実行
  • ブラウザで見ていたファイルが開かれるので、そのまま編集

昔から良くある「emacsclient等を使った通信」ではなく、ファイルの実体を開けるのがいい所です。

インストール

基本セットとして以下のものが必要です。

続いてプラグインをインストールします。

Firefoxの設定

  1. [アドオンマネージャー]からMozReplをインストールします
  2. [ツール] → [MozRepl] -> [Activate on Startup] のチェックをONに

Emacsの設定

  1. moz.el と milkode.el をロードパスの通った場所に置きます。
  2. init.elに以下を追記します。
(require 'moz)
(require 'milkode)

使い方

  1. Milkodeを使ってブラウザで検索
  2. 書き換えたいファイルが見つかったら行をクリックしてマーク
  3. ブラウザでそのページを開いたままEmacsに移動
  4. M-x milkode:jump-from-browser を実行

ブラウザで見ているファイルがエディタで開ければ成功です!

原理の説明

  • ブラウザが今開いているURLを取得する
  • URL(http://xxx/home/proj/to/file#n5) → Milkodeパス(/proj/to/file:5)に変換
  • Milkodeパスからファイルの実体パスを取得し、エディタで開く

説明すると3行ですが複数のツールの連携によって実現されています。(この組み合わせを探すのに時間がかかりました)

まとめ

ツールが限定されてしまうので誰でも使えるという訳ではないですが、ブラウザで検索してエディタで編集するというワークフローは快適です。(慣れると手放せなくなります。)

色々な人に使ってもらえると嬉しいので動作報告や上手くいかないようなことがあれば是非教えて下さい。