Tritonn 1.0.9でsennaを使って全文検索してみる
Tritonn 1.0.9でsennaを使って全文検索してみる
0.改訂履歴
1.はじめに
このドキュメントでは,MySQLにて日本語全文検索を利用する為にSennaをインストールしている環境で,N-GRAMやMeCabによる形態素解析後のインデックスが利用されている事を確認する手順についてまとめる.
2.sennaを使ってみる(動作テスト)
- ここでは,sennaが正しく稼働しているかを確認する為に,テスト用のデータベースに仮のテーブルを作成し,インデックスを作成して検索を実際に行ってみる.
- まず,MySQLモニターで接続する.
[root@prost mysql]# mysql -uroot -p
Enter password: ■■■■■■■
Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 1
Server version: 5.0.51a-modified MySQL Community Server (GPL) (portions (c)
Tritonn Project)
Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.
mysql>
|
- テスト用のデータベースtestを確認し,useします.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.00 sec)
mysql> use test;
Database changed
mysql>
|
- テスト用のテーブルを作成する.
- bodyフィールドをTEXT型として定義している.
mysql> create table senna_test ( id int, body text )
mysql> default charset utf8 engine = MyISAM;
Query OK, 0 rows affected (0.01 sec)
mysql>
|
- 問題無く作成された.
- TEXT型は,64KBまでの文字列を格納できるが,このテーブルフィールドに日本語テキストデータを格納して,検索してみる事になる.
- 作成したテーブルに,full_text_indexという名前のインデックスを作成する.
mysql> create fulltext index full_text_index on senna_test(body);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql>
|
- 今回導入したIPA辞書は,UTF8でコンパイルされているので,それにあわせる必要がある.
- 明示的にこのセッションのキャラクタコードをUTF8として宣言する.
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)
mysql>
|
mysql> insert into senna_test (id,body) value(1,"今日の天気は晴れです");
Query OK, 1 row affected (0.03 sec)
mysql> insert into senna_test (id,body) value(2,"明日は会社に行こうかなと思います.");
Query OK, 1 row affected (0.00 sec)
mysql>
|
mysql> select * from senna_test;
+------+-----------------------------------------------------+
| id | body |
+------+-----------------------------------------------------+
| 1 | 今日の天気は晴れです |
| 2 | 明日は会社に行こうかなと思います. |
+------+-----------------------------------------------------+
2 rows in set (0.00 sec)
mysql>
|
- このレコードの中から,"会社"というキーワードを含んだデータを取り出してみる.
mysql> select * from senna_test where match(body) against("会社");
+------+-----------------------------------------------------+
| id | body |
+------+-----------------------------------------------------+
| 2 | 明日は会社に行こうかなと思います. |
+------+-----------------------------------------------------+
1 row in set (0.00 sec)
mysql>
|
- sennaの拡張が行われているので,where句には,対象となるフィールドをmatch()で指定し,検索したいキーワードをagainst()で指定して検索を行う.
3.N-GRAMと分かち書き(MeCab)を試す
mysql> insert into senna_test (id,body) value(3,"明日の夜はチャイコフスキーを聴きます");
Query OK, 1 row affected (0.01 sec)
mysql> insert into senna_test (id,body) value(4,"土曜日はスキーに行きます");
Query OK, 1 row affected (0.02 sec)
mysql>
|
mysql> select * from senna_test;
s+------+--------------------------------------------------------+
| id | body |
+------+--------------------------------------------------------+
| 1 | 今日の天気は晴れです |
| 2 | 明日は会社に行こうかなと思います. |
| 3 | 明日の夜はチャイコフスキーを聴きます |
| 4 | 土曜日はスキーに行きます |
+------+--------------------------------------------------------+
4 rows in set (0.00 sec)
mysql>
|
- ここで,追加した行には,"スキー"が含まれている事に注目する.
- 全文検索にて"スキー"を含むデータを取り出す.
mysql> select * from senna_test where match(body) against("スキー");
+------+--------------------------------------------------------+
| id | body |
+------+--------------------------------------------------------+
| 3 | 明日の夜はチャイコフスキーを聴きます |
| 4 | 土曜日はスキーに行きます |
+------+--------------------------------------------------------+
2 rows in set (0.01 sec)
mysql>
|
- この場合,チャイコフスキーが検索されているが,厳密に言うとこれは期待値ではない.
- チャイコフスキーは,チャイコフとスキーに分離されるべきではない.
- 現在のテーブルを確認する.
mysql> show create table senna_test ¥G
*************************** 1. row ***************************
Table: senna_test
Create Table: CREATE TABLE `senna_test` (
`id` int(11) default NULL,
`body` text,
FULLTEXT KEY `full_text_index` USING NGRAM, NORMALIZE, 512 (`body`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql>
|
- 現在のTritonnでは,デフォルトはN-Gramによってデータが分割されるようになっている.
- 先の手順では,明示的に指定しなかったので,デフォルトのN-GRAMとなっている.
- N-GRAMでは,単語ではなく文字数毎に分割したキーワードを元にインデックスを作成している.
- よって,「チャイコフスキー」というキーワードから「スキー」というキーワードで検索できる様になる.
- では,もう1つの分かち書きによる全文検索を試してみる.
- 「分かち書き」事態には,MeCabという形態素解析エンジンを使う事になる.
- まずは,インデックスにmecabを使う様に明示的に指定してみる.
mysql> create table senna_test2
-> ( id int, body text,
-> fulltext index using mecab(body)
-> ) default charset utf8 engine = MyISAM ;
Query OK, 0 rows affected (0.02 sec)
mysql>
|
- この場合は,インデックスは,フィールドbodyをmecabエンジンによって作成する様に明示している.
- 新しく作成したテーブルに,先ほどと同じデータを投入してみる.
mysql> insert into senna_test2 (id,body) value(100,"明日の夜はチャイコフスキーを聴きます");
Query OK, 1 row affected (0.72 sec)
mysql> insert into senna_test2 (id,body) value(101,"土曜日はスキーに行きます");
Query OK, 1 row affected (0.14 sec)
mysql> select * from senna_test2;
+------+--------------------------------------------------------+
| id | body |
+------+--------------------------------------------------------+
| 100 | 明日の夜はチャイコフスキーを聴きます |
| 101 | 土曜日はスキーに行きます |
+------+--------------------------------------------------------+
2 rows in set (0.01 sec)
mysql>
|
mysql> select * from senna_test2 where match(body) against("スキー");
+------+--------------------------------------+
| id | body |
+------+--------------------------------------+
| 100 | 土曜日はスキーに行きます |
+------+--------------------------------------+
1 row in set (0.00 sec)
mysql>
|
- 今回利用しているIPA辞書によって"スキー"という単語が認識されてインデックスが作成されているので,チャイコフスキーは検索されない.
- また,ここでは試用していないが,英文と同じ様に空白で区切られた文字ごとにインデックスを作成する事ができるDELIMITEDというインデックスタイプもある.