デフォルトの状態や IN NATURAL
LANGUAGE MODE
修飾子が指定された場合には、MATCH()
関数は「テキストコレクション」に対して文字列の自然言語検索を実行します。コレクションは、FULLTEXT
インデックスを含む、ひとつ以上のカラムのセットです。検索文字列は、AGAINST()
への引数として与えられます。テーブルの各行に対し、検索文字列と、MATCH()
リストで名付けられたカラムの行内のテキスト間の類似性を測り、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 (title,body) VALUES
->('MySQL Tutorial','DBMS stands for DataBase ...'),
->('How To Use MySQL Well','After you went through a ...'),
->('Optimizing MySQL','In this tutorial we will show ...'),
->('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
->('MySQL vs. YourSQL','In the following database comparison ...'),
->('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' IN NATURAL LANGUAGE MODE);
+----+-------------------+------------------------------------------+ | 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)
デフォルトでは、検索は大文字小文字の区別のある方法で行われます。しかし、バイナリ照合を用いて、インデックスのつけられたカラムに対し、大文字小文字の区別のある古テキスト検索を行うことができます。たとえば、latin1
キャラクタセットを使用するカラムに、全文検索のために大文字小文字の区別をするよう、latin1_bin
の照合を割り当てることができます。
以前に挙げた例のように、MATCH()
が WHERE
節で使用されるとき、返された行はまず、最高レベルの関連性があるとした上で自動的に保管されます。関連値は、負でない浮動小数点数です。ゼロレリバンスとは、類似性がまったくないという意味です。レリバンスは、行の単語の数、行の一意性のある単語の数、コレクション内の単語の合計数、そして特定の単語を含む資料
(行) の数に基づいて計算されます。
単に検出を数えるには、次のクエリーを使用してください :
mysql>SELECT COUNT(*) FROM articles
->WHERE MATCH (title,body)
->AGAINST ('database' IN NATURAL LANGUAGE MODE);
+----------+ | COUNT(*) | +----------+ | 2 | +----------+ 1 row in set (0.00 sec)
しかし、次のようにクエリーを書き換えたほうが手軽な場合もあります :
mysql>SELECT
->COUNT(IF(MATCH (title,body) AGAINST ('database' IN NATURAL LANGUAGE MODE), 1, NULL))
->AS count
->FROM articles;
+-------+ | count | +-------+ | 2 | +-------+ 1 row in set (0.03 sec)
最初のクエリーは関連性の大きさによって結果をソートし、2 番目のクエリーではそれを行いません。しかし、2 番目のクエリーは 1 番目が行わない、テーブル全体のスキャンをします。1 番目は数行のマッチしか検出されなければ時間はかかりませんが、そうでなくとも 2 番目は、どちらにしても多くの行を読むので素早く終わります。
自然言語の全文検索では、MATCH()
関数で名付けられたカラムが、テーブルの
FULLTEXT
インデックスのどれかに含まれるカラムと同じでなければなりません。先行のクエリーに関しては、MATCH()
関数で名付けられたカラム
(title
and
body
)
は、article
テーブルの
FULLTEXT
インデックスの定義で名付けられたものと同じです。title
と body
を別々に検索したい場合は、各カラムに別々の
FULLTEXT
インデックスを作成する必要があります。
また、ブール検索またはクエリー拡張との検索を行うことも可能です。これらの検索タイプは 項7.8.2. 「ブール全文検索」 と 項7.8.3. 「クエリー拡張を伴う全文検索」 で説明されています。
インデックスを用いた全文検索は、インデックスが複数のテーブルをまたぐことはできないため、MATCH()
節の単一テーブルからのカラムにしか名前が付けられません。ブール検索はインデックスがなくても行えます
(ただしスピードは落ちる)
。その場合、複数のテーブルからのカラムを名付けることは可能です。
先行の例は、関連性が減少する順序に行が戻される
MATCH()
関数の使い方を簡単に説明したものでした。次の例は関連値を明示的に引き出す方法です。SELECT
が WHERE
節も
ORDER BY
節も含んでいないため、行は順序付けられていません
:
mysql>SELECT id, MATCH (title,body)
->AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) AS score
->FROM articles;
+----+------------------+ | id | score | +----+------------------+ | 1 | 0.65545833110809 | | 2 | 0 | | 3 | 0.66266459226608 | | 4 | 0 | | 5 | 0 | | 6 | 0 | +----+------------------+ 6 rows in set (0.00 sec)
次の例はさらに複雑なものです。クエリーは関連値を返し、また、関連性が減少する順序に行をソートします。この結果を得るため、MATCH()
を 2 度指定してください : 一度は
SELECT
リスト、そしてもう一度は
WHERE
節で指定します。MySQL
の最適化プログラムが、ふたつの
MATCH()
呼び出しがまったく同じもので、全文検索コードを一度だけ実行されることに気付くため、これによって追加のオーバーヘッドが起こることはありません。
mysql>SELECT id, body, MATCH (title,body) AGAINST
->('Security implications of running MySQL as root'
->IN NATURAL LANGUAGE MODE) AS score
->FROM articles WHERE MATCH (title,body) AGAINST
->('Security implications of running MySQL as root'
->IN NATURAL LANGUAGE MODE);
+----+-------------------------------------+-----------------+ | id | body | score | +----+-------------------------------------+-----------------+ | 4 | 1. Never run mysqld as root. 2. ... | 1.5219271183014 | | 6 | When configured properly, MySQL ... | 1.3114095926285 | +----+-------------------------------------+-----------------+ 2 rows in set (0.00 sec)
MySQL FULLTEXT
の実装は、true 語文字
(文字、数字、および線文字)
のすべてのシークエンスを言葉みなします。そのシークエンスはまた、アポストロフィ
(「'
」)
も含む、1 行に 1
つのみです。つまり、aaa'bbb
は一語とみなされますが、aaa''bbb
は二語の扱いです。単語の頭または終わりのアポストロフィは、FULLTEXT
パーサーが取ってしまうので、'aaa'bbb'
ならば aaa'bbb
になります。
FULLTEXT
パーサーは特定の区切り文字を見て、語の頭と最後を定義します。その例には、「
」
(スペース)、「,
」
(コンマ)、および
「.
」
(ピリオド) があります。単語が非区切り文字
(たとえば中国語)
で区切られている場合は、FULLTEXT
パーサーは単語の最初と最後を定義することができません。単語や、インデックスのついたほかの表現をそのような言語で
FULLTEXT
インデックスに加えるには、事前に処理して
「"
」
などの任意の区切り文字で区切る必要があります。
MySQL 5.1
では、組み込まれたフルテキストパーサーを置き換えるプラグインを書くことができます。詳細については、The MySQL Plugin APIをご参照ください。たとえば、パーサプラグンのソースコードについては、MySQL
のソース配布物の
plugin/fulltext
ディレクトリをご覧ください。
単語のあるものは、全文検索では無視されます :
短すぎる単語は無視されます。全文検索で検出される言葉でもっとも短いものは 4 文字です。
ストップワードリストにある言葉は無視されます。ストップワードは 「the」 や 「some」 などの常用語で、語義の値はゼロとされています。すでに組み込まれているストップワードのリストがありますが、ユーザー定義リストで書き換えることができます。
デフォルトのストップワードリストは 項7.8.4. 「全文ストップワード」 で挙げられています。デフォルトの最短の単語の長さとストップワードリストは、項7.8.6. 「微調整 MySQL 全文検索」 で説明されているように変更することができます。
コレクションとクエリーの中のすべての正しい言葉は、コレクションまたはクエリーでの重要性によって加重されています。従って、多くの資料に登場する言葉は、このコレクションでは語義の値が低いので、比重が低く (あるものはゼロ) なっています。逆に、稀な言葉は高く重みづけがされます。言葉の比重は、行の関連性を計算するために組み合わせて応用されます。
このような技術は、コレクションが大きいほど効果的に作用します
(実際、そうなるように綿密に調整されています)
。ごく小さなテーブルでは、言葉の分配が語義の値を適切に反映しないため、この形式においてはときに不可解な結果が出ることがあります。たとえば、「MySQL」
という言葉は既出の
articles
テーブルのすべての行に含まれていますが、この単語で検索しても結果は出ません
:
mysql>SELECT * FROM articles
->WHERE MATCH (title,body)
->AGAINST ('MySQL' IN NATURAL LANGUAGE MODE);
Empty set (0.00 sec)
「MySQL」 という言葉は少なくとも 50 % の行で提示されているため、検索結果は空になります。このように、この言葉は効果的にストップワードとして扱われます。大きなデータセットでは、これはもっとも望ましい動作です。自然言語のクエリーは、1G バイトテーブルの毎 2 行目は戻さないようになっています。小さなデータセットにとっては、これはあまり望ましい動作ではありません。
テーブルの行の半分にマッチする言葉は、関連のある資料を見つけるのに適しません。事実、関連のないものも大量に検出されるでしょう。これはインターネットのサーチエンジンでの検索と同じ論理です。このため、この言葉を含む行は、「この特定のデータセットにおいて」語義の値が低く定められています。あるデータセットでは、提示された単語が 50% の境界値に達しても、ほかのデータセットではまた異なります。
50% の境界値は、全文検索を行うとその重要性が明らかになります : テーブルを作成し、テキストの 1 行または 2 行のみをインサートしてみると、テキストのすべての単語は少なくとも 50% の行に存在することが分かります。そのため、検出結果は検出されません。少なくとも 3 行以上をインサートするようにしてください。50% の制限を避ける必要がある場合は、ブール検索をお試しください。詳細は 項7.8.2. 「ブール全文検索」 をご覧ください。