先日、るりまの成果物であるRubyのリファレンスマニュアルを検索するWebアプリケーションるりまサーチを公開しました。
OpenSearchにも対応しているため、Firefoxの右上の検索窓から検索することもできます。
これまでも、るりまの成果物はBitClustを使ってWebブラウザから見ることができました1。しかし、BitClustのWebインターフェイスは検索機能が弱く、目的の情報にたどり着くのが難しいと感じたことがあったのではないでしょうか。例えば、全文検索ができなかったり、そもそも検索がとても遅かったりしました。
るりまサーチでは全文検索エンジンとしてgroongaを利用することにより、高速な全文検索機能と使いやすい絞り込み機能を実現しています。それでは、るりまサーチの機能とその実装について簡単に紹介します。
機能
るりまサーチは多くの情報を絞り込んでいきながら目的の情報に到達することを意識したインターフェイスになっています。そのため、できるだけ簡単に絞り込んでいけるような機能を組み込んであります。
ここでは、絞り込みに関する機能を2点だけ紹介します。
ドリルダウン
groongaの得意な機能の1つはドリルダウンと呼ばれる、検索結果の中から特定の値をグループ化し、それぞれのグループのレコード処理を数える処理です。るりまサーチでもこの機能を利用して絞り込みやすいインターフェイスを提供しています。
るりまサーチではページ上部にそのときに絞り込める条件を表示します。例えば、トップページではマニュアルの種類によって絞り込めるリンクを表示しています。
このとき、事前に絞り込んだ後のレコード数も表示しています。この時点で絞り込み後のレコード数を数えているので、絞り込んだ後にレコード数がないリンクを表示しないことができます。つまり、「リンクを辿ったけど絞り込んだらマッチするレコードがない!」という状況を防ぐことができます。
便利に絞り込めるリンクを提供し、その一方で、無駄な絞り込みを行わずに済むようになっています。
条件解除
簡単に条件を絞り込めるようにするだけではなく、簡単に条件を解除することもできます。これは様々な絞り込みを行いながら目的の情報に辿りつけるようにするためです。
ページ上部にはどのような条件で絞り込んでいったかが表示されるようになっています。それぞれの絞り込み条件は条件の横にあるリンク2を辿るだけで簡単に解除することができます。
絞り込みすぎてしまったときは、これで条件を解除して違う条件で絞り込んでいくことができます。
実装
るりまサーチはRuby 1.9.1とRackとrroongaを用いて実装されています。rroongaはgroongaをRubyから利用するためのRubyバインディングです。るりまサーチではgroongaをサーバとしてではなく、ライブラリとして利用しています。
rroongaはgroongaの高速な機能を活かしたまま、より使いやすいRubyらしいAPIを提供しています。るりまサーチはそんなrroongaを使って、すっきりとした記述で実現されています。ここでは、rroongaを使ったコードを2つ紹介します。
スキーマ定義
groongaは関係データベースと同じようにデータの格納場所毎に型を持っています。groongaにデータを格納する前に格納場所を用意する必要があります。
rroongaでは格納場所の定義(スキーマ(データベース))をより宣言的に記述するためのAPIを用意しています。以下は検索対象の情報を保存する「Entries」テーブルの定義です。RDBなどのスキーマを見たことがあるなら、この定義からgroongaがどのようなデータを格納できるようになるかを想像できるのではないでしょうか。
Groonga::Schema.define do |schema|
schema.create_table("Entries",
:type => :hash,
:key_type => "ShortText") do |table|
table.short_text("name")
table.short_text("local_name")
table.short_text("label")
table.text("document")
table.text("signature")
table.text("description")
table.reference("type", "Types")
table.reference("class", "Classes")
table.reference("module", "Modules")
table.reference("object", "Objects")
table.reference("version", "Versions")
table.reference("visibility", "Visibilities")
end
end
このように、Rubyでは宣言的に処理を記述することがわりとよく行われます。これは、ドメイン固有言語とも呼ばれ、やりすぎる人も出るほどです。例えば、上記のような記述を以下のようにすることもできますが、これは少しやりすぎではないかと感じます。
Groonga::Schema.define do
create_table("Entries",
:type => :hash,
:key_type => "ShortText") do
short_text :name
short_text :local_name
short_text :label
text :document
text :signature
text :description
reference :type, :Types
reference :class, :Classes
reference :module, :Modules
reference :object, :Objects
reference :version, :Versions
reference :visibility, :Visibilities
end
end
検索条件
rroongaでは検索条件をクエリ文字列ではなく、Rubyの式として記述することができます。
例えば、「name」カラムの値が「Regexp」であるレコードを検索するときは以下のようになります。
entries.select do |record|
record.name == "Regexp"
end
「name」カラムの値が「Regexp」あるいは「description」カラムに「正規表現」が含まれているレコードを検索するときは以下のようになります。
entries.select do |record|
(record.name == "Regexp") | (record.description =~ "正規表現")
end
「name」カラムか「description」カラムに「encoding」を含むレコードを検索するときは以下のようになります。ただし、「name」カラムにマッチした場合はスコアをあげて、より上位に表示するようにします。
entries.select do |record|
target = record.match_target do |match_record|
(match_record.name * 100) |
(match_record.description)
end
target =~ "encoding"
end
DataMapperやSequelなど文字列ではなくRubyの式で条件を指定できるようにするオブジェクト関係マッピングはいくつかありますが、最終的にそれらはSQLになります。しかし、rroongaの場合はRubyで書いた式がそのままgroongaのネイティブな条件式になります。カッコいいですね。
また、ORマッパーも少しやりすぎてしまう傾向がある分野ですが、rroongaはやりすぎることなく、Rubyらしさを保ったまま条件式を指定できているのではないでしょうか。少しやりすぎてしまうと、Symbolにメソッドを追加してしまったりします。
まとめ
Rubyのリファレンスマニュアルを検索するWebアプリケーション「るりまサーチ」の機能と実装を簡単に紹介しました。
るりまサーチを使うことでるりまプロジェクトの成果物であるRubyのリファレンスマニュアルをより便利に活用することができます。
また、るりまサーチの実装はgroongaのRubyバインディングであるrroongaのよいサンプルでもあります。groongaをRubyから利用しようと考えていた方はGitHub上にある、るりまサーチのソースコードを読んでみるとよいでしょう。ライセンスはLGPLv3+です。
るりまサーチはSinatraなどのフレームワークを使わずに、直接Rackを使っています。そのような場合にどのようにテスト環境を構築するか、というのもいつか紹介できるとよいですね。今、興味のある人はソースコードを見てください。
このように、るりまサーチにはまだおもしろいところが色々あるのですが、今回はこのへんにしておきます。
-
自分で設定するのが面倒な場合はokkezさんが公開しているBitClustを利用することもできます。 ↩
-
画像にしたいですね。 ↩