MATCH (col1,col2,...) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION] )
バージョン 3.23.23 以降、MySQL
ではフルテキストインデックスと全文検索をサポートしています。
MySQL のフルテキストインデックスは
FULLTEXT
型のインデックスです。
FULLTEXT
インデックスは
MyISAM
テーブルにのみ使用され、CHAR
型、VARCHAR
型、TEXT
型のいずれかのカラムから作成することができます。この作成は
CREATE TABLE
時に行えますが、ALTER TABLE
か
CREATE INDEX
を使用して後から追加することも可能です。データセットのサイズが大きい場合は、FULLTEXT
インデックスを持たないテーブルにデータをロードしてから、ALTER
TABLE
(または CREATE
INDEX
)を使用してインデックスを作成する方が処理がはるかに迅速です。すでに
FULLTEXT
インデックスを持っているテーブルにデータをロードすると、処理がかなり遅くなることがあります。
全文検索を実行するには、MATCH()
関数を使用します。
mysql>CREATE TABLE articles (
->id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
->title VARCHAR(200),
->body TEXT,
->FULLTEXT (title,body)
->);
Query OK, 0 rows affected (0.00 sec) mysql>INSERT INTO articles VALUES
->(NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'),
->(NULL,'How To Use MySQL Efficiently', 'After you went through a ...'),
->(NULL,'Optimizing MySQL','In this tutorial we will show ...'),
->(NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
->(NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'),
->(NULL,'MySQL Security', 'When configured properly, MySQL ...');
Query OK, 6 rows affected (0.00 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql>SELECT * FROM articles
->WHERE MATCH (title,body) AGAINST ('database');
+----+-------------------+------------------------------------------+ | id | title | body | +----+-------------------+------------------------------------------+ | 5 | MySQL vs. YourSQL | In the following database comparison ... | | 1 | MySQL Tutorial | DBMS stands for DataBase ... | +----+-------------------+------------------------------------------+ 2 rows in set (0.00 sec)
MATCH()
関数では、テキストのコレクション(FULLTEXT
インデックスに含まれる 1
つ以上のカラムのセット)に対して、文字列の自然言語検索が実行されます。検索文字列は
AGAINST()
の引数として指定します。検索はケース非依存方式で実行されます。
MATCH()
からは、テーブルの各レコードについて、関連性を示す値(つまり、検索文字列と、そのレコードの
MATCH()
リストに指定したカラムのテキストとの間の類似度)が返されます。
MATCH()
を WHERE
節で使用すると(上の例を参照)、返されるレコードは関連性が最も高いレコードから低いレコードの順に自動でソートされます。
関連性を示す値は負の数でない浮動小数点数です。関連性がゼロのときは、類似性がまったくないことを意味します。関連性は、レコードに含まれるワード数、そのレコードに含まれる一意のワード数、コレクションに含まれる合計ワード数、特定のワードを含むドキュメント(レコード)数に基づいて計算されます。
ブール値モードの検索も実行できます。これについては後述します。
上記の例は、MATCH()
関数の基本的な使用方法を示したものです。レコードは関連性が高いものから低いものの順に返されます。
次の例は、関連値を明示的に取り出す方法を示したものです。
WHERE
節も ORDER BY
節もないので、返されるレコードは順序付けられていません。
mysql> SELECT id,MATCH (title,body) AGAINST ('Tutorial') FROM articles;
+----+-----------------------------------------+
| id | MATCH (title,body) AGAINST ('Tutorial') |
+----+-----------------------------------------+
| 1 | 0.64840710366884 |
| 2 | 0 |
| 3 | 0.66266459031789 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
+----+-----------------------------------------+
6 rows in set (0.00 sec)
次の例はより複雑です。このクエリでは、関連性が返され、関連性の高いものから低いものの順にレコードがソートされます。この結果を出力するためには、MATCH()
を 2
回指定します。それによって追加のオーバーヘッドが発生することはありません。なぜなら、MySQL
のオプティマイザは 2 つの MATCH()
呼び出しが同じものであると認識し、全文検索コードを
1 度しか起動しないためです。
mysql>SELECT id, body, MATCH (title,body) AGAINST
->('Security implications of running MySQL as root') AS score
->FROM articles WHERE MATCH (title,body) AGAINST
->('Security implications of running MySQL as root');
+----+-------------------------------------+-----------------+ | id | body | score | +----+-------------------------------------+-----------------+ | 4 | 1. Never run mysqld as root. 2. ... | 1.5055546709332 | | 6 | When configured properly, MySQL ... | 1.31140957288 | +----+-------------------------------------+-----------------+ 2 rows in set (0.00 sec)
バージョン 4.1.1 以降、全文検索ではクエリの拡張(特に、その異型の ``ブラインドクエリ拡張'')をサポートしています。通常、これは、検索語句が短すぎるときに役立ちます。検索語句が短い場合、その語句を指定したユーザが暗黙的な知識に頼っていることがよくあります。暗黙的な知識といったものは、通常、全文検索エンジンは備えていません。たとえば、ユーザが ``データベース'' という語句を検索している場合、実際にはそのユーザは、単に ``データベース'' だけでなく、``MySQL''、``Oracle''、``DB2''、``RDBMS'' といった語句もすべて ``データベース'' に一致し、返されるはずだと想定していることがあります。暗黙的な知識とは、このようなことを意味します。
ブラインドクエリ拡張(自動関連性フィードバック)では、検索が 2 回実行されます。2 回目の検索の検索語句には、元の検索語句に、最初の検索で上位に検出された少数のドキュメントが結び付けられたものが使用されます。したがって、たとえば、これらのドキュメントの 1 つに ``データベース'' という語と ``MySQL'' という語が含まれている場合、2 回目の検索では、``MySQL'' という語を含み、``データベース'' という語は含まないドキュメントが検索されます。また、たとえば、Georges Simenonの著書で ``Maigret'' 警視に関する本を検索しようとするときに、``Maigret'' のスペルが正確にわからないとします。この場合、``Megre and the reluctant witnesses'' を検索語句として指定すると、クエリの拡張を使用しなければ ``Maigret and the Reluctant Witnesses'' しか検出されません。しかし、クエリの拡張を使用すると、2 回目の検索で ``Maigret'' という語が含まれるすべての本が検出されます。注意:ブラインドクエリ拡張では、関連しないドキュメントが返されることでノイズが大幅に増加しがちです。そのため、この機能を使用する意味があるのは、検索語句が比較的短い場合に限られます。
MySQL
では、非常に単純なパーサを使用してテキストをワード(語)に分割します。``ワード''
とは、文字、数字、‘'
’、‘_
’
で構成される文字列です。ストップワードリストに含まれる
``ワード''
や短すぎるものは無視されます。全文検索で検出されるワードのデフォルトの最小長は
4 文字です。この長さは
項6.8.2. 「MySQL 全文検索の調整」
の説明に従って変更可能です。
コレクションおよびクエリに含まれる正しい各ワードには、そのクエリまたはコレクションでのそのワードの重要度に基づいて重みが設定されます。そのため、多くのドキュメントに存在するワードは低く重み付けされます(重みがゼロの場合もあります)。なぜなら、そのワードはそのコレクションにおいて意味値が低いためです。そのワードがまれにしか存在しない場合は、高く重み付けされます。その後、各ワードの重みが結合されてレコードの関連性が計算されます。
このようなテクニックは、サイズの大きなコレクションの場合に最も効果があります(実際に、それを目的として入念に調整されています)。小さいテーブルでは、ワードの分布はそれぞれの意味値を正しく反映するものとはならず、このモデルを使用した場合、奇妙な結果が出ることがあります。
mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('MySQL');
Empty set (0.00 sec)
上の例では、MySQL
というワードの検索で何も結果が生成されません。これは、このワードが半分以上のレコードに存在するためです。したがって、このワードは事実上ストップワード(意味値がゼロのワード)として扱われます。これは最も望ましい動作です。自然言語のクエリの場合
、1 GB のテーブルから 1
つおきにレコードが返されるのは適切ではありません。
ワードがテーブルの半分を占めるレコードに一致する場合、関連するドキュメントが検出される見込みはあまりありません。むしろ、無関係のドキュメントが大量に検出される可能性が多分にあります。 これは、検索エンジンを使用してインターネットで検索をするときに誰もが頻繁に経験することです。このようなレコードに該当のデータセットにおいて低い意味値が設定されている理由は、ここにあります。
バージョン 4.0.1 以降、MySQL では、IN BOOLEAN
MODE
修飾子を使用してブール値の全文検索も実行できます。
mysql>SELECT * FROM articles WHERE MATCH (title,body)
->AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE);
+----+------------------------------+-------------------------------------+ | id | title | body | +----+------------------------------+-------------------------------------+ | 1 | MySQL Tutorial | DBMS stands for DataBase ... | | 2 | How To Use MySQL Efficiently | After you went through a ... | | 3 | Optimizing MySQL | In this tutorial we will show ... | | 4 | 1001 MySQL Tricks | 1. Never run mysqld as root. 2. ... | | 6 | MySQL Security | When configured properly, MySQL ... | +----+------------------------------+-------------------------------------+
このクエリでは、MySQL
というワードを含み(注意: 50%
のしきい値は使用されません)、YourSQL
というワードは含まないすべてのレコードが取り出されます。注意:
ブール値モードの検索では、関連値の高いもの順のレコードの自動ソートは行われません。これは上のクエリの結果を見るとわかります。上のクエリでは、関連性が最も高いレコード(MySQL
というワードを 2
つ含むレコード)が最初ではなく最後にリストされています。また、ブール値の全文検索は
FULLTEXT
インデックスがなくても機能します。ただし、この場合、処理速度は遅くなります。
ブール値の全文検索機能では、次の演算子をサポートしています。
+
先行するプラス記号は、返される各レコードにそのワードが存在しなければならないことを表す。
-
先行するマイナス記号は、返される各レコードにそのワードが存在してはならないことを表す。
デフォルト(プラスもマイナスも指定しない場合)では、そのワードは必ずしも存在する必要はないが、そのワードを含むレコードは高く評価される。これは、IN
BOOLEAN MODE
修飾子を指定していない
MATCH() ... AGAINST()
の動作に類似する。
< >
これら 2
つの演算子は、各レコードに割り当てられる関連性の値に対する個々のワードの貢献度を変更するために使用される。<
演算子は貢献度を減少させ、>
演算子は貢献度を増加させる。
下の例を参照。
( )
かっこは、ワードを副次式にグループ化するために使用される。
~
先行するチルダは否定演算子として機能し、レコードの関連性に対するワードの貢献度をマイナスにする。これはノイズワードをマークするのに役立つ。このようなワードを含むレコードは、他のワードより低く評価されるが、-
演算子を使用したときのように完全に除外されるわけではない。
*
アスタリスクは切り捨て演算子。他の演算子と異なり、これはワードの前ではなく後ろに付ける。
"
二重引用符 "
で囲んだ語句は、この語句とまったく同じ語句を含むレコードにのみ一致する。
次に、例をいくつか示します。
apple banana
これらのワードの最低 1 つを含むレコードが検索される。
+apple +juice
... 両方のワードを含むレコードを検索。
+apple macintosh
... ワード ``apple'' を含むレコードを検索。``apple'' に加えて ``macintosh'' というワードも含んでいれば、高く評価される。
+apple -macintosh
... ワード ``apple'' を含み、``macintosh'' は含まないレコードを検索。
+apple +(>turnover <strudel)
... ``apple'' と ``turnover''、または ``apple'' と ``strudel'' を含むレコード(2 つのワードの順序は問わない)を検索。ただし、``apple pie'' は ``apple strudel'' より高く評価される。
apple*
... ``apple''、``apples''、``applesauce''、``applet'' はいずれもこれと一致する。
"some words"
... ``some words of wisdom'' とは一致するが、``some noise words'' とは一致しない。
This is a translation of the MySQL Reference Manual that can be found at dev.mysql.com. The original Reference Manual is in English, and this translation is not necessarily as up to date as the English version.