[轉]MySQL FullText檢索和MySQL5.6 InnoDB FULLTEXT Indexes研究測試



FULL TEXT索引 Mysql 3.23.23以及更高版本支持一種特殊類型的索引 全文索引在 MySQL 中是一個 全文索引在 MySQL 中是一個 FULLTEXT 類型索引。FULLTEXT 索引用於 MyISAM 表(且僅支持該類型的表),可以在 CREATE TABLE 時或之後使用 ALTER TABLE 或 CREATE INDEX 在 CHARVARCHAR 或 TEXT 列上創建。對於大的數據庫,將數據裝載到一個沒有FULLTEXT 索引的表中,然後再使用 ALTER TABLE (或 CREATE INDEX) 創建索引,這將是非常快的。將數據裝載到一個已經有 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 VALUES
    -> (NULL,'MySQL Tutorial', 'DBMS stands for DataBase ...'),
    -> (NULL,'How To Use MySQL Efficiently', 'After you went through a ...'),
    -> (NULL,'Optimising MySQL','In this tutorial we will show ...'),
    -> (NULL,'1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
    -> (NULL,'MySQL vs. YourSQL', 'In the following database comparison ...'),
    -> (NULL,'MySQL Security', 'When configured properly, MySQL ...');
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

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)

函數 MATCH() 對照一個文本集(包含在一個 FULLTEXT 索引中的一個或多個列的列集)執行一個自然語言搜索一個字符串。搜索字符串做爲 AGAINST() 的參數被給定。搜索以忽略字母大小寫的方式執行。對於表中的每個記錄行,MATCH() 返回一個相關性值。即,在搜索字符串與記錄行在 MATCH() 列表中指定的列的文本之間的相似性尺度。 如果即沒有 WHERE 也沒有 ORDER BY 子句,返回行是不排序的。

下一個示例顯示如何檢索一個明確的相似性值
mysql> SELECT id,MATCH (title,body) AGAINST ('Tutorial') FROM articles;
+----+-----------------------------------------+
| id | MATCH (title,body) AGAINST ('Tutorial') |
+----+-----------------------------------------+
|  1 |                        0.64840710366884 |
|  2 |                                       0 |
|  3 |                        0.66266459031789 |
|  4 |                                       0 |
|  5 |                                       0 |
|  6 |                                       0 |
+----+-----------------------------------------+
6 rows in set (0.00 sec)

到 4.0.1 時,MySQL 也可以使用 IN BOOLEAN MODE 修飾語來執行一個邏輯全文搜索。

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 Efficiently | After you went through a ...        |
|  3 | Optimising 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 的記錄行(注意: 50% 的閾值沒有使用),但是它沒有包含詞 YourSQL。注意,一個邏輯模式的搜索不會自動地以相似值的降序排序記錄行。你可以從上面的結果出看得出來,最高的相似值(包含 MySQL 兩次的那個) 最列在最後,而不是第一位。一個邏輯全文搜索即使在沒有一個 FULLTEXT 索引的情況下也可以工作,然而它 些。

邏輯全文搜索支持下面的操作符:

+
一個領頭的加號表示,該詞必須出現在每個返回的記錄行中。

-
一個領頭的減號表示,該詞必須不出現在每個返回的記錄行中。

缺省的 (當既沒有加號也沒有負號被指定時)詞是隨意的,但是包含它的記錄行將被排列地更高一點。這個模仿沒有 IN BOOLEAN MODE 修飾詞的 MATCH() ... AGAINST() 的行爲。

< >
這兩個操作符用於改變一個詞的相似性值的基值。< 操作符減少基值,> 操作符則增加它。參看下面的示例。

( )
圓括號用於對子表達式中的詞分組。

~
一個領頭的否定號的作用象一個否定操作符,引起行相似性的詞的基值爲負的。它對標記一個噪聲詞很有用。一個包含這樣的詞的記錄將被排列得低一點,但是不會被完全的排除,因爲這樣可以使用 - 操作符。

*
一個星號是截斷操作符。不想其它的操作符,它應該被追加到一個詞後,不加在前面。

"
短語,被包圍在雙引號"中,只匹配包含這個短語(字面上的,就好像被鍵入的)的記錄行。

這裏是一些示例:

apple banana
找至少包含上面詞中的一個的記錄行
+apple +juice
... 兩個詞均在被包含
+apple macintosh
... 包含詞 “apple”,但是如果同時包含 “macintosh”,它的排列將更高一些
+apple -macintosh
... 包含 “apple” 但不包含 “macintosh”
+apple +(>pie <strudel)
... 包含 “apple” 和 “pie”,或者包含的是 “apple” 和 “strudel” (以任何次序),但是 “apple pie” 排列得比 “apple strudel” 要高一點
apple*
... 包含 “apple”,“apples”,“applesauce” 和 “applet”
"some words"
... 可以包含 “some words of wisdom”,但不是 “some noise words”

