经过索引字段的前缀进行查找,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
,查询分为两个阶段: