如何使用MySQL的全文本搜索功能

1.全文本搜索

1.1理解全文本搜索

並非所有引擎都支持全文本搜索
兩個最常使用的引擎爲MyISAM和InnoDB,前者支持全文本搜索,而後者不支持這就是爲什麼雖然本書中創建的多數樣例表使用InnoDB,而有一個樣例表(productnotes表)卻使用MyISAM的原因。

一些搜索機制的限制如下:

  • 性能——通配符和正則表達式匹配通常要求MySQL嘗試匹配表中所有行(而且這些搜索極少使用表索引)。因此,由於被搜索行數不斷增加,這些搜索可能非常耗時
  • 明確控制——使用通配符和正則表達式匹配,很難(而且並不總是能)明確地控制匹配什麼和不匹配什麼。例如,指定一個詞必須匹配,一個詞必須不匹配,而一個詞僅在第一個詞確實匹配的情況下纔可以匹配或者纔可以不匹配。
  • 智能化的結果——雖然基於通配符和正則表達式的搜索提供了非常靈活的搜索,但它們都不能提供一種智能化的選擇結果的方法。例如,一個特殊詞的搜索將會返回包含該詞的所有行,而不區分包含單個匹配的行和包含多個匹配的行(按照可能是更好的匹配來排列它們)。類似,一個特殊詞的搜索將不會找出不包含該詞但包含其他相關詞的行。

所有這些限制以及更多的限制都可以用全文本搜索來解決。

2.使用全文搜索

2.1啓用全文本搜索支持

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

下面的 CREATE語句演示了FULL TEXT子句的使用:
輸入

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

分析:這條CREATE TABLE語句定義表productnotes並列出它所包含的列。
這些列中有一個名爲note_text的列,爲了進行全文本搜索,MySQL根據子句FULLTEXT(note_text)的指示對它進行索引。這裏的FULLTEXT索引單個列,如果需要也可以指定多個列。

在定義之後,MySQL自動維護該索引。在增加、更新或刪除行時,索引隨之自動更新。可以在創建表時指定FULLTEXT,或者在稍後指定(在這種情況下所有已有數據必須立即索引)。

2.2進行全文本搜索

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

下面舉一個例子:
輸入

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

輸出
在這裏插入圖片描述
分析:此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%';

輸出
使用LIKE語句
分析:這條SELECT語句同樣檢索出兩行,但次序不同(雖然並不總是出現這種情況)。上述兩條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的行),如何排序結果(按等級以降序排序)。

2.3使用查詢擴展

查詢擴展用來設法放寬所返回的全文本搜索結果的範圍。

你想找出所有提到anvils的註釋。只有一個註釋包含詞anvils,但你還想找出可能與你的搜索有關的所有其他行,即使它們不包含詞anvils。 這也是查詢擴展的一項任務。

輸入

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

輸出
在這裏插入圖片描述
分析:這次返回了7行。第一行包含詞anvils,因此等級最高。第二行與anvils無關,但因爲它包含第一行中的兩個詞(customer和recommend),所以也被檢索出來。第3行也包含這兩個相同的詞,但它們在文本中的位置更靠後且分開得更遠,因此也包含這一行,但等級爲第三。第三行確實也沒有涉及anvils(按它們的產品名)。

行越多越好 表中的行越多(這些行中的文本就越多),使用查詢擴展返回的結果越好。

2.4布爾文本搜索

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

  • 要匹配的詞;
  • 要排斥的詞(如果某行包含這個詞,則不返回該行,即使它包含其他指定的詞也是如此);
  • 排列提示(指定某些詞比其他詞更重要,更重要的詞等級更高);
  • 表達式分組;
  • 另外一些內容。

爲演示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);

輸出
在這裏插入圖片描述
分析:這次只返回一行。這一次仍然匹配詞heavy,但-rope*明確地指示MySQL排除包含rope*(任何以rope開始的詞,包括ropes)的行,這就是爲什麼上一個例子中的第一行被排除的原因。

全文本布爾操作符

在這裏插入圖片描述
例子如下:

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+safe +(<combination)' IN BOOLEAN MODE);

分析:這個搜索匹配詞safe和combination,降低後者的等級。

2.5全文搜索的使用說明

關於全文本搜索的某些重要的說明:

  • 在索引全文本數據時,短詞被忽略且從索引中排除。短詞定義爲那些具有3個或3個以下字符的詞(如果需要,這個數目可以更改)。
  • MySQL帶有一個內建的非用詞(stopword)列表,這些詞在索引全文本數據時總是被忽略。如果需要,可以覆蓋這個列表(請參閱MySQL文檔以瞭解如何完成此工作)。
  • 許多詞出現的頻率很高,搜索它們沒有用處(返回太多的結果)。因此,MySQL規定了一條50%規則,如果一個詞出現在50%以上的行中,則將它作爲一個非用詞忽略。50%規則不用於IN BOOLEAN MODE
  • 如果表中的行數少於3行,則全文本搜索不返回結果(因爲每個詞或者不出現,或者至少出現在50%的行中)。
  • 忽略詞中的單引號。例如,don’t索引爲dont。
  • 不具有詞分隔符(包括日語和漢語)的語言不能恰當地返回全文本搜索結果。
  • 如前所述,僅在MyISAM數據庫引擎中支持全文本搜索
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章