MySQL基礎教程10 —— 函數之全文搜索功能
語法:
MATCH (col1,col2,...) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION])MySQL支持全文索引和搜索功能。MySQL中的全文索引類型FULLTEXT的索引。 FULLTEXT索引僅可用于MyISAM表;他們可以從CHAR、VARCHAR或TEXT列中作為CREATE TABLE語句的一部分被創建,或是隨后使用ALTER TABLE或CREATE INDEX被添加。對于較大的數據集,將你的資料輸入一個沒有FULLTEXT索引的表中,然后創建索引, 其速度比把資料輸入現有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 (title,body) VALUES -> (’MySQL Tutorial’,’DBMS stands for DataBase ...’), -> (’How To Use MySQL Well’,’After you went through a ...’), -> (’Optimizing MySQL’,’In this tutorial we will show ...’), -> (’1001 MySQL Tricks’,’1. Never run mysqld as root. 2. ...’), -> (’MySQL vs. YourSQL’,’In the following database comparison ...’), -> (’MySQL Security’,’When configured properly, MySQL ...’);Query OK, 6 rows affected (0.00 sec)Records: 6 Duplicates: 0 Warnings: 0mysql> 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()函數對于一個字符串執行資料庫內的自然語言搜索。一個資料庫就是1套1個或2個包含在FULLTEXT內的列。搜索字符串作為對AGAINST()的參數而被給定。對于表中的每一行, MATCH()返回一個相關值,即,搜索字符串和MATCH()表中指定列中該行文字之間的一個相似性度量。
在默認狀態下,搜索的執行方式為不區分大小寫方式。然而,你可以通過對編入索引的列使用二進制排序方式執行區分大小寫的全文搜索。例如,可以向一個使用latin1字符集的列給定latin1_bin的排序方式,對于全文搜索區分大小寫。
如上述所舉例子,當MATCH()被用在一個WHERE語句中時,相關值是非負浮點數。零相關的意思是沒有相似性。相關性的計算是基于該行中單詞的數目,該行中獨特子的數目,資料庫中單詞的總數,以及包含特殊詞的文件(行)數目。
對于自然語言全文搜索,要求MATCH()函數中命名的列和你的表中一些FULLTEXT索引中包含的列相同。對于前述問訊, 注意,MATCH()函數(題目及全文)中所命名的列和文章表的FULLTEXT索引中的列相同。若要分別搜索題目和全文,應該對每個列創建FULLTEXT索引。
或者也可以運行布爾搜索或使用查詢擴展進行搜索。
上面的例子基本上展示了怎樣使用返回行的相關性順序漸弱的MATCH()函數。而下面的例子則展示了怎樣明確地檢索相關值。返回行的順序是不定的,原因是 SELECT語句不包含WHERE或ORDER BY子句:
mysql> SELECT id, MATCH (title,body) AGAINST (’Tutorial’) -> FROM articles;+----+-----------------------------------------+| id | MATCH (title,body) AGAINST (’Tutorial’) |+----+-----------------------------------------+| 1 | 0.65545833110809 || 2 | 0 || 3 | 0.66266459226608 || 4 | 0 || 5 | 0 || 6 | 0 |+----+-----------------------------------------+6 rows in set (0.00 sec)
下面的例子則更加復雜。詢問返回相關值,同時對行按照相關性漸弱的順序進行排序。為實現這個結果,你應該兩次指定MATCH(): 一次在SELECT列表中而另一次在WHERE子句中。這不會引起額外的內務操作,原因是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.5219271183014 || 6 | When configured properly, MySQL ... | 1.3114095926285 |+----+-------------------------------------+-----------------+2 rows in set (0.00 sec)
表中有2行(0.00秒)
MySQL FULLTEXT執行將任何單字字符原形(字母、數字和下劃線部分)的序列視為一個單詞。這個序列或許也包含單引號(’),但在一行中不會超過一個。 這意味著aaa’bbb會被視為一個單詞,而aaa’’bbb則被視為2個單詞。位于單詞之前或其后的單引號會被FULLTEXT分析程序去掉;’aaa’bbb’會變成 aaa’bbb。
FULLTEXT分析程序會通過尋找某些分隔符來確定單詞的起始位置和結束位置,例如’ ’ (間隔符號)、, (逗號)以及. (句號)。假如單詞沒有被分隔符分開,(例如在中文里),則FULLTEXT分析程序不能確定一個詞的起始位置和結束位置。為了能夠在這樣的語言中向FULLTEXT索引添加單詞或其它編入索引的術語,你必須對它們進行預處理,使其被一些諸如'之類的任意分隔符分隔開。
一些詞在全文搜索中會被忽略:
任何過于短的詞都會被忽略。 全文搜索所能找到的詞的默認最小長度為4個字符。停止字中的詞會被忽略。禁用詞就是一個像“the” 或“some” 這樣過于平常而被認為是不具語義的詞。存在一個內置的停止字, 但它可以通過用戶自定義列表被改寫。詞庫和詢問中每一個正確的單詞根據其在詞庫和詢問中的重要性而被衡量。通過這種方式,一個出現在許多文件中的單詞具有較低的重要性(而且甚至很多單詞的重要性為零),原因是在這個特別詞庫中其語義價值較低。反之,假如這個單詞比較少見,那么它會得到一個較高的重要性。然后單詞的重要性被組合,從而用來計算該行的相關性。
這項技術最適合同大型詞庫一起使用(事實上,此時它經過仔細的調整)。對于很小的表,單詞分布并不能充分反映它們的語義價值, 而這個模式有時可能會產生奇特的結果。例如,雖然單詞 “MySQL” 出現在文章表中的每一行,但對這個詞的搜索可能得不到任何結果:
mysql>SELECT * FROM articles
->WHERE MATCH (title,body) AGAINST (’MySQL’);
找不到搜索的詞(0.00秒)
這個搜索的結果為空,原因是單詞 “MySQL” 出現在至少全文的50%的行中。 因此,它被列入停止字。對于大型數據集,使用這個操作最合適不過了----一個自然語言問詢不會從一個1GB的表每隔一行返回一次。對于小型數據集,它的用處可能比較小。
一個符合表中所有行的內容的一半的單詞查找相關文檔的可能性較小。事實上,它更容易找到很多不相關的內容。我們都知道,當我們在因特網上試圖使用搜索引擎尋找資料的時候,這種情況發生的頻率頗高。可以推論,包含該單詞的行因其所在特別數據集而被賦予較低的語義價值。 一個給定的詞有可能在一個數據集中擁有超過其50%的域值,而在另一個數據集卻不然。
當你第一次嘗試使用全文搜索以了解其工作過程時,這個50%的域值提供重要的蘊涵操作:若你創建了一個表,并且只將文章的1、2行插入其中, 而文中的每個單詞在所有行中出現的機率至少為 50%。那么結果是你什么也不會搜索到。一定要插入至少3行,并且多多益善。需要繞過該50%限制的用戶可使用布爾搜索代碼。
1.布爾全文搜索利用IN BOOLEAN MODE修改程序,MySQL也可以執行布爾全文搜索:
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 Well | After you went through a ... || 3 | Optimizing 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”的行,但不檢索包含單詞“YourSQL”的行。
布爾全文搜索具有以下特點:
它們不使用50%域值。.它們不會按照相關性漸弱的順序將行進行分類。你可以從上述問詢結果中看到這一點:相關性最高的行是一個包含兩個“MySQL” 的行,但它被列在最后的位置,而不是開頭位置。即使沒有FULLTEXT,它們仍然可以工作,盡管這種方式的搜索執行的速度非常之慢。最小單詞長度全文參數和最大單詞長度全文參數均適用。停止字適用。布爾全文搜索的性能支持以下操作符:
+一個前導的加號表示該單詞必須出現在返回的每一行的開頭位置。
-一個前導的減號表示該單詞一定不能出現在任何返回的行中。
(無操作符)在默認狀態下(當沒有指定+或–的情況下),該單詞可有可無,但含有該單詞的行等級較高。這和MATCH() ... AGAINST()不使用IN BOOLEAN MODE修改程序時的運作很類似。
> <這兩個操作符用來改變一個單詞對賦予某一行的相關值的影響。>操作符增強其影響,而<操作符則減弱其影響。請參見下面的例子。
( )括號用來將單詞分成子表達式。括入括號的部分可以被嵌套。
~一個前導的代字號用作否定符, 用來否定單詞對該行相關性的影響。 這對于標記“noise(無用信息)”的單詞很有用。包含這類單詞的行較其它行等級低,但因其可能會和-號同時使用,因而不會在任何時候都派出所有無用信息行。
*星號用作截斷符。于其它符號不同的是,它應當被追加到要截斷的詞上。
'一個被括入雙引號的短語(‘'’)只和字面上包含該短語輸入格式的行進行匹配。全文引擎將短語拆分成單詞,在FULLTEXT索引中搜索該單詞。非單詞字符不需要嚴密的匹配:短語搜索只要求符合搜索短語包含的單詞且單詞的排列順序相同的內容。例如,'test phrase'符合'test, phrase'。
若索引中不存在該短語包含的單詞,則結果為空。例如,若所有單詞都是禁用詞,或是長度都小于編入索引單詞的最小長度,則結果為空。
以下例子展示了一些使用布爾全文符號的搜索字符串:
’apple banana’尋找包含至少兩個單詞中的一個的行。
’+apple +juice’尋找兩個單詞都包含的行。
’+apple macintosh’尋找包含單詞“apple”的行,若這些行也包含單詞“macintosh”, 則列為更高等級。
’+apple -macintosh’尋找包含單詞“apple” 但不包含單詞 “macintosh”的行。
’+apple +(>turnover <strudel)’尋找包含單詞“apple”和“turnover” 的行,或包含“apple” 和“strudel”的行(無先后順序),然而包含 “apple turnover”的行較包含“apple strudel”的行排列等級更為高。
’apple*’尋找包含“apple”、“apples”、“applesauce”或“applet”的行。
’'some words'’尋找包含原短語“some words”的行(例如,包含“some words of wisdom” 的行,而非包含“some noise words”的行)。注意包圍詞組的‘'’ 符號是界定短語的操作符字符。它們不是包圍搜索字符串本身的引號。
2.全文搜索帶查詢擴展全文搜索支持查詢擴展功能(特別是其多變的“盲查詢擴展功能”)。若搜索短語的長度過短,那么用戶則需要依靠全文搜索引擎通常缺乏的內隱知識進行查詢。這時,查詢擴展功能通常很有用。例如,某位搜索 “database” 一詞的用戶,可能認為“MySQL”、“Oracle”、“DB2”and“RDBMS”均為符合 “databases”的項,因此都應被返回。這既為內隱知識。
在下列搜索短語后添加WITH QUERY EXPANSION,激活盲查詢擴展功能(即通常所說的自動相關性反饋)。它將執行兩次搜索,其中第二次搜索的搜索短語是同第一次搜索時找到的少數頂層文件連接的原始搜索短語。這樣,假如這些文件中的一個 含有單詞 “databases” 以及單詞 “MySQL”,則第二次搜索會尋找含有單詞“MySQL” 的文件,即使這些文件不包含單詞 “database”。下面的例子顯示了這個不同之處:
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)mysql> SELECT * FROM articles -> WHERE MATCH (title,body) -> AGAINST (’database’ WITH QUERY EXPANSION);+----+-------------------+------------------------------------------+| id | title | body |+----+-------------------+------------------------------------------+| 1 | MySQL Tutorial | DBMS stands for DataBase ... || 5 | MySQL vs. YourSQL | In the following database comparison ... || 3 | Optimizing MySQL | In this tutorial we will show ... |+----+-------------------+------------------------------------------+3 rows in set (0.00 sec)
另一個例子是Georges Simenon搜索關于Maigret的書籍,這個用戶不確定“Maigret”一詞的拼法。若不使用查詢擴展而搜索“Megre and the reluctant witnesses” 得到的結果只能是的“Maigret and the Reluctant Witnesses” 。 而帶有查詢擴展的搜索會在第二遍得到帶有“Maigret”一詞的所有書名。
注釋:盲查詢擴展功能很容易返回非相關文件而增加無用信息,因此只有在查詢一個長度很短的短語時才有必要使用這項功能。
3.全文停止字以下表列出了默認的全文停止字:
a’sableaboutaboveaccordingaccordinglyacrossactuallyafterafterwardsagainagainstain’tallallowallowsalmostalonealongalreadyalsoalthoughalwaysamamongamongstanandanotheranyanybodyanyhowanyoneanythinganywayanywaysanywhereapartappearappreciateappropriatearearen’taroundasasideaskaskingassociatedatavailableawayawfullybebecamebecausebecomebecomesbecomingbeenbeforebeforehandbehindbeingbelievebelowbesidebesidesbestbetterbetweenbeyondbothbriefbutbyc’monc’scamecancan’tcannotcantcausecausescertaincertainlychangesclearlycocomcomecomesconcerningconsequentlyconsiderconsideringcontaincontainingcontainscorrespondingcouldcouldn’tcoursecurrentlydefinitelydescribeddespitediddidn’tdifferentdodoesdoesn’tdoingdon’tdonedowndownwardsduringeacheduegeighteitherelseelsewhereenoughentirelyespeciallyetetcevenevereveryeverybodyeveryoneeverythingeverywhereexexactlyexampleexceptfarfewfifthfirstfivefollowedfollowingfollowsforformerformerlyforthfourfromfurtherfurthermoregetgetsgettinggivengivesgogoesgoinggonegotgottengreetingshadhadn’thappenshardlyhashasn’thavehaven’thavinghehe’shellohelphenceherherehere’shereafterherebyhereinhereuponhersherselfhihimhimselfhishitherhopefullyhowhowbeithoweveri’di’lli’mi’veieifignoredimmediateininasmuchincindeedindicateindicatedindicatesinnerinsofarinsteadintoinwardisisn’titit’dit’llit’sitsitselfjustkeepkeepskeptknowknowsknownlastlatelylaterlatterlatterlyleastlesslestletlet’slikelikedlikelylittlelooklookinglooksltdmainlymanymaymaybememeanmeanwhilemerelymightmoremoreovermostmostlymuchmustmymyselfnamenamelyndnearnearlynecessaryneedneedsneitherneverneverthelessnewnextninenonobodynonnonenoonenornormallynotnothingnovelnownowhereobviouslyofoffoftenohokokayoldononceoneonesonlyontoorotherothersotherwiseoughtouroursourselvesoutoutsideoveroverallownparticularparticularlyperperhapsplacedpleasepluspossiblepresumablyprobablyprovidesquequiteqvratherrdrereallyreasonablyregardingregardlessregardsrelativelyrespectivelyrightsaidsamesawsaysayingsayssecondsecondlyseeseeingseemseemedseemingseemsseenselfselvessensiblesentseriousseriouslysevenseveralshallsheshouldshouldn’tsincesixsosomesomebodysomehowsomeonesomethingsometimesometimessomewhatsomewheresoonsorryspecifiedspecifyspecifyingstillsubsuchsupsuret’staketakentelltendsththanthankthanksthanxthatthat’sthatsthetheirtheirsthemthemselvesthenthencetherethere’sthereaftertherebythereforethereintheresthereuponthesetheythey’dthey’llthey’rethey’vethinkthirdthisthoroughthoroughlythosethoughthreethroughthroughoutthruthustotogethertootooktowardtowardstriedtriestrulytrytryingtwicetwoununderunfortunatelyunlessunlikelyuntiluntoupuponususeusedusefulusesusingusuallyvaluevariousveryviavizvswantwantswaswasn’twaywewe’dwe’llwe’rewe’vewelcomewellwentwereweren’twhatwhat’swhateverwhenwhencewheneverwherewhere’swhereafterwhereaswherebywhereinwhereuponwhereverwhetherwhichwhilewhitherwhowho’swhoeverwholewhomwhosewhywillwillingwishwithwithinwithoutwon’twonderwouldwouldwouldn’tyesyetyouyou’dyou’llyou’reyou’veyouryoursyourselfyourselveszero4.全文限定條件全文搜索只適用于MyISAM表。全文搜索可以同大多數多字節字符集一起使用。Unicode屬于例外情況;可使用utf8字符集,而非ucs2字符集。諸如漢語和日語這樣的表意語言沒有自定界符。因此,FULLTEXT分析程序不能確定在這些或其它的這類語言中詞的起始和結束的位置。若支持在一個單獨表中使用多字符集,則所有FULLTEXT索引中的列 必須使用同樣的字符集和庫。MATCH()列列表必須同該表中一些FULLTEXT索引定義中的列列表完全符合,除非MATCH()在IN BOOLEAN MODE。對AGAINST()的參數必須是一個常數字符串。5.微調MySQL全文搜索MySQL的全文搜索容量幾乎不具有用戶調節參數。假如你擁有一個MySQL源分布,你就能對全文搜索性能行使更多控制,原因是一些變化需要源代碼修改。
注意,為了更加有效,需要對全文搜索謹慎調節。實際上,在大多數情況下修改默認性能只能降低其性能。除非你知道自己在做什么,否則不要改變MySQL源。
下述的大多數全文變量必須在服務器啟動時被設置。為了改變它們,還要重新啟動服務器;在服務器正在運行期間,他們不會被改變。
一些變量的改變需要你重建表中的FULLTEXT索引。本章結尾部分給出了其有關操作說明。
ft_min_word_len and ft_max_word_len系統自變量規定了被編入索引單詞的最小長度和最大長度。默認的最小值為四個字符;默認的最大值取決于使用的MySQL版本。假如你改變任意一個值,那么你必須重建你的FULLTEXT索引。 例如,若你希望一個3字符的單詞變為可查找項,則可以通過將以下行移動到一個供選擇文件里,從而設置ft_min_word_len變量:· [mysqld]
· ft_min_word_len=3
然后重新啟動服務器,重建你的FULLTEXT索引。同時還要特別注意該表后面的說明中的關于myisamchk的注釋。
若要覆蓋默認停止字,則可設置ft_stopword_file系統變量。變量值應為包含停止字的文件路徑名,或是用來截止禁用詞過濾的空字符串。在改變了這個變量的值或禁用詞文件的內容后,重建你的FULLTEXT索引。停止字是自由形態的,換言之,你可使用任何諸如newline、space或comma這樣的非字母數字字符來分隔禁用詞。 下劃線字符(_)和被視為單詞的一部分的單引號(’)例外。停止字字符集為服務器默認字符集。
自然語言查詢的50%閾值由所選擇的特別權衡方案所決定。若要阻止它,myisam/ftdefs.h中尋找以下行:· #define GWS_IN_USE GWS_PROB
將該行改為:
#define GWS_IN_USE GWS_FREQ
然后重新編譯MySQL。此時不需要重建索引。注釋:這樣做你會嚴重的By降低MySQL為MATCH()函數提供合適的相關值得能力。假如你爭得需要搜索這樣的普通詞,而使用IN BOOLEAN MODE代替的效果更好,因為它不遵循50%閾值。
要改變用于布爾全文搜索的操作符,設置ft_boolean_syntax系統變量。 這個變量也可以在服務器運行時被改變,但你必須有SUPER特權才能這么做。在這種情況下不需要重建索引。假如你改變了影響索引的全文變量(ft_min_word_len、ft_max_word_len或ft_stopword_file),或假如你改變了禁用詞文件本身,則你必須在改變和重新啟動服務器后重建你的FULLTEXT索引。這時,要重建索引, 只需進行一個QUICK修理操作:
mysql>REPAIR TABLEtbl_nameQUICK;
注意,假如你使用myisamchk來執行一項修改表索引的操作(諸如修理或分析),則使用最小單詞長度和最大單詞長度以及停止字的默認全文參數值重建FULLTEXT索引,除非你已另外指定。這會導致問詢失敗。
發生這個問題的原因是只有服務器認識這些參數。它們的存儲位置不在 MyISAM索引文件中。若你已經修改了最小單詞長度或最大單詞長度或服務器中的停止字,為避免這個問題,為你對mysqld所使用的myisamchk指定同樣的ft_min_word_len、ft_max_word_len和ft_stopword_file值。例如,假如你已經將最小單詞長度設置為3,則你可以這樣修改一個帶有myisamchk的表:
shell>myisamchk --recover --ft_min_word_len=3tbl_name.MYI
為保證myisamchk及服務器對全文參數使用相同的值, 可將每一項都放在供選文件中的[mysqld]和[myisamchk]部分:
[mysqld]
ft_min_word_len=3
[myisamchk]
ft_min_word_len=3
使用REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLE或ALTER TABLE來代替使用myisamchk。這些語句通過服務器來執行,服務器知道使用哪個全文參數值更加合適。
相關文章:
