天天看點

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;
           
MySQL 的全文索引.

可以看到每個 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)
           
MySQL 的全文索引.

四、其他

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)的語言,如中文、日語、韓語等。