MySQL-全文本搜索(學習如何使用MySQL的全文本搜索功能進行高級的數據查詢。)


  並非所有引擎都支持全文本搜索MySQL。與所有其他的DBMS一樣,MySQL具有一個具體管理和處理數據的內部引擎。在你使用CREATE TABLE語句時,該引擎具體創建表,而在你使用SELECT語句或進行其它的數據庫處理時,該引擎在內部處理你的請求。多數時候,該引擎都隱藏在DBMS內,不需要過多關注它。

  但MySQL與其它的DBMS不一樣,它具有多種引擎。它打包多個引擎,這些引擎都隱藏在MySQL服務器內,全都能執行CREATE TABLE與SELECT命令。

  為什么要發行多種引擎呢?因為它們具有不同的功能和特性,為不同的任務選擇正確的引擎獲得良好的功能和靈活性。

  當然,你可以忽略這些數據庫引擎。如果省略ENGINE=語句,則使用默認引擎(很可能是MyISAM),多數SQL語句都會默認使用它。但不是所有的語句都默認使用它,這就是為什么ENGINE=語句很重要的原因。

  以下是幾個需要知道的引擎:

  1.InnoDB是一個可靠的事務處理引擎,它不支持全文本搜索。

  2.MEMORY在功能等同於MyISAM,但由於數據存儲在內存(不是磁盤)中,速度很快(特別適合於臨時表)

  3.MyISAM是一個性能極高的引擎,它支持全文本搜索,但不支持事務處理。

  所支持引擎的完整列表(及它們之間的不同),請參閱(http://dev.mysql.com/doc/refman/5.0/en/storage_engines.html)

 

  LIKE關鍵字,利用通配操作符匹配文本(和部分文本)。使用LIKE,能夠查找包含特殊值或部分值得行(不管這些值位於列內的什么位置)。

  用基於文本的搜索作為正則表達式匹配列值,使用正則表達式,可以編寫查找所需行的非常復雜的匹配模式。

  雖然這些搜索機制非常有用,但存在幾個重要的機制。

  1.性能:通配符和正則表達式匹配通常要求MySQL嘗試匹配表中所有行(而且這些搜索極少使用表索引)。因此,由於被搜索行數不斷增加,這些搜索可能非常耗時。

  2.明確控制:使用通配符和正則表達式匹配,很難(而且並不總是能)明確地控制匹配什么和不匹配什么。例如,指定一個詞匹配和指定一個詞不匹配....

  3.智能化的結果:雖然基於通配符和正則表達式的搜索提供了非常靈活的搜索,但它們都不能提供一種智能化的選擇結果的方法。例如:一個特殊詞的搜索將會返回包含這些詞的所有行,而不區分包含單個匹配的行和包含多個匹配的行(按照可能是更好地匹配來排列它們)。類似,一個特殊詞的搜索將不會找出不包含該詞但包含其他相關詞的行。

  所有這些限制以及更多的限制都可以用全文本搜索來解決,在使用全文本搜索時,MySQL不需要分別查看每個行,不需要分別分析和處理每個詞。MySQL創建指定列中各詞的一個索引,搜索可以針對這些詞進行。這樣,MySQL可以快速有效的決定那些詞分配(那些行包含它們),那些詞不匹配,它們匹配的頻率,等等。

  使用全文本搜索

  為了進行全文本搜索,必須索引被搜索的列,而且要隨着數據的改變不斷重新索引。在對表列進行適當的設計后,MySQL會自動進行所有的索引和重新索引。

  在索引之后,SELECT可與Match()和Against()一起使用以實際執行搜索。

  啟用全文本搜索

  一般在創建表時啟用全文本搜索。CREATE TABLE接受FULLTEXT字句,它給出被索引列的一個逗號分隔的列表。

  下面的CREATE語句演示了FULLTEXT字句的使用:

CREATE TABLE productnotes           
(
    note_id int NOT NULL AUTO_INCREMENT,
    prod_id char(10) NOT NULL,
    note_text text NOT NULL,
    note_date datetime NOT NULL,
    PRIMARY KEY(note_id),
    FULLTEXT(note_text)
)ENGINE=MyISAM;

  這些列中有一個名為note_text的列,為了進行全文本搜索,MySQL根據字句FULLTEXT(note_text)的指示對它進行了索引,這里的FULLTEXT索引單個列,如果需要也可以指定多個列。

  在定義之后,MySQL自動維護該索引。在增加、更新或刪除行時,索引隨之自動更新。

  可以在創建表時指定FULLTEXT,或者在稍后指定。但是不要在導入數據時使用FULLTEXT,因為更新索引需要時間,雖然不是很多,但畢竟要花時間。如果正在導入數據到一個新表,此時不應該啟用FULLTEXT索引。應該首先導入所有數據,然后在修改表,定義FULLTEXT,這要有助於更快地導入數據(而且使索引的總時間小於在導入每行每行時分別進行索引所需的總時間)。

  進行全文本搜索

  在索引之后,使用兩個函數Match()和Against()函數執行全文本搜索,其中Match指定被搜索的列,Against指定要使用的搜索表達式。

SELECT note_text
 FROM productnotes
WHERE Match(note_text) Against('rabbit');

  輸出:note_text

  此SELECT語句檢索單個列note_text。由於WHERE子句,一個全文本搜索被執行。Match(note_text)指示MySQL針對指定的列進行搜索,Against('rabbit')指定詞rabbit作為搜索文本)。由於有兩行包含詞rabbit,這兩個行被返回。

  注意:使用完整的Match()說明,傳遞給Match()的值必須與FULLTEXT()定義中的相同。如果指定多個列,則必須列出它們(而且次序必須正確)。

  搜索不區分大小寫,除非使用BINARY方式,否則全文本搜索不區分大小寫。

  事實是剛才的搜索可以簡單的用LIKE子句完成,如下所示:

