ActiveRecordのモデルに全文検索機能をつけちゃうGem「AttrSearchable」

全文検索エンジンを使わずともActiveRecordに手軽に全文検索機能をつけるGemがありました。AttrSearchableというGemです。

さすがに一般的な全文検索エンジンと同じようにPDFやExcelファイルの中身まで検索することはできませんが、RDBに保存してあるテキストを検索するぐらいの用途には良いかもしれません。MySQLやPostgreSQLで対応している、全文検索用のインデックスにも対応しているので、通常のLIKE検索よりは良さそうです。

使い方

gem 'attr_searchable'をGemfileに追加してbundle install`したあと、下のコードのように、ActiveRecordのモデルにattr_seachableというクラスマクロを追加します。

class Book < ActiveRecord::Base
  include AttrSearchable

  attr_searchable :title, :description, :stock, :price, :created_at, :available
  attr_searchable :comment => ["comments.title", "comments.message"]
  attr_searchable :author => "author.name"
  # ...

  has_many :comments
  belongs_to :author
end

すると、こんな風に検索することができるようになります。

Book.search("stock > 0")
# ... WHERE books.stock > 0

Book.search("price > 10 stock > 0")
# ... WHERE books.price > 10 AND books.stock > 0

Book.search("Harry Potter")
# ... WHERE (books.title LIKE '%Harry%' OR books.description LIKE '%Harry%' OR ...) AND (books.title LIKE '%Potter%' OR books.description LIKE '%Potter%' ...)

Book.search("available:yes OR created_at:2014")
# ... WHERE books.available = 1 OR (books.created_at >= '2014-01-01 00:00:00' and books.created_at <= '2014-12-31 00:00:00')

文字列検索の場合は自動的にカラムをまたいでLIKE検索してくれるようになるのが便利ですね。

RDBの全文検索機能を利用する場合

RDBの全文検索機能を利用する場合は、以下のコードのように、対象のカラムにtype: :fulltextというオプションをつけます。

class Book < ActiveRecord::Base
  # ...

  attr_searchable_options :title, :type => :fulltext
  attr_searchable_options :author, :type => :fulltext

  # ...
end

すると、クエリが以下のように変わります。

Book.search("Harry Potter")
# MySQL: ... WHERE (MATCH(books.title) AGAINST('+Harry' IN BOOLEAN MODE) OR MATCH(books.author) AGAINST('+Harry' IN BOOLEAN MODE)) AND (MATCH(books.title) AGAINST ('+Potter' IN BOOLEAN MODE) OR MATCH(books.author) AGAINST('+Potter' IN BOOLEAN MODE))
# PostgreSQL: ... WHERE (to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Harry') OR to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Harry')) AND (to_tsvector('simple', books.title) @@ to_tsquery('simple', 'Potter') OR to_tsvector('simple', books.author) @@ to_tsquery('simple', 'Potter'))

2014/6/29現在でバージョンが0.0.3とかなり若いGemではありますが、かなり便利そうなので、ぜひ育っていって欲しいGemです。

mrkamel / attr_searchable