はじめまして,
今回は私が作っているソースコード検索エンジンのMilkodeにて,
ソースコードを検索するということ
プログラマの仕事はプログラムを書くことですが,
- ある関数の名前を変えたいので使っている箇所をすべて見つけたい
- ライブラリの仕様が変わった。使っているコードはどこだったか?
- コードリーディング中。今読んでいる関数の実体はどこにあるのか?
ベーマガを買ってゲームのプログラムを写経していた頃から時代は進み,
- ※1
- ライセンスの制約はありますが,
それでも10年前を考えるとGitHubで何でも読めるのはとても幸せなことです。
既存の検索ツールの問題点
私もソースコードを検索するためのツールとして色々なものを使ってきました。その内に
Wikipediaの
それぞれのタイプの不満を挙げてみます。
- grep型の不満
- ファイル数が増えると遅い
- 検索のたびに
*.rb
などと対象のファイルを指定するのが面倒。基本はプロジェクト単位で検索したい .git
,.svn
,*~
などは自動で検索対象から外してほしい(※2) - .gitignoreの除外対象に含まれているものも検索対象から外してほしい
(※2) - ブラウザからも検索したい
- インデックス型の不満
- 複数のキーワードにマッチする行を見つけることができない
- ファイル単位で見つけるものが多い
- 非公開のコードも検索対象に含めたい
- Webアプリのみ提供しているタイプのものはオープンソースしか検索対象にできない
- grep型と同じくらい,
簡単にインストールできるようにしてほしい
- 複数のキーワードにマッチする行を見つけることができない
これらの問題を上手く解決することができればそれなりに需要があるのではないかと考え,
- ※2
- この辺りの問題を解決しようとしているgrep型のツールもあります。agが有名です。
- ※3
- 幸か不幸かまだまだやりたいことが尽きません。もうちょっとで1.
0を出せそうな気がしています。
さてどうやって作ろう?
ソースコード検索エンジンを作ろうと思い立ったものの,
- 主要なOSで使える
- (比較的)
簡単にインストールできる - 日本語の情報が豊富
groongaとの出会い
いくつかの検索エンジンを調べていくなかで,
他にも候補はあったのですが,
- Sennaという有名な検索エンジンの後継
(らしい) - 他の検索エンジンと比べると後発のため,
老舗のものにありがちな問題が解消されていそう - 日本人の開発者を中心に作られているので日本語の情報が豊富
- MLのログを読むと質問やバグ報告に対するレスポンスも速い
- 若いプロジェクトなのでパッチも積極的に受け入れてくれそう
正直検索エンジンに対する知識が皆無だったため,
その後,
もう少し真剣にリファレンスマニュアルなどを読み始め,
- 単体で全文検索+ストレージとして動作する
- Rubyだけで書ける
- ライブラリとして動作する
順に説明していきます。
1. 単体で全文検索+ストレージとして動作する
groongaの場合は,
- ファイルの内容をデータベースに格納
- 格納されたデータを全文検索
別途MySQLなどのストレージエンジンのインストールを要求するタイプもあったのですが,
- ※4
- デスクトップアプリケーションは必要なソフトが増えるたびにインストールしてもらえる確率がどんどん下がります…。
2. Rubyだけで書ける
groonga本体はC言語で書かれていますが,
require 'rubygems'
require 'groonga'
# データベースの作成
Groonga::Context.default_options = {:encoding => :utf8}
Groonga::Database.create(:path => "bookmark.db")
# テーブルの定義
Groonga::Schema.define do |schema|
Groonga::Schema.create_table("Items", :type => :hash) do |table|
table.text("title")
end
Groonga::Schema.create_table("Terms",
:type => :patricia_trie,
:key_normalize => true,
:default_tokenizer => "TokenBigram") do |table|
table.index("Items.title")
end
end
# レコードの追加
items = Groonga["Items"]
items.add("http://gihyo.jp" , title:"技術評論社")
items.add("http://ja.wikipedia.org/wiki/Ruby", title:"Ruby")
items.add("http://www.ruby-lang.org/ja" , title:"オブジェクトスクリプト言語Ruby")
# 全文検索
result = items.select {|record| record.title =~ "Ruby"}
# 結果を集計
p result.map{|record| record.title} #=> ["Ruby", "オブジェクトスクリプト言語Ruby"]
Milkodeではrroongaを使っており,
3. ライブラリとして動作する
rroongaはRubyGemsライブラリとして提供されているため,
$ gem install rroonga
bundlerであればGemfileに次の記述を一行追加するだけです。とっても簡単ですね!
gem 'rroonga'
すべての機能はRubyのクラスやメソッドとして提供されているため,
これらのメリットと,