來源:http://lgn0402.blog.163.com/blog/static/126692363201092964210534/ 


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: 0 

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) 
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% 限制的用戶可使用布爾搜索代碼

來源:http://xiaofeng1982.blog.163.com/blog/static/31572458201254105953824/ 




MySQL5.6 InnoDB FULLTEXT Indexes研究測試




1.概要

InnoDB引擎對FULLTEXT索引的支持是 MySQL5.6.4 新引入的特性,之前只有MyISAM引擎支持FULLTEXT索引。對於FULLTEXT索引的內容可以使用MATCH()…AGAINST語法進行查詢。

爲了在InnoDB驅動的表中使用FULLTEXT索引MySQL5.6引入了一些新的配置選項和INFORMATION_SCHEMA表。比如,爲了監視一個FULLTEXT索引中文本處理過程的某一方面可以查詢INNODB_FT_CONFIG,INNODB_FT_INDEX_TABLE,INNODB_FT_INDEX_CACHE,INNODB_FT_DEFAULT_STOPWORD,INNODB_FT_DELETED和INNODB_FT_BEING_DELETED這些表。可以通過innodb_ft_num_word_optimize和innodb_optimize_fulltext_only選項控制OPTIMIZETABLE命令對InnoDB FULLTEXT索引的更新。


2.相關庫表


INFORMATION_SCHEMA庫中與InnoDB全文索引相關的表如下:

INNODB_SYS_INDEXES

INNODB_SYS_TABLES 

INNODB_FT_CONFIG

INNODB_FT_INDEX_TABLE

INNODB_FT_INDEX_CACHE

INNODB_FT_DEFAULT_STOPWORD

INNODB_FT_DELETED

INNODB_FT_BEING_DELETED


Ø INNODB_SYS_INDEXES:提供了InnoDB索引的狀態信息。

Ø INNODB_SYS_TABLES:提供了InnoDB表的狀態信息。

Ø INNODB_FT_CONFIG:顯示一個InnoDB表的FULLTEXT索引及其相關處理的元數據。

Ø INNODB_FT_INDEX_TABLE:轉化後的索引信息用於處理基於InnoDB表FULLTEXT索引的文本搜索。一般用於調試診斷目的。使用該表前需先配置innodb_ft_aux_table配置選項,將其指定爲想要查看的含FULLTEXT索引的InnoDB表,選項值的格式爲database_name/table_name。配置了該選項後INNODB_FT_INDEX_TABLE,INNODB_FT_INDEX_CACHE, INNODB_FT_CONFIG, INNODB_FT_DELETED和INNODB_FT_BEING_DELETED表將被填充與innodb_ft_aux_table配置選項指定的表關聯的搜索索引相關信息。

Ø INNODB_FT_INDEX_CACHE:向含FULLTEXT索引的InnoDB表插入數據後新插入數據轉後的索引信息。表結構與INNODB_FT_INDEX_TABLE一致。爲含FULLTEXT索引的InnoDB表執行DML操作期間重組索引開銷很大,因此將新插入的被索引的詞單獨存儲於該表中,當且僅當爲InnoDB表執行OPTIMIZE TABLE語句後纔將新的轉換後的索引信息與原有的主索引信息合併。使用該表前需先配置innodb_ft_aux_table配置選項。

Ø INNODB_FT_DEFAULT_STOPWORD:在InnoDB表上創建FULLTEXT索引所使用的默認停止字表。

Ø INNODB_FT_DELETED:記錄了從InnoDB表FULLTEXT索引中刪除的行。爲了避免爲InnoDB的FULLTEXT索引執行DML操作期間重組索引的高開銷,新刪除的詞的信息單獨存儲於此表。當且僅當爲此InnoDB表執行了OPTIMIZE TABLE操作後纔會從主搜索索引中移除已刪除的詞信息。使用該表前需先配置innodb_ft_aux_table選項。

Ø INNODB_FT_BEING_DELETED:爲含FULLTEXT索引的InnoDB表執行OPTIMIZE TABLE操作時會根據INNODB_FT_DELETED表中記錄的文檔ID從InnoDB表的FULLTEXT索引中刪除相應的索引信息。而INNOFB_FT_BEING_DELETED表用於記錄正在被刪除的信息,用於監控和調試目的。



3.相關配置選項


Name

Cmd-
Line

Option file

System Var

Status Var

Scope

Dynamic

innodb_ft_aux_table

Yes

Yes

Yes

 

Global

Yes

innodb_ft_cache_size

Yes

Yes

Yes

 

Global

No

innodb_ft_enable_diag_print

Yes

Yes

Yes

 

Global

Yes

