Rspec on Railsで、controllerで使うライブラリのテストをする方法
ライブラリ
例えば、includeしたら、before_filterで、params[:price]の末尾に"円"を追加するライブラリのテストを書く場合
# -*- encoding: utf-8 -*- module TestLib # includeされたら、before_filterを追加する def self.included(klass) klass.class_eval do before_filter :add_unit end end # "円"を追加する def add_unit params['price'] = "#{params['price']}円" end end
テスト
テストはこんな感じになる
# -*- encoding: utf-8 -*- require File.dirname(__FILE__) + '/../spec_helper' # テスト用のコントローラ class TestLibController < ApplicationController include TestLib def index response.content_type = 'text/html' render :text => params['price'] end end # :type => :controller でcontrollerのspec_helperを使えるようにする # * controllerディレクトリのテストの場合は勝手にやってくれる describe TestLibController, :type => :controller do before :all do # テスト用のroutesを追加 AppLibTest::Application.routes.draw do match 'index', :to => 'test_lib#index' end end # routesの初期化 after(:all){ Rails.application.reload_routes! } subject do get :index, :price => '100' response end it{ subject.should be_success } its(:body){ '100円' } end
ポイント
- テストを実行するためのコントローラを作る
- describeで明示的に、コントローラのテストであることを、rspec側に教える
- before :all で、Application.routesでテスト用コントローラのルーティングを切る
- after :all で、ルーティングを初期化する
gistにコード上げてみた
HomebrewでMemcachedのインストール
インストール
$ brew install memcached ==> Installing memcached dependency: libevent ==> Downloading https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz ######################################################################## 100.0% ==> ./configure --disable-debug-mode --prefix=/usr/local/Cellar/libevent/2.0.21 ==> make ==> make install /usr/local/Cellar/libevent/2.0.21: 48 files, 1.9M, built in 77 seconds ==> Installing memcached ==> Downloading http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz ######################################################################## 100.0% ==> ./configure --prefix=/usr/local/Cellar/memcached/1.4.15 --disable-coverage ==> make install ==> Caveats To have launchd start memcached at login: ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents Then to load memcached now: launchctl load ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist Or, if you don't want/need launchctl, you can just run: /usr/local/opt/memcached/bin/memcached /usr/local/Cellar/memcached/1.4.15: 10 files, 180K, built in 17 seconds
起動テスト
$ /usr/local/opt/memcached/bin/memcached
接続確認
接続して、ステータスをチェック
その後、値の出し入れをしてみる
$ telnet localhost 11211 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. stats STAT pid 20725 STAT uptime 25 STAT time 1357612193 STAT version 1.4.15 STAT libevent 2.0.21-stable STAT pointer_size 64 STAT rusage_user 0.001140 STAT rusage_system 0.003183 STAT curr_connections 10 STAT total_connections 11 STAT connection_structures 11 STAT reserved_fds 20 STAT cmd_get 0 STAT cmd_set 0 STAT cmd_flush 0 STAT cmd_touch 0 STAT get_hits 0 STAT get_misses 0 STAT delete_misses 0 STAT delete_hits 0 STAT incr_misses 0 STAT incr_hits 0 STAT decr_misses 0 STAT decr_hits 0 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 0 STAT touch_hits 0 STAT touch_misses 0 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 7 STAT bytes_written 0 STAT limit_maxbytes 67108864 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 4 STAT conn_yields 0 STAT hash_power_level 16 STAT hash_bytes 524288 STAT hash_is_expanding 0 STAT bytes 0 STAT curr_items 0 STAT total_items 0 STAT expired_unfetched 0 STAT evicted_unfetched 0 STAT evictions 0 STAT reclaimed 0 END set foo 0 0 3 123 STORED get foo VALUE foo 0 3 123 END quit Connection closed by foreign host.
launchctlの設定
この辺はHomebrewでインストールした時に出てきたメッセージに沿っていくだけ。簡単。
$ ln -sfv /usr/local/opt/memcached/*.plist ~/Library/LaunchAgents /Users/kobayashi/Library/LaunchAgents/homebrew.mxcl.memcached.plist -> /usr/local/opt/memcached/homebrew.mxcl.memcached.plist $ ll ~/Library/LaunchAgents lrwxr-xr-x 1 kobayashi staff 54 1 8 11:31 homebrew.mxcl.memcached.plist@ -> /usr/local/opt/memcached/homebrew.mxcl.memcached.plist
起動していることを確認
$ ps aux | grep memcached kobayashi 21392 0.0 0.0 2438616 940 ?? S 11:31AM 0:00.00 /usr/local/opt/memcached/bin/memcached -l localhost
SnowLeopardにhomebrewで、MySQLにmysqlftppc mecab pluginをICU対応で入れようとして頓挫した話
MySQL、mecabのインストールまでは、macportsからHomebrewに乗り換えてMySQL5.1をインストールするまでの流れ 参照
mysqlftppc mecab pluginって何?
MySQLでFULLTEXTインデックスをパースする時に、mecabを使うようにするプラグイン
FULLTEXTインデックスって何?
MySQLで使える全文検索機能用のインデックス
like検索より早い
内部的にはパーサを使って文章を分割して、インデックス用のデータを作っている
標準のパーサだと、カンマや空白区切りでパースするので、日本語の検索に向かない
FULLTEXT パーサは特定の区切り文字を見て、語の頭と最後を定義します。 その例には、‘ ’ ( スペース ) , ‘,’ ( カンマ ) , そして ‘.’ ( ピリオド ) があります。 単語が非区切り文字 ( 例えば中国語 ) で区切られている場合は、FULLTEXT パーサは単語の最初と最後を定義することができません。 単語や、インデックスのついた他の表現をそのような言語で FULLTEXT インデックスに加えるには、事前に処理して ‘"’ などの任意の区切り文字で区切る必要があります。
なので、FULLTEXTインデックスを作るときのパーサーをプラグインで拡張する必要がある
上記mysqlftppc mecab pluginは、mecabを使って文章を解析してFULLTEXTインデックスを作ってくれるプラグイン
mecabのインストール
$ brew install mecab
mecab用の辞書 naist-jdic をインストール
mecabは標準では、IPAdicという辞書を使うような設定になっているのだけど、
IPAdicはライセンス上の問題があったりするので、IPAdicの改良版のnaist-jdic を入れるのが良いらしい
$ brew create "http://sourceforge.jp/frs/redir.php?m=iij&f=%2Fnaist-jdic%2F48487%2Fmecab-naist-jdic-0.6.3-20100801.tar.gz" $ cd /usr/local/Library/Formula # すごい名前になるのでmv $ mv redir.php\?m=iij\&f=%2fnaist-jdic%2f48487%2fmecab-naist-jdic.rb mecab-naist-jdic.rb # コンパイル時に、/etc/mecab が必要なので作っておく $ sudo mkdir /etc/mecab $ sudo chown kobayashi /etc/mecab $ vim mecab-naist-jdic.rb
一部設定を編集
require 'formula' # Documentation: https://github.com/mxcl/homebrew/wiki/Formula-Cookbook # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST! # class名も修正 class MecabNaistJdic < Formula homepage '' url 'http://sourceforge.jp/frs/redir.php?m=iij&f=%2Fnaist-jdic%2F48487%2Fmecab-naist-jdic-0.6.3-20100801.tar.gz' version '0.6.3-20100801' homepage 'http://sourceforge.jp/projects/naist-jdic/' #追加した sha1 '86ccbb15d208a99d81ebcef9f31aee384cc7b31e' # depends_on 'cmake' => :build depends_on :x11 # if your formula requires any X11/XQuartz components def install # ENV.j1 # if your formula's build system can't parallelize system "./configure", "--disable-debug", "--disable-dependency-tracking", "--prefix=#{prefix}", "--with-charset=utf8" # utf8を追加 # system "cmake", ".", *std_cmake_args system "make install" # if this fails, try separate make/make install steps end def test # This test will fail and we won't accept that! It's enough to just replace # "false" with the main program this formula installs, but it'd be nice if you # were more thorough. Run the test with `brew test redir.php?m=iij&f=%2Fnaist-jdic%2F48487%2Fmecab-naist-jdic`. system "false" end end
$ brew install mecab-naist-jdic
辞書の設定を更新
mecab-naist-jdicを使うように設定ファイルを更新
vim /usr/local/Cellar/mecab/0.994/etc/mecabrc
;dicdir = /usr/local/Cellar/mecab/0.994/lib/mecab/dic/ipadic dicdir = /usr/local/Cellar/mecab/0.994/lib/mecab/dic/naist-jdic
動作確認
ここまではOK
$ echo "東急東横線" | mecab 東急東横 名詞,固有名詞,一般,*,*,*,東急東横,トウキュウトウヨコ,トーキュートーヨコ,, 線 名詞,接尾,一般,*,*,*,線,セン,セン,, EOS
icu4cをインストール
$ brew install icu4c
mysqlftppc-mecabをインストール
$ brew create http://sourceforge.net/projects/mysqlftppc/files/mysqlftppc/1.6.1/mysqlftppc-mecab-1.6.1.tar.gz/download?use_mirror=jaist $ cd /usr/local/Library/Formula $ mv download\?use.rb mysqlftppc-mecab.rb $ vim mysqlftppc-mecab.rb
require 'formula' # Documentation: https://github.com/mxcl/homebrew/wiki/Formula-Cookbook # PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST! # class名も修正 class MysqlftppcMecab < Formula homepage '' url 'http://sourceforge.net/projects/mysqlftppc/files/mysqlftppc/1.6.1/mysqlftppc-mecab-1.6.1.tar.gz/download?use_mirror=jaist' version '1.6.1' sha1 'dbccb787f4f6f588481e0b0623993cec5ba0f106' # depends_on 'cmake' => :build depends_on :x11 # if your formula requires any X11/XQuartz components def install # ENV.j1 # if your formula's build system can't parallelize system "./configure", "--disable-debug", "--disable-dependency-tracking", "--prefix=#{prefix}" "--enable-utf8-only", # icuを使うように設定 "--with-icu-config=/usr/local/Cellar/icu4c/50.1/bin/icu-config" # system "cmake", ".", *std_cmake_args system "make install" # if this fails, try separate make/make install steps end def test # This test will fail and we won't accept that! It's enough to just replace # "false" with the main program this formula installs, but it'd be nice if you # were more thorough. Run the test with `brew test download?use`. system "false" end end
インストール
$ brew install mysqlftppc-mecab ==> Downloading http://sourceforge.net/projects/mysqlftppc/files/mysqlftppc/1.6.1/mysqlftppc-mecab-1.6.1.tar.gz/download?use_mirror=jaist Already downloaded: /Library/Caches/Homebrew/mysqlftppc-mecab-1.6.1 ==> ./configure --prefix=/usr/local/Cellar/mysqlftppc-mecab/1.6.1 --enable-utf8-only --with-icu-dir=/usr/local/Cellar/icu4c/50.1 ==> make install i686-apple-darwin10-gcc-4.2.1: c: No such file or directory i686-apple-darwin10-gcc-4.2.1: c: No such file or directory make: *** [libftmecab_la-ftnorm.lo] Error 1 make: *** Waiting for unfinished jobs.... make: *** [libftmecab_la-ftbool.lo] Error 1 READ THIS: https://github.com/mxcl/homebrew/wiki/troubleshooting
エラーが発生
64bitを明示的に指定して手動でコンパイル
tar-ball をダウンロードした場合は展開した後、configureスクリプトを実行してください。 mysqld_config が見つからない場合は、--mysqld-config=/path/to/mysqld_config 引数をつけてください。 mysqld 自体が 64bit でビルドされていたり、debug=full でコンパイルされている場合は、適宜適切な CFLAGS を渡してください。
と、あるので明示的に64bitでコンパイルしてみる
$ make clean $ CFLAGS="-m64" ./configure --disable-debug --disable-dependency-tracking --enable-utf8-only --with-icu-config=/usr/local/Cellar/icu4c/50.1/bin/icu-config $ make $ make install make/bin/sh ./libtool --tag=CC --mode=compile gcc -DPACKAGE_NAME=\"plugin_mecab\" -DPACKAGE_TARNAME=\"plugin_mecab\" -DPACKAGE_VERSION=\"1.6.1\" -DPACKAGE_STRING=\"plugin_mecab\ 1.6.1\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"plugin_mecab\" -DVERSION=\"1.6.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -I. -I. -I./include -I./include -I/usr/local/Cellar/mysql51/5.1.67/include/mysql -I/usr/local/Cellar/mecab/0.994/include -F/usr/local/Frameworks -I/usr/local/Cellar/icu4c/50.1/include \c -DMYSQL_DYNAMIC_PLUGIN -m64 -DHAVE_ICU -c -o libftmecab_la-ftnorm.lo `test -f 'ftnorm.c' || echo './'`ftnorm.c mkdir .libs gcc -DPACKAGE_NAME=\"plugin_mecab\" -DPACKAGE_TARNAME=\"plugin_mecab\" -DPACKAGE_VERSION=\"1.6.1\" "-DPACKAGE_STRING=\"plugin_mecab 1.6.1\"" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE=\"plugin_mecab\" -DVERSION=\"1.6.1\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -I. -I. -I./include -I./include -I/usr/local/Cellar/mysql51/5.1.67/include/mysql -I/usr/local/Cellar/mecab/0.994/include -F/usr/local/Frameworks -I/usr/local/Cellar/icu4c/50.1/include c -DMYSQL_DYNAMIC_PLUGIN -m64 -DHAVE_ICU -c ftnorm.c -fno-common -DPIC -o .libs/libftmecab_la-ftnorm.o i686-apple-darwin10-gcc-4.2.1: c: No such file or directory In file included from /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_global.h:86, from ftnorm.c:2: /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1167:1: warning: "PACKAGE" redefined <command-line>: warning: this is the location of the previous definition /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1173:1: warning: "PACKAGE_NAME" redefined <command-line>: warning: this is the location of the previous definition /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1176:1: warning: "PACKAGE_STRING" redefined <command-line>: warning: this is the location of the previous definition /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1179:1: warning: "PACKAGE_TARNAME" redefined <command-line>: warning: this is the location of the previous definition /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1182:1: warning: "PACKAGE_VERSION" redefined <command-line>: warning: this is the location of the previous definition /usr/local/Cellar/mysql51/5.1.67/include/mysql/my_config.h:1298:1: warning: "VERSION" redefined <command-line>: warning: this is the location of the previous definition make: *** [libftmecab_la-ftnorm.lo] Error 1
やっぱりエラー
諦めて、icuを外してみる
$ make clean $ CFLAGS="-m64" ./configure --disable-debug --disable-dependency-tracking --enable-utf8-only $ make $ make install make[1]: Nothing to be done for `install-exec-am'. test -z "/usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin" || /Users/kobayashi/tmp/mysqlftppc-mecab/mysqlftppc-mecab-1.6.1/install-sh -d "/usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin" /bin/sh ./libtool --mode=install /usr/bin/install -c 'libftmecab.la' '/usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin/libftmecab.la' /usr/bin/install -c .libs/libftmecab.0.0.0.so /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin/libftmecab.0.0.0.so (cd /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin && { ln -s -f libftmecab.0.0.0.so libftmecab.0.so || { rm -f libftmecab.0.so && ln -s libftmecab.0.0.0.so libftmecab.0.so; }; }) (cd /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin && { ln -s -f libftmecab.0.0.0.so libftmecab.so || { rm -f libftmecab.so && ln -s libftmecab.0.0.0.so libftmecab.so; }; }) /usr/bin/install -c .libs/libftmecab.lai /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin/libftmecab.la ---------------------------------------------------------------------- Libraries have been installed in: /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `DYLD_LIBRARY_PATH' environment variable during execution See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages. ----------------------------------------------------------------------
あっさり成功
必要なファイルが作られていることを確認
$ ll /usr/local/Cellar/mysql51/5.1.67/lib/mysql/plugin | grep ftm -rwxr-xr-x 1 kobayashi admin 20392 1 7 18:58 libftmecab.0.0.0.so* lrwxr-xr-x 1 kobayashi admin 19 1 7 18:58 libftmecab.0.so@ -> libftmecab.0.0.0.so -rwxr-xr-x 1 kobayashi admin 890 1 7 18:58 libftmecab.la* lrwxr-xr-x 1 kobayashi admin 19 1 7 18:58 libftmecab.so@ -> libftmecab.0.0.0.so
mysql> INSTALL PLUGIN mecab SONAME 'libftmecab.so'; Query OK, 0 rows affected (0.00 sec) mysql> SHOW STATUS LIKE "Mecab_info"; +---------------+-------------------------------+ | Variable_name | Value | +---------------+-------------------------------+ | Mecab_info | with mecab 0.994, without ICU | +---------------+-------------------------------+ 1 row in set (0.00 sec)
参考
- ここだと明示的にicu-configの場所を指定してない。自前の環境だとwithoutICUになる...
MySQL full-text parser plugin collectionのmecab pluginを入れる - kouheiの日記
- エラーの内容が似ている。後日調査
PHP で MySQL FULLTEXT + MeCab で簡単に全文検索を実装する | ウェブル
- FULLTEXTインデックスの説明や、MeCebを選択する理由などがわかりやすくまとめられている
チラシの裏
以下うまくいかない原因の考察
SnowLeopardでは、32bitアプリと64bitアプリが混在しているけどこの辺が悪さをしている?
例えば、icuを32bitでしか作ってなくて、mysqlftppcを64bitでコンパイルしようとしたためにエラーが出たとか
Homebrewには、ユニバーサルバイナリでmakeするか否かを決める環境変数を設定するメソッドがある
Library/Homebrew/extend/ENV.rb
# i386 and x86_64 (no PPC) def universal_binary append_to_cflags '-arch i386 -arch x86_64' replace_in_cflags '-O4', '-O3' # O4 seems to cause the build to fail append 'LDFLAGS', '-arch i386 -arch x86_64' unless compiler == :clang # Can't mix "-march" for a 32-bit CPU with "-arch x86_64" replace_in_cflags(/-march=\S*/, '-Xarch_i386 \0') if Hardware.is_32_bit? end end
で、MySQLとか、icu4cのFormulaでは、ユニバーサルバイナリでコンパイルする設定が書かれている
def install # Make universal for bindings to universal applications ENV.universal_binary if build.universal?
だけど、mysqlftppc-mecabは自作の為そのような設定が無いのでそれが原因かなぁ... と思ったけど
そもそも、build.universal? がfalseを返していて64bit版を作っていたので違った
Lionだと特に躓くことも無くあっさりICU版がインストールできた
なので、SnowLeopard環境に何かしらの原因があるはずだが...
mysql> SHOW STATUS LIKE "Mecab_info"; +---------------+-----------------------------------------+ | Variable_name | Value | +---------------+-----------------------------------------+ | Mecab_info | with mecab 0.994, ICU 50.1(Unicode 6.2) | +---------------+-----------------------------------------+ 1 row in set (0.01 sec)
そんな煮え切らない感じで
mecabにユーザ辞書を追加して、MySQL5.1のフルテキストインデックスを更新するまでの話
環境
- MySQL5.1
- Homebrewでmecabをインストール済
- DBに以下のようなテーブルを追加してある
CREATE TABLE stations (name CHAR(255), info TEXT, FULLTEXT(info) WITH PARSER mecab); mysql> CREATE TABLE stations (name CHAR(255), info TEXT, FULLTEXT(info) WITH PARSER mecab); Query OK, 0 rows affected (0.01 sec) mysql> desc stations; +-------+-----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------+------+-----+---------+-------+ | name | char(255) | YES | | NULL | | | info | text | YES | MUL | NULL | | +-------+-----------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
-
- 中身は、駅名とwikipediaから取ってきた適当なテキスト
駅名を正しく認識してくれない問題
標準の辞書では駅名を正しく形態素解析してくれない
$ echo "愛甲石田" | mecab 愛甲 名詞,固有名詞,人名,姓,*,*,愛甲,アイコウ,アイコー,, 石田 名詞,固有名詞,地域,一般,*,*,石田,イシダ,イシダ,, EOS
mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST("愛甲石田駅")\G *************************** 1. row *************************** name: 愛甲石田駅 info: 愛甲石田駅 北口(2008年7月13日) あいこういしだ - Aikō-Ishida ◄本厚木 (3.1km) (3.7km) 伊勢原► 所在地 神奈川県厚木市愛甲1丁目1番1号 (一部は同県伊勢原市石田) 北緯35度25分3.5秒 東経139度20分38秒座標: 北緯35度25分3.5秒 東経139度20分38秒 所属事業者 ■小田急電鉄 所属路線 小田原線 キロ程 48.5km(新宿起点) 駅構造 地上駅(橋上駅) ホーム 2面2線 乗降人員 -統計年度- 47,052人/日 -2011年- 開業年月日 1927年(昭和2年)4月1日 この表について この表はテンプレートを用いて表示しています。編集の仕方はTemplate:駅情報をごらんください。 *************************** 2. row *************************** name: 芦沢駅 info: 芦沢駅 駅舎(2005年5月) あしさわ - Ashisawa ◄北大石田 (2.9km) (6.6km) 舟形► 所在地 山形県尾花沢市大字芦沢1012 北緯38度39分19.76秒 東経140度21分39.83秒 所属事業者 東日本旅客鉄道(JR東日本) 所属路線 ■奥羽本線(山形線) キロ程 133.7km(福島起点) 電報略号 アハ 駅構造 地上駅 ホーム 2面2線 乗車人員 -統計年度- 66人/日(降車客含まず) -2011年- 開業年月日 1916年(大正5年)12月1日 備考 簡易委託駅 この表について この表はテンプレートを用いて表示しています。編集の仕方はTemplate:駅情報をごらんください。 2 rows in set (0.00 sec)
特に隣接駅でもない芦沢駅が出てくる
- 「北大石田」がヒットしている??
なので、ユーザ辞書に駅名を追加して、全文検索の結果を正しくする
- ちなみにブーリアンモードならば正しい結果が出るのだけど、速度的に問題があるので今回は見送り
ユーザ辞書の作成
以下のスクリプトでユーザ辞書生成に必要な形式のcsvファイルを作成する
このコードには不具合があるので、下の「追記」も参照してください
# -*- encoding: utf-8 -*- require 'rubygems' require 'csv' CSV.open('./02.csv', 'w') do |csv_w| CSV.open('./01.csv', 'r:UTF-8').each do |csv| name = csv.first csv_w << [name.gsub(/駅$/, ''), nil, nil, 10, '名詞', '一般', '*', '*', '*', '*', 'ユーザ設定', 'ユーザセッテイ', 'ユーザセッテイ', '追加エントリ'] end end
こんなのが生成される
あいの里公園,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あいの里教育大,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あおば通,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あかおか,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あかぢ,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あきた白神,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あさぎり,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あざみ野,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あつみ温泉,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あぶくま,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あまや,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あやめ公園,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あわくら温泉,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ あわら湯のまち,,,10,名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ ...
2012/01/11 追記
上記のようにコストを0に固定していると辞書の単語を含む長文の単語が形態素解析されない問題がある
例えば辞書に「循環器」「内科」「循環器内科」がある時に「循環器内科」を形態素解析すると、
$ echo "循環器内科" | mecab 循環器 名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ 内科 名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ EOS
のように、「循環器内科」で形態素解析されない
なので、以下のように、長文の方のコストを低くしてあげる必要がある
result.each do |name| cost = -400 * name.split(//u).size ** 1.5 cost = -36000 if cost < -36000 csv<< [name, nil, nil, cost, '名詞', '一般', '*', '*', '*', '*', 'ユーザ設定', 'ユーザセッテイ', 'ユーザセッテイ', '追加エントリ'] end
ユーザ辞書のコンパイル
$ /usr/local/Cellar/mecab/0.994/libexec/mecab/mecab-dict-index -d /usr/local/Cellar/mecab/0.994/lib/mecab/dic/naist-jdic/ -u usr.dic -f utf8 -t utf8 02.csv reading 02.csv ... 479 emitting double-array: 100% |###########################################| done!
コンパイルした辞書を使うように設定
生成した辞書を適当な場所に移動
$ cp usr.dic /usr/local/lib/mecab/dic/.
設定ファイルを更新
$ vim /usr/local/Cellar/mecab/0.994/etc/mecabrc
ユーザ辞書のpathを設定する
userdic = /usr/local/lib/mecab/dic/usr.dic
動作確認
$ echo "愛甲石田" | mecab 愛甲石田 名詞,一般,*,*,*,*,ユーザ設定,ユーザセッテイ,ユーザセッテイ,追加エントリ EOS
ちなみにmecabのユーザ辞書設定後、MySQLを更新するまでの間は正しい検索は期待できない様子
mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST("愛甲石田駅")\G Empty set (0.01 sec) mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST('+"愛甲石田駅"' IN BOOLEAN MODE)\G Empty set (0.00 sec)
フルテキストインデックスの更新
mysql> REPAIR TABLE stations QUICK; +---------------+--------+----------+----------+ | Table | Op | Msg_type | Msg_text | +---------------+--------+----------+----------+ | test.stations | repair | status | OK | +---------------+--------+----------+----------+ 1 row in set (0.16 sec)
MySQLの動作確認
芦沢駅がヒットしなくなることを確認
mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST("愛甲石田駅")\G *************************** 1. row *************************** name: 愛甲石田駅 info: 愛甲石田駅 北口(2008年7月13日) あいこういしだ - Aikō-Ishida ◄本厚木 (3.1km) (3.7km) 伊勢原► 所在地 神奈川県厚木市愛甲1丁目1番1号 (一部は同県伊勢原市石田) 北緯35度25分3.5秒 東経139度20分38秒座標: 北緯35度25分3.5秒 東経139度20分38秒 所属事業者 ■小田急電鉄 所属路線 小田原線 キロ程 48.5km(新宿起点) 駅構造 地上駅(橋上駅) ホーム 2面2線 乗降人員 -統計年度- 47,052人/日 -2011年- 開業年月日 1927年(昭和2年)4月1日 この表について この表はテンプレートを用いて表示しています。編集の仕方はTemplate:駅情報をごらんください。 1 row in set (0.00 sec)
ユーザ辞書追加後、フルテキストインデックスが更新されるまでの挙動の考察
以下チラシの裏
愛甲石田は検索できなくなった
mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST("愛甲石田駅")\G Empty set (0.01 sec) mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST('+"愛甲石田駅"' IN BOOLEAN MODE)\G Empty set (0.00 sec)
ただし、元々固有名詞として存在している名詞の検索は大丈夫だった
echo "あざみ野" | mecab あざみ野 名詞,固有名詞,一般,*,*,*,あざみ野,アザミノ,アザミノ,, EOS
mysql> SELECT * FROM stations WHERE MATCH(info) AGAINST("あざみ野")\G *************************** 1. row *************************** name: あざみ野駅 info: あざみ野駅 田園都市線あざみ野駅西口(2011年11月) あざみの - Azamino 所在地 横浜市青葉区あざみ野二丁目 所属事業者 東京急行電鉄(駅詳細) 横浜市交通局(駅詳細) この表につ いて この表はテンプレートを用いて表示しています。編集の仕方はTemplate:駅情報をごらんください。 東急 あざみ野駅 あざみの - Azamino ◄たまプラーザ (1.1km) (1.1km) 江田► 所在地 横浜 市青葉区あざみ野二丁目1番地1 北緯35度34分7.4秒 東経139度33分12.8秒座標: 北緯35度34分7.4秒 東経139度33分12.8秒 駅番号  DT 16  所属事業者 東京急行電鉄(東急) 所属路線 ■田園都市線 キロ程 18.2km(渋谷起点) 駅構造 高架駅 ホーム 相対式 2面2線 乗降人員 -統計年度- 128,986人/日 -2011年- 開業年月日 1977年(昭和52年)5月25日 この表について この表はテンプレートを 用いて表示しています。編集の仕方はTemplate:駅情報をごらんください。 横浜市交通局 あざみ野駅 あざみの - Azamino ◄B31 中川 (1.5km) 所在地 北緯35度34分5.1秒 東経139度33分12.5秒 駅番号 ○B32 所属事業者 横浜市交通局(横浜市営地下鉄) 所属路線 ■ブルーライン(3号線) キロ程 20.7km(関内*起点) 湘南台から40.4km 駅構造 地下駅 ホーム 1面2線 乗車人員 -統計年度- 38,897人/日(降車客含まず) -2010年- 開業年月日 1993年(平成5年)3月18日 備考 *3号線の起点として この表について この表はテンプレートを用いて表示しています。編集の仕方はTemplate:駅情 報をごらんください。 1 row in set (0.00 sec)
「愛甲石田」で検索した場合
以下のような処理になっていると思う
なので、ユーザ辞書に「愛甲石田」が追加されると、
形態素解析、「愛甲石田」でフルテキストインデックスを探しに行く為、1件もヒットしないのではないか?
「あざみ野」で検索した場合
ユーザ辞書追加前から「あざみ野」で形態素解析されているので、きちんとヒットするのだと思う
rubyでRailsなしでActiveRecordを使う
DBの環境
Homebrewで構築した、ローカルのMySQL5.1
テーブルはこんな感じのを用意
CREATE TABLE stations (name CHAR(255), info TEXT, FULLTEXT(info) WITH PARSER mecab); mysql> CREATE TABLE stations (name CHAR(255), info TEXT, FULLTEXT(info) WITH PARSER mecab); Query OK, 0 rows affected (0.01 sec) mysql> desc stations; +-------+-----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-----------+------+-----+---------+-------+ | name | char(255) | YES | | NULL | | | info | text | YES | MUL | NULL | | +-------+-----------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
使い方
# -*- encoding: utf-8 -*- require 'rubygems' require 'active_record' #DBに接続 ActiveRecord::Base.establish_connection( :adapter => 'mysql2', :username => 'root', :password => '********', :host => 'localhost', :database => 'test', :encoding => 'utf8' ) # テーブル用のクラスを用意 class Station < ActiveRecord::Base end # 1個データを作ってsaveしてみる station = Station.new station.name = '入間市駅' station.info = '解説文' station.save # 検索 Station.find(:all).each{|s| puts s.name # "入間市駅" が出力される }
ハマったこと
adapterをmysqlにしていたらエラーになった
`rescue in mysql_connection': !!! Missing the mysql2 gem. Add it to your Gemfile: gem 'mysql2' (RuntimeError)
Rails3では、mysql2をアダブターにしているので修正する
mysql2をインストールする時に警告が発生する
$ gem install mysql2 WARNING: This version of mysql2 (0.3.11) doesn't ship with the ActiveRecord adapter bundled anymore as it's now part of Rails 3.1 WARNING: Please use the 0.2.x releases if you plan on using it in Rails <= 3.0.x
ActiveRecordでは、0.2.x を入れる必要があるらしい
- ActiveRecordとmysql2のバージョン問題 - tetsuwan blog
- Install mysql2 gem on Snow Leopard for Rails 3 with rvm - Stack Overflow
バージョンを指定して、mysql2 を入れる
$ gem install mysql2 -v 0.2.6
Homebrewで入れたMySQL5.1でutf-8を使えるようにする設定
クライアント、サーバ側それぞれをutf8にする
方法
~/.my.cnf にクライアント側の設定を追加
[client] default-character-set = utf8
/usr/local/var/mysql/my.cnf にサーバ側の設定を追加
[mysqld] character-set-server=utf8
サーバの再起動
mysql.server restart
MySQLでのキャラクタ設定の確認方法
mysql> show variables like 'char%'; +--------------------------+--------------------------------------------------------+ | Variable_name | Value | +--------------------------+--------------------------------------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/local/Cellar/mysql51/5.1.67/share/mysql/charsets/ | +--------------------------+--------------------------------------------------------+ 8 rows in set (0.00 sec)
変数の意味はリファレンス参照
テーブルの文字コードの確認方法
mysql> CREATE TABLE stations (name CHAR(255), info TEXT, FULLTEXT(info) WITH PARSER mecab); mysql> mysql> SHOW CREATE TABLE stations\G *************************** 1. row *************************** Table: stations Create Table: CREATE TABLE `stations` ( `name` char(255) DEFAULT NULL, `info` text, FULLTEXT KEY `info` (`info`) /*!50100 WITH PARSER `mecab` */ ) ENGINE=MyISAM DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
メモ
サーバ側に skip-character-set-client-handshake を設定して、クライアント側の文字コードの設定を自動的にサーバに合わせる方法もあるけど、セキュリティ的に問題があるらしい
Homebrewで入れたMySQL5.1を停止できない件の対策
現象
MySQLを停止しようとするとエラーがでる
$ mysql.server stop Shutting down MySQL ....... ERROR! Manager of pid-file quit without updating file. ERROR! Failed to stop running server, so refusing to try to start.
対策
plistのKeepAliveの値をtrueから、falseに修正する
$ vim ~/Library/LaunchAgents/com.mysql.mysqld.plist
<key>KeepAlive</key> <false/>
KeepAliveは、そのプロセスを常に起動した状態にするか否かを設定するオプション
KeepAlive <boolean or dictionary of stuff> This optional key is used to control whether your job is to be kept continuously running or to let demand and conditions control the invocation.
変更後、plistを再読込させる
$ launchctl unload -w ~/Library/LaunchAgents/com.mysql.mysqld.plist $ launchctl load -w ~/Library/LaunchAgents/com.mysql.mysqld.plist
無事終了/起動できるようになった
$ mysql.server stop Shutting down MySQL ... SUCCESS! $ mysql.server start Starting MySQL . SUCCESS! $ mysql.server restart Shutting down MySQL .. SUCCESS! Starting MySQL . SUCCESS!