Groongaで学ぶ全文検索 2015-10-02に参加

groonga

投稿日 2015年10月02日


今回は実際に作って使ってみる Groongaという事でMroongaを使ったRailsi製アプリで実際に全文検索を使うアプリを作ってみました

※rails new の部分は省きます

Mroongaとは

Mroongaは全文検索が得意なMySQLのステレージエンジン
Mroongaはトランザクションがない分検索が早い
今回はMroongaを利用するためにMySQLを利用し全文検索を行いました

Railsアプリ作成

今回は全文検索を行いやすくするためGroongaBlogというお題で作成を開始します

Gemfileにmysql2を追加します

Gemfile

gem 'mysql2', '~> 0.3.20'

mysql2を追加してbundle install

今回はBlogということでscaffoldでPost機能を作成します

bundle exec rails g Post title body:text

bundle exec rake db:migrate

これでタイトルと本文があるブログ機能ができました

この状態で
まず全文検索を使ってみる

今回は簡易的にURLパラメータにkeywordを追加し、そのkeywordを検索対象にする
 

posts_controller.rb

変更前

def index
  @posts = Post.all
end

LIKE検索に変更する

def index
  @posts = Post.where('body LIKE ?', "%#{params[:keyword]}%")
end

これでkeywordで入ってきた単語を全文検索する事ができる

http://localhost:3000/posts?keyword=hogehoge

LIKE検索の時MySQLは逐次検索を行うので文章の量が増加するに従って遅くなる
文章量が少ないサービスやシステムでは全文検索エンジンを使う必要がないが、
検索エンジンを使う一つの目安として検索に1秒以上かかる場合は検索エンジンを検討するといいと言っていました

今回はMroongaを利用するのでまずMroongaのインストールから行う

Mroongaインストール

インストール方法の詳細はmroongaドキュメントを参照

Macの場合

brew install https://raw.github.com/mroonga/homebrew/master/mroonga.rb --use-homebrew-mysql

トークナイザーとしてMeCabを利用する場合は--with-mecabオプション付きでインストールしてください。

MeCabサポート付きでインストール

brew install https://raw.github.com/mroonga/homebrew/master/mroonga.rb --use-homebrew-mysql --with-mecab

今回は使ってみるというのが大事なのでトークナイザーは指定しませんでした

Mroongaのインストールが完了したら成功しているかmysqlにログインし、下記コマンドを実行して確認する

mysql> SHOW PLUGINS;

+-------------------+----------+--------------------+---------------+---------+
| Name              | Status   | Type               | Library       | License |
+-------------------+----------+--------------------+---------------+---------+
| Mroonga           | ACTIVE   | STORAGE ENGINE     | ha_mroonga.so | GPL     |
+-------------------+----------+--------------------+---------------+---------+

このように一番下に追加されていればインストール完了です

ここからRailsでMroongaを利用する方法を実践して行きます

まず、大きく分けてやる事は下記の3Step
Step 1. ストレージエンジンをInnoDBからMroongaに切り替える
Step 2. 検索したい対象のカラムに対してIndexを作成する
Step 3. LIKEでそのまま検索しても検索速度はかわらないので検索方法を修正する

の3ステップです

Step 1

ストレージエンジンをInnoDBからMroongaに切り替える

ストレージエンジンを切り替えるためにmigrationファイルを作成します

bundle exec rails g migration ChangeEngineToMroonga

作成したmigrationファイルを編集します

class ChangeEngineToMroonga < ActiveRecord::Migration
  def change 
    reversible do |dir|
      dir.up do
        execute 'ALTER TABLE posts ENGINE=Mroonga;'
      end

      dir.down do
        execute 'ALTER TABLE posts ENGINE=InnoDB;'
      end
    end
  end
end

作成したらmigrationを実行します

bundle exec rake db:migrate

実際にMySQLにログインしてEngineがMroongaに変更されているか確認をします

mysql> show create table posts;
+-------+---------------------------------------------------------------------------------+
| Table | Create Table                                                                    |
+-------+---------------------------------------------------------------------------------+
| posts | CREATE TABLE `posts` (                                                          |
|       |   `id` int(11) NOT NULL AUTO_INCREMENT,                                         |
|       |   `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,                    |
|       |   `body` text COLLATE utf8_unicode_ci,                                          |
|       |   `created_at` datetime NOT NULL,                                               |
|       |   `updated_at` datetime NOT NULL,                                               |
|       |   PRIMARY KEY (`id`)                                                            |
|       | ) ENGINE=Mroonga AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci  |
+-------+---------------------------------------------------------------------------------+
1 row in set (0.00 sec)

これでストレージエンジンをMroongaに変更できました

Step 2

検索したい対象のカラムに対してIndexを作成する

対象カラムに対してIndexを追加するためmigrationファイルを作成します

bundle exec rails g migration AddFulltextIndexToBody

作成したmigrationファイルを編集します

class AddFulltextIndexToBody < ActiveRecord::Migration
  def change
    change_table :posts do |t|
      t.index :body, type: :fulltext
    end
  end
end

ここでpostsテーブルのbodyに対して typeにfulltextを追加してIndexを追加します
作成したらmigrationを実行します

bundle exec rake db:migrate

実際にMySQLにログインしてインデックスが追加されたか確認します

mysql> show create table posts;
+-------+---------------------------------------------------------------------------------+
| Table | Create Table                                                                    |
+-------+---------------------------------------------------------------------------------+
| posts | CREATE TABLE `posts` (                                                          |
|       |   `id` int(11) NOT NULL AUTO_INCREMENT,                                         |
|       |   `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,                    |
|       |   `body` text COLLATE utf8_unicode_ci,                                          |
|       |   `created_at` datetime NOT NULL,                                               |
|       |   `updated_at` datetime NOT NULL,                                               |
|       |   PRIMARY KEY (`id`)                                                            |
|       |   FULLTEXT KEY `index_posts_on_body` (`body`)                                   |
|       | ) ENGINE=Mroonga AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci  |
+-------+---------------------------------------------------------------------------------+
1 row in set (0.00 sec)

インデックスが追加されました

Step 3

LIKEでそのまま検索しても検索速度はかわらないので検索方法を修正する

posts_controller.rb

  def index
    @posts = Post.where('MATCH(body) AGAINST(? IN BOOLEAN MODE)', "+#{params[:keyword]}")
  end

BOOLEAN MODEとは

これら語句を必ず含むレコード」や、「この語句を含んで、この語句を含まないレコード」を検索できるモード
+でキーワードを含む
- でキーワードを含まない
検索を指定できる

繋げて書く事で AND検索にできる

NATURAL LANGUAGE MODEとは

デフォルトで設定されている修飾子
文章から検索結果を出す

これでMroongaを使った全文検索の完成です

思っていたよりずっと簡単に使う事ができました。

今日の内容は濃かった!!

次回、Groongaで学ぶ全文検索 2015-10-16


2016 GakuBlog