innodb_ft_enable_stopword

Yes

Yes

Yes

 

Global

Yes

innodb_ft_max_token_size

Yes

Yes

Yes

 

Global

No

innodb_ft_min_token_size

Yes

Yes

Yes

 

Global

No

innodb_ft_num_word_optimize

Yes

Yes

Yes

 

Global

Yes

innodb_ft_server_stopword_table

Yes

Yes

Yes

 

Global

Yes

innodb_ft_sort_pll_degree

Yes

Yes

Yes

 

Global

No

innodb_ft_user_stopword_table

Yes

Yes

Yes

 

Both

Yes

innodb_optimize_fulltext_only

Yes

Yes

Yes

 

Global

Yes


Ø innodb_ft_aux_table:指定包含FULLTEXT索引的InnoDB表的的名稱。該變量在運行時設置用於診斷目的。設置該值後INNODB_FT_INDEX_TABLE, INNODB_FT_INDEX_CACHE, INNODB_FT_CONFIG,INNODB_FT_DELETED和INNODB_FT_BEING_DELETED表將被填充與innodb_ft_aux_table指定的表關聯的搜索索引相關信息。

Ø innodb_ft_cache_size:當創建一個InnoDB FULLTEXT索引時在內存中存儲已解析文檔的緩存大小。

Ø innodb_ft_enable_diag_print:是否開啓額外的全文搜索診斷輸出。

Ø innodb_ft_enable_stopword:是否開啓停止字。InnoDB FUllTEXT索引被創建時爲其指定一個關聯的停止字集。(若設置了innodb_ft_user_stopword_table則停止字由該選項指定的表獲取,若沒有設置innodb_ft_user_stopword_table而設置了innodb_ft_server_stopword_table則停止字由該選項指定的表獲取,否則使用內置的停止字。)

Ø innodb_ft_max_token_size:存儲在InnoDB的FULLTEXT索引中的最大詞長。設置這樣一個限制後可通過忽略過長的關鍵字等有效降低索引大小從而加速查詢。

Ø innodb_ft_min_token_size:存儲在InnoDB的FULLTEXT索引中的最小詞長。增加該值後會忽略掉一些通用的沒有顯著意義的詞彙從而降低索引大小繼而加速查詢。

Ø innodb_ft_num_word_optimize:爲InnoDB FULLTEXT索引執行OPTIMIZE操作每次所處理的詞數。因爲在含有全文搜索索引的表中執行批量的插入或更新操作需要大量的索引維護操作來合併所有的變化。因此,一般會運行一系列OPTIMIZE TABLE語句,每次從上一次的位置開始,處理指定數目的詞,知道搜索索引被完全更新。

Ø innodb_ft_server_stopword_table:含有停止字的表,在創建InnoDB FULLTEXT索引時或忽略表中的停止字。停止字表需爲InnoDB表,且在指定前應當已存在。

Ø innodb_ft_sort_pll_degree:爲較大的表構建搜索索引時用於索引和記號化文本的並行線程數。

Ø innodb_ft_user_stopword_table:含有停止字的表,在創建InnoDB FULLTEXT索引時或忽略表中的停止字。停止字表需爲InnoDB表,且在指定前應當已存在。

Ø innodb_optimize_fulltext_only:改變OPTIMIZE TABLE語句對InnoDB表操作的方式。對含FULLTEXT 索引的InnoDB表進行維護操作期間,一般臨時的開啓該選項。默認情況下,OPTIMIZE TABLE語句會重組表的聚集索引中的數據。若開啓了該選項則該語句會跳過表數據的重組,而是隻處理FULLTEXT索引中新插入的、刪除的、更新的標記數據。(在對作爲FULLTEXT索引的一部分的InnoDB表列進行了大量的插入、更新或刪除操作後,先將innodb_optimize_fulltext_only設置爲on以改變OPTIMIZE TABLE的默認行爲,然後設置innodb_ft_num_word_optimize爲合適的值以將索引維護時間控制在一個合理的可接受範圍內,最後執行一系列的OPTIMIZE語句知道搜索索引被完全更新。)



4.全文搜索功能


全文搜索的語法:MATCH(col1,col2,…) AGAINST (expr[search_modifier])。其中MATCH中的內容爲已建立FULLTEXT索引並要從中查找數據的列,AGAINST中的expr爲要查找的文本內容,search_modifier爲可選搜索類型。search_modifier的可能取值有:IN NATURAL LANGUAGEMODE、IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION、IN BOOLEAN MODE、WITH QUERY EXPANSION。search_modifier的每個取值代表一種類型的全文搜索,分別爲自然語言全文搜索、帶查詢擴展的自然語言全文搜索、布爾全文搜索、查詢擴展全文搜索(默認使用IN NATURAL LANGUAGE MODE)。

