SQL Server 的全文搜索(Full-Text Search)是基于分词的文本检索功能,依赖于全文索引。全文索引不一样于传统的平衡树(B-Tree)索引和列存储索引,它是由数据表构成的,称做倒转索引(Invert Index),存储分词和行的惟一键的映射关系。倒转索引是在建立全文索引或更新全文索引时,由SQL Server自动建立和维护的。全文索引主要包含三种分析器:分词器(Word Breaker)、词干分析器(stemmer)和同义词分析器。全文索引中存储的数据是分词及其位置等信息,分词是基于特定语言的语法规则,按照特定的符号寻找词语的边界,把文本分解为“单词”,每个单词叫作一个分词(term);全文索引有时会提取分词的词干,把词干的多种派生形式存储为单一词干,这个过程叫作提取词干;根据用户提供的自定义同义词列表,把相关的单词转换为同义词,这个过程叫作提取同义词。html
生成全文索引是把用户表中的文本数据进行分词(Word breaker)和提取词干(Stemmer),并转换同义词(Thesaurus),过滤掉分词中的停用词(Stopword),最后把处理以后的数据存储到全文索引中。把数据存储到全文数据的过程叫作填充(Populate)或爬虫(Crawl)进程,全文索引的更新方式能够手动填充,自动填充,或增量填充。sql
一,全文搜索的基本组件数据库
1,分词器架构
分词器(Word Breaker),顾名思义,用于分词,它根据特定语言的语法规则,分割文本中的单词,分词器在拆分单词时,还会记录每一个分词在字符串中的位置,分词器把分词,分词的位置,文档ID,全文索引列的序号等信息的组合,称做标记(Token)。并发
例如,对于语句"Kitty is a cute cat",在全文索引填充时,分词器把该语句拆分红5个单词:Kitty,is,a,cute,cat。less
虽然停用词不会添加到全文索引中,可是分词的位置会被考虑。“Kitty” ,“cute” 和 “cat”的Position 分别是1,4 和 5。经过分词的位置,全文搜索ide
2,停用词函数
停用字词列表(StopList)是非索引字词的列表,每一个StopList中存储的分词都是不会用于搜索的分词,叫作停用词(StopWords),全文索引不会存储停用词,可是停用词所占的位置会被记录,若是对停用词进行contians查询,即便基础表(underly table)中的字段中存在该停用词,全文索引也不会返回任何数据行。一般状况下,停用词(Stopword)都是经常使用的单词,在语句中出现的频率十分高,过滤掉停用词,可以减小全文索引的size,提升全文查询的性能。post
3,词干(Stemmer) 和 同义词(Thesaurus)性能
同义词词典(Thesaurus)是一个XML文件,用于定义特定语言的同义词列表,例如,咱们能够设置“Author” , “Writer” ,“journalist”是同义词。
二,建立全文索引
建立全文索引以前,必须建立全文目录(Full-Text Catalog),全文目录用于组织全文索引,是全文索引的容器。每个全文索引必须属于一个全文目录。全文目录是个逻辑结构,跟数据库的架构(Schema)相同,根据全文索引的存储位置无关。
create fulltext catalog catalog_test as default;
为了建立全文索引,基础表上必须存在一个惟一的(unique)、单列的(single-column)、非空的(non-nullable)的索引,全文引擎使用该索引把基础表上的每行数据映射惟一索引键上,倒转索引存储的就是该索引键和分词之间的映射关系。
create unique index uidx_dbLogID on [dbo].[DatabaseLog] ([DatabaseLogID]);
每一个表只能建立一个全文索引,建立全文索引时,必须考虑全文索引存储的文件组,全文索引关联的停用词列表,全文索引的更新方式,以及跟文本关联的语言,全文索引列必须是文本字段,例如:
create fulltext index on [dbo].[DatabaseLog] ( [tsql] language 1033 ) key index ui_dbLogID on (catalog_test,filegroup [primary]) with(change_tracking=off ,no population ,stoplist=system);
1,语言(language)
选项 language 是可选的,用于指定列级别的语言,该选项的值能够是语言的名称或LCID,若是没有指定language选项,那么使用SQL Server实例的默认语言。从系统视图 sys.fulltext_languages (Transact-SQL)中查看系统支持的语言及其对应的LCID 和名称。
2,全文目录(fulltext_catalog)
选项fulltext_catalog_name 用于指定全文索引的分组,
3,文件组(filegroup)
选项 filegroup filegroup_name 用于指定全文索引存储的文件组,若是没有指定文件组,那么全文索引和基础表存储在相同的文件组中。因为更新全文索引是IO密集型操做,所以,为了更快的更新全文索引,最好把全文索引存储在不一样于基础表的的物理硬盘或文件组上,以达到最大的IO并发。
4,填充全文索引的方式
和普通的索引相同,当基础表数据更新时,全文索引必须自动更新,这是系统默认的行为,也能够配置手动更新全文索引,或者间隔特定的时间点自动更新全文索引。
选项CHANGE_TRACKING 用于指定跟全文索引列相关的数据更新(Update,Delete,或Insert)是否须要同步到全文索引,
5,停用词(STOPLIST)
停用词(StopWord)也称做噪音词,每个全文索引都会关联一个停用词列表,默认状况下,全文索引关联的是系统停用词(system stoplist)。全文引擎把停用词从分词中删除,使全文索引不会包含停用词。
STOPLIST [ = ] { OFF | SYSTEM | stoplist_name }
三,填充全文索引
填充全文索引也叫作爬虫(crawl)进程,或填充(Population)进程。因为建立或填充全文索引会消耗大量的系统(IO、内存)资源,所以尽可能选择在系统空闲时对全文索引进行填充。在建立全文索引时,经过指定选项 CHANGE_TRACKING= MANUAL,或 CHANGE_TRACKING= OFF, NO POPULATION,新建的全文索引不会当即填充,用户能够选择在系统空闲时,使用 alter fulltext index 语句执行填充操做。只有填充全文索引以后,全文索引才包含基础表的分词数据。
alter fulltext index on table_name start { full | incremental | update } population;
更新全文索引有三种方式:
在建立全文索引时,若是指定CHANGE_TRACKING=AUTO 或 CHANGE_TRACKING= OFF , 那么新建的全文索引会当即开始填充进程。
四,使用 contains 谓词查询全文索引
若是想要在查询中使用全文索引,一般使用CONTAINS谓词来调用全文索引,实现比LIKE关键字更复杂的文本匹配查询,而LIKE关键字是模糊匹配,不会调用全文索引。
例如,利用contains谓词执行单个分词的彻底匹配查询:
select [tsql] from [dbo].[DatabaseLog] where contains([tsql], 'searchword', language 1033);
全文查询跟Like相比,速度更快,支持的搜索功能更复杂,使用contains谓词,不只可以执行分词的彻底匹配或分词的前缀匹配查询,还可以执行基于词根的查询,基于自定义同义词的查询,基于距离和顺序的相邻分词查询。可是,和Like 相比,contains谓词不能进行后缀匹配查询。
contains谓词返回的结果是布尔值,若是全文索引列中包含指定的关键字或查找模式(pattern),返回TRUE;不然,返回FALSE。
contains谓词支持word查询和短语查询,word是指单个分词,短语(phrase)是由多个word和间隔的空格组成的,对于短语,必须使用双引号,将多个word组成一个短语。
1,逻辑组合查询
使用and ,and not, 或 or 逻辑运算符 匹配多个word 或 多个phrase
CONTAINS(Name, '"Mountain" OR "Road" ') CONTAINS(Name, ' Mountain OR Road ')
2,前缀查询
使用contains谓词进行前缀匹配,和like 'prefix%'功能相同,只不过contains谓词使用“*”做为通配符,“*”匹配0,1或多个字符,前缀匹配的写法是:'"prefix*"',全文索引只能执行前缀匹配。
CONTAINS(Name, ' "Chain*" ') CONTAINS(Name, '"chain*" OR "full*"')
3,查询同义词(thesaurus)或词干(stemmer)
Stemmer(词干),例如,根据语法规程,英语的动词 根据数(单数,复数),人称,时态的不一样而存在不一样的变化形式,这些单词都是同源的。
CONTAINS(Description, ' FORMSOF (INFLECTIONAL, ride) ')
THESAURUS (同义词),须要导入XML进行配置,SQL Server 提供一个默认的Thesaurus file,是Empty的。若是在Thesaurus file 配置“Author”,“Writer”,“journalist” 是同义词,在使用fulltext index查询时,只要知足任意一个同义词,都匹配成功。
CONTAINS(Description, ' FORMSOF (THESAURUS, author) ')
4,距离查询
使用 near 函数,查询匹配相邻分词的数据行,near函数的定义以下,用于须要在查询模式中指定距离查询的查询模式:
NEAR ( ( { <simple_term> | <prefix_term> } [ ,…n ] ) [, <maximum_distance> ] [, <match_order> ] )
例如:使用Near 函数指定相邻分词的距离和匹配顺序,near((term1,term2,term3),5)表示任意两个term之间的距离不能超过5, near((term1,term2,term3),5,true),表示任意两个term的距离不能超过5,而且按照 term1,term2,term3的顺序存在于字符串中。
--regardless of the intervening distance and regardless of order CONTAINS(column_name, 'NEAR(term1,"term3 term4")') --searches for "AA" and "BB", in either order, within a maximum distance of five CONTAINS(column_name, 'NEAR((AA,BB),5)') --in the specified order with regardless of the distance CONTAINS(column_name, 'NEAR ((Monday, Tuesday, Wednesday), MAX, TRUE)')
对于 near((term1,term2,term3),5,true),term1 和 term5之间最多存在5个term,不包括内部的搜索分词,“term2”,例如:
CONTAINS(column_name, 'NEAR((AA,BB,CC),5)')
这个查询会匹配下面的文本,注意,内部的搜索分词CC没有计算距离:
BB one two CC three four five AA
例如,在原文本中,分词bike和control的最大距离不能超过10,分词bike必须出如今分词control的前面:
CONTAINS(Comments , 'NEAR((bike,control), 10, TRUE)')
SQL Server提供的全文搜索功能,比LIKE关键字丰富,具有初级的全文搜索功能,速度快,维护简单,缺点是,全文搜索功能很是有限,在实际的开发中,能够配合开源的全文搜索引擎,例如,Solr,Elasticsearch等来开发功能更强大的全文搜索功能。
参考文档:
CREATE FULLTEXT CATALOG (Transact-SQL)