本篇單獨整理MySQL中用於高級數據查詢和選擇的全文本搜索功能。
一、認識全文本搜索
注意:並非所有的引擎都支持全文本搜索。兩個最常使用的引擎為MyISAM和InnoDB,前者支持全文本搜索,而后者不支持。如果應用中需要全文本搜索功能,應該記住這一點。
對於LIKE關鍵字及正則表達式匹配等文本搜索方式有幾個重要限制:
性能——通配符和正則表達式匹配通常要求MySQL嘗試匹配表中所有行(而且這些搜索極少使用表索引)。因此,由於被搜索行數不斷增加,這些搜索可能非常耗時。
明確控制——使用通配符和正則表達式匹配,很難(而且並不總是能)明確地控制匹配什么和不匹配什么。例如,指定一個詞必須匹配,一個詞必須不匹配,而一個詞僅在第一個詞確實匹配的情況下才可以匹配或者才可以不匹配。
智能化的結果——雖然基於通配符和正則表達式的搜索提供了非常靈活的搜索,但它們都不能提供一種智能化的選擇結果的方法。例如,一個特殊詞的搜索將會返回包含該詞的所有行,而不區分包含單個匹配的行和包含多個匹配的行(按照可能是更好的匹配來排列它們)。類似,一個特殊詞的搜索將不會找出不包含該詞但包含其他相關詞的行。
在使用全文本搜索時,MySQL不需要分別查看每個行,不需要分別分析和處理每個詞。MySQL創建指定列中各詞的一個索引,搜索可以針對這些詞進行。這樣,MySQL可以快速有效地決定哪些詞匹配(哪些行包含它們),哪些詞不匹配,它們匹配的頻率,等等。因此,使用全文本搜索時,必須索引被搜索的列,而且要隨着數據的改變不斷地重新索引。在對表列進行適當設計后,MySQL會自動進行所有的索引和重新索引。
二、使用全文本搜索關鍵字:fulltext(),match(),against()
in boolean mode
全文本搜索的兩種方式:
1、FULLTEXT索引:
實例1: 定義一個新表並列出它所包含的列
為了進行全文本搜索,MySQL根據子句FULLTEXT(note_text)的指示對它進行索引。這里的 FULLTEXT索引單個列,如果需要也可以指定多個列。在定義之后,MySQL自動維護該索引。在增加、更新或刪除行時,索引隨之自動更新。
可以在創建表時指定FULLTEXT,或者在稍后指定(在這種情況下所有已有數據必須立即索引)。
不要在導入數據時使用FULLTEXT: 更新索引要花一點時間,如果正在導入數據到一個新表,此時不應該啟用FULLTEXT索引。應該首先導入所有數據,然 后再修改表,定義FULLTEXT。這樣有助於更快地導入數據(而且使索引數據的總時間小於在導入每行時分別進行索引所需的總時間)。
實例2:檢索單個列note_text中含有特定文本的行
Match()指定被搜索的列。傳遞給Match()的值必須與FULLTEXT()定義中的相同。如果指定多個列,則必須列出它們(而且次序正確)。
Against()指定要使用的搜索表達式。
全文本搜索不區分大小寫,若需要區別,則可以使用BINARY方式(以后詳細介紹)
利用 LIKE 可以得到相同的結果,但是結果並不一定是有效排序。使用全文本搜索返回以文本匹配的良好程度排序(具有較高等級的行先返回)的數據。全文本搜索的一個重要部分就是對結果排序。
如果指定多個搜索項,則包含多數匹配詞的那些行將具有比包含較少詞(或僅有一個匹配)的那些行高的等級值。
查詢擴展:用來設法放寬所返回的全文本搜索結果的范圍。只用於MySQL版本4.1.1或更高級的版本
實例3:找出所有提到anvils的注釋,包括可能與其有關的所有其他行,即使它們不包含詞anvils(查詢擴展)
第一行包含詞anvils,因此等級最高。第二 行與anvils無關,但因為它包含第一行中的兩個詞(customer 和recommend),所以也被檢索出來。第3行也包含這兩個相同的詞,但它們在文本中的位置更靠后且分開得更遠,因此也包含這一行,但等級為第三。第三行確實也沒有涉及anvils(按它們的產品名)
使用查詢擴展時,MySQL對數據和索引進行兩遍掃描來完成搜索:
1. 進行一個基本的全文本搜索,找出與搜索條件匹配的所有行;
2. MySQL檢查這些匹配行並選擇所有有用的詞(我們將會簡要地解釋MySQL如何斷定什么有用,什么無用)。
3. MySQL再次進行全文本搜索,這次不僅使用原來的條件, 而且還使用所有有用的詞。
利用查詢擴展,能找出可能相關的結果,即使它們並不精確包含所查找的詞。 表中的行越多(這些行中的文本就越多),使用查詢擴展返回的結果越好。
2、布爾文本搜索
注意:布爾搜索不需要FULLTEXT索引,但是搜索速率較低(性能將隨着數據量的增加而降低)。
通過布爾方式可以得到:
1、 要匹配的詞;
2、要排斥的詞(如果某行包含這個詞,則不返回該行,即使它包含 其他指定的詞也是如此);
3、排列提示(指定某些詞比其他詞更重要,更重要的詞等級更高);
4、表達式分組;
5、另外一些內容。
實例4:
兩個對比可以看出,第一個例子由於沒有指定布爾操作符,因此,看上去其結果與沒有指定布爾方式相同;第二個例子中,-rope*明確地指示MySQL排除包含rope*(任何以rope開始的詞,包括 ropes)的行,因此第一個例子中的第一行被排除。
附:
實例5:搜索匹配包含rabbit和bait中的至少一 個詞的行
該例子中沒有指定操作符。若為’+rabbit +bait’ 則搜索匹配包含詞rabbit和bait的行
實例6:匹配短語rabbit bait(而不是匹配兩個詞rabbit和 bait)
補充說明:
在布爾方式中,不按等級值降序排序返回的行。
在索引全文本數據時,短詞被忽略且從索引中排除。短詞定義為那些具有3個或3個以下字符的詞(如果需要,這個數目可以更改)。
MySQL帶有一個內建的非用詞(stopword)列表,這些詞在索引全文本數據時總是被忽略。如果需要,可以覆蓋這個列表(請參閱MySQL文檔以了解如何完成此工作)。
許多詞出現的頻率很高,搜索它們沒有用處(返回太多的結果)。因此,MySQL規定了一條50%規則,如果一個詞出現在50%以上的行中,則將它作為一個非用詞忽略。50%規則不用於IN BOOLEAN MODE。
如果表中的行數少於3行,則全文本搜索不返回結果(因為每個詞或者不出現,或者至少出現在50%的行中)。
忽略詞中的單引號。例如,don’t索引為dont。
不具有詞分隔符(包括日語和漢語)的語言不能恰當地返回全文本搜索結果。
僅在MyISAM數據庫引擎中支持全文本搜索。
沒有鄰近操作符。鄰近搜索是許多全文本搜索支持的一個特性,它能搜索相鄰的詞(在相同的句子中、相同的段落中或者在特定數目的詞的部分中,等等)。MySQL全文本搜索現在還不支持鄰近操作符,不過未來的版本有支持這種操作符的計划