MySQL中全文索引的關鍵字爲FULLTEXT,目前可對MyISAM表和InnoDB表的CHAR、VARCHAR、TEXT類型的列創建全文索引。全文索引同其他索引一樣,可在創建表是由CREATE TABLE語句創建也可以在表創建之後用ALTER TABLE或者CREATE INDEX命令創建(對於要導入大量數據的表先導入數據再創建FULLTEXT索引比先創建索引後導入數據會更快)。


4.1自然語言全文搜索

自然語言全文搜索是MySQL全文搜索的默認搜索方式,實現從一個文本集合中搜索給定的字符串。這裏,文本集合指的是指由FULLTEXT索引的一個或者多個列。


建表,並給title,body字段加FULLTEXT索引

CREATE TABLE articles (

     id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,

     title VARCHAR(200),

     body TEXT,

     FULLTEXT (title,body)

) ENGINE=InnoDB;


導入數據

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 ...');


例1:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('database' IN NATURAL LANGUAGE MODE);



可以看到,語句查找到了包含指定內容的行。實際上,返回的行是按與所查找內容的相關度由高到低的順序排列的。這個相關度的值由WHERE語句中的MATCH (…) AGAINST (…)計算所得,是一個非負浮點數。該值越大表明相應的行與所查找的內容越相關,0值表明不相關。該值基於行中的單詞數、行中不重複的單詞數、文本集合中總單詞數以及含特定單詞的行數計算得出。


例2:

由上例可知MATCH (…) AGAINST (…)實際上會計算一個相關值,可通過下例來驗證。

SELECT id, MATCH (title,body)

AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) AS score

FROM articles;


可以看到,所得結果的第二列即爲改行與查找內容的相關度。上例1中所得結果的順序就是按此相關度排列的。


例3:

若想既看到查找到的結果又需要了解具體的相關度,可用下述方法達成。

SELECT id, body, MATCH (title,body) AGAINST

   ('Security implications of running MySQL as root'

   IN NATURAL LANGUAGE MODE) AS score

   FROM articles WHERE MATCH (title,body) AGAINST

   ('Security implications of running MySQL as root'

IN NATURAL LANGUAGE MODE);



可以看到,通過在查找部分和條件部分分別使用相同的MATCH(…) AGAINST(…)可以同時獲取兩方面的內容(不會增加額外開銷,優化器知道兩個MATCH(…) AGAINST(..)是相同的,只會執行一次該語句)


注意事項

默認情況下全文搜索大小寫不敏感,如上例1,查找的內容爲‘database’但含有‘DataBase’的行也會返回。可以通過爲FULLTEXT索引列所使用的字符集指定一個特定的校對集來改變這種行爲。

考慮下述兩個SELECT語句:

1.  SELECTCOUNT(*) FROM articles

            WHEREMATCH (title,body)

            AGAINST('database' IN NATURAL LANGUAGE MODE);

2.  SELECTCOUNT(IF(MATCH (title,body)

AGAINST('database' IN NATURAL LANGUAGE MODE), 1, NULL)) AS count

            FROMarticles;

這兩條查詢語句均可返回匹配的行數。但第一條語句可以利用基於WHERE從句的索引查找,因此在匹配的行數較少時速度較第二句更快。第二句執行了全表掃描,因此在匹配的行數較多時較第一句更快。

MATCH()函數中的列必須與FULLTEXT索引中的列相同。如MATCH(title,body)與FULLTEXT(title,body)。若要單獨搜索某列,如body列,則需另外單獨爲該列建全文索引FULLTEXT(body),然後用MATCH(body)搜索。

對於InnoDB表MATCH()中的列僅能來自於同一個表,因爲索引不能快多張表(MyISAM表的的布爾搜索因爲可以不使用索引所以可以跨多張表中的列,但速度很慢)。

全文搜索不僅可以搜索類似例1中‘database’這樣的單個的單詞,還可以搜索句子(這纔是其被稱爲‘全文搜索‘的關鍵),如例3。全文搜索把任何數字、字母、下劃線序列看作是單詞,還可以包含“’”如aaa’bbb備解析爲一個單詞,但aaa’’bbb備解析爲兩個單詞,FULLTEXT解析器自動移除首尾的“’”,如’aaa’bbb’被解析爲aaa’bbb。FULLTEXT解析器用“ ”(空格)、“,”(逗號)“.”(點號)作爲默認的單詞分隔符,因此對於不使用這些分隔符的語言如漢語來說FULLTEXT解析器不能正確的識別單詞,對於這種情況需做額外處理。