SELECT note_text
FROM productnotes
WHERE note_text LIKE '%rabbit%';

  檢索結果相同,但是次序不同!(雖然並不是總是出現這種情況);

  已知上述兩條SELECT語句都不包含ORDER BY子句。后者(LIKE)以不特別有用的順序返回數據。前者(使用全文本搜索)返回以文本匹配的良好程度排序的數據。兩個行都包含詞rabbit,但包含詞rabbit作為第3個詞的行的等級比作為第20個詞的行高。這很重要,全文本搜索的一個重要部分就是對結果進行排序,具有較高等級的行先返回(因為這些可能是你真正想要的行)。

  如何查看等級呢?如下所示:

SELECT note_text,Match(note_text) Against('rabbit') AS rank
FROM productnotes

  這里,在SELECT而不是WHERE子句中石油Match()和Against()。這使所有行都被返回(因為沒有WHERE子句)。Match()和Against()用來簡歷一個計算列(別名為rank),此列包含全文本搜索計算出的等級值。等級由MySQL根據行的數目計算出來。正如縮減,不包含rabbit的行等級為0。確實包含rabbit的兩行都有一個等級值,文本中詞靠前的行等級比詞靠后的行的等級值高。

  這個例子有助於說明全文本搜索如何排除行(排除那些等級為0的行),如何排序結果(按等級以降序排序)

  排序多個搜索項:如果指定多個搜索項,則包含多數匹配詞的那些航將具有比包含較少詞(或僅有一個匹配)的哪些行高的等級值。

  正如所見,全文本搜索提供了簡單的LIKE搜索所不能提供的功能。而且,由於數據時索引的,全文本搜索還相當快

  使用查詢擴展

  查詢擴展是用來設法放寬所返回的全文本搜索結果的范圍。在使用查詢擴展時,MySQL對數據和索引進行兩邊掃描來完成搜索。

  1.首先,進行一個基本的全文本搜索,找出與搜索條件匹配的所有行。

  2.其次,MySQL檢查這些匹配行並選擇所有有用的詞。(什么是有用?無用?

  3.再其次,MySQL再次進行全文本搜索,這次不僅使用原來的條件,而且還使用有用的詞。

  利用查詢擴展,能找出所有可能相關的結果,即時它們並不精確包含所有查找的詞。

  查詢擴展功能是MySQL4.1.1中引入的。因此不能用於之前的版本。

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION)

  布爾文本搜索

  MySQL支持全文本搜索的另一種形式:稱為布爾方式(boolean mode)。以布爾方式,可以提供關於如下內容的細節:

  1.要匹配的詞;

  2.要排斥的詞(如果某行包含這個詞,則不反含該行,即時它包含其他指定的詞也是如此);

  3:排列提示:(指定某些詞比其它詞更重要,更重要的詞的等級高);

  4:表達式分組;

  5:另外一些內容;

  布爾文本搜索即使沒有FULLTEXT索引也可以使用,布爾方式不同於迄今為止使用的全文本搜索搜索語法的地方在於,即使沒有定義FULLTEXT索引,也可以使用它。但這是一種非常緩慢的操作(其性能將隨着數據量的添加而降低)。

  為演示IN BOOLEAN MODE的作用,例子如下:

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy' IN BOOLEAN MODE);

  此全文本搜索檢索包含詞heavy的所有行(有兩行)。其中使用了關鍵字IN BOOLEAN MODE,但實際上沒有指定布爾操作符,因此,其結果與沒有指定布爾方式的結果相同。

  為了匹配包含heavy但不包含任意以rope開始的詞的所有行,可使用如下查詢:

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE);

  我們已經看到可兩個全文本搜索布爾操作符 - 和 * ,- 排除一個詞,而 * 是截斷操作符(可想象為用於詞尾的一個通配符)。下列所見為MySQL支持的布爾操作符:

                             全文本布爾操作符

