MySQL - 第十九章 | 全文本搜索(下)
使用查詢擴展
查詢擴展用來設法放寬所返回的全文本搜索結果的範圍。考慮下面 的情況。你想找出所有提到anvils的注釋。只有一個注釋包含詞anvils,但你還想找出可能與你的搜索有關的所有其他行,即使它們不包含詞anvils。
這也是查詢擴展的一項任務。在使用查詢擴展時,MySQL對資料和索引進行兩遍掃描來完整搜索:
- 首先,進行一個基本的全文本搜索,找出與搜索條件匹配的所有行;
- 其次,MySQL檢查這些匹配行並選擇所有有用的詞(我們將會簡要地解釋MySQL如何斷定什麼有用,什麼無用)。
- 再其次,MySQL再次進行全文本搜索,這次不僅使用原來的條件,而且還使用所有有用的詞。
利用查詢擴展,能找出可能相關的結果,即使它們並不精確包含所查找的詞。
首先進行一個簡單的全文本搜索,沒有查詢擴展:
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils'); |
分析:只有一行包含詞anvils,因此只返回一行。
下面是相同的搜索,這次使用查詢擴展:
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION); |
分析:這次返回了7行。第一行包含詞anvils,因此等級最高。第二行與anvils無關,但因為它包含第一行中的兩個詞(customer和recommend),所以也被檢索出來。第3行也包含這兩個相同的詞,但它們在文本中的位置更靠後且分開得更遠,因此也包含這一行,但等級為第三。第三行確實也沒有涉及anvils(按它們的產品名)。
正如所見,查詢擴展極大地增加了返回的行數,但這樣做也增加了你實際上並不想要的行的數目。
提示:行越多越好 表中的行越多(這些行中的文本就越多),使用查詢擴展返回的結果越好。
布林文本搜索
MySQL支持全文本搜索的另外一種形式,稱為布林方式(boolean mode)。以布林方式,可以提供關於如下內容的細節:
- 要匹配的詞;
- 要排斥的詞(如果某行包含這個詞,則不返回該行,即使它包含其他指定的詞也是如此);
- 排列提示(指定某些詞比其他詞更重要,更重要的詞等級更高);
- 表達式分組;
- 另外一些內容。
提示:即使沒有FULLTEXT索引也可以使用 布林方式不同於迄今為止使用的全文本搜索語法的地方在於,即使沒有定義FULLTEXT索引,也可以使用它。但這是一種非常緩慢的操作(其性能將隨著資料量的增加而降低)。
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy' IN BOOLEAN MODE); |
分析:此全文本搜索檢索包含詞heavy的所有行(有兩行)。其中使用了關鍵字IN BOOLEAN MODE,但實際上沒有指定布林操作符,因此,其結果與沒有指定布林方式的結果相同。
說明:IN BOOLEAN MODE的行為差異 雖然這個例子的結果與沒有IN BOOLEAN MODE的相同,但其行為有一個重要的差別(即使在這個特殊的例子沒有表現出來)。
為了匹配包含heavy但不包含任意以rope開始的詞的行:
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('heavy -rope*' IN BOOLEAN MODE); |
分析:這次只返回一行。這一次仍然匹配詞heavy,但-rope明確地指示MySQL排除包含rope(任何以rope開始的詞,包括ropes)的行,這就是為什麼上一個例子中的第一行被排除的原因。
目前介紹了兩個全文本搜索布林操作符-和,-排除一個詞,而是截斷操作符(可想象為用於詞尾的一個萬用字元)。
布林操作符 | 說明 |
---|---|
+ | 包含,詞必須存在 |
- | 排除,詞必須不出現 |
> | 包含,而且增加等級值 |
< | 包含,且減少等級值 |
() | 把詞組成子表達式(允許這些子表達式作為一個組被包含、排除、排列等) |
~ | 取消一個詞的排序值 |
* | 詞尾的萬用字元 |
"" | 定義一個短語(與單個詞的列表不一樣,它匹配整個短語以便包含或排除這個短語) |
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('+rabbit +bait' IN BOOLEAN MODE); |
分析:這個搜索匹配包含詞rabbit和bait的行。
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('rabbit bait' IN BOOLEAN MODE); |
分析:沒有指定操作符,這個搜索匹配包含rabbit和bait中的至少一個詞的行。
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('"rabbit bait"' IN BOOLEAN MODE); |
分析:這個搜索匹配短語rabbit bait而不是匹配兩個詞rabbit和bait。
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('>rabbit <carrot"' IN BOOLEAN MODE); |
分析:匹配rabbit和carrot,增加前者的等級,降低後者的等級。
1 | mysql> SELECT note_text FROM productnotes WHERE Match(note_text) Against('+safe +(<combination)' IN BOOLEAN MODE); |
分析:這個搜索匹配詞safe和combination,降低後者的等級。
說明:排列而不排序 在布林方式中,不按等級值降序排序返回的行。
全文本搜索的使用說明
關於全文本搜索的某些重要的說明。
- 在索引全文本資料時,短詞被忽略且從索引中排除。短詞定義為那些具有3個或3個以下字符的詞(如果需要,這個數目可以更改)。
- MySQL帶有一個內建的非用詞(stopword)列表,這些詞在索引全文本資料時總是被忽略。
- 許多詞出現的頻率很高,搜索它們沒有用處(返回太多的結果)。因此,MySQL規定了一條50%規則,如果一個詞出現在50%以上的行中,則將它作為一個非用詞忽略。50%規則不用於IN BOOLEAN MODE。
- 如果表中的行數少於3行,則全文本搜索不返回結果(因為每個詞或者不出現,或者至少出現在50%的行中)。
- 忽略詞中的單引號。例如,don’t索引為dont。
- 不具有詞分隔符(包括日語和漢語)的語言不能恰當地返回全文本搜索結果。
- 如前所述,僅在MyISAM資料庫引擎中支持全文本搜索。
說明:沒有鄰近操作符 鄰近搜索是許多全文本搜索支持的一個特性,它能搜索相鄰的詞(在相同的句子中、相同的段落中或者在特定數目的詞的部分中,等等)。MySQL全文本搜索現在還不支持鄰近操作符,不過未來的版本有支持這種操作符的計劃。
結語
這邊主要學到如何使用MySQL的 Match()和Against()函數進行全文本搜索,還有查詢擴展。我只能說這塊我可以說完全沒碰過。希望在將來有機會用到這樣的語法來應用在專案上面。
註:以上參考了
MySQL必知必会 MySQL Crash Course