全文搜索中一些單詞會被忽略。首先是過短的單詞,InnoDB全文搜索中默認爲3個字符,MyISAM默認4個字符,可通過在創建FULLTEXT索引前改變配置參數來改變默認行爲,對於InnoDB該參數爲:innodb_ft_min_token_size,對於MyISAM爲ft_min_word_len;另外stopword列表中的單詞會被忽略。stopword列表包含諸如“the”、“or”、“and”等常用單詞,這些詞通常被認爲沒有什麼語義價值。MySQL由內建的停止字列表,但是可以所使用自定義的停止字列表來覆蓋默認列表。對於InnoDB控制停止字的配置參數爲innodb_ft_enable_stopword,innodb_ft_server_stopword_table,  innodb_ft_user_stopword_table對於MyISAM參數爲ft_stopword_file。

文本集合和查詢語句中的單詞的權重由該單詞在集合或語句中的重要性確定。單詞在越多的行中出現則該單詞的權重越低,因爲這表明其在文本集合中的語義價值較小。反之權重越高。例1中提到的相關度計算也與此值有關。


4.2布爾全文搜索

如果在AAGAINST()函數中指定了INBOOLEN MODE模式,則MySQL會執行布爾全文搜索。在該搜索模式下,待搜索單詞前或後的一些特定字符會有特殊的含義。


例1:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('+MySQL-YourSQL' IN BOOLEAN MODE);



該查詢語句中“MySQL”前的“+”表明結果中必須包含“MySQL”而“YourSQL”前的“-”表明所得結果中不能含有“YourSQL”。

除了“+”和“-”外還有其他一些特定的字符。如空字符表明後跟的單詞是可選的,但出現的話會增加該行的相關性;“@distance”用於指定兩個或多個單詞相互之間的距離(以單詞度量)需在指定的範圍內;“>”用於增加後跟單詞對其所在行的相關性的貢獻“<”用於降低該貢獻;“()”用於將單詞分組爲子表達式且可以嵌套;“~”是後跟單詞對其所在行的相關性的貢獻值爲負;“*”爲普通的通配符,若爲單詞指定了通配符,那麼即使該單詞過短或者出現在了停止字列表中它也不會被移除;“””,括在雙引號中的短語指明行必須在字面上包含指定的短語,全文搜索將短語分割爲詞後在FULLTEXT索引中搜索。非字字符無需完全匹配,如”test phrase”可以匹配含”test phrase”和”test phrase”的行,但匹配含”phrase test”的行。


例2:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('MySQL YourSQL' IN BOOLEAN MODE);




找到包含MySQL或者YourSQL的行


例3:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('+MySQL+YourSQL' IN BOOLEAN MODE);



找到包含同時MySQL和YourSQL的行


例4:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('+MySQL YourSQL' IN BOOLEAN MODE);



找到必須包含MySQl的行,YourSQL可有可無,但有YourSQL會增加相關性。

例5:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('+MySQL ~YourSQL' INBOOLEAN MODE);




找到包含必須包含MySQL的行,YourSQL可有可無,若出現了YourSQL則會降低其所在行的相關性。


例6:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('+MySQL +(>Security <Optimizing)' IN BOOLEANMODE);



找到必須同時包含MySQL以及Security或Optimizing的行Security會增加所在行的相關性,而Optimizing會降低所在行的相關性。


例7:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('da*' IN BOOLEAN MODE);


找到包含da*的行。如包含DataBase、database等。


例8:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST('"MySQL,Tutorial"' IN BOOLEAN MODE);


找到包含“MySQL Tutorial”短語的行。


布爾全文搜索的一些特點

Ø MyISAM全文搜索會忽略至少在一半以上數據行中出現的單詞(也即所謂的50%閾值),InnoDB無此限制。而在布爾全文搜索中MyISAM的50%閾值不生效。

Ø 停止字列表也適用於布爾全文搜索。

Ø 最小和最大詞長全文搜索參數也適用於布爾全文搜索

Ø MyISAM中的布爾搜索在FULLTEXT索引不存在的時候仍可工作,但速度很慢。而InnoDB表的各類全文搜索必須有FULLTEXT索引,否則會出現找不到與指定列相匹配的FULLTEXT索引的錯誤

Ø InnoDB中的全文搜索不支持在單一搜索單詞前使用多個操作符如“++MySQL”。MyISAM中全文搜索可以處理這種情況,但是會忽略除了緊鄰單詞之外的其他操作符。


4.3查詢擴展全文搜索


某些時候我們通過全文搜索來查找包含某方面內容的行,比如我們搜索“database”,實際上我們期望返回結果不僅僅是僅包含“database”單詞的行,一些包含“MySQL”、“SQLServer”、“Oracle”、“DB2”、“RDBMS”等的行也期望被返回。這個時候查詢擴展全文搜索就能大顯身手。