布爾操作符 說明
+ 包含,詞必須存在
- 排除,詞必須不出現
> 包含,而且增加等級值
< 包含,且減少等級值
() 把詞組成子表達式(允許這些子表達式作為一個組被包含、排除、排列等)
~ 取消一個詞的牌謔值
* 詞尾的通配符
"" 定義一個短語(與單個詞的列表不一樣,它匹配整個短語以便包含或排除這個短語)

  

 下面舉幾個例子,說明這些操作符如何使用:

  

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+rabbit +bait' IN BOOLEAN MODE);
這個搜索匹配包含詞rabbit和bait的行


SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit bait' IN BOOLEAN MODE);
沒有指定操作符,這個搜索匹配包含詞rabbit和bait中的至少一個詞的行;


SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('“rabbit bait”' IN BOOLEAN MODE);
這個搜索匹配短語rabbit bait,而不是匹配兩個詞;



SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('>rabbit <carrot' IN BOOLEAN MODE);
這個搜索匹配rabbit 和carrot,增加前者的等級,降低后者的等級;


SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+safe +(<combination)' IN BOOLEAN MODE);
這個搜索匹配safe 和combination,降低后者的等級;

  全文本搜索數據時,短詞被忽略而且從索引中刪除。短詞定義為那些具有3個或者3個以下字符的詞(如果需要,這個數目可以修改)。

  許多詞出現的頻率高,搜索它們沒有用處(返回太多的結果),因此,MySQL定義了一條50%的規則,如果一個詞出現在50%以上的行中,則將它作為一個非用詞忽略。50%規則不用於IN BOOLEAN MODE

  如果表中的行數小於3行,則全文本搜索將不返回結果(因為每個詞或者不出現,或者至少出現在50%的行中)。

  忽略詞中的單引號 ' 。

  盡在MyISAM的數據庫引擎中支持全文本搜索。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM