MySQLで全文検索

MySQL全文検索しようと思い立った。
というのは、自作サイトでタグとコメント欄の全文検索を行いたくなったからだ。

MySQLは日本語の全文検索に対応できていない。

MySQLはバージョン5.0の時点では英文の全文検索にしか対応していない。
日本語で全文検索を行うには、外部ツールの助けが必要になる。
その外部ツールとして senna がある。
sennaを使えばMySQLで日本語の全文検索が可能になる。
しかしsennaは純粋なライブラリである。MySQLからそれを利用するにはMySQLコンパイルして、sennaを組み込む必要がある。この手間を省くべく、tritonnというソフトウェアが存在する。
今回はこのtritonnを利用して、MySQLでの全文検索を利用可能にした。

今回の手順概略

  • インストール済みの MySQLパッケージを削除
  • senna 組込み済みの MySQLをインストール
  • DBのテーブルに FULLTEXT インデックスを追加

インストール済みの MySQLパッケージを削除

利用している ubuntuには、apt-get install で MySQLパッケージを導入していた。
これとtritonnがぶつかるので、以下のパッケージを削除した。

例:

apt-get remove mysql-client-5.0

senna 組込み済みの MySQLをインストール

すごく丁寧な説明がここにある。
http://qwik.jp/tritonn/installtarball.html
このとおりにやれば、問題なし。

DBのテーブルに FULLTEXT インデックスを追加

以下のようにして、テーブルにFULLTEXTインデックスを追加した。

class CreateVideoItems < ActiveRecord::Migration
  def self.up
    create_table (:video_items, :options => "ENGINE MyISAM  DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci") do |t|
      t.string :vid
      t.string :title
      t.text :my_comment
      t.text :tags
      t.string :thumbnail_url

      t.timestamps
    end
    add_index :video_items, :vid, :unique=>true
    execute "CREATE FULLTEXT INDEX idx_my_comment ON video_items(my_comment)"
    execute "CREATE FULLTEXT INDEX ids_tags ON video_items(tags)"
  end

  def self.down
    drop_table :video_items
  end
end

以下の点に注意。

  • エンジンを MyISAMに指定する(InnoDBでは全文検索できない)。
  • execute メソッドで FULLTEXT インデックスを作成する。

動作確認

ここに素晴らしいチュートリアルがある。
http://qwik.jp/tritonn/basictutorial.html
このとおりにして動作を確認した。

いやー、疲れた。

will_paginate を導入

日本語のサイトを見て、そのとおりにやったけどうまくいかなかった。
undefined method `paginate'
なんてエラーが発生。
そこで、本家のGitHub - mislav/will_paginate: Pagination library for Rails, Sinatra, Merb, DataMapper, and moreを参照してwill_paginateを導入した。

まずはインストール。

  gem install mislav-will_paginate --source http://gems.github.com/

"config/environment.rb"の最後に、以下を追加する。

gem 'mislav-will_paginate', '~> 2.2'
require 'will_paginate'

インストールはこれでOK。

次はコントローラの修正。

    #@items = VideoItem.find(:all)
    @items = VideoItem.paginate(:all,:per_page => 10, :page => params[:page])

ポイントは
(1) "find"だったところを"paginate"に変更。
(2) パラメータに1ページあたりの表示件数である :per_page を追加。
(3) パラメータに、表示対象のページ番号を示す :page を追加。

params[:page]は、以降でViewに追加する項目(タグ)で自動的に追加される。

次にビューの修正。
以下をページのナビゲータを表示したい箇所に追加する。

<%= will_paginate @items %>

これで終了。

gemのアップデート後にエラー:uninitialized constant Gem::GemRunner (NameError)

Ubuntu上のgemをアップデートしたら、uninitialized constant Gem::GemRunner (NameError)というエラーが出るようになってしまった・・・

ぐぐってみたら、こんなページ(Ubuntuでrubygemsを1.0.1にudpateしたら"uninitialized constant Gem::GemRunner(NameError)"のエラー - iビジネス&テクノロジー)が

一応、Rails Forumの該当トピックを参考に、/usr/bin/gemの10行目(require 'rubygems'の下の行)に

require 'rubygems/gem_runner'

の一行を追加することで解決。激しく気持ち悪いですが・・・

同様にして、解決。

さらに参考ページはこちら。
http://weblog.rubyonrails.com/2007/12/19/trouble-installing-new-gems

カラムの名前を変更する(rename)

video_items テーブルのthumbnailカラムの名前を変更する。

まずはマイグレーションファイルを作成する。

ruby script/generate migration rename_column_thumbnail

このファイルを以下のように修正。

class RenameColumnThumbnail < ActiveRecord::Migration
  def self.up
    rename_column :video_items, :thumbnail, :thumbnail_url
  end

  def self.down
    rename_column :video_items, :thumbnail_url, :thumbnail
  end
end

マイグレーションを実行する。

rake db:migrate

railsでAjaxを使う

railsAjaxを使うための概略をまとめておく。

  1. erbファイルに呼び出し部分を書く。 --> xxx.html.erb
  2. 必要なjavascriptファイルをロードするよう、呼び出し元erbファイルを編集する。
  3. Ajaxで更新する部分を部分テンプレートにする。--> part.html.erb
  4. 部分テンプレートを呼び出すRJSファイルを書く。--> action_name.rjs
  5. 呼び出し側をかく。--> yyy_controller.rb


javascript ファイルの呼び出しはこんな感じ。

<head>
<%= javascript_include_tag :defaults%>
</head>


erbファイルでのAjax呼び出し部分はこんな感じ。
form_remote_tag を使った。

<% form_remote_tag(
   :url => {:action => :watch_video, :vid => entry.id}) do %>
   <%= submit_tag "watch" %>
<% end %>

link_to_remote というメソッドもある。


controller では画面に表示する情報を編集して、RJSファイルに引き渡す。

respond_to do |format|
  format.js # { render :action => "#{action_name}.rjs" }
end

呼び出しの階層関係は、
browser --> controller --> RJSファイル --> 部分テンプレート --> browser
となる。
ちょっと面倒くさいが、こうすると部分テンプレートを部品化できる。

カラムにインデックスを付ける

video_items テーブルのvidカラムにインデックスを追加する。
まずはマイグレーションファイルを作成する。

ruby script/generate migration add_index_on_vid

このファイルを以下のように修正。

class AddIndexOnVid < ActiveRecord::Migration
  def self.up
    add_index :video_items, :vid, :unique=>true
  end

  def self.down
    remove_index :video_items, :vid
  end
end

マイグレーションを実行する。

rake db:migrate