通過在AGAINST()函數中指定WITHQUERY EXPANSION 或者IN NATURAL MODE WITH QUERY EXPANSION可以開啓查詢擴展全文搜索模式。其工作原理是執行兩次搜索,第一次用給定的短語搜索,第二次使用給定的短語結合第一次搜索返回結果中相關性非常高的一些行進行搜索。


例1:

SELECT * FROM articles

WHERE MATCH (title,body)

AGAINST ('database' IN NATURAL LANGUAGE MODE);


使用自然語言搜索返回了包含“database”的行。


例2:

SELECT * FROM articles

 WHERE MATCH (title,body)

AGAINST ('database' WITH QUERY EXPANSION);


使用查詢擴展全文搜索,不進返回了包含“database”的行,也返回了與例1中返回的行的內容相關的行。


注意事項

因爲查詢擴展會返回一些不相關的內容,因此會顯著的引入噪聲。索引僅當要查詢的短語較短時纔在考慮使用查詢擴展全文搜索。


4.4全文搜索的停止字


上文已經簡單介紹過了停止字列表,這裏做詳細介紹。停止字列表用MySQL Server所使用的字符集和校對集(分別由character_set_server和collation_server兩個參數控制)載入並執行搜索。若用於全文索引和搜索的停止字文件或者停止字表使用了與MySQL Server不同的字符集和校對集會則導致查找停止字時錯誤的命中或未命中。

停止字查找的大小寫敏感性也依賴於MySQL Server所使用的校對集,例如校對集爲latin1_swedish_ci則查找是大小寫不敏感的,若校對集爲latin1_geberal_cs或者latin1_bin則查找是大小寫敏感的。

InnoDB默認的停止字列表相對較短(因爲技術上的或者文學等方面的文檔常使用較短的詞作爲關鍵字或者有其他顯著意義)。InnoDB默認的停止字列表存儲在information_schema.innodb_ft_default_stopword表中。當然也可以通過自定義與innodb_ft_default_stopword表結構相同的表,填充期望的停止字,然後通過innodb_ft_server_stopword_table選項指定自定義的停止字表db_name/table_name,來改變默認的行爲。另外還可以爲innodb_ft_user_stopword_table選項指定含停止字的表,若同時指定了innodb_ft_default_stopword和innodb_ft_user_stopword_table則將使用後者指定的停止字表。上述操作改變所使用停止字表的操作需在創建全文索引前完成。且在指定所使用的停止字表時,表必須已經存在。

對於MyISAM可通過 ft_stopword_file選項指定所使用的停止字列表。MyISAM默認的停止字列表可在MySQL源碼的 storage/myisam/ft_static.c文件中找到。


4.5全文搜索的限制


Ø 目前只有InnoDB和MyISAM引擎支持全文搜索。其中InnodB表對FULLTEXT索引的支持從MySQL5.6.4開始。

Ø 分區表不支持全文搜索。

Ø 全文索引適用於多數多字節字符集。例外情況是:對於Unicode,utf8字符集可用但ucs2字符集不適用。儘管不能在ucs2列建立FULLTEXT索引,但可以在MyISAM表IN BOOLEAN MODE模式的搜索中搜索沒有建立FULLTEXT索引的列。utf8的特性適用於utf8mb4,ucs2的特性適用於utf16、utf16e和utf32。

Ø 表意型語言如漢語、日語沒有諸如空格之類的單詞定界符。因此FULLTEXT解析器不能確定此類語言中詞的起止。對於此種情況要特殊處理(比如將中文轉換成一種單字節類似英文習慣的存儲方式)。

Ø 允許在同一表中使用多種字符集,但FULLTEXT索引中的列必須使用同一字符集和校對集。

Ø MATCH()函數中的列必須與FULLTEXT索引中定義的列完全一致,除非是在MyISAM表中使用IN BOOLEAN MODE模式的全文搜索(可在沒有建立索引的列執行搜索,但速度很慢)。

Ø AGAINST()函數中的參數需爲在查詢評估期間保持不變的字符串常量。

Ø FULLTEXT搜索的索引提示比non-FULLTEXT搜索的索引提示要多一些限定:對於自然語言模式的全文搜索,索引提示會被忽略而不給出任何提示,比如雖明確在查詢語句中給出了IGNORE INDEX(i)指明不使用i索引,但是該索引提示會被忽略掉,最終的查詢中仍會使用索引i;對於布爾模式的全文搜索,FOR ORDER BY和FOR GROUP BY的索引提示會被忽略,FOR JOIN和不帶FOR修飾符的索引提示不被忽略。


4.6全文搜索參數調整


僅有少量的用戶可調參數用於調整MySQL的全文搜索能力。可以通過修改源碼來獲取更多對MySQL全文搜索行爲的控制。但一般情況下不推薦這麼做,除非很清楚自己在做什麼,因爲這些參數已經針對效率做過調整,修改默認的行爲多數情況下反而會帶來性能下降。

