1. 程式人生 > 實用技巧 >MySQL 的全文索引.

MySQL 的全文索引.

一、為什麼需要全文索引?

通過 前面的文章 我們瞭解到 B+ 樹索引具有"最左字首匹配"的特性,因此,對於以下查詢 B+ 樹索引能很好的適配。

SELECT * FROM blog WHERE content like 'xxx%'

但是 B+ 樹索引對於 '%xxx%' 式的匹配卻顯得無能為力,而這正是全文索引的用武之地。從 InnoDB 1.2.x 版本開始,InnoDB 儲存引擎開始支援全文索引。

全文檢索(Full-Text Search)是將儲存於資料庫中的整本書或整篇文章中的任意內容資訊查找出來的技術,它可以根據需要獲得全文中有關章、節、段、句、詞等資訊,也可以進行各種統計和分析。

二、全文索引的實現?

全文索引通常使用倒排索引(inverted index)來實現。倒排索引和 B+ 樹索引一樣,也是一種資料結構。它在輔助表中儲存了單詞與單詞自身在一個或多個文件中所在位置之間的對映。這通常利用關聯陣列來實現,其擁有兩種表現形式:

  • inverted file index,其表現形式為 {單詞,單詞所在文件的 ID}
  • full inverted index,其表現形式為 {單詞,(單詞所在文件的 ID,在具體文件中的位置)}

InnoDB 儲存引擎採用 full inverted index 的方式,將(DocumentId,Position)視為一個 “ilist”。因此在全文索引的表中,有兩個列,一個是 word 欄位,另一個是 ilist 欄位,並且在 word 欄位上設有索引。

另外,倒排索引還將 word 存放在一張表中,這個表就是 Auxiliary Table(輔助表),在 InnoDB 儲存引擎中,共有 6 張 Auxiliary Table,存放在磁碟上,並且每張表根據 word 的 Latin-1(ISO8859-1)編碼進行分割槽。

全文檢索索引快取(FTS Index Cache)是一個紅黑樹結構,其根據(word,ilist)進行排序,用來提高全文索引的效能。引數 innodb_ft_cache_size 用來控制 FTS Index Cache 的大小,預設值為 32M。

SHOW GLOBAL VARIABLES LIKE 'innodb_ft_cache_size' 

對於 InnoDB 儲存引擎而言,其總是在事務提交時將分詞寫入到 FTS Index Cache,然後通過批量寫入到磁碟;當資料庫關閉時,在 FTS Index Cache 中的資料會同步到磁碟上的 Auxiliary Table 中。

三、實戰全文索引

CREATE TABLE `fts_a`  (
  `FTS_DOC_ID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  `body` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
  PRIMARY KEY (`FTS_DOC_ID`) USING BTREE,
  FULLTEXT INDEX `idx_fts`(`body`)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `fts_a` VALUES (1, 'hello welcome to mysql world');

FTS_DOC_ID 欄位名固定,並且必須為 BIGINT UNSIGNED NOT NULL 型別,用來與 word 進行對映,如果沒有手動建立該欄位,InnoDB 引擎會自動建立併為其加上 Unique Index 索引。

通過 innodb_ft_aux_table 來檢視分詞對應的資訊:

SET GLOBAL innodb_ft_aux_table ='test/fts_a';

SELECT * FROM information_schema.INNODB_FT_INDEX_TABLE;

可以看到每個 WORD 都對應了一個 DOC_ID 和 POSITION。此外還記錄了 FIRST_DOC_ID、LAST_DOC_ID 以及 DOC_COUNT,分別代表了該 WORD 第一次出現的文件 ID,最後一次出現的文件 ID,以及該 WORD 在多少個文件中存在。

MySQL 資料庫支援全文檢索(Full-Text Search)的查詢,其語法為:

MATCH(col1,col2,…) AGAINST (expr[search_modifier])

search_modifier:

  • IN NATURAL LANGUAGEMODE
  • IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
  • IN BOOLEAN MODE
  • WITH QUERY EXPANSION
EXPLAIN SELECT * FROM fts_a WHERE MATCH(body) AGAINST ('world' IN NATURAL LANGUAGE MODE)

四、其他

stopword 列表(stopword list)表示該列表中的 word 不需要對其進行索引分詞操作。InnoDB 儲存引擎有一張預設的 stopword 列表,其在 information_schema 架構下 INNODB_FT_DEFAULT_STOPWORD,預設共用 36 個 stopword。

SELECT * FROM information_schema.INNODB_FT_DEFAULT_STOPWORD

此外使用者也可以通過引數 innodb_ft_server_stopword_table 來自定義 stopword 列表:

SHOW GLOBAL VARIABLES LIKE 'innodb_ft_server_stopword_table';

SET GLOBAL innodb_ft_server_stopword_table = '庫/表';

當前 InnoDB 儲存引擎的全文索引還存在以下的限制:

  • 每張表只能有一個全文檢索的索引;
  • 由多個組合而成的全文索引列必須使用相同的字符集和排序規則;
  • 不支援沒有單詞界定符(delimiter)的語言,如中文、日語、韓語等。