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件もヒットしないのではないか?
「あざみ野」で検索した場合
ユーザ辞書追加前から「あざみ野」で形態素解析されているので、きちんとヒットするのだと思う