多數全文搜索相關的變量不能在Server運行的時候修改。需在Server啓動時指定這些參數,或者修改完參數之後重新啓動Server。另外,某些變量修改後需要重建FULLTEXT索引。

控制最小、最大字長的配置選項對於InnoDB爲:innodb_ft_min_token_size和innodb_ft_max_token_size,對於MyISAM爲:ft_min_word_len 和 ft_max_word_len。改變這些選項中任意一個的值都需重建FULLTEXT索引並重啓Server。

用於停止字列表的配置選項對於InnoDB爲:innodb_ft_enable_stopword、innodb_ft_server_stopword_table和innodb_ft_user_stopword_table,對於MyISAM爲:ft_stopword_file。可以通過改變這些選項的值來開啓/關閉停止字過濾並指定停止字列表。修改了這些選項後需重建索引並在必要的時候重啓Server。

ft_stopword_file指定了包含停止字列表的文件,Server默認在數據目錄搜索該文件除非用絕對路徑指定了文件位置,若文件內容爲空,則會關閉MyISAM的停止字過濾功能。停止字文件格式很靈活,可以使用任何非字母或數字的字符來界定停止字,但“_”和“’”例外,它們會被當作字的一部分處理。停止字列表使用Server默認的字符集。

MyISAM全文搜索的50%閾值特性可通過修改源碼來關閉,將源碼storage/myisam/ftdefs.h中的宏#define GWS_IN_USEGWS_PROB替換爲#define GWS_IN_USE GWS_FREQ後重新編譯MySQL即可。同樣,不推薦上述方式,如果確實需要搜索一些通用的詞,可以用布爾模式的全文搜獲,此種情況下50%閾值特性不生效。

可以通過修改ft_boolean_syntax選項的值來更改MyISAM布爾全文搜做中默認使用的操作符(InnoDB無此選項)。該選項可動態改變但須超級用戶權限,另外,改變了改制後無需重建FULLTEXT索引。

可以通過多種方式更改期望被認作是單詞字符成分的字符集合。默認情況下“_”和“’”以及字母和數字被認爲是組成單詞的字符,其他的被默認爲定界符。例如,我們現在想把連字符“-”也作爲組成單詞的字符處理,那麼可以通過如下方式完成:

Ø 修改MySQL源碼,在storage/myisam/ftdefs.h文件中找到true_word_char()和misc_word_char()兩個宏,在任一個宏定義裏添加“-”,重新編譯MySQL。


Ø 修改字符集文件,true_word_char()宏實際上利用“character type”表來從其他字符中區分出字母和數字。可以通過編輯字符集對應的XML文件中<ctype><map>節點中的內容來將“-”指定爲“字母“,然後將該字符集用於FULLTEXT索引。此種方式無需重新編譯MySQL。對於編輯字符集XML文件,可參閱MySQL參考手冊CharacterDefinition Arrays部分。
http://dev.mysql.com/doc/refman/5.6/en/character-arrays.html

Ø 對FULLTEXT索引列使用的字符集添加新的校對集,然後更新該列以使用新添加的校對集。具體參閱MySQL手冊Adding a Collation to a Character Set以及Adding a Collation for Full-Text Indexing部分。
http://dev.mysql.com/doc/refman/5.6/en/full-text-adding-collation.html
http://dev.mysql.com/doc/refman/5.6/en/adding-collation.html

爲InnoDB表重建FULLTEXT索引可以通過帶DROP INDEX和ADD INDEX從句的ALTER TABLE語句完成,先刪除舊的再創建新的。爲MyISAM表重建FULLTEXT索引同樣可通過上述語句完成,也可以通過QUICK repair操作來重建(但通常第一種方式會更快),如:

mysql> REPAIR TABLE tbl_name QUICK;

需要特別說明的是,若通過repair表的方式來爲MyISAM表重建FULLTEXT索引,則通過上述語句進行即可。用myisamchk工具也可以爲MyISAM表重建索引,但是容易導致查詢產生錯誤的結果,對錶的修改可能使Server認爲該表被損壞了。究其原因是因爲通過myisamchk工具執行修改MyISAM表的索引的操作時,除非明確指定了要使用的參數值否則使用默認的全文索引參數值(如最小最大詞長等)重建FULLTEXT索引。導致這種情況是因爲只有Server才知道這些全文索引參數值,MyISAM索引文件中不存儲這些值。若更改過了這些值,如設置了ft_min_word_len=2,則在通過myisamchk工具修復表時要明確指定該修改過的參數值如:

shell> myisamchk --recover--ft_min_word_len=3 tbl_name.MYI

當然也可以通過在MySQL配置文件[myisamchk]節中加入同[mysqld]節中與全文搜索相關參數一致的參數來確保myisamchk使用最新的參數值來重建表的FULLTEXT索引。

