經過索引字段的前綴進行查找,B+樹索引是支持的,利用B+樹索引就能夠進行快速查詢。mysql
SELECT * FROM blog WHERE content like 'xxx%';
可是查詢包含單詞的狀況,就無能爲力了。因此須要進入全文檢索技術Full-Test Search
sql
select * from blog where content like '%xxx%';
全文檢索是將存儲於數據庫中的整本書或者整片文章中的任意內容信息查找出來的技術。數據庫
全文檢索一般使用倒排索引inverted index
來實現。倒排索引同B+樹索引同樣,也是一種索引結構。它在輔助表auxiliary table
中存儲了單詞與單詞自身在一個或多個文檔中所在位置之間的映射。這一般利用關聯數組實現,其擁有兩種表現形式:數組
invert file index
:{單詞,單詞所在文檔的ID}full inverted index
:{單詞,(單詞所在文檔的ID,在具體文檔中的位置)}一個demo:緩存
DocumentId
表示進行全文檢索文檔的ID,Text
保溼存儲的內容,須要對內容進行全文檢索,獲得某個單詞的出現過的文檔ID。架構
對於使用invert file index
的關聯數組,其存儲內容以下,以後進行查找就簡單了併發
對於使用full inverted index
的關聯數組,其存儲內容以下ide
不只存儲了ID,還存儲了出現的位置。空間佔用更多,可是功能更強。函數
InnoDB
全文檢索 InnoDB
存儲引擎採用full inverted index
的方式,將(DocumentId
,Position
)視爲一個ilist
,所以在全文檢索表中,有兩個列,一個是word字段,另外一個是ilist字段。性能
InnoDB
存儲引擎中,爲了提升全文檢索的並行性能,共有六張Auxiliary Table
輔助表,目前每張表根據word的Latin
編碼進行分區。
Auxiliary Table
輔助表是持久表,存放在磁盤上,使用FTS Index Cache
全文檢索縮進緩存,用來提升全文檢索的性能。FTS Index Cache
是一個紅黑樹結構,其根據(word, ilist)進行排序。
表數據更新後,先導入到FTS Index Cache
中,可是尚未更新到Auxiliary Table
中。InnoDB
存儲引擎會批量對Auxiliary Table
進行更新,而不是每次插入後更新一次Auxiliary Table
。
當對全文檢索進行查詢時,Auxiliary Table
首先將會在FTS Index Cache
中對應的word字段合併到Auxiliary Table
中,而後再進行查詢。
引擎容許用戶查看指定倒排索引的Auxilary Table
中分詞的信息,能夠經過設置參數innodb_ft_aux_table
來觀察倒排索引的Auxiliary Table
。
set global innodb_ft_aux_table = 'test/fts_a';
設置完成後,能夠經過查詢information_scheme
架構下的表Innodb_ft_index_table
獲得表fts_a
的分詞信息。
對於InnoDB存儲引擎而言,老是在事務提交時將分詞寫入到FTS Index Cache
,而後再經過批量更新寫入到磁盤。因此在數據庫關閉時,會將FTS Index Cache
同步到Auxiliary Table
中。若是發生宕機的話,下次重啓數據庫時,當用戶對錶進行全文索引(查詢或插入操做時)時,會自動讀取未完成的文檔,而後進行分詞操做,再將分詞的結果放入到FTS Index Cache
中。
參數innodb_ft_cache_size
用來控制FTS Index Cache
的大小,默認值爲32M。當緩存滿時,會將其中的分詞信息同步到磁盤的輔助表中。增大參數能夠提升全文檢索的性能。可是宕機的時候,未同步到磁盤的索引信息須要更長的時間恢復。
FTS Document ID
是另一個重要的概念。爲了支持全文檢索,必須有一個列與word進行映射,在InnoDB存儲引擎重這個列被命名爲FTC_DOC_ID
,其類型必須是BIGINT UNSIGNED NOT NULL
,而且Innodb
存儲引擎自動會在該列上加入一個名爲FTS_DOC_ID_INDEX
的Unqiue Index
。上述操做都由引擎本身完成。
對於刪除操做,在事務提交時,只刪除FTS Cache Index
中的記錄,對於Auxiliary Table
中被刪除的記錄,會記錄下其FTS Documont ID
,並將其保存在DELETED auxiliary table
中。在設置參數innodb_ft_aux_table
後,用戶一樣能夠訪問information_scheme
架構下的表INNODB_FT_DELETED
來觀察刪除的FTS Document ID
。
由於文檔的DML操做實際並不刪除索引中的數據,反而還會在對應的DELETED表中插入數據,所以索引會變的很是大。從因此中清理已經刪除的記錄,命令是OPTIMIZE TABLE
。可是這個命令會進行一些其餘操做,若是進但願對倒排索引進行操做,經過設置參數innodb_optimize_fulltext_only
進行設置。
set global innodb_optimize_fulltext_only = 1; optimize table fts_a;
若被刪除的文檔很是多,那麼OPTIMIZE TABLE
操可能須要佔用很是多的時間,會影響程序的併發性,能夠設置參數innodb_ft_num_word_optimize
來限制每次實際刪除的分詞數量。默認值爲2000。
一個demo:
建立表,添加全文檢索
CREATE TABLE fts_a( FTS_DOC_ID BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, body TEXT, PRIMARY KEY(FTS_DOC_ID); ) INSERT INTO fts_a select null, 'Pease porrideg in the pot'; INSERT INTO fts_a select null, 'Pease porrideg in the hot, pease porridege cold'; INSERT INTO fts_a select null, 'Nine days old'; CREATE FULLTEXT INDEX idx_fts ON fts_a(body);
經過設置參數查看分詞對應信息:
set global innodb_ft_aux_table='test/fts_a'; select * from information.innodb_ft_index_table;
刪除FTS_DOC_ID
爲3的文檔。
DELETE FROM test.fts_a where fts_doc_id = 3;
並不會直接刪除索引中對應的數據,而是將刪除的文檔ID插入到DELETED表,所以能夠進行查詢
select * from innodb_ft_deleted;
若是要完全刪除倒排索引中改文檔的分詞信息。執行
set global innodb_optimize_fulltext_only = 1; optimize table test.fts_a; select * from innodb_ft_deleted; select * from innodb_ft_being_deleted;
運行OPTIMIZE TABLE
能夠將記錄進行完全的刪除,而且完全刪除的文檔ID會記錄到表INNODB_FT_BEING_DELETED
中。此外,被刪除的文檔ID,不容許再次進行插入。
stopword
列表,表示在該列表中的word
不須要進行索引分詞操做。默認的表在information_schema
下的INNODB_FT_DEFAULT_STOPWORD
,默認共有36個stopword
。此外用戶也能夠經過參數innodb_ft_server_stopword_table
來自定義stopword
列表。
create table user_stopword ( value varchar(30) )ENGINE = INNODB; SET GLOBAL innodb_ft_server_stopword_table = "test/user_stopword";
INNODB全文檢索的限制:
語法爲:
MATCH(col1, col2, ...) AGAINST (expr (serch_modifier)) search_modifier: { IN NATURAL LANGUAGE MODE | IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION | IN BOOLEAN MODE | WITH QUERY EXPANSIONS }
Natural Language
經過MACTH函數進行查詢,默認採用的模式,表示查詢帶有指定word的文檔。
select * from fts_a where match(body) against('Porridge' IN NATURAL LANGUAGE MODE) select * from fts_a where match(body) against('Porridge');
在where條件中使用MATCH函數,其返回結果是根據相關性進行降序排序的,即相關性最高的結果放在第一位。相關性的值是一個非負的浮點數字。0表示咩有任何相關行。
相關性的計算依據的條件:
經過SQL語句查看相關性:
select fts_doc_id, body, Match(body) against('Porridge' IN NATURAL LANGUAGE MODE) as Relevance from fts_a;
INNODB存儲引擎的全文檢索,還須要考慮一下的因素:
[innodb_ft_min_token_size, innodb_ft_max_token_size]
內,不在內部,忽略該字符串的查詢。Boolean
使用IN BOOLEAN MODE
修飾符時,查詢字符串的先後字符會有特殊的含義。例如
#pease這個字符串必定存在但hot這個字符串不存在 select * from fts_a where match(body) against ('+Pease -hot' in boolean mode)\G;
Boolean
全文索引支持如下幾種操做符:
+表示該word必須存在
-表示該word必須被排除
(no operator)表示該word是可選的,可是若是出現,相關性會更高
@distance表示查詢的多個單詞之間的距離是否在distance以內,distance的單位是字節。這種全文檢索的查詢也成爲Proximity Search
,例如
match(body) against ('"Pease pot"@30' IN BOOLEAN MODE)
表示字符串Pease和hot之間的距離須要在30字節內。
'>'表示出現該單詞增長相關性
'<'表示出現該單詞下降相關性
'~'表示容許出現該單詞,可是出現時相關性爲負(全文檢索查詢容許負相關性)。
'*'表示以該單詞開的單詞
"表示短語。
Query Expansion
支持全文索引的擴展查詢。經過在查詢短語中添加WITH QUERY EXPANSION
或IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
能夠開啓bind query expansion
,查詢分爲兩個階段: