MySQL Reference Manual for version 4.1.0-alpha.


6.8 MySQL 全文搜尋

到 3.23.23 時,MySQL 開始支援全文索引和搜尋。全文索引在 MySQL 中是一個 FULLTEXT 類型索引。FULLTEXT 索參照於 MyISAM 表,可以在 CREATE TABLE 時或之後使用 ALTER TABLECREATE INDEXCHARVARCHARTEXT 列上建立。對於大的資料庫,將資料裝載到一個沒有 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,'Optimising 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 索引中的一個或多個列的列集)執行一個自然語言搜尋一個字串。搜尋字串做為 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() 兩次。這不會引起附加的開銷,因為 MySQL 最佳化器會注意到兩次同樣的 MATCH() 調用,並只調用一次全文搜尋代碼。

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)

MySQL 使用一個非常簡單的剖析器來將純文字分隔成詞。一個“詞”是由文字、資料、“'”“_” 組成的任何字元序列。任何在 stopword 清單上出現的,或太短的(3 個字元或更少的)的 “word” 將被忽略。

在集和查詢中的每個合適的詞根據其在集與查詢中的重要性衡量。這樣,一個出現在多個文件中的詞將有較低的權重(可能甚至有一個零權重),因為在這個特定的集中,它有較低的語義值。否則,如果詞是較少的,它將得到一個較高的權重。然後,詞的權重將被結合用於計算記錄行的相似性。

這樣一個技術工作可很好地工作與大的集(實際上,它會小心地與之諧調)。 對於非常小的表,詞分類不足以充份地反應它們的語義值,有時這個樣式可能產生奇怪的結果。

mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('MySQL');
Empty set (0.00 sec)

在上面的範例中,搜尋詞 MySQL 卻沒有得到任何結果,因為這個詞在超過一半的記錄行中出現。同樣的,它被有效地處理為一個 stopword (即,一個零語義值的詞)。這是最理想的行為 -- 一個自然語言的查詢不應該從一個 1GB 的表中傳回每個次行(second row)。

相符表中一半記錄行的詞很少可能找到相關文件。實際上,它可能會發現許多不相關的文件。我們都知道,當我們在互聯網上通過搜尋引擎試圖搜尋某些東西時,這會經常發生。因為這個原因,在這個特殊的資料集中,這樣的行被設定一個低的語義值。

到 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 | Optimising 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 兩次的那個) 最列在最後,而不是第一位。一個邏輯全文搜尋即使在沒有一個 FULLTEXT 索引的情況下也可以工作,然而它 些。

邏輯全文搜尋支援下面的運算子:

+
一個領頭的加號表示,該詞必須出現在每個傳回的記錄行中。

-
一個領頭的減號表示,該詞必須不出現在每個傳回的記錄行中。

預設的 (當既沒有加號也沒有負號被指定時)詞是隨意的,但是包含它的記錄行將被排列地更高一點。這個模仿沒有 IN BOOLEAN MODE 修飾詞的 MATCH() ... AGAINST() 的行為。

< >
這兩個運算子用於改變一個詞的相似性值的基值。< 運算子減少基值,> 運算子則增加它。參看下面的範例。

( )
圓括號用於對幾表達式中的詞分組。

~
一個領頭的否定號的作用象一個否定運算子,引起行相似性的詞的基值為負的。它對標記一個噪聲詞很有用。一個包含這樣的詞的記錄將被排列得低一點,但是不會被完全的排除,因為這樣可以使用 - 運算子。

*
一個星號是截斷運算子。不想其它的運算子,它應該被追加到一個詞後,不加在前面。

"
短語,被包圍在雙引號"中,只相符包含這個短語(字面上的,就好像被輸入的)的記錄行。

這裡是一些範例:

apple banana
找至少包含上面詞中的一個的記錄行
+apple +juice
... 兩個詞均在被包含
+apple macintosh
... 包含詞 “apple”,但是如果同時包含 “macintosh”,它的排列將更高一些
+apple -macintosh
... 包含 “apple” 但不包含 “macintosh”
+apple +(>pie <strudel)
... 包含 “apple” 和 “pie”,或者包含的是 “apple” 和 “strudel” (以任何次序),但是 “apple pie” 排列得比 “apple strudel” 要高一點
apple*
... 包含 “apple”,“apples”,“applesauce” 和 “applet”
"some words"
... 可以包含 “some words of wisdom”,但不是 “some noise words”

6.8.1 全文的限制

6.8.2 微調 MySQL 全文搜尋

不幸地,全文搜尋仍然只有很少的使用者可調參數,雖然增加一些在 TODO 上排列很高。如果你有一個 MySQL 源碼發行(查看章節 2.3 安裝一個 MySQL 源碼發行),你可以發揮對全文搜尋的更多控制。

注意,全文搜尋為最佳的搜尋效果,被仔細地調整了。修改預設值的行為,在大多數情況下,只會使搜尋結果更糟。不要修改 MySQL 的來源碼,除非你知道你在做什麼!

對於這些變更,要求你重建你的 FULLTEXT 索引,對於一個 MyISAM 表,最容易的重建索引文件的方式如下面的語句:

mysql> REPAIR TABLE tbl_name QUICK;

6.8.3 全文搜尋 TODO