用myisamchk爲MyISAM表修改索引的替代方式是使用REPAIR TABLE、ANALYZE TABLE、 OPTIMIZE TABLE、ALTER TABLE,這些語句是由Server執行的因此可以讀取到正確的全文索引參數值,不會引起問題。

4.7爲全文搜索添加校對字符集

參考

10.4. Adding a Collation to a Character Set

http://dev.mysql.com/doc/refman/5.6/en/adding-collation.html

12.9.7. Adding a Collation for Full-Text Indexing

http://dev.mysql.com/doc/refman/5.6/en/full-text-adding-collation.html

5.性能對比測試

5.1測試環境

測試機:SVR644HP380

內存容量:8G

MySQL Server版本:5.6.12

5.2測試設計

詞彙量:6個等級,分別用vocab01k、vocab05k、vocab10k、vocab15k,vocab25k、vocab35k標記,每個等級的詞彙數如下,1000、5000、10000、15000、25000、35000。(取牛津詞典單詞部分,去重複後隨機打亂順序,分別截取前1000、5000、10000……作爲對應的詞彙量)

記錄數:20個等級,分別用rec005k、rec010k、rec015k、rec020k、……rec095k、rec100k標記,每個等級的記錄數如下,5000、10000、15000、20000、25000、30000、……、95000、100000。

根據詞彙量等級和記錄數等級分別生成含不同記錄數且表中文本列是由對應的詞彙量生成的隨機文本的表,共6*20=120個。表的存儲引擎使用InnoDB。表由id和body兩個字段組成,分別爲整型和文本型,且在body列創建了FULLTEXT索引。表名的命名規則爲vocab01k_rec005k,表示該表中共含有5千條記錄,每條記錄中的body列由vocab01k對應的詞彙量生成的隨機單詞組成,以此類推。每行記錄中的body列定爲由50個隨機單詞組成。

比較兩類查詢:LIKE從句查詢以及使用FULLTEXT索引的MATCH()AGAINST()查詢。在每個表上分別執行LIKE查詢和MATCH() AGAINST()全文查詢,每個表上的每個查詢分別執行50次,記錄每次所耗費的時間。對於每50個消耗的時間,刪除其最大兩個值和最小兩個值,取剩餘值的均值作爲查詢耗時的最終結果。這樣一共可獲得120*2 = 240個時間數據,根據這些數據繪圖。在每個表上執行的查詢如下(其中random_word1、random_word2、random_word3是根據查詢時表對應的詞彙量生成的隨機單詞。):

LIKE搜索:
SELECT body FROM table_name WHERE body LIKE "%random_word1%" AND bodyLIKE "% random_word2%" AND body LIKE "% random_word3%";

FULLTEXT搜索:
SELECT body FROM table_name WHERE MATCH(body) AGAINST("+random_word3 + random_word3+ random_word3" IN BOOLEAN MODE)


5.3測試結果

圖示

LIKE搜索:



FULLTEXT搜索:




FULLTEXT搜索與LIKE搜索對比:




結果討論


LIKE搜索的耗時隨着記錄數的增加而線性增長,但對於10萬行記錄以下的表(這裏共100000*50個單詞)搜索時間基本上能保持在1秒以內,所以like搜索的性能也不是特別差。由不同詞彙量生成的文本對LIKE搜索的性能影響不大,不同詞彙量對應的搜索時間基本上在一個很小的時間範圍內變化。

FULLTEXT搜索耗時也隨表中記錄數的增長而線性增加。對於10萬行記錄以下的表(這裏共100000*50個單詞)搜索時間基本上能保持在0.01秒以內。由不同詞彙量生成的隨機文本對FULLTEXT搜索性能有相對來說比較顯著的影響。每行記錄中含同樣的單詞數,這樣,較大的詞彙量傾向於生成冗餘度更低的文本,相應的搜索耗時傾向於更少。這可能與FULLTEXT索引建立單詞索引的機制有關,較大的詞彙量傾向於生成範圍廣但相對較淺的索引,因而能快速確定文本是否匹配。


與LIKE搜索相比,FULLTEXT全文搜索的性能要強很多,對於10萬行記錄的表,搜索時間都在0.02秒以下。因此可以將基於FULLTEXT索引的文本搜索部署於網站項目中的文本搜索功能中。但是,正如上述提到的,無論是LIKE搜索還是FULLTEXT搜索,其性能都會隨着記錄數的增長而下降,因此,若網站項目中的文本搜索數據庫記錄數龐大的一定規模後,可能需要考慮使用MySQL數據庫全文搜索以外的文本搜索解決方案了。


來源:http://blog.csdn.net/zyz511919766/article/details